diff --git a/common/constant.go b/common/constant.go index 39e5f71..d393cd4 100644 --- a/common/constant.go +++ b/common/constant.go @@ -67,13 +67,13 @@ const ( GameID_ThirteenFree = 213 // 十三张(自由场经典场) GameID_ThirteenFreeLaiZi = 214 // 十三张(自由场癞子场) __GameId_Slot_Min__ = 300 //################拉霸类################ - GameId_CaiShen = 301 //财神 - GameId_Avengers = 302 //复仇者联盟 - GameId_EasterIsland = 303 //复活岛 - GameId_IceAge = 304 //冰河世纪 - GameId_TamQuoc = 305 //百战成神 - GameId_Fruits = 306 //水果拉霸 - GameId_Richblessed = 307 //多福多财 + GameId_CaiShen = 301 // 财神 + GameId_Avengers = 302 // 复仇者联盟 + GameId_EasterIsland = 303 // 复活岛 + GameId_IceAge = 304 // 冰河世纪 + GameId_TamQuoc = 305 // 百战成神 + GameId_Fruits = 306 // 水果拉霸 + GameId_Richblessed = 307 // 多福多财 __GameId_Fishing_Min__ = 400 //################捕鱼类################ GameId_HFishing = 401 //欢乐捕鱼 GameId_TFishing = 402 //天天捕鱼 diff --git a/data/DB_GameFree.dat b/data/DB_GameFree.dat index 99b1926..4099424 100644 Binary files a/data/DB_GameFree.dat and b/data/DB_GameFree.dat differ diff --git a/data/DB_GameFree.json b/data/DB_GameFree.json index 4b11fa4..19bd0cb 100644 --- a/data/DB_GameFree.json +++ b/data/DB_GameFree.json @@ -3508,383 +3508,6 @@ "MatchMode": 1, "BetWaterRate": 100 }, - { - "Id": 3040001, - "Name": "冰河世纪", - "Title": "新手场", - "GameId": 304, - "GameRule": 30400, - "GameType": 3, - "SceneType": 1, - "Desc": "0", - "ShowType": 2, - "ShowId": 82000, - "LimitCoin": 500000, - "LowerThanKick": 800, - "BaseScore": 1000, - "Turn": 82000, - "BetDec": "20 ", - "Ai": [ - 0 - ], - "OtherIntParams": [ - 0 - ], - "Jackpot": [ - 5000, - 25, - 100 - ], - "RobotNumRng": [ - 0 - ], - "RobotTakeCoin": [ - 2000, - 20000 - ], - "RobotLimitCoin": [ - 40000, - 80000 - ], - "GameDif": "304", - "GameClass": 2, - "PlatformName": "越南棋牌", - "MaxBetCoin": [ - 0 - ], - "PlayerWaterRate": 100, - "BetWaterRate": 100 - }, - { - "Id": 3040002, - "Name": "冰河世纪", - "Title": "大众场", - "GameId": 304, - "GameRule": 30400, - "GameType": 3, - "SceneType": 2, - "Desc": "0", - "ShowType": 2, - "ShowId": 82000, - "LimitCoin": 20000000, - "LowerThanKick": 2000, - "BaseScore": 50000, - "Turn": 82000, - "BetDec": "50 ", - "Ai": [ - 0 - ], - "OtherIntParams": [ - 0 - ], - "Jackpot": [ - 5000, - 20, - 50 - ], - "RobotNumRng": [ - 0 - ], - "RobotTakeCoin": [ - 5000, - 50000 - ], - "RobotLimitCoin": [ - 100000, - 200000 - ], - "GameDif": "304", - "GameClass": 2, - "PlatformName": "越南棋牌", - "MaxBetCoin": [ - 0 - ], - "PlayerWaterRate": 100, - "BetWaterRate": 100 - }, - { - "Id": 3040003, - "Name": "冰河世纪", - "Title": "富豪场", - "GameId": 304, - "GameRule": 30400, - "GameType": 3, - "SceneType": 3, - "Desc": "0", - "ShowType": 2, - "ShowId": 82000, - "LimitCoin": 40000000, - "LowerThanKick": 5000, - "BaseScore": 100000, - "Turn": 82000, - "BetDec": "500 ", - "Ai": [ - 0 - ], - "OtherIntParams": [ - 0 - ], - "Jackpot": [ - 5000, - 15, - 40 - ], - "RobotNumRng": [ - 0 - ], - "GameDif": "304", - "GameClass": 2, - "PlatformName": "越南棋牌", - "MaxBetCoin": [ - 0 - ], - "PlayerWaterRate": 100, - "BetWaterRate": 100 - }, - { - "Id": 3060001, - "Name": "水果拉霸", - "Title": "初级场", - "GameId": 306, - "GameRule": 30600, - "GameType": 3, - "SceneType": 1, - "Desc": "0", - "ShowType": 3, - "ShowId": 33001, - "LimitCoin": 10000, - "BaseScore": 100, - "Turn": 48000, - "BetDec": "1000", - "Ai": [ - 0 - ], - "OtherIntParams": [ - 900, - 1800, - 2700, - 3600, - 4500 - ], - "Jackpot": [ - 0 - ], - "RobotNumRng": [ - 1, - 3 - ], - "RobotTakeCoin": [ - 80000, - 500000 - ], - "RobotLimitCoin": [ - 1000000, - 2000000 - ], - "SameIpLimit": 1, - "GameDif": "306", - "GameClass": 2, - "PlatformName": "越南棋牌", - "MaxBetCoin": [ - 0 - ], - "CreateRoomNum": 1, - "MatchTrueMan": 1, - "PlayerWaterRate": 100, - "BetWaterRate": 100, - "BalanceLine": [ - -10000, - -5000, - 0, - 5000, - 10000 - ], - "JackpotRatio": 1, - "JackpotMin": 100000 - }, - { - "Id": 3060002, - "Name": "水果拉霸", - "Title": "中级场", - "GameId": 306, - "GameRule": 30600, - "GameType": 3, - "SceneType": 2, - "Desc": "0", - "ShowType": 3, - "ShowId": 33001, - "LimitCoin": 100000, - "BaseScore": 1000, - "Turn": 48000, - "BetDec": "1000", - "Ai": [ - 0 - ], - "OtherIntParams": [ - 9000, - 18000, - 27000, - 36000, - 45000 - ], - "Jackpot": [ - 0 - ], - "RobotNumRng": [ - 1, - 3 - ], - "RobotTakeCoin": [ - 80000, - 500000 - ], - "RobotLimitCoin": [ - 1000000, - 2000000 - ], - "SameIpLimit": 1, - "GameDif": "306", - "GameClass": 2, - "PlatformName": "越南棋牌", - "MaxBetCoin": [ - 0 - ], - "CreateRoomNum": 1, - "MatchTrueMan": 1, - "PlayerWaterRate": 100, - "BetWaterRate": 100, - "BalanceLine": [ - -10000, - -5000, - 0, - 5000, - 10000 - ], - "JackpotRatio": 1, - "JackpotMin": 1000000 - }, - { - "Id": 3060003, - "Name": "水果拉霸", - "Title": "高级场", - "GameId": 306, - "GameRule": 30600, - "GameType": 3, - "SceneType": 3, - "Desc": "0", - "ShowType": 3, - "ShowId": 33001, - "LimitCoin": 1000000, - "BaseScore": 10000, - "Turn": 48000, - "BetDec": "1000", - "Ai": [ - 0 - ], - "OtherIntParams": [ - 90000, - 180000, - 270000, - 360000, - 450000 - ], - "Jackpot": [ - 0 - ], - "RobotNumRng": [ - 1, - 3 - ], - "RobotTakeCoin": [ - 80000, - 500000 - ], - "RobotLimitCoin": [ - 1000000, - 2000000 - ], - "SameIpLimit": 1, - "GameDif": "306", - "GameClass": 2, - "PlatformName": "越南棋牌", - "MaxBetCoin": [ - 0 - ], - "CreateRoomNum": 1, - "MatchTrueMan": 1, - "PlayerWaterRate": 100, - "BetWaterRate": 100, - "BalanceLine": [ - -10000, - -5000, - 0, - 5000, - 10000 - ], - "JackpotRatio": 1, - "JackpotMin": 10000000 - }, - { - "Id": 3060004, - "Name": "水果拉霸", - "Title": "大师场", - "GameId": 306, - "GameRule": 30600, - "GameType": 3, - "SceneType": 4, - "Desc": "0", - "ShowType": 3, - "ShowId": 33001, - "LimitCoin": 10000000, - "BaseScore": 100000, - "Turn": 48000, - "BetDec": "1000", - "Ai": [ - 0 - ], - "OtherIntParams": [ - 900000, - 1800000, - 2700000, - 3600000, - 4500000 - ], - "Jackpot": [ - 0 - ], - "RobotNumRng": [ - 1, - 3 - ], - "RobotTakeCoin": [ - 80000, - 500000 - ], - "RobotLimitCoin": [ - 1000000, - 2000000 - ], - "SameIpLimit": 1, - "GameDif": "306", - "GameClass": 2, - "PlatformName": "越南棋牌", - "MaxBetCoin": [ - 0 - ], - "CreateRoomNum": 1, - "MatchTrueMan": 1, - "PlayerWaterRate": 100, - "BetWaterRate": 100, - "BalanceLine": [ - -10000, - -5000, - 0, - 5000, - 10000 - ], - "JackpotRatio": 1, - "JackpotMin": 100000000 - }, { "Id": 4010001, "Name": "欢乐捕鱼", @@ -5854,6 +5477,1050 @@ "CreateRoomNum": 1, "PlayerWaterRate": 100, "BetWaterRate": 100 + }, + { + "Id": 3010001, + "Name": "财运神", + "Title": "新手场", + "GameId": 301, + "GameRule": 30100, + "GameType": 3, + "SceneType": 1, + "Desc": "0", + "ShowType": 2, + "ShowId": 79000, + "LimitCoin": 500000, + "LowerThanKick": 800, + "BaseScore": 1000, + "Turn": 79000, + "BetDec": "20 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 50, + 100 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "301", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3010002, + "Name": "财运神", + "Title": "大众场", + "GameId": 301, + "GameRule": 30100, + "GameType": 3, + "SceneType": 2, + "Desc": "0", + "ShowType": 2, + "ShowId": 79000, + "LimitCoin": 5000000, + "LowerThanKick": 2000, + "BaseScore": 10000, + "Turn": 79000, + "BetDec": "50 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 40, + 60 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "301", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3010003, + "Name": "财运神", + "Title": "富豪场", + "GameId": 301, + "GameRule": 30100, + "GameType": 3, + "SceneType": 3, + "Desc": "0", + "ShowType": 2, + "ShowId": 79000, + "LimitCoin": 25000000, + "LowerThanKick": 5000, + "BaseScore": 50000, + "Turn": 79000, + "BetDec": "250", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 30, + 50 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "301", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3010004, + "Name": "财运神", + "Title": "至尊场", + "GameId": 301, + "GameRule": 30100, + "GameType": 3, + "SceneType": 4, + "Desc": "0", + "ShowType": 2, + "ShowId": 79000, + "LimitCoin": 50000000, + "LowerThanKick": 25000, + "BaseScore": 100000, + "Turn": 79000, + "BetDec": "500", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 20, + 40 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "301", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3020001, + "Name": "复仇者联盟", + "Title": "新手场", + "GameId": 302, + "GameRule": 30200, + "GameType": 3, + "SceneType": 1, + "Desc": "0", + "ShowType": 2, + "ShowId": 80000, + "LimitCoin": 500000, + "LowerThanKick": 800, + "BaseScore": 1000, + "Turn": 80000, + "BetDec": "20 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 50, + 100 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "302", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3020002, + "Name": "复仇者联盟", + "Title": "大众场", + "GameId": 302, + "GameRule": 30200, + "GameType": 3, + "SceneType": 2, + "Desc": "0", + "ShowType": 2, + "ShowId": 80000, + "LimitCoin": 5000000, + "LowerThanKick": 2000, + "BaseScore": 10000, + "Turn": 80000, + "BetDec": "50 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 40, + 60 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "302", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3020003, + "Name": "复仇者联盟", + "Title": "富豪场", + "GameId": 302, + "GameRule": 30200, + "GameType": 3, + "SceneType": 3, + "Desc": "0", + "ShowType": 2, + "ShowId": 80000, + "LimitCoin": 25000000, + "LowerThanKick": 5000, + "BaseScore": 50000, + "Turn": 80000, + "BetDec": "250", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 30, + 50 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "302", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3020004, + "Name": "复仇者联盟", + "Title": "至尊场", + "GameId": 302, + "GameRule": 30200, + "GameType": 3, + "SceneType": 4, + "Desc": "0", + "ShowType": 2, + "ShowId": 80000, + "LimitCoin": 50000000, + "LowerThanKick": 25000, + "BaseScore": 100000, + "Turn": 80000, + "BetDec": "500 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 20, + 40 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "302", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3030001, + "Name": "复活节岛", + "Title": "新手场", + "GameId": 303, + "GameRule": 30300, + "GameType": 3, + "SceneType": 1, + "Desc": "0", + "ShowType": 2, + "ShowId": 81000, + "LimitCoin": 500000, + "LowerThanKick": 800, + "BaseScore": 1000, + "Turn": 81000, + "BetDec": "20 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 50, + 100 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "303", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3030002, + "Name": "复活节岛", + "Title": "大众场", + "GameId": 303, + "GameRule": 30300, + "GameType": 3, + "SceneType": 2, + "Desc": "0", + "ShowType": 2, + "ShowId": 81000, + "LimitCoin": 5000000, + "LowerThanKick": 2000, + "BaseScore": 10000, + "Turn": 81000, + "BetDec": "50 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 40, + 60 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "303", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3030003, + "Name": "复活节岛", + "Title": "富豪场", + "GameId": 303, + "GameRule": 30300, + "GameType": 3, + "SceneType": 3, + "Desc": "0", + "ShowType": 2, + "ShowId": 81000, + "LimitCoin": 25000000, + "LowerThanKick": 5000, + "BaseScore": 50000, + "Turn": 81000, + "BetDec": "250", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 30, + 50 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "303", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3030004, + "Name": "复活节岛", + "Title": "至尊场", + "GameId": 303, + "GameRule": 30300, + "GameType": 3, + "SceneType": 4, + "Desc": "0", + "ShowType": 2, + "ShowId": 81000, + "LimitCoin": 50000000, + "LowerThanKick": 25000, + "BaseScore": 100000, + "Turn": 81000, + "BetDec": "500", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 20, + 40 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "303", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3040001, + "Name": "冰河世纪", + "Title": "新手场", + "GameId": 304, + "GameRule": 30400, + "GameType": 3, + "SceneType": 1, + "Desc": "0", + "ShowType": 2, + "ShowId": 82000, + "LimitCoin": 500000, + "LowerThanKick": 800, + "BaseScore": 1000, + "Turn": 82000, + "BetDec": "20 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 25, + 100 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "304", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3040002, + "Name": "冰河世纪", + "Title": "大众场", + "GameId": 304, + "GameRule": 30400, + "GameType": 3, + "SceneType": 2, + "Desc": "0", + "ShowType": 2, + "ShowId": 82000, + "LimitCoin": 20000000, + "LowerThanKick": 2000, + "BaseScore": 50000, + "Turn": 82000, + "BetDec": "50 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 20, + 50 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "304", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3040003, + "Name": "冰河世纪", + "Title": "富豪场", + "GameId": 304, + "GameRule": 30400, + "GameType": 3, + "SceneType": 3, + "Desc": "0", + "ShowType": 2, + "ShowId": 82000, + "LimitCoin": 40000000, + "LowerThanKick": 5000, + "BaseScore": 100000, + "Turn": 82000, + "BetDec": "500 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 15, + 40 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "304", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3050001, + "Name": "百战成神", + "Title": "新手场", + "GameId": 305, + "GameRule": 30500, + "GameType": 3, + "SceneType": 1, + "Desc": "0", + "ShowType": 2, + "ShowId": 83000, + "LimitCoin": 500000, + "LowerThanKick": 800, + "BaseScore": 1000, + "Turn": 83000, + "BetDec": "20 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 70, + 150, + 30, + 5 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "305", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3050002, + "Name": "百战成神", + "Title": "大众场", + "GameId": 305, + "GameRule": 30500, + "GameType": 3, + "SceneType": 2, + "Desc": "0", + "ShowType": 2, + "ShowId": 83000, + "LimitCoin": 25000000, + "LowerThanKick": 2000, + "BaseScore": 50000, + "Turn": 83000, + "BetDec": "50 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 70, + 150, + 120, + 10 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "305", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3050003, + "Name": "百战成神", + "Title": "富豪场", + "GameId": 305, + "GameRule": 30500, + "GameType": 3, + "SceneType": 3, + "Desc": "0", + "ShowType": 2, + "ShowId": 83000, + "LimitCoin": 50000000, + "LowerThanKick": 5000, + "BaseScore": 100000, + "Turn": 83000, + "BetDec": "500 ", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 70, + 150, + 180, + 30 + ], + "RobotNumRng": [ + 0 + ], + "GameDif": "305", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3060001, + "Name": "水果拉霸", + "Title": "初级场", + "GameId": 306, + "GameRule": 30600, + "GameType": 3, + "SceneType": 1, + "Desc": "0", + "ShowType": 2, + "ShowId": 33001, + "LimitCoin": 10000, + "LowerThanKick": 800, + "BaseScore": 1000, + "Turn": 48000, + "BetDec": "1000", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 50, + 100 + ], + "RobotNumRng": [ + 0 + ], + "SameIpLimit": 1, + "GameDif": "306", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "CreateRoomNum": 1, + "MatchTrueMan": 1, + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3060002, + "Name": "水果拉霸", + "Title": "中级场", + "GameId": 306, + "GameRule": 30600, + "GameType": 3, + "SceneType": 2, + "Desc": "0", + "ShowType": 2, + "ShowId": 33001, + "LimitCoin": 100000, + "LowerThanKick": 2000, + "BaseScore": 10000, + "Turn": 48000, + "BetDec": "1000", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 40, + 60 + ], + "RobotNumRng": [ + 0 + ], + "SameIpLimit": 1, + "GameDif": "306", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "CreateRoomNum": 1, + "MatchTrueMan": 1, + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3060003, + "Name": "水果拉霸", + "Title": "高级场", + "GameId": 306, + "GameRule": 30600, + "GameType": 3, + "SceneType": 3, + "Desc": "0", + "ShowType": 2, + "ShowId": 33001, + "LimitCoin": 1000000, + "LowerThanKick": 5000, + "BaseScore": 50000, + "Turn": 48000, + "BetDec": "1000", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 30, + 50 + ], + "RobotNumRng": [ + 0 + ], + "SameIpLimit": 1, + "GameDif": "306", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "CreateRoomNum": 1, + "MatchTrueMan": 1, + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3060004, + "Name": "水果拉霸", + "Title": "大师场", + "GameId": 306, + "GameRule": 30600, + "GameType": 3, + "SceneType": 4, + "Desc": "0", + "ShowType": 2, + "ShowId": 33001, + "LimitCoin": 10000000, + "LowerThanKick": 25000, + "BaseScore": 100000, + "Turn": 48000, + "BetDec": "1000", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 20, + 40 + ], + "RobotNumRng": [ + 0 + ], + "SameIpLimit": 1, + "GameDif": "306", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "CreateRoomNum": 1, + "MatchTrueMan": 1, + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3070001, + "Name": "多福多财", + "Title": "初级场", + "GameId": 307, + "GameRule": 30700, + "GameType": 3, + "SceneType": 1, + "Desc": "0", + "ShowType": 2, + "ShowId": 34001, + "LimitCoin": 10000, + "LowerThanKick": 800, + "BaseScore": 1000, + "Turn": 49000, + "BetDec": "1000", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 50, + 100 + ], + "RobotNumRng": [ + 0 + ], + "SameIpLimit": 1, + "GameDif": "307", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "CreateRoomNum": 1, + "MatchTrueMan": 1, + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3070002, + "Name": "多福多财", + "Title": "中级场", + "GameId": 307, + "GameRule": 30700, + "GameType": 3, + "SceneType": 2, + "Desc": "0", + "ShowType": 2, + "ShowId": 34001, + "LimitCoin": 100000, + "LowerThanKick": 2000, + "BaseScore": 10000, + "Turn": 49000, + "BetDec": "1000", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 40, + 60 + ], + "RobotNumRng": [ + 0 + ], + "SameIpLimit": 1, + "GameDif": "307", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "CreateRoomNum": 1, + "MatchTrueMan": 1, + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3070003, + "Name": "多福多财", + "Title": "高级场", + "GameId": 307, + "GameRule": 30700, + "GameType": 3, + "SceneType": 3, + "Desc": "0", + "ShowType": 2, + "ShowId": 34001, + "LimitCoin": 1000000, + "LowerThanKick": 5000, + "BaseScore": 50000, + "Turn": 49000, + "BetDec": "1000", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 30, + 50 + ], + "RobotNumRng": [ + 0 + ], + "SameIpLimit": 1, + "GameDif": "307", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "CreateRoomNum": 1, + "MatchTrueMan": 1, + "PlayerWaterRate": 100, + "BetWaterRate": 100 + }, + { + "Id": 3070004, + "Name": "多福多财", + "Title": "大师场", + "GameId": 307, + "GameRule": 30700, + "GameType": 3, + "SceneType": 4, + "Desc": "0", + "ShowType": 2, + "ShowId": 34001, + "LimitCoin": 10000000, + "LowerThanKick": 25000, + "BaseScore": 100000, + "Turn": 49000, + "BetDec": "1000", + "Ai": [ + 0 + ], + "OtherIntParams": [ + 0 + ], + "Jackpot": [ + 5000, + 20, + 40 + ], + "RobotNumRng": [ + 0 + ], + "SameIpLimit": 1, + "GameDif": "307", + "GameClass": 2, + "PlatformName": "越南棋牌", + "MaxBetCoin": [ + 0 + ], + "CreateRoomNum": 1, + "MatchTrueMan": 1, + "PlayerWaterRate": 100, + "BetWaterRate": 100 } ] } \ No newline at end of file diff --git a/data/DB_GameRule.dat b/data/DB_GameRule.dat index 5c70ce3..814c530 100644 Binary files a/data/DB_GameRule.dat and b/data/DB_GameRule.dat differ diff --git a/data/DB_GameRule.json b/data/DB_GameRule.json index 599ed27..626dccc 100644 --- a/data/DB_GameRule.json +++ b/data/DB_GameRule.json @@ -54,18 +54,6 @@ "GameId": 401, "GameDif": "401" }, - { - "Id": 30600, - "Name": "水果拉霸", - "GameId": 306, - "GameDif": "306" - }, - { - "Id": 30400, - "Name": "冰河世纪", - "GameId": 304, - "GameDif": "304" - }, { "Id": 52100, "Name": "ChessCambodian", @@ -165,6 +153,48 @@ "Name": "小火箭", "GameId": 607, "GameDif": "607" + }, + { + "Id": 30100, + "Name": "财运神", + "GameId": 301, + "GameDif": "301" + }, + { + "Id": 30200, + "Name": "复仇者联盟", + "GameId": 302, + "GameDif": "302" + }, + { + "Id": 30300, + "Name": "复活节岛", + "GameId": 303, + "GameDif": "303" + }, + { + "Id": 30400, + "Name": "冰河世纪", + "GameId": 304, + "GameDif": "304" + }, + { + "Id": 30500, + "Name": "百战成神", + "GameId": 305, + "GameDif": "305" + }, + { + "Id": 30600, + "Name": "水果拉霸", + "GameId": 306, + "GameDif": "306" + }, + { + "Id": 30700, + "Name": "多财多福", + "GameId": 307, + "GameDif": "307" } ] } \ No newline at end of file diff --git a/data/DB_PropExchange.dat b/data/DB_PropExchange.dat index 5b4f370..c47bf25 100644 --- a/data/DB_PropExchange.dat +++ b/data/DB_PropExchange.dat @@ -1,5 +1,5 @@ -6׆ӆԆՆֆ"= +6ֆ׆ӆԆՆ"= .؆نچۆ"= -WՆֆۆӆ׆؆نچԆ"  -]؆ن܆ӆԆՆֆ׆چۆ" \ No newline at end of file +WӆֆԆՆ׆؆نچۆ"  +]ԆՆن܆چۆӆֆ׆؆" \ No newline at end of file diff --git a/data/DB_Task.dat b/data/DB_Task.dat index 5c2c40e..bd1eeed 100644 Binary files a/data/DB_Task.dat and b/data/DB_Task.dat differ diff --git a/gamesrv/avengers/action_avengers.go b/gamesrv/avengers/action_avengers.go new file mode 100644 index 0000000..6950891 --- /dev/null +++ b/gamesrv/avengers/action_avengers.go @@ -0,0 +1,54 @@ +package avengers + +import ( + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/netlib" + + "mongo.games.com/game/common" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/protocol/avengers" +) + +// 复仇者联盟的操作 +type CSAvengersOpPacketFactory struct { +} +type CSAvengersOpHandler struct { +} + +func (this *CSAvengersOpPacketFactory) CreatePacket() interface{} { + pack := &avengers.CSAvengersOp{} + return pack +} +func (this *CSAvengersOpHandler) Process(s *netlib.Session, packetid int, data interface{}, sid int64) error { + logger.Logger.Trace("CSAvengersOpHandler Process recv ", data) + if csAvengersOp, ok := data.(*avengers.CSAvengersOp); ok { + p := base.PlayerMgrSington.GetPlayer(sid) + if p == nil { + logger.Logger.Warn("CSAvengersOpHandler p == nil") + return nil + } + scene := p.GetScene() + if scene == nil { + logger.Logger.Warn("CSAvengersOpHandler p.scene == nil") + return nil + } + if scene.GameId != common.GameId_Avengers { + logger.Logger.Error("CSAvengersOpHandler gameId Error ", scene.GameId) + return nil + } + if !scene.HasPlayer(p) { + return nil + } + sp := scene.GetScenePolicy() + if sp != nil { + sp.OnPlayerOp(scene, p, int(csAvengersOp.GetOpCode()), csAvengersOp.GetParams()) + } + return nil + } + return nil +} +func init() { + // 复仇者联盟的操作 + common.RegisterHandler(int(avengers.AvengersPacketID_PACKET_CS_AVENGERS_PLAYEROP), &CSAvengersOpHandler{}) + netlib.RegisterFactory(int(avengers.AvengersPacketID_PACKET_CS_AVENGERS_PLAYEROP), &CSAvengersOpPacketFactory{}) +} diff --git a/gamesrv/avengers/constant.go b/gamesrv/avengers/constant.go new file mode 100644 index 0000000..52ff2b0 --- /dev/null +++ b/gamesrv/avengers/constant.go @@ -0,0 +1,116 @@ +package avengers + +import ( + "encoding/json" + "time" + + "mongo.games.com/game/model" +) + +// 玩家游戏数据索引 +const ( + AvengersFreeTimes int = iota //0 当前剩余免费次数 + AvengersIndexMax +) + +// 场景状态 +const ( + AvengersSceneStateStart int = iota //开始游戏 + AvengersSceneStateMax +) + +// 玩家操作 +const ( + AvengersPlayerOpStart int = iota //游戏 + AvengersPlayerHistory // 游戏记录 + AvengersBurstHistory // 奖池记录 + AvengersBonusGame // 小游戏 + AvengersBonusGameRecord // 小游戏操作记录 +) + +const ( + AvengersBonusGameTimeout = time.Second * 60 // 小游戏最大超时时间 + AvengersBonusGameStageTimeout = 15 // 小游戏每阶段的超时时间 秒 +) + +type GameResultLog struct { + BaseResult *model.SlotBaseResultType + AllLine int32 //线路数 + UserName string //昵称 + WinLines []int //赢分的线 + BetLines []int64 //下注的线 +} + +// 复仇者联盟解析的数据 +type AvengersGameNoteData struct { + Source int32 + Data *GameResultLog +} + +// 复仇者联盟游戏记录 +func UnMarshalAvengersGameNote(data string) (roll interface{}, err error) { + gnd := &AvengersGameNoteData{} + if err := json.Unmarshal([]byte(data), gnd); err != nil { + return nil, err + } + roll = gnd.Data + return +} + +var DebugData = [][]int{ + { + 5, 5, 8, 4, 5, + 4, 4, 1, 4, 1, + 4, 4, 2, 4, 10, + }, + { + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, + }, + { + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, + }, + { + 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, + }, + { + 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, + }, + { + 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, + }, + { + 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, + }, + { + 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, + }, + { + 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, + }, + { + 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, + }, + { + 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, + }, +} diff --git a/gamesrv/avengers/playerdata_avengers.go b/gamesrv/avengers/playerdata_avengers.go new file mode 100644 index 0000000..21637bf --- /dev/null +++ b/gamesrv/avengers/playerdata_avengers.go @@ -0,0 +1,156 @@ +package avengers + +import ( + "encoding/json" + "math/rand" + + "mongo.games.com/goserver/core/timer" + + rule "mongo.games.com/game/gamerule/avengers" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/protocol/avengers" +) + +type AvengersPlayerData struct { + *base.Player + spinID int64 //当前旋转ID + score int32 //单线押注数 + freeTimes int32 //免费转动次数 + cards []int32 //15张牌 + //RollGameType *model.AvengersType //记录信息 + RollGameType *GameResultLog //记录信息 + enterGameCoin int64 //玩家进入初始金币 + taxCoin int64 //本局税收 + winCoin int64 //本局收税前赢的钱 + linesWinCoin int64 //本局中奖线赢得钱 + jackpotWinCoin int64 //本局奖池赢的钱 + smallGameWinCoin int64 //本局小游戏赢的钱 + betLines []int64 //下注的选线 + currentLogId string //爆奖玩家logid + leavetime int32 //用户离开时间 + totalPriceBonus int64 //小游戏得分 + bonusTimerHandle timer.TimerHandle //托管超时handle + bonusStage int32 //小游戏所处阶段 1选金额 2选倍率 + bonusStartTime int64 //小游戏阶段开始时间 + bonusOpRecord []int32 //小游戏操作记录 + bonusGame *avengers.AvengersBonusGameInfo //小游戏 + bonusX []int32 //小游戏倍率选项 + billedData *avengers.GameBilledData //上一局结算信息 + DebugGame bool //测试 + TestNum int +} + +// 玩家初始化 +func (this *AvengersPlayerData) init(s *base.Scene) { + this.Clean() + this.score = 0 + this.freeTimes = 0 + //this.RollGameType = &model.AvengersType{} + //this.RollGameType.Init() + this.RollGameType = &GameResultLog{} + this.RollGameType.BaseResult = &model.SlotBaseResultType{} + this.enterGameCoin = this.Coin + this.currentLogId = "" + this.billedData = &avengers.GameBilledData{} + this.DebugGame = true + this.TestNum = 0 + + // 加载玩家游戏数据 + if this.GDatas == nil { + this.GDatas = make(map[string]*model.PlayerGameInfo) + } + + if d, exist := this.GDatas[s.KeyGamefreeId]; exist { + gLen := len(d.Data) + if gLen < AvengersIndexMax { + for i := gLen; i < AvengersIndexMax; i++ { + d.Data = append(d.Data, 0) + } + } + } else { + pgd := &model.PlayerGameInfo{ + Data: make([]int64, AvengersIndexMax), + } + this.GDatas[s.KeyGamefreeId] = pgd + } + this.LoadPlayerGameData(s.KeyGamefreeId) + //线条全选 + if len(this.betLines) == 0 { + this.betLines = rule.AllBetLines + } +} + +// 玩家清理数据 +func (this *AvengersPlayerData) Clean() { + for i := 0; i < len(this.cards); i++ { + this.cards[i] = -1 + } + this.winCoin = 0 + this.taxCoin = 0 + this.linesWinCoin = 0 + this.jackpotWinCoin = 0 + this.smallGameWinCoin = 0 + this.CleanBonus() +} + +// 清理小游戏数据 +func (this *AvengersPlayerData) CleanBonus() { + this.totalPriceBonus = 0 + this.bonusStage = 0 + this.bonusTimerHandle = timer.TimerHandle(0) + this.bonusStartTime = 0 + this.bonusOpRecord = make([]int32, 0) + this.bonusGame = nil + this.bonusX = nil +} + +// 加载玩家游戏数据 +func (this *AvengersPlayerData) LoadPlayerGameData(gameFreeId string) { + if d, exist := this.GDatas[gameFreeId]; exist { + this.freeTimes = int32(d.Data[AvengersFreeTimes]) + if this.freeTimes > 0 && len(d.DataEx) != 0 { + json.Unmarshal(d.DataEx, &this.betLines) + } + } +} + +// 存储玩家游戏数据 +func (this *AvengersPlayerData) SavePlayerGameData(gameFreeId string) { + if d, exist := this.GDatas[gameFreeId]; exist { + d.Data[AvengersFreeTimes] = int64(this.freeTimes) + d.DataEx, _ = json.Marshal(this.betLines) + } +} + +// 黑白名单的限制是否生效 +func (this *AvengersPlayerData) CheckBlackWriteList(isWin bool) bool { + if isWin && this.BlackLevel > 0 && this.BlackLevel <= 10 { + if rand.Int31n(100) < this.BlackLevel*10 { + return true + } + } else if !isWin && this.WhiteLevel > 0 && this.WhiteLevel <= 10 { + if rand.Int31n(100) < this.WhiteLevel*10 { + return true + } + } + return false +} + +// 玩家是否是新手 +func (this *AvengersPlayerData) IsFNovice(keyGameId string) { + if f, ok := this.IsFoolPlayer[keyGameId]; ok { + if !f { + return + } + } else { + this.IsFoolPlayer[keyGameId] = true + return + } + if data, ok := this.GDatas[keyGameId]; ok { + if data.Statics.GameTimes < 100 && data.Statics.TotalOut-data.Statics.TotalIn <= 2000000 { + return + } + this.IsFoolPlayer[keyGameId] = false + } +} diff --git a/gamesrv/avengers/scenedata_avengers.go b/gamesrv/avengers/scenedata_avengers.go new file mode 100644 index 0000000..f412299 --- /dev/null +++ b/gamesrv/avengers/scenedata_avengers.go @@ -0,0 +1,339 @@ +package avengers + +import ( + "encoding/json" + "math" + "math/rand" + "time" + + "mongo.games.com/game/common" + rule "mongo.games.com/game/gamerule/avengers" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/proto" + "mongo.games.com/game/protocol/avengers" + "mongo.games.com/game/protocol/gamehall" + "mongo.games.com/goserver/core/basic" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/task" +) + +type AvengersJackpot struct { + createdTime time.Time + userName string + priceValue int64 + roomID int64 + spinID string +} + +type AvengersSceneData struct { + *base.Scene //房间信息 + players map[int32]*AvengersPlayerData //玩家信息 + jackpot *base.SlotJackpotPool //奖池 + lastJackpotValue int64 //上一次奖池变化时的值 + lastJackPot time.Time //增加奖池时间 + lastBurstJackPot map[int32]time.Time //爆池时间 +} + +func NewAvengersSceneData(s *base.Scene) *AvengersSceneData { + return &AvengersSceneData{ + Scene: s, + players: make(map[int32]*AvengersPlayerData), + } +} + +func (this *AvengersSceneData) SaveData(force bool) { +} + +func (this *AvengersSceneData) OnPlayerLeave(p *base.Player, reason int) { + if p, exist := this.players[p.SnId]; exist { + delete(this.players, p.SnId) + } +} + +func (this *AvengersSceneData) SceneDestroy(force bool) { + //销毁房间 + this.Scene.Destroy(force) +} + +func (this *AvengersSceneData) init() bool { + if this.DbGameFree == nil { + return false + } + params := this.DbGameFree.GetJackpot() + this.jackpot = &base.SlotJackpotPool{} + if this.jackpot.Small <= 0 { + this.jackpot.Small = 0 + this.jackpot.VirtualJK = int64(params[rule.AVENGERS_JACKPOT_InitJackpot] * this.DbGameFree.GetBaseScore()) + } + str := base.SlotsPoolMgr.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 AvengersSpinResult struct { + LinesInfo []*avengers.AvengersLinesInfo + SlotsData []int32 + TotalPrizeLine int64 // 线条总金额 + TotalPrizeJackpot int64 // 爆奖总金额 + JackpotCnt int // 爆奖的次数 + AddFreeTimes int32 // 新增免费次数 + IsJackpot bool // 是否爆奖 + BonusGame avengers.AvengersBonusGameInfo + BonusX []int32 + TotalWinRate int32 // 中奖总倍率 + TotalTaxScore int64 // 税收 + WinLines []int // 赢分的线 +} + +func (this *AvengersSceneData) CalcLinePrize(cards []int, betLines []int64, betValue int64) (spinRes AvengersSpinResult) { + taxRate := this.DbGameFree.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 := &avengers.AvengersLinesInfo{ + 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_FREESPIN { + 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 = avengers.AvengersBonusGameInfo{ + TotalPrizeValue: proto.Int64(totalBonusValue * int64(bonusGame.Mutiplier)), + Mutiplier: proto.Int32(int32(bonusGame.Mutiplier)), + DataMultiplier: proto.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 *AvengersSceneData) 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.DbGameFree.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 *AvengersSceneData) 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 *AvengersSceneData) 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 *AvengersSceneData) RecordBurstLog(name string, wincoin, totalbet int64) { + log := model.NewBurstJackpotLog(this.Platform, this.DbGameFree.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 *AvengersSceneData) BurstHistory(player *AvengersPlayerData) { + task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { + return model.GetBurstJackpotLog(this.Platform, this.DbGameFree.GameId) + }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { + var logsp []*avengers.AvengersBurstHistoryInfo + if data != nil { + logs := data.([]model.BurstJackpotLog) + if len(logs) > 0 { + for _, log := range logs { + logsp = append(logsp, &avengers.AvengersBurstHistoryInfo{ + UserName: log.Name, + PriceValue: log.WinCoin, + TotalBet: log.TotalBet, + Ts: log.Ts, + }) + } + } + } + pack := &avengers.SCAvengersBurstHistory{ + BurstLog: logsp, + } + logger.Logger.Trace("SCAvengersBurstHistory:", pack) + player.SendToClient(int(avengers.AvengersPacketID_PACKET_SC_AVENGERS_BURSTHISTORY), pack) + }), "BurstHistory").Start() +} +func (this *AvengersSceneData) GetLastBurstJackPot() time.Time { + return this.lastBurstJackPot[this.GetGameFreeId()] +} +func (this *AvengersSceneData) SetLastBurstJackPot() { + var randT = rand.Intn(25200-7200+1) + 7200 + switch this.DbGameFree.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 *AvengersSceneData) AIAddJackPot() { + if time.Now().Sub(this.lastJackPot) > 0 { + var randT = rand.Intn(3) + 1 + switch this.DbGameFree.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.DbGameFree.GetBaseScore()) * float64(rule.LINENUM) * float64(500) / 10000)) + this.jackpot.VirtualJK += val + } +} +func (this *AvengersSceneData) AIBurstJackPot() { + if time.Now().Sub(this.GetLastBurstJackPot()) > 0 { + this.SetLastBurstJackPot() + jackpotParams := this.DbGameFree.GetJackpot() + var jackpotInit = int64(jackpotParams[rule.AVENGERS_JACKPOT_InitJackpot] * this.DbGameFree.GetBaseScore()) //奖池初始值 + + //AI机器人爆奖 + val := this.jackpot.VirtualJK + this.jackpot.VirtualJK = jackpotInit + bet := this.DbGameFree.GetBaseScore() * int32(rule.LINENUM) + this.RecordBurstLog(this.RandNickName(), val, int64(bet)) + } +} +func (this *AvengersSceneData) 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.DbGameFree.GetId())) + // if !p.IsRob && + // todayGamefreeIDSceneData != nil && + // this.DbGameFree.GetPlayNumLimit() != 0 && + // todayGamefreeIDSceneData.GameTimes >= int64(this.DbGameFree.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) + } + } + } +} diff --git a/gamesrv/avengers/scenepolicy_avengers.go b/gamesrv/avengers/scenepolicy_avengers.go new file mode 100644 index 0000000..5eaab50 --- /dev/null +++ b/gamesrv/avengers/scenepolicy_avengers.go @@ -0,0 +1,1008 @@ +package avengers + +import ( + "fmt" + "math" + "math/rand" + "os" + "strconv" + "sync" + "time" + + "mongo.games.com/goserver/core" + "mongo.games.com/goserver/core/basic" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/task" + "mongo.games.com/goserver/core/timer" + + "mongo.games.com/game/common" + rule "mongo.games.com/game/gamerule/avengers" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/proto" + "mongo.games.com/game/protocol/avengers" + "mongo.games.com/game/protocol/server" +) + +//////////////////////////////////////////////////////////////////////////////// +//复仇者联盟 +//////////////////////////////////////////////////////////////////////////////// + +// 房间内主要逻辑 +var ScenePolicyAvengersSington = &ScenePolicyAvengers{} + +type ScenePolicyAvengers struct { + base.BaseScenePolicy + states [AvengersSceneStateMax]base.SceneState +} + +// 创建场景扩展数据 +func (this *ScenePolicyAvengers) CreateSceneExData(s *base.Scene) interface{} { + sceneEx := NewAvengersSceneData(s) + if sceneEx != nil { + if sceneEx.init() { + s.ExtraData = sceneEx + } + } + return sceneEx +} + +// 创建玩家扩展数据 +func (this *ScenePolicyAvengers) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} { + playerEx := &AvengersPlayerData{Player: p} + if playerEx != nil { + p.ExtraData = playerEx + } + return playerEx +} + +// 场景开启事件 +func (this *ScenePolicyAvengers) OnStart(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyAvengers) OnStart, SceneId=", s.SceneId) + sceneEx := NewAvengersSceneData(s) + if sceneEx != nil { + if sceneEx.init() { + s.ExtraData = sceneEx + s.ChangeSceneState(AvengersSceneStateStart) //改变当前的玩家状态 + } + } +} + +// 场景关闭事件 +func (this *ScenePolicyAvengers) OnStop(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyAvengers) OnStop , SceneId=", s.SceneId) + if sceneEx, ok := s.ExtraData.(*AvengersSceneData); ok { + sceneEx.SaveData(true) + } +} + +// 场景心跳事件 +func (this *ScenePolicyAvengers) OnTick(s *base.Scene) { + if s == nil { + return + } + if s.SceneState != nil { + s.SceneState.OnTick(s) + } +} + +// 玩家进入事件 +func (this *ScenePolicyAvengers) OnPlayerEnter(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyAvengers) OnPlayerEnter, SceneId=", s.SceneId, " player=", p.SnId) + if sceneEx, ok := s.ExtraData.(*AvengersSceneData); ok { + playerEx := &AvengersPlayerData{Player: p} + playerEx.init(s) // 玩家当前信息初始化 + playerEx.score = sceneEx.DbGameFree.GetBaseScore() // 底注 + sceneEx.players[p.SnId] = playerEx + p.ExtraData = playerEx + AvengersSendRoomInfo(s, p, sceneEx, playerEx, nil) + s.FirePlayerEvent(p, base.PlayerEventEnter, nil) //回调会调取 onPlayerEvent事件 + } +} + +// 玩家离开事件 +func (this *ScenePolicyAvengers) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyAvengers) OnPlayerLeave, SceneId=", s.SceneId, " player=", p.SnId) + if sceneEx, ok := s.ExtraData.(*AvengersSceneData); ok { + if this.CanChangeCoinScene(s, p) { + if playerEx, ok := p.ExtraData.(*AvengersPlayerData); ok { + playerEx.SavePlayerGameData(strconv.Itoa(int(s.GetGameFreeId()))) + } + sceneEx.OnPlayerLeave(p, reason) + s.FirePlayerEvent(p, base.PlayerEventLeave, []int64{int64(reason)}) + } + } +} + +// 玩家掉线 +func (this *ScenePolicyAvengers) OnPlayerDropLine(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyAvengers) OnPlayerDropLine, SceneId=", s.SceneId, " player=", p.SnId) + s.FirePlayerEvent(p, base.PlayerEventDropLine, nil) + if sceneEx, ok := s.ExtraData.(*AvengersSceneData); ok { + if sceneEx.Gaming { + return + } + } +} + +// 玩家重连 +func (this *ScenePolicyAvengers) OnPlayerRehold(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyAvengers) OnPlayerRehold, SceneId=", s.SceneId, " player=", p.Name) + //if sceneEx, ok := s.ExtraData.(*AvengersSceneData); ok { + // if playerEx, ok := p.ExtraData.(*AvengersPlayerData); ok { + //发送房间信息给自己 + //AvengersSendRoomInfo(s, p, sceneEx, playerEx) + s.FirePlayerEvent(p, base.PlayerEventRehold, nil) + // } + //} +} + +// 玩家返回房间 gs添加 +func (this *ScenePolicyAvengers) OnPlayerReturn(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyIceAge) OnPlayerReturn,sceneId =", s.GetSceneId(), " player= ", p.Name) + if sceneEx, ok := s.GetExtraData().(*AvengersSceneData); ok { + if playerEx, ok := p.GetExtraData().(*AvengersPlayerData); ok { + AvengersSendRoomInfo(s, p, sceneEx, playerEx, playerEx.billedData) + s.FirePlayerEvent(p, base.PlayerEventReturn, nil) + } + } +} + +// 玩家操作 +func (this *ScenePolicyAvengers) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + if s == nil || p == nil { + return false + } + if s.SceneState != nil { + return s.SceneState.OnPlayerOp(s, p, opcode, params) + } + return true +} + +// 玩家事件 +func (this *ScenePolicyAvengers) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { + if s == nil || p == nil { + return + } + if s.SceneState != nil { + s.SceneState.OnPlayerEvent(s, p, evtcode, params) + } +} + +// 是否完成了整个牌局 +func (this *ScenePolicyAvengers) IsCompleted(s *base.Scene) bool { return false } + +// 是否可以强制开始 +func (this *ScenePolicyAvengers) IsCanForceStart(s *base.Scene) bool { return true } + +// 当前状态能否换桌 +func (this *ScenePolicyAvengers) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if s == nil || p == nil { + return true + } + if s.SceneState != nil { + return s.SceneState.CanChangeCoinScene(s, p) + } + return true +} + +func (this *ScenePolicyAvengers) RegisteSceneState(state base.SceneState) { + if state == nil { + return + } + stateid := state.GetState() + if stateid < 0 || stateid >= AvengersSceneStateMax { + return + } + this.states[stateid] = state +} + +func (this *ScenePolicyAvengers) GetSceneState(s *base.Scene, stateid int) base.SceneState { + if stateid >= 0 && stateid < AvengersSceneStateMax { + return ScenePolicyAvengersSington.states[stateid] + } + return nil +} +func (this *ScenePolicyAvengers) GetJackPotVal(s *base.Scene) int64 { + if sceneEx, ok := s.ExtraData.(*AvengersSceneData); ok { + if sceneEx.lastJackpotValue != sceneEx.jackpot.VirtualJK { + return sceneEx.jackpot.VirtualJK + } + } + return 0 +} +func AvengersSendRoomInfo(s *base.Scene, p *base.Player, sceneEx *AvengersSceneData, playerEx *AvengersPlayerData, data *avengers.GameBilledData) { + logger.Logger.Trace("-------------------发送房间消息 ", s.RoomId, p.SnId) + pack := &avengers.SCAvengersRoomInfo{ + RoomId: proto.Int(s.SceneId), + Creator: proto.Int32(s.Creator), + GameId: proto.Int(s.GameId), + RoomMode: proto.Int(s.GameMode), + Params: s.Params, + State: proto.Int(s.SceneState.GetState()), + Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), + GameFreeId: proto.Int32(s.DbGameFree.Id), + BilledData: data, + } + if playerEx != nil { + pd := &avengers.AvengersPlayerData{ + SnId: proto.Int32(playerEx.SnId), + Name: proto.String(playerEx.Name), + Head: proto.Int32(playerEx.Head), + Sex: proto.Int32(playerEx.Sex), + Coin: proto.Int64(playerEx.Coin), + HeadOutLine: proto.Int32(playerEx.HeadOutLine), + VIP: proto.Int32(playerEx.VIP), + } + pack.Players = append(pack.Players, pd) + pack.BetLines = playerEx.betLines + pack.FreeTimes = proto.Int32(playerEx.freeTimes) + pack.Chip = proto.Int32(s.DbGameFree.BaseScore) + pack.SpinID = proto.Int64(playerEx.spinID) + if playerEx.totalPriceBonus > 0 { + switch playerEx.bonusStage { + case 0: + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + case 1: + if time.Now().Unix()-playerEx.bonusStartTime >= AvengersBonusGameStageTimeout*2 { + playerEx.CleanBonus() + } else if time.Now().Unix()-playerEx.bonusStartTime >= AvengersBonusGameStageTimeout { + playerEx.bonusStage = 2 + playerEx.bonusStartTime += AvengersBonusGameStageTimeout + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + leftTime := playerEx.bonusStartTime + AvengersBonusGameStageTimeout + 2 - time.Now().Unix() + pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) + } else { + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + leftTime := playerEx.bonusStartTime + AvengersBonusGameStageTimeout + 2 - time.Now().Unix() + pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusOpRecord...) + } + case 2: + if time.Now().Unix()-playerEx.bonusStartTime >= AvengersBonusGameStageTimeout { + playerEx.CleanBonus() + } else { + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + leftTime := playerEx.bonusStartTime + AvengersBonusGameStageTimeout + 2 - time.Now().Unix() + pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) + } + } + } + if playerEx.totalPriceBonus > 0 { + pack.TotalPriceBonus = proto.Int64(playerEx.totalPriceBonus) + pack.BonusGame = playerEx.bonusGame + pack.BonusX = playerEx.bonusX + } + } + proto.SetDefaults(pack) + p.SendToClient(int(avengers.AvengersPacketID_PACKET_SC_AVENGERS_ROOMINFO), pack) +} + +type SceneStateAvengersStart struct { +} + +// 获取当前场景状态 +func (this *SceneStateAvengersStart) GetState() int { return AvengersSceneStateStart } + +// 是否可以切换状态到 +func (this *SceneStateAvengersStart) CanChangeTo(s base.SceneState) bool { return true } + +// 当前状态能否换桌 +func (this *SceneStateAvengersStart) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if _, ok := p.ExtraData.(*AvengersPlayerData); ok { + return true + } + return true +} + +func (this *SceneStateAvengersStart) GetTimeout(s *base.Scene) int { return 0 } + +func (this *SceneStateAvengersStart) OnEnter(s *base.Scene) { + if sceneEx, ok := s.ExtraData.(*AvengersSceneData); ok { + logger.Logger.Tracef("(this *Scene) [%v] 场景状态进入 %v", s.SceneId, len(sceneEx.players)) + sceneEx.StateStartTime = time.Now() + pack := &avengers.SCAvengersRoomState{ + State: proto.Int(this.GetState()), + } + proto.SetDefaults(pack) + s.Broadcast(int(avengers.AvengersPacketID_PACKET_SC_AVENGERS_ROOMSTATE), pack, 0) + } +} + +func (this *SceneStateAvengersStart) OnLeave(s *base.Scene) {} + +func (this *SceneStateAvengersStart) OnTick(s *base.Scene) { + if sceneEx, ok := s.ExtraData.(*AvengersSceneData); ok { + sceneEx.AIAddJackPot() + sceneEx.AIBurstJackPot() + sceneEx.KickPlayerByTime() + } +} + +func (this *SceneStateAvengersStart) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + playerEx, ok := p.ExtraData.(*AvengersPlayerData) + if !ok { + return false + } + sceneEx, ok := s.ExtraData.(*AvengersSceneData) + if !ok { + return false + } + if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { + //离开有统计 + sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) + return false + } + switch opcode { + case AvengersPlayerOpStart: //开始 + //if !avengersBenchTest { + // avengersBenchTest = true + // for i := 0; i < 10; i++ { + // //this.BenchTest(s, p) + // this.WinTargetBenchTest(s, p) + // } + // return true + //} + + //参数是否合法 + //params 参数0底注,后面跟客户端选择的线n条线(1<=n<=25),客户端线是从1开始算起1~25条线 + if len(params) < 2 || len(params) > rule.LINENUM+1 { + logger.Logger.Warnf("avengers snid[%v] opcode[%v] params[%v]", p.SnId, opcode, params) + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + //先做底注校验 + if sceneEx.DbGameFree.GetBaseScore() != int32(params[0]) { + logger.Logger.Warnf("avengers snid[%v] opcode[%v] params[%v] BaseScore[%v]", p.SnId, opcode, params, sceneEx.DbGameFree.GetBaseScore()) + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + playerEx.score = int32(params[0]) // 单线押注数 + // 小游戏未结束 不能进行下一次旋转 + if playerEx.totalPriceBonus > 0 { + logger.Logger.Warnf("avengers snid[%v] opcode[%v] params[%v] totalPriceBonus[%v]", p.SnId, opcode, params, playerEx.totalPriceBonus) + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + //判断线条是否重复,是否合法 + lineFlag := make(map[int64]bool) + lineParams := make([]int64, 0) + for i := 1; i < len(params); i++ { + lineNum := params[i] + if lineNum >= 1 && lineNum <= int64(rule.LINENUM) && !lineFlag[lineNum] { + lineParams = append(lineParams, lineNum) + lineFlag[lineNum] = true + } else { + logger.Logger.Warnf("avengers snid[%v] opcode[%v] params[%v] lineNum[%v]", p.SnId, opcode, params, lineNum) + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + } + //没有选线参数 + if len(lineParams) == 0 { + logger.Logger.Warnf("avengers snid[%v] opcode[%v] params[%v] lineParams[%v]", p.SnId, opcode, params, lineParams) + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + + //获取总投注金额(所有线的总投注) | 校验玩家余额是否足够 + totalBetValue := (int64(len(lineParams))) * params[0] + if playerEx.freeTimes <= 0 && totalBetValue > playerEx.Coin { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_CoinNotEnough, params) + return false + } else if playerEx.freeTimes <= 0 && int64(sceneEx.DbGameFree.GetBetLimit()) > playerEx.Coin { //押注限制 + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_CoinNotEnough, params) + return false + } + + p.LastOPTimer = time.Now() + sceneEx.GameNowTime = time.Now() + sceneEx.NumOfGames++ + //p.GameTimes++ + //playerEx.StartCoin = playerEx.Coin + + //获取当前水池的上下文环境 + sceneEx.CpCtx = base.CoinPoolMgr.GetCoinPoolCtx(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) + //税收比例 + taxRate := sceneEx.DbGameFree.GetTaxRate() + if taxRate < 0 || taxRate > 10000 { + logger.Logger.Warnf("AvengersErrorTaxRate [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate) + taxRate = 500 + } + //水池设置 + coinPoolSetting := base.CoinPoolMgr.GetCoinPoolSetting(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) + //baseRate := coinPoolSetting.GetBaseRate() //基础赔率 + ctroRate := 500 //调节赔率 暗税系数 + //if baseRate >= 10000 || baseRate <= 0 || ctroRate < 0 || ctroRate >= 1000 || baseRate+ctroRate > 9900 { + // logger.Logger.Warnf("AvengersErrorBaseRate [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, baseRate, ctroRate) + // baseRate = 9700 + // ctroRate = 200 + //} + //jackpotRate := 10000 - (baseRate + ctroRate) //奖池系数 + jackpotRate := ctroRate //奖池系数 + logger.Logger.Tracef("AvengersRates [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate, ctroRate) + + //playerEx.IsFNovice(sceneEx.KeyGameId) + isFoolPlayer := false + var gamePoolCoin int64 + //if isFoolPlayer { + // gamePoolCoin = base.CoinPoolMgr.GetNoviceCoinPool(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} else { + gamePoolCoin = base.CoinPoolMgr.GetCoin(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} + prizeFund := gamePoolCoin - sceneEx.jackpot.VirtualJK // 除去奖池的水池剩余金额 + + // 奖池参数 + jackpotParams := sceneEx.DbGameFree.GetJackpot() + var jackpotInit = int64(jackpotParams[rule.AVENGERS_JACKPOT_InitJackpot] * sceneEx.DbGameFree.GetBaseScore()) //奖池初始值 + + var jackpotFundAdd, prizeFundAdd int64 //奖池/水池增量 + if playerEx.freeTimes <= 0 { //正常模式才能记录用户的押注变化,免费模式不能改变押注 + playerEx.betLines = lineParams // 选线记录 + jackpotFundAdd = int64(math.Floor(float64(totalBetValue) * (float64(jackpotRate) / 10000.0))) //奖池要增加的金额 + prizeFundAdd = totalBetValue - jackpotFundAdd + playerEx.TotalBet += totalBetValue //总下注额(从进房间开始,包含多局游戏的下注) + //扣除投注金币 + p.AddCoin(-totalBetValue, common.GainWay_HundredSceneLost, base.SyncFlag_ToClient, "system", s.GetSceneName()) + //p.Statics(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, -totalBetValue, true) + if !p.IsRob && !sceneEx.Testing { + // 推送金币 + sceneEx.PushCoinPool(prizeFundAdd, false) + //base.CoinPoolMgr.PushCoin(sceneEx.GetGameFreeId(), sceneEx.GroupId, sceneEx.Platform, int64(float64(totalBetValue)*(float64(10000-ctroRate)/10000.0))) + } + + ////统计参与游戏次数 + //if !sceneEx.Testing && !playerEx.IsRob { + // pack := &server.GWSceneEnd{ + // GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), + // Players: []*server.PlayerCtx{&server.PlayerCtx{SnId: proto.Int32(playerEx.SnId), Coin: proto.Int64(playerEx.Coin)}}, + // } + // proto.SetDefaults(pack) + // sceneEx.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENEEND), pack) + //} + } else { //免费次数时,不能改线改选线 + totalBetValue = 0 + } + + writeBlackTryTimes := 0 + WriteBlack: + slotData := make([]int, 0) + var spinRes AvengersSpinResult + var slotDataIsOk bool + for { + var symbolType rule.Symbol + if gamePoolCoin < int64(coinPoolSetting.GetLowerLimit()) { // userInfo.prizeFund < limit * roomId + symbolType = rule.SYMBOL1 + } else { + symbolType = rule.SYMBOL2 + } + slotData, _ = rule.GenerateSlotsData_v2(symbolType) + + spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) + + // 免费次数时 不允许爆奖 + if playerEx.freeTimes > 0 && spinRes.IsJackpot { + break + } + if spinRes.JackpotCnt > 1 { + break + } + + if spinRes.IsJackpot { + if sceneEx.jackpot.Small < sceneEx.jackpot.VirtualJK { + break + } + } + spinCondition := prizeFund + prizeFundAdd - (spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue() + spinRes.TotalPrizeJackpot) + spinCondition += jackpotFundAdd + sceneEx.jackpot.VirtualJK - jackpotInit + win := spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue() + spinRes.TotalPrizeJackpot + // 现金池不足时 重新发牌 + if spinCondition < 0 && win > totalBetValue { + if !spinRes.IsJackpot { // 非爆奖 水池不足 不再进行黑白名单调控 + writeBlackTryTimes = 999 + } + break + } + + // 非爆奖时 不允许赢取太大的奖励 + var limitBigWin int64 = 50 + if spinCondition < int64(coinPoolSetting.GetLowerLimit()) { //现金池不足时 + limitBigWin = int64(jackpotParams[rule.AVENGERS_JACKPOT_LIMITWIN_PRIZELOW]) + } else { + limitBigWin = int64(jackpotParams[rule.AVENGERS_JACKPOT_LIMITWIN_PRIZEHIGH]) + } + if totalBetValue > 0 && !spinRes.IsJackpot && spinRes.TotalPrizeLine+spinRes.BonusGame.GetTotalPrizeValue() > totalBetValue*limitBigWin { + break + } + + // 小游戏次数限制 + // 爆奖次数限制 + + slotDataIsOk = true + break + } + + if !slotDataIsOk { + slotData = rule.MissData[rand.Intn(len(rule.MissData))] + spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) + } + + // 黑白名单调控 防止异常循环,添加上限次数 + if writeBlackTryTimes < 100 && playerEx.CheckBlackWriteList(spinRes.TotalPrizeLine+spinRes.TotalPrizeJackpot+spinRes.BonusGame.GetTotalPrizeValue() > totalBetValue) { + writeBlackTryTimes++ + goto WriteBlack + } else if writeBlackTryTimes >= 100 && writeBlackTryTimes != 999 { + logger.Logger.Warnf("AvengersWriteBlackTryTimesOver [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, gamePoolCoin, playerEx.BlackLevel, playerEx.WhiteLevel) + } + + //if playerEx.DebugGame && sceneEx.SceneType == 1 { + // if playerEx.TestNum >= len(DebugData) { + // playerEx.TestNum = 0 + // } + // slotData = DebugData[playerEx.TestNum] + // spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) + // playerEx.TestNum++ + //} + + // 奖池水池处理 + if spinRes.IsJackpot { + sceneEx.jackpot.Small -= sceneEx.jackpot.VirtualJK + if sceneEx.jackpot.Small < 0 { + sceneEx.jackpot.Small = 0 + } + sceneEx.jackpot.VirtualJK = jackpotInit + } else { + sceneEx.jackpot.Small += jackpotFundAdd + sceneEx.jackpot.VirtualJK += jackpotFundAdd + } + + // 玩家赢钱 + totalWinScore := spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot + if totalWinScore > 0 || len(spinRes.BonusX) > 0 { + p.AddCoin(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue(), common.GainWay_HundredSceneWin, 0, "system", s.GetSceneName()) + //p.Statics(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore, true) + if !p.IsRob && !sceneEx.Testing { + sceneEx.PopCoinPool(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore, isFoolPlayer) + //base.CoinPoolMgr.PopCoin(sceneEx.GetGameFreeId(), sceneEx.GroupId, sceneEx.Platform, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore) + } + playerEx.taxCoin = spinRes.TotalTaxScore + playerEx.AddServiceFee(playerEx.taxCoin) + } + p.StaticsLaba(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, totalBetValue, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore) + + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Sucess, append(params[:1], playerEx.betLines...)) + + //免费次数 + var isFreeFlag bool + if playerEx.freeTimes > 0 { + playerEx.freeTimes-- + isFreeFlag = true + } + playerEx.freeTimes += spinRes.AddFreeTimes + + rule.SpinID++ + playerEx.spinID = rule.SpinID + playerEx.cards = spinRes.SlotsData + playerEx.winCoin = spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot + spinRes.BonusGame.GetTotalPrizeValue() + playerEx.taxCoin + playerEx.linesWinCoin = spinRes.TotalPrizeLine + playerEx.jackpotWinCoin = spinRes.TotalPrizeJackpot + playerEx.smallGameWinCoin = spinRes.BonusGame.GetTotalPrizeValue() + playerEx.CurrentBet = totalBetValue + playerEx.CurrentTax = playerEx.taxCoin + + // 小游戏超时处理 + if len(spinRes.BonusX) > 0 { + playerEx.CleanBonus() + playerEx.totalPriceBonus = spinRes.BonusGame.GetTotalPrizeValue() + playerEx.bonusGame = &spinRes.BonusGame + playerEx.bonusX = spinRes.BonusX + logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) + //playerEx.bonusTimerHandle, _ = timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool { + // this.OnPlayerOp(s, p, AvengersBonusGame, []int64{playerEx.spinID}) + // return true + //}), nil, AvengersBonusGameTimeout, 1) + } + playerEx.billedData = &avengers.GameBilledData{ + SpinID: proto.Int64(playerEx.spinID), + SlotsData: spinRes.SlotsData, + AddFreeSpin: proto.Int32(spinRes.AddFreeTimes), + IsJackpot: proto.Bool(spinRes.IsJackpot), + PrizeLines: spinRes.LinesInfo, + TotalPrizeValue: proto.Int64(totalWinScore), + TotalPaylinePrizeValue: proto.Int64(spinRes.TotalPrizeLine), + TotalJackpotValue: proto.Int64(spinRes.TotalPrizeJackpot), + Balance: proto.Int64(playerEx.Coin - spinRes.BonusGame.GetTotalPrizeValue()), + FreeSpins: proto.Int32(playerEx.freeTimes), + Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), + BonusX: spinRes.BonusX, + BonusGame: &spinRes.BonusGame, + } + pack := &avengers.SCAvengersGameBilled{ + BilledData: playerEx.billedData, + } + proto.SetDefaults(pack) + logger.Logger.Infof("AvengersPlayerOpStart %v", pack) + p.SendToClient(int(avengers.AvengersPacketID_PACKET_SC_AVENGERS_GAMEBILLED), pack) + + // 记录本次操作 + playerEx.RollGameType.BaseResult.WinTotal = pack.BilledData.GetTotalPrizeValue() + pack.BilledData.GetBonusGame().GetTotalPrizeValue() + pack.BilledData.GetTotalJackpotValue() + playerEx.RollGameType.BaseResult.IsFree = isFreeFlag + playerEx.RollGameType.BaseResult.WinJackpot = pack.BilledData.GetTotalJackpotValue() + playerEx.RollGameType.BaseResult.WinLineScore = pack.BilledData.GetTotalPrizeValue() + playerEx.RollGameType.BaseResult.WinSmallGame = pack.BilledData.BonusGame.GetTotalPrizeValue() + playerEx.RollGameType.BaseResult.AllWinNum = int32(len(pack.BilledData.PrizeLines)) + playerEx.RollGameType.BaseResult.WinRate = spinRes.TotalWinRate + playerEx.RollGameType.BaseResult.Cards = pack.BilledData.GetSlotsData() + playerEx.RollGameType.BaseResult.IsFoolPlayer = isFoolPlayer + playerEx.RollGameType.WinLines = spinRes.WinLines + AvengersCheckAndSaveLog(sceneEx, playerEx) + + // 广播奖池 + if totalBetValue == 0 && !spinRes.IsJackpot { // 没改变奖池 + return true + } + // 添加进开奖记录里面 + if spinRes.IsJackpot { + sceneEx.RecordBurstLog(playerEx.Name, pack.BilledData.GetTotalJackpotValue(), playerEx.CurrentBet) + } + logger.Logger.Tracef("---avengers---当前奖池:真人[%v] 虚拟[%v]", sceneEx.jackpot.Small, sceneEx.jackpot.VirtualJK) + case AvengersPlayerHistory: + task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { + spinid := strconv.Itoa(int(playerEx.SnId)) + gpl := model.GetPlayerListByHallEx(p.SnId, p.Platform, 0, 80, 0, 0, 0, s.DbGameFree.GetGameClass(), s.GameId) //复仇者联盟存储个人操作记录不分场次,因为选场界面也需要拉去个人操作记录 + pack := &avengers.SCAvengersPlayerHistory{} + for _, v := range gpl.Data { + if v.GameDetailedLogId == "" { + logger.Logger.Error("AvengersPlayerHistory GameDetailedLogId is nil") + break + } + //gdl := model.GetPlayerHistory(p.Platform, v.GameDetailedLogId) + //if gdl == nil { + // logger.Logger.Error("AvengersPlayerHistory gdl is nil") + // continue + //} + //data, err := UnMarshalAvengersGameNote(gdl.GameDetailedNote) + //if err != nil { + // logger.Logger.Errorf("UnMarshalAvengersGameNote error:%v", err) + //} + //gnd := data.(*GameResultLog) + player := &avengers.AvengersPlayerHistoryInfo{ + SpinID: proto.String(spinid), + CreatedTime: proto.Int64(int64(v.Ts)), + TotalBetValue: proto.Int64(v.BetAmount), + TotalPriceValue: proto.Int64(v.WinTotal), + IsFree: proto.Bool(v.IsFree), + TotalBonusValue: proto.Int64(v.WinSmallGame), + } + pack.PlayerHistory = append(pack.PlayerHistory, player) + } + proto.SetDefaults(pack) + logger.Logger.Trace("AvengersPlayerHistory: ", pack) + return pack + + }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { + if data == nil { + logger.Logger.Error("AvengersPlayerHistory data is nil") + return + } + p.SendToClient(int(avengers.AvengersPacketID_PACKET_SC_AVENGERS_PLAYERHISTORY), data) + }), "CSGetAvengersPlayerHistoryHandler").Start() + case AvengersBurstHistory: + sceneEx.BurstHistory(playerEx) + case AvengersBonusGame: + //params 参数0 spinID + //参数是否合法 + if len(params) < 1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + if playerEx.spinID != params[0] || playerEx.totalPriceBonus <= 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + if playerEx.bonusTimerHandle != timer.TimerHandle(0) { + timer.StopTimer(playerEx.bonusTimerHandle) + playerEx.bonusTimerHandle = timer.TimerHandle(0) + } + logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) + + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Sucess, []int64{playerEx.totalPriceBonus, playerEx.Coin}) + playerEx.CleanBonus() + case AvengersBonusGameRecord: + // params[0] 小游戏阶段: 0 小游戏动画开始 1 小游戏界面1 2 切换小游戏界面2 + // params[1] 小游戏界面1时,选择奖项的界面位置信息 + if len(params) < 1 || params[0] < 0 || params[0] > 2 || playerEx.totalPriceBonus <= 0 || (params[0] == 1 && len(params) < 2) { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + if params[0] == 0 { + if playerEx.bonusStage > 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + playerEx.bonusStage = 1 + playerEx.bonusStartTime = time.Now().Unix() + } else if params[0] == 2 { + if playerEx.bonusStage != 1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + playerEx.bonusStage = 2 + playerEx.bonusStartTime = time.Now().Unix() + } else if params[0] == 1 { + if params[1] < 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } else if playerEx.bonusGame != nil && len(playerEx.bonusOpRecord) >= len(playerEx.bonusGame.BonusData) { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Error, params) + return false + } + playerEx.bonusOpRecord = append(playerEx.bonusOpRecord, int32(params[1])) + } + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, avengers.OpResultCode_OPRC_Sucess, params) + } + return true +} + +func (this *SceneStateAvengersStart) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { +} + +// 发送玩家操作情况 +func (this *SceneStateAvengersStart) OnPlayerSToCOp(s *base.Scene, p *base.Player, pos int, opcode int, + opRetCode avengers.OpResultCode, params []int64) { + pack := &avengers.SCAvengersOp{ + SnId: proto.Int32(p.SnId), + OpCode: proto.Int(opcode), + OpRetCode: opRetCode, + Params: params, + } + proto.SetDefaults(pack) + p.SendToClient(int(avengers.AvengersPacketID_PACKET_SC_AVENGERS_PLAYEROP), pack) +} + +var avengersBenchTest bool +var avengersBenchTestTimes int + +func (this *SceneStateAvengersStart) BenchTest(s *base.Scene, p *base.Player) { + const BENCH_CNT = 10000 + setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) + oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + if avengersBenchTestTimes == 0 { + defaultVal := int64(setting.GetLowerLimit()) + if oldPoolCoin != defaultVal { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) + } + } + avengersBenchTestTimes++ + + fileName := fmt.Sprintf("avengers-%v-%d.csv", p.SnId, avengersBenchTestTimes) + file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + defer file.Close() + if err != nil { + file, err = os.Create(fileName) + if err != nil { + return + } + } + file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,爆奖,中线倍数,中线数,剩余免费次数\r\n") + + oldCoin := p.Coin + p.Coin = int64(5000 * s.DbGameFree.GetBaseScore()) + if playerEx, ok := p.ExtraData.(*AvengersPlayerData); ok { + for i := 0; i < BENCH_CNT; i++ { + startCoin := p.Coin + freeTimes := playerEx.freeTimes + poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + playerEx.UnmarkFlag(base.PlayerState_GameBreak) + suc := this.OnPlayerOp(s, p, AvengersPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) + inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) + outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin + taxCoin := playerEx.RollGameType.BaseResult.Tax + lineScore := float64(playerEx.RollGameType.BaseResult.WinRate*s.DbGameFree.GetBaseScore()) * float64(10000.0-s.DbGameFree.GetTaxRate()) / 10000.0 + jackpotScore := outCoin - playerEx.RollGameType.BaseResult.ChangeCoin - int64(lineScore+0.00001) + + str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, startCoin, p.Coin, inCoin, outCoin, taxCoin, + playerEx.RollGameType.BaseResult.WinSmallGame, jackpotScore, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) + file.WriteString(str) + if !suc { + break + } + + if playerEx.totalPriceBonus > 0 { + this.OnPlayerOp(s, p, AvengersBonusGame, []int64{playerEx.spinID}) + } + } + } + p.Coin = oldCoin +} +func (this *SceneStateAvengersStart) WinTargetBenchTest(s *base.Scene, p *base.Player) { + const BENCH_CNT = 10000 + var once = sync.Once{} + once.Do(func() { + setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) + oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + if avengersBenchTestTimes == 0 { + defaultVal := int64(setting.GetLowerLimit()) + if oldPoolCoin != defaultVal { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) + } + } + }) + avengersBenchTestTimes++ + + fileName := fmt.Sprintf("avengers-%v-%d.csv", p.SnId, avengersBenchTestTimes) + file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + defer file.Close() + if err != nil { + file, err = os.Create(fileName) + if err != nil { + return + } + } + file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,爆奖,中线倍数,中线数,剩余免费次数\r\n") + oldCoin := p.Coin + switch s.DbGameFree.GetSceneType() { + case 1: + p.Coin = 100000 + case 2: + p.Coin = 500000 + case 3: + p.Coin = 1000000 + case 4: + p.Coin = 10000000 + default: + p.Coin = 100000 + } + var targetCoin = p.Coin + p.Coin/10 + if playerEx, ok := p.ExtraData.(*AvengersPlayerData); ok { + for i := 0; p.Coin < targetCoin; i++ { + startCoin := p.Coin + freeTimes := playerEx.freeTimes + poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + playerEx.UnmarkFlag(base.PlayerState_GameBreak) + suc := this.OnPlayerOp(s, p, AvengersPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) + inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) + outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin + taxCoin := playerEx.RollGameType.BaseResult.Tax + lineScore := float64(playerEx.RollGameType.BaseResult.WinRate*s.DbGameFree.GetBaseScore()) * float64(10000.0-s.DbGameFree.GetTaxRate()) / 10000.0 + jackpotScore := outCoin - playerEx.RollGameType.BaseResult.WinSmallGame - int64(lineScore+0.00001) + + str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, startCoin, p.Coin, inCoin, outCoin, taxCoin, + playerEx.RollGameType.BaseResult.WinSmallGame, jackpotScore, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) + file.WriteString(str) + if !suc { + break + } + + if playerEx.totalPriceBonus > 0 { + this.OnPlayerOp(s, p, AvengersBonusGame, []int64{playerEx.spinID}) + } + if i > BENCH_CNT { + break + } + } + } + p.Coin = oldCoin +} + +func AvengersCheckAndSaveLog(sceneEx *AvengersSceneData, playerEx *AvengersPlayerData) { + //统计金币变动 + //log1 + logger.Logger.Trace("AvengersCheckAndSaveLog Save ", playerEx.SnId) + //changeCoin := playerEx.Coin - playerEx.StartCoin + changeCoin := playerEx.winCoin - playerEx.taxCoin - playerEx.CurrentBet + startCoin := playerEx.Coin - changeCoin + playerEx.SaveSceneCoinLog(startCoin, changeCoin, + playerEx.Coin, playerEx.CurrentBet, playerEx.taxCoin, playerEx.winCoin, playerEx.jackpotWinCoin, playerEx.smallGameWinCoin) + + //log2 + playerEx.RollGameType.BaseResult.ChangeCoin = changeCoin + playerEx.RollGameType.BaseResult.BasicBet = sceneEx.DbGameFree.GetBaseScore() + playerEx.RollGameType.BaseResult.RoomId = int32(sceneEx.SceneId) + playerEx.RollGameType.BaseResult.AfterCoin = playerEx.Coin + playerEx.RollGameType.BaseResult.BeforeCoin = startCoin + playerEx.RollGameType.BaseResult.IsFirst = sceneEx.IsPlayerFirst(playerEx.Player) + playerEx.RollGameType.BaseResult.PlayerSnid = playerEx.SnId + playerEx.RollGameType.BaseResult.TotalBet = int32(playerEx.CurrentBet) + playerEx.RollGameType.AllLine = int32(len(playerEx.betLines)) + playerEx.RollGameType.BaseResult.FreeTimes = playerEx.freeTimes + playerEx.RollGameType.UserName = playerEx.Name + playerEx.RollGameType.BetLines = playerEx.betLines + playerEx.RollGameType.BaseResult.Tax = playerEx.taxCoin + playerEx.RollGameType.BaseResult.WBLevel = sceneEx.players[playerEx.SnId].WBLevel + if playerEx.score > 0 { + if !playerEx.IsRob { + info, err := model.MarshalGameNoteByROLL(playerEx.RollGameType) + if err == nil { + logid, _ := model.AutoIncGameLogId() + playerEx.currentLogId = logid + sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) + totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin + validFlow := totalin + totalout + validBet := common.AbsI64(totalin - totalout) + logParam := &base.SaveGamePlayerListLogParam{ + Platform: playerEx.Platform, + Channel: playerEx.Channel, + Promoter: playerEx.BeUnderAgentCode, + PackageTag: playerEx.PackageID, + InviterId: playerEx.InviterId, + LogId: logid, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: playerEx.taxCoin, + BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), + WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, + ValidBet: validBet, + ValidFlow: validFlow, + IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), + IsFree: playerEx.RollGameType.BaseResult.IsFree, + WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, + WinTotal: playerEx.RollGameType.BaseResult.WinTotal, + } + sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + } + } + } + + //统计输下注金币数 + if !sceneEx.Testing && !playerEx.IsRob { + playerBet := &server.PlayerData{ + SnId: proto.Int32(playerEx.SnId), + Bet: proto.Int64(playerEx.CurrentBet), + Gain: proto.Int64(playerEx.RollGameType.BaseResult.ChangeCoin), + Tax: proto.Int64(playerEx.taxCoin), + OtherTax: 0, + Coin: proto.Int64(playerEx.GetCoin()), + FlowCoin: 0, + Lottery: 0, + Kind: 0, + Card: nil, + GameCoinTs: proto.Int64(playerEx.GameCoinTs), + WBGain: 0, + WinState: 0, + } + gwPlayerBet := &server.GWPlayerData{ + SceneId: proto.Int(sceneEx.SceneId), + GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), + } + gwPlayerBet.Datas = append(gwPlayerBet.Datas, playerBet) + sceneEx.SyncPlayerDatas(&base.PlayerDataParam{ + HasRobotGaming: false, + Data: gwPlayerBet, + }) + } + + playerEx.taxCoin = 0 + playerEx.winCoin = 0 + playerEx.linesWinCoin = 0 + playerEx.jackpotWinCoin = 0 + playerEx.smallGameWinCoin = 0 + + if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { + sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) + } +} + +func init() { + ScenePolicyAvengersSington.RegisteSceneState(&SceneStateAvengersStart{}) + core.RegisteHook(core.HOOK_BEFORE_START, func() error { + base.RegisteScenePolicy(common.GameId_Avengers, 0, ScenePolicyAvengersSington) + return nil + }) +} diff --git a/gamesrv/base/xslotspoolmanager.go b/gamesrv/base/xslotspoolmanager.go index ba266f4..1d046ca 100644 --- a/gamesrv/base/xslotspoolmanager.go +++ b/gamesrv/base/xslotspoolmanager.go @@ -1,94 +1,98 @@ package base -//import ( -// "encoding/json" -// "fmt" -// -// "mongo.games.com/goserver/core/logger" -// "mongo.games.com/goserver/core/module" -// -// "mongo.games.com/game/common" -// "mongo.games.com/game/model" -//) -// -//var XSlotsPoolMgr = &XSlotsPoolManager{ -// //SlotsPoolData: make(map[string]interface{}), -// SlotsPoolStr: make(map[string]string), -//} -// -//type XSlotsPoolManager struct { -// //SlotsPoolData map[string]interface{} -// SlotsPoolStr map[string]string -// SlotsPoolDBKey string -//} -// -//func (this *XSlotsPoolManager) GetPool(gamefreeId int32, platform string) string { +import ( + "encoding/json" + "fmt" + "time" + + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/module" + + "mongo.games.com/game/common" + "mongo.games.com/game/model" +) + +var XSlotsPoolMgr = &XSlotsPoolManager{ + SlotsPoolData: make(map[string]interface{}), + SlotsPoolStr: make(map[string]string), +} + +type XSlotsPoolManager struct { + // + SlotsPoolData map[string]interface{} + // + SlotsPoolStr map[string]string + // + SlotsPoolDBKey string +} + +func (this *XSlotsPoolManager) GetPool(gamefreeId int32, platform string) string { + key := fmt.Sprintf("%v-%v", gamefreeId, platform) + if str, exist := this.SlotsPoolStr[key]; exist { + return str + } + return "" +} + +//func (this *XSlotsPoolManager) SetPool(gamefreeId int32, platform string, pool interface{}) { // key := fmt.Sprintf("%v-%v", gamefreeId, platform) -// if str, exist := this.SlotsPoolStr[key]; exist { -// return str +// this.SlotsPoolData[key] = pool +//} + +//func (this *XSlotsPoolManager) GetPoolByPlatform(platform string) map[string]interface{} { +// slots := make(map[string]interface{}) +// for k, v := range this.SlotsPoolData { +// str := strings.Split(k, "-") +// if len(str) == 2 && str[1] == platform { +// idStr := str[0] +// slots[idStr] = v +// } // } -// return "" -//} -// -////func (this *XSlotsPoolManager) SetPool(gamefreeId int32, platform string, pool interface{}) { -//// key := fmt.Sprintf("%v-%v", gamefreeId, platform) -//// this.SlotsPoolData[key] = pool -////} -// -////func (this *XSlotsPoolManager) GetPoolByPlatform(platform string) map[string]interface{} { -//// slots := make(map[string]interface{}) -//// for k, v := range this.SlotsPoolData { -//// str := strings.Split(k, "-") -//// if len(str) == 2 && str[1] == platform { -//// idStr := str[0] // gamefreeid -//// slots[idStr] = v -//// } -//// } -//// return slots -////} -// -//// ////////////////////////////////////////////////////////////////// -//// / Module Implement [beg] -//// ////////////////////////////////////////////////////////////////// -//func (this *XSlotsPoolManager) ModuleName() string { -// return "XSlotsPoolManager" -//} -// -//func (this *XSlotsPoolManager) Init() { -// this.SlotsPoolDBKey = fmt.Sprintf("XSlotsPoolManager_Srv%v", common.GetSelfSrvId()) -// data := model.GetStrKVGameData(this.SlotsPoolDBKey) -// err := json.Unmarshal([]byte(data), &this.SlotsPoolStr) -// if err != nil { -// logger.Logger.Error("Unmarshal slots pool error:", err) -// } -//} -// -//func (this *XSlotsPoolManager) Update() { -// this.Save() -//} -// -//func (this *XSlotsPoolManager) Shutdown() { -// this.Save() -// module.UnregisteModule(this) -//} -// -//func (this *XSlotsPoolManager) Save() { -// //数据先整合 -// //for k, v := range this.SlotsPoolData { -// // data, err := json.Marshal(v) -// // if err == nil { -// // this.SlotsPoolStr[k] = string(data) -// // } -// //} -// //再保存 -// buff, err := json.Marshal(this.SlotsPoolStr) -// if err == nil { -// model.UptStrKVGameData(this.SlotsPoolDBKey, string(buff)) -// } else { -// logger.Logger.Error("Marshal coin pool error:", err) -// } -//} -// -//func init() { -// //module.RegisteModule(XSlotsPoolMgr, time.Minute, 0) +// return slots //} + +// ////////////////////////////////////////////////////////////////// +// / Module Implement [beg] +// ////////////////////////////////////////////////////////////////// +func (this *XSlotsPoolManager) ModuleName() string { + return "XSlotsPoolManager" +} + +func (this *XSlotsPoolManager) Init() { + this.SlotsPoolDBKey = fmt.Sprintf("XSlotsPoolManager_Srv%v", common.GetSelfSrvId()) + data := model.GetStrKVGameData(this.SlotsPoolDBKey) + err := json.Unmarshal([]byte(data), &this.SlotsPoolStr) + if err != nil { + logger.Logger.Error("Unmarshal slots pool error:", err) + } +} + +func (this *XSlotsPoolManager) Update() { + this.Save() +} + +func (this *XSlotsPoolManager) Shutdown() { + this.Save() + module.UnregisteModule(this) +} + +func (this *XSlotsPoolManager) Save() { + //数据先整合 + for k, v := range this.SlotsPoolData { + data, err := json.Marshal(v) + if err == nil { + this.SlotsPoolStr[k] = string(data) + } + } + //再保存 + buff, err := json.Marshal(this.SlotsPoolStr) + if err == nil { + model.UptStrKVGameData(this.SlotsPoolDBKey, string(buff)) + } else { + logger.Logger.Error("Marshal coin pool error:", err) + } +} + +func init() { + module.RegisteModule(XSlotsPoolMgr, time.Minute, 0) +} diff --git a/gamesrv/caishen/action_caishen.go b/gamesrv/caishen/action_caishen.go new file mode 100644 index 0000000..0930d90 --- /dev/null +++ b/gamesrv/caishen/action_caishen.go @@ -0,0 +1,55 @@ +package caishen + +import ( + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/netlib" + + "mongo.games.com/game/common" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/protocol/caishen" +) + +// 财神的操作 +type CSCaiShenOpPacketFactory struct { +} +type CSCaiShenOpHandler struct { +} + +func (this *CSCaiShenOpPacketFactory) CreatePacket() interface{} { + pack := &caishen.CSCaiShenOp{} + return pack +} +func (this *CSCaiShenOpHandler) Process(s *netlib.Session, packetid int, data interface{}, sid int64) error { + logger.Logger.Trace("CSCaiShenOpHandler Process recv ", data) + if csCaiShenOp, ok := data.(*caishen.CSCaiShenOp); ok { + p := base.PlayerMgrSington.GetPlayer(sid) + if p == nil { + logger.Logger.Warn("CSCaiShenOpHandler p == nil") + return nil + } + scene := p.GetScene() + if scene == nil { + logger.Logger.Warn("CSCaiShenOpHandler p.scene == nil") + return nil + } + if scene.GameId != common.GameId_CaiShen { + logger.Logger.Error("CSCaiShenOpHandler gameId Error ", scene.GameId) + return nil + } + if !scene.HasPlayer(p) { + return nil + } + sp := scene.GetScenePolicy() + if sp != nil { + sp.OnPlayerOp(scene, p, int(csCaiShenOp.GetOpCode()), csCaiShenOp.GetParams()) + } + return nil + } + return nil +} + +func init() { + // 财神的操作 + common.RegisterHandler(int(caishen.CaiShenPacketID_PACKET_CS_CAISHEN_PLAYEROP), &CSCaiShenOpHandler{}) + netlib.RegisterFactory(int(caishen.CaiShenPacketID_PACKET_CS_CAISHEN_PLAYEROP), &CSCaiShenOpPacketFactory{}) +} diff --git a/gamesrv/caishen/constant.go b/gamesrv/caishen/constant.go new file mode 100644 index 0000000..c181c0b --- /dev/null +++ b/gamesrv/caishen/constant.go @@ -0,0 +1,120 @@ +package caishen + +import ( + "encoding/json" + "time" + + "mongo.games.com/game/model" +) + +// 玩家游戏数据索引 +const ( + CaiShenFreeTimes int = iota //0 当前剩余免费次数 + CaiShenIndexMax +) + +// 通知奖池变化的时间间隔 +const jackpotNoticeInterval = time.Second + +// 场景状态 +const ( + CaiShenSceneStateStart int = iota //开始游戏 + CaiShenSceneStateMax +) + +// 玩家操作 +const ( + CaiShenPlayerOpStart int = iota //游戏 + CaiShenPlayerHistory // 游戏记录 + CaiShenBurstHistory // 爆奖记录 + CaiShenBonusGame // 小游戏 + CaiShenBonusGameRecord // 小游戏操作记录 +) + +// 小游戏超时时间 +const ( + CaiShenBonusGameTimeout = time.Second * 60 + CaiShenBonusGameStageTimeout = 15 // 小游戏每阶段的超时时间 秒 +) + +type GameResultLog struct { + BaseResult *model.SlotBaseResultType + AllLine int32 //线路数 + UserName string //昵称 + WinLines []int //赢分的线 + BetLines []int64 //下注的线 +} + +// 财神解析的数据 +type CaiShenGameNoteData struct { + Source int32 + Data *GameResultLog +} + +// 财神游戏记录 +func UnMarshalCaiShenGameNote(data string) (roll interface{}, err error) { + gnd := &CaiShenGameNoteData{} + if err := json.Unmarshal([]byte(data), gnd); err != nil { + return nil, err + } + roll = gnd.Data + return +} + +var DebugData = [][]int{ + { + 1, 1, 1, 5, 5, + 1, 1, 1, 3, 4, + 6, 7, 8, 9, 10, + }, + { + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, + }, + { + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, + }, + { + 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, + }, + { + 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, + }, + { + 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, + }, + { + 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, + }, + { + 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, + }, + { + 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, + }, + { + 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, + }, + { + 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, + }, +} diff --git a/gamesrv/caishen/playerdata_caishen.go b/gamesrv/caishen/playerdata_caishen.go new file mode 100644 index 0000000..cdfa9af --- /dev/null +++ b/gamesrv/caishen/playerdata_caishen.go @@ -0,0 +1,156 @@ +package caishen + +import ( + "encoding/json" + "math/rand" + + "mongo.games.com/goserver/core/timer" + + rule "mongo.games.com/game/gamerule/caishen" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/protocol/caishen" +) + +type CaiShenPlayerData struct { + *base.Player + spinID int64 //当前旋转ID + score int32 //单线押注数 + freeTimes int32 //免费转动次数 + cards []int32 //15张牌 + //RollGameType *model.CaiShenType //记录信息 + RollGameType *GameResultLog //记录信息 + enterGameCoin int64 //玩家进入初始金币 + taxCoin int64 //本局税收 + winCoin int64 //本局收税前赢的钱 + linesWinCoin int64 //本局中奖线赢得钱 + jackpotWinCoin int64 //本局奖池赢的钱 + smallGameWinCoin int64 //本局小游戏赢的钱 //新版本已废弃 + betLines []int64 //下注的选线 + totalPriceBonus int64 //小游戏得分 + bonusTimerHandle timer.TimerHandle //托管handle + currentLogId string //爆奖玩家logid + leavetime int32 //用户离开时间 + bonusStage int32 //小游戏所处阶段 1选金额 2选倍率 + bonusStartTime int64 //小游戏阶段开始时间 + bonusOpRecord []int32 //小游戏操作记录 + bonusGame *caishen.CaiShenBonusGameInfo //小游戏 + bonusX []int32 //小游戏倍率选项 + bonusGameIconData []int32 //小游戏选项图标,用于客户端展示 + billedData *caishen.GameBilledData + DebugGame bool //测试 + TestNum int +} + +// 玩家初始化 +func (this *CaiShenPlayerData) init(s *base.Scene) { + this.Clean() + this.score = 0 + this.freeTimes = 0 + //this.RollGameType = &model.CaiShenType{} + this.RollGameType = &GameResultLog{} + this.RollGameType.BaseResult = &model.SlotBaseResultType{} + this.enterGameCoin = this.Coin + this.currentLogId = "" + this.billedData = &caishen.GameBilledData{} + this.DebugGame = true + this.TestNum = 0 + + // 加载玩家游戏数据 + if this.GDatas == nil { + this.GDatas = make(map[string]*model.PlayerGameInfo) + } + if d, exist := this.GDatas[s.KeyGamefreeId]; exist { + gLen := len(d.Data) + if gLen < CaiShenIndexMax { + for i := gLen; i < CaiShenIndexMax; i++ { + d.Data = append(d.Data, 0) + } + } + } else { + pgd := &model.PlayerGameInfo{ + Data: make([]int64, CaiShenIndexMax, CaiShenIndexMax), + } + this.GDatas[s.KeyGamefreeId] = pgd + } + this.LoadPlayerGameData(s.KeyGamefreeId) + //线条全选 + if len(this.betLines) == 0 { + this.betLines = rule.AllBetLines + } +} + +// 玩家清理数据 +func (this *CaiShenPlayerData) Clean() { + for i := 0; i < len(this.cards); i++ { + this.cards[i] = -1 + } + this.winCoin = 0 + this.taxCoin = 0 + this.linesWinCoin = 0 + this.jackpotWinCoin = 0 + this.smallGameWinCoin = 0 + this.CleanBonus() +} + +// 清理小游戏数据 +func (this *CaiShenPlayerData) CleanBonus() { + this.totalPriceBonus = 0 + this.bonusStage = 0 + this.bonusTimerHandle = timer.TimerHandle(0) + this.bonusStartTime = 0 + this.bonusOpRecord = make([]int32, 0) + this.bonusGame = nil + this.bonusX = nil + this.bonusGameIconData = make([]int32, 0) +} + +// 加载玩家游戏数据 +func (this *CaiShenPlayerData) LoadPlayerGameData(gameFreeId string) { + if d, exist := this.GDatas[gameFreeId]; exist { + this.freeTimes = int32(d.Data[CaiShenFreeTimes]) + if this.freeTimes > 0 && len(d.DataEx) != 0 { + json.Unmarshal(d.DataEx, &this.betLines) + } + } +} + +// 存储玩家游戏数据 +func (this *CaiShenPlayerData) SavePlayerGameData(gameFreeId string) { + if d, exist := this.GDatas[gameFreeId]; exist { + d.Data[CaiShenFreeTimes] = int64(this.freeTimes) + d.DataEx, _ = json.Marshal(this.betLines) + } +} + +// 黑白名单的限制是否生效 +func (this *CaiShenPlayerData) CheckBlackWriteList(isWin bool) bool { + if isWin && this.BlackLevel > 0 && this.BlackLevel <= 10 { + if rand.Int31n(100) < this.BlackLevel*10 { + return true + } + } else if !isWin && this.WhiteLevel > 0 && this.WhiteLevel <= 10 { + if rand.Int31n(100) < this.WhiteLevel*10 { + return true + } + } + return false +} + +// 玩家是否是新手 +func (this *CaiShenPlayerData) IsFNovice(keyGameId string) { + if f, ok := this.IsFoolPlayer[keyGameId]; ok { + if !f { + return + } + } else { + this.IsFoolPlayer[keyGameId] = true + return + } + if data, ok := this.GDatas[keyGameId]; ok { + if data.Statics.GameTimes < 100 && data.Statics.TotalOut-data.Statics.TotalIn <= 2000000 { + return + } + this.IsFoolPlayer[keyGameId] = false + } +} diff --git a/gamesrv/caishen/scenedata_caishen.go b/gamesrv/caishen/scenedata_caishen.go new file mode 100644 index 0000000..abfc83e --- /dev/null +++ b/gamesrv/caishen/scenedata_caishen.go @@ -0,0 +1,339 @@ +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.DbGameFree == nil { + return false + } + params := this.DbGameFree.GetJackpot() + this.jackpot = &base.SlotJackpotPool{} + if this.jackpot.Small <= 0 { + this.jackpot.Small = 0 + this.jackpot.VirtualJK = int64(params[rule.CAISHEN_JACKPOT_InitJackpot] * this.DbGameFree.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.DbGameFree.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.DbGameFree.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.DbGameFree.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.DbGameFree.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.DbGameFree.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.DbGameFree.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.DbGameFree.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.DbGameFree.GetJackpot() + var jackpotInit = int64(jackpotParams[rule.CAISHEN_JACKPOT_InitJackpot] * this.DbGameFree.GetBaseScore()) //奖池初始值 + + //AI机器人爆奖 + val := this.jackpot.VirtualJK + this.jackpot.VirtualJK = jackpotInit + bet := this.DbGameFree.GetBaseScore() * int32(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.DbGameFree.GetId())) + // if !p.IsRob && + // todayGamefreeIDSceneData != nil && + // this.DbGameFree.GetPlayNumLimit() != 0 && + // todayGamefreeIDSceneData.GameTimes >= int64(this.DbGameFree.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) + } + } + } +} diff --git a/gamesrv/caishen/scenepolicy_caishen.go b/gamesrv/caishen/scenepolicy_caishen.go new file mode 100644 index 0000000..cd634e7 --- /dev/null +++ b/gamesrv/caishen/scenepolicy_caishen.go @@ -0,0 +1,1096 @@ +package caishen + +import ( + "fmt" + "math" + "math/rand" + "os" + "strconv" + "sync" + "time" + + "mongo.games.com/goserver/core" + "mongo.games.com/goserver/core/basic" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/task" + "mongo.games.com/goserver/core/timer" + + "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/server" +) + +//////////////////////////////////////////////////////////////////////////////// +//财神 +//////////////////////////////////////////////////////////////////////////////// + +// 房间内主要逻辑 +var ScenePolicyCaiShenSington = &ScenePolicyCaiShen{} + +type ScenePolicyCaiShen struct { + base.BaseScenePolicy + states [CaiShenSceneStateMax]base.SceneState +} + +// 创建场景扩展数据 +func (this *ScenePolicyCaiShen) CreateSceneExData(s *base.Scene) interface{} { + sceneEx := NewCaiShenSceneData(s) + if sceneEx != nil { + if sceneEx.init() { + s.ExtraData = sceneEx + } + } + return sceneEx +} + +// 创建玩家扩展数据 +func (this *ScenePolicyCaiShen) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} { + playerEx := &CaiShenPlayerData{Player: p} + if playerEx != nil { + p.ExtraData = playerEx + } + return playerEx +} + +// 场景开启事件 +func (this *ScenePolicyCaiShen) OnStart(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyCaiShen) OnStart, SceneId=", s.SceneId) + sceneEx := NewCaiShenSceneData(s) + if sceneEx != nil { + if sceneEx.init() { + s.ExtraData = sceneEx + s.ChangeSceneState(CaiShenSceneStateStart) //改变当前的玩家状态 + } + } +} + +// 场景关闭事件 +func (this *ScenePolicyCaiShen) OnStop(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyCaiShen) OnStop , SceneId=", s.SceneId) + if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { + sceneEx.SaveData(true) + } +} + +// 场景心跳事件 +func (this *ScenePolicyCaiShen) OnTick(s *base.Scene) { + if s == nil { + return + } + if s.SceneState != nil { + s.SceneState.OnTick(s) + } +} + +// 玩家进入事件 +func (this *ScenePolicyCaiShen) OnPlayerEnter(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerEnter, SceneId=", s.SceneId, " player=", p.SnId) + if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { + playerEx := &CaiShenPlayerData{Player: p} + playerEx.init(s) // 玩家当前信息初始化 + playerEx.score = sceneEx.DbGameFree.GetBaseScore() // 底注 + sceneEx.players[p.SnId] = playerEx + p.ExtraData = playerEx + CaiShenSendRoomInfo(s, p, sceneEx, playerEx, nil) + s.FirePlayerEvent(p, base.PlayerEventEnter, nil) //回调会调取 onPlayerEvent事件 + } +} + +// 玩家离开事件 +func (this *ScenePolicyCaiShen) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerLeave, SceneId=", s.SceneId, " player=", p.SnId) + if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { + if this.CanChangeCoinScene(s, p) { + if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { + playerEx.SavePlayerGameData(s.KeyGamefreeId) + } + sceneEx.OnPlayerLeave(p, reason) + s.FirePlayerEvent(p, base.PlayerEventLeave, []int64{int64(reason)}) + } + } +} + +// 玩家掉线 +func (this *ScenePolicyCaiShen) OnPlayerDropLine(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerDropLine, SceneId=", s.SceneId, " player=", p.SnId) + s.FirePlayerEvent(p, base.PlayerEventDropLine, nil) + if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { + if sceneEx.Gaming { + return + } + } +} + +// 玩家重连 +func (this *ScenePolicyCaiShen) OnPlayerRehold(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerRehold, SceneId=", s.SceneId, " player=", p.Name) + //if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { + // if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { + //发送房间信息给自己 + //CaiShenSendRoomInfo(s, p, sceneEx, playerEx) + s.FirePlayerEvent(p, base.PlayerEventRehold, nil) + // } + //} +} + +// 玩家返回房间 +func (this *ScenePolicyCaiShen) OnPlayerReturn(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyCaiShen) OnPlayerReturn, SceneId=", s.SceneId, " player=", p.Name) + if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { + if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { + //发送房间信息给自己 + CaiShenSendRoomInfo(s, p, sceneEx, playerEx, playerEx.billedData) + s.FirePlayerEvent(p, base.PlayerEventReturn, nil) + } + } +} + +// 玩家操作 +func (this *ScenePolicyCaiShen) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + if s == nil || p == nil { + return false + } + if s.SceneState != nil { + return s.SceneState.OnPlayerOp(s, p, opcode, params) + } + return true +} + +// 玩家事件 +func (this *ScenePolicyCaiShen) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { + if s == nil || p == nil { + return + } + if s.SceneState != nil { + s.SceneState.OnPlayerEvent(s, p, evtcode, params) + } +} + +// 是否完成了整个牌局 +func (this *ScenePolicyCaiShen) IsCompleted(s *base.Scene) bool { return false } + +// 是否可以强制开始 +func (this *ScenePolicyCaiShen) IsCanForceStart(s *base.Scene) bool { return true } + +// 当前状态能否换桌 +func (this *ScenePolicyCaiShen) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if s == nil || p == nil { + return true + } + if s.SceneState != nil { + return s.SceneState.CanChangeCoinScene(s, p) + } + return true +} + +func (this *ScenePolicyCaiShen) RegisteSceneState(state base.SceneState) { + if state == nil { + return + } + stateid := state.GetState() + if stateid < 0 || stateid >= CaiShenSceneStateMax { + return + } + this.states[stateid] = state +} + +func (this *ScenePolicyCaiShen) GetSceneState(s *base.Scene, stateid int) base.SceneState { + if stateid >= 0 && stateid < CaiShenSceneStateMax { + return ScenePolicyCaiShenSington.states[stateid] + } + return nil +} +func (this *ScenePolicyCaiShen) GetJackPotVal(s *base.Scene) int64 { + if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { + if sceneEx.lastJackpotValue != sceneEx.jackpot.VirtualJK { + return sceneEx.jackpot.VirtualJK + } + } + return 0 +} +func CaiShenSendRoomInfo(s *base.Scene, p *base.Player, sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerData, data *caishen.GameBilledData) { + logger.Logger.Trace("-------------------发送房间消息 ", s.RoomId, p.SnId) + pack := &caishen.SCCaiShenRoomInfo{ + RoomId: proto.Int(s.SceneId), + Creator: proto.Int32(s.Creator), + GameId: proto.Int(s.GameId), + RoomMode: proto.Int(s.GameMode), + Params: s.Params, + State: proto.Int(s.SceneState.GetState()), + Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), + GameFreeId: proto.Int32(s.DbGameFree.Id), + BilledData: data, + } + + if playerEx != nil { + pd := &caishen.CaiShenPlayerData{ + SnId: proto.Int32(playerEx.SnId), + Name: proto.String(playerEx.Name), + Head: proto.Int32(playerEx.Head), + Sex: proto.Int32(playerEx.Sex), + Coin: proto.Int64(playerEx.Coin), + HeadOutLine: proto.Int32(playerEx.HeadOutLine), + VIP: proto.Int32(playerEx.VIP), + } + pack.Players = append(pack.Players, pd) + //for _, value := range playerEx.cards { + // pack.Cards = append(pack.Cards, int32(value)) + //} + pack.BetLines = playerEx.betLines + pack.FreeTimes = proto.Int32(playerEx.freeTimes) + pack.Chip = proto.Int32(s.DbGameFree.BaseScore) + pack.SpinID = proto.Int64(playerEx.spinID) + if playerEx.totalPriceBonus > 0 { + switch playerEx.bonusStage { + case 0: + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + case 1: + if time.Now().Unix()-playerEx.bonusStartTime >= CaiShenBonusGameStageTimeout*2 { + playerEx.CleanBonus() + } else if time.Now().Unix()-playerEx.bonusStartTime >= CaiShenBonusGameStageTimeout { + playerEx.bonusStage = 2 + playerEx.bonusStartTime += CaiShenBonusGameStageTimeout + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + leftTime := playerEx.bonusStartTime + CaiShenBonusGameStageTimeout + 2 - time.Now().Unix() + pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) + } else { + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + leftTime := playerEx.bonusStartTime + CaiShenBonusGameStageTimeout + 2 - time.Now().Unix() + pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusGameIconData...) + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusOpRecord...) + } + case 2: + if time.Now().Unix()-playerEx.bonusStartTime >= CaiShenBonusGameStageTimeout { + playerEx.CleanBonus() + } else { + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + leftTime := playerEx.bonusStartTime + CaiShenBonusGameStageTimeout + 2 - time.Now().Unix() + pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) + } + } + } + if playerEx.totalPriceBonus > 0 { + pack.TotalPriceBonus = proto.Int64(playerEx.totalPriceBonus) + pack.BonusGame = playerEx.bonusGame + pack.BonusX = playerEx.bonusX + } + } + proto.SetDefaults(pack) + p.SendToClient(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_ROOMINFO), pack) +} + +type SceneStateCaiShenStart struct { +} + +// 获取当前场景状态 +func (this *SceneStateCaiShenStart) GetState() int { return CaiShenSceneStateStart } + +// 是否可以切换状态到 +func (this *SceneStateCaiShenStart) CanChangeTo(s base.SceneState) bool { return true } + +// 当前状态能否换桌 +func (this *SceneStateCaiShenStart) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if _, ok := p.ExtraData.(*CaiShenPlayerData); ok { + return true + } + return true +} + +func (this *SceneStateCaiShenStart) GetTimeout(s *base.Scene) int { return 0 } + +func (this *SceneStateCaiShenStart) OnEnter(s *base.Scene) { + if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { + logger.Logger.Tracef("(this *Scene) [%v] 场景状态进入 %v", s.SceneId, len(sceneEx.players)) + sceneEx.StateStartTime = time.Now() + pack := &caishen.SCCaiShenRoomState{ + State: proto.Int(this.GetState()), + } + proto.SetDefaults(pack) + s.Broadcast(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_ROOMSTATE), pack, 0) + } +} + +func (this *SceneStateCaiShenStart) OnLeave(s *base.Scene) {} + +func (this *SceneStateCaiShenStart) OnTick(s *base.Scene) { + if sceneEx, ok := s.ExtraData.(*CaiShenSceneData); ok { + sceneEx.AIAddJackPot() + sceneEx.AIBurstJackPot() + sceneEx.KickPlayerByTime() + } +} + +func (this *SceneStateCaiShenStart) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + playerEx, ok := p.ExtraData.(*CaiShenPlayerData) + if !ok { + return false + } + sceneEx, ok := s.ExtraData.(*CaiShenSceneData) + if !ok { + return false + } + if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { + //离开有统计 + sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) + return false + } + switch opcode { + case CaiShenPlayerOpStart: //开始 + //if !caiShenBenchTest { + // caiShenBenchTest = true + // //for i := 0; i < 10; i++ { + // // //this.BenchTest(s, p) + // // this.WinTargetBenchTest(s, p) + // //} + // this.MultiplayerBenchTest(s) + // return true + //} + + //参数是否合法 + //params 参数0底注,后面跟客户端选择的线n条线(1<=n<=25),客户端线是从1开始算起1~25条线 + if len(params) < 2 || len(params) > rule.LINENUM+1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + //先做底注校验 + if sceneEx.DbGameFree.GetBaseScore() != int32(params[0]) { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + playerEx.score = int32(params[0]) // 单线押注数 + // 小游戏未结束 不能进行下一次旋转 + if playerEx.totalPriceBonus > 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + //判断线条是否重复,是否合法 + lineFlag := make(map[int64]bool) + lineParams := make([]int64, 0) + for i := 1; i < len(params); i++ { + lineNum := params[i] + if lineNum >= 1 && lineNum <= int64(rule.LINENUM) && !lineFlag[lineNum] { + lineParams = append(lineParams, lineNum) + lineFlag[lineNum] = true + } else { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + } + //没有选线参数 + if len(lineParams) == 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + + //获取总投注金额(所有线的总投注) | 校验玩家余额是否足够 + totalBetValue := (int64(len(lineParams))) * params[0] + if playerEx.freeTimes <= 0 && totalBetValue > playerEx.Coin { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_CoinNotEnough, params) + return false + } else if playerEx.freeTimes <= 0 && int64(sceneEx.DbGameFree.GetBetLimit()) > playerEx.Coin { //押注限制 + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_CoinNotEnough, params) + return false + } + + p.LastOPTimer = time.Now() + sceneEx.GameNowTime = time.Now() + sceneEx.NumOfGames++ + p.GameTimes++ + //playerEx.StartCoin = playerEx.Coin + + //获取当前水池的上下文环境 + sceneEx.CpCtx = base.CoinPoolMgr.GetCoinPoolCtx(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) + + //税收比例 + taxRate := sceneEx.DbGameFree.GetTaxRate() + if taxRate < 0 || taxRate > 10000 { + logger.Logger.Tracef("CaiShenErrorTaxRate [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate) + taxRate = 500 + } + //水池设置 + coinPoolSetting := base.CoinPoolMgr.GetCoinPoolSetting(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) + //baseRate := coinPoolSetting.GetBaseRate() //基础赔率 + ctroRate := 500 //调节赔率 暗税系数 + jackpotRate := ctroRate //奖池系数 + logger.Logger.Tracef("CaiShenRates [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate, ctroRate) + + playerEx.IsFNovice(sceneEx.KeyGameId) + isFoolPlayer := false + var gamePoolCoin int64 + //if isFoolPlayer { + // gamePoolCoin = base.CoinPoolMgr.GetNoviceCoinPool(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} else { + gamePoolCoin = base.CoinPoolMgr.GetCoin(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} + prizeFund := gamePoolCoin - sceneEx.jackpot.VirtualJK // 除去奖池的水池剩余金额 + + // 奖池参数 + var jackpotParam = sceneEx.DbGameFree.GetJackpot() + var jackpotInit = int64(jackpotParam[rule.CAISHEN_JACKPOT_InitJackpot] * sceneEx.DbGameFree.GetBaseScore()) //奖池初始值 + + var jackpotFundAdd, prizeFundAdd int64 + if playerEx.freeTimes <= 0 { //正常模式才能记录用户的押注变化,免费模式不能改变押注 + playerEx.betLines = lineParams // 选线记录 + jackpotFundAdd = int64(math.Floor(float64(totalBetValue) * (float64(jackpotRate) / 10000.0))) //奖池要增加的金额 + prizeFundAdd = totalBetValue - jackpotFundAdd + playerEx.TotalBet += totalBetValue //总下注额(从进房间开始,包含多局游戏的下注) + //扣除投注金币 + p.AddCoin(-totalBetValue, common.GainWay_HundredSceneLost, base.SyncFlag_ToClient, "system", s.GetSceneName()) + //p.Statics(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, -totalBetValue, true) + if !p.IsRob && !sceneEx.Testing { + // 推送金币 + sceneEx.PushCoinPool(prizeFundAdd, isFoolPlayer) + //base.CoinPoolMgr.PushCoin(sceneEx.GetGameFreeId(), sceneEx.GroupId, sceneEx.Platform, int64(float64(totalBetValue)*(float64(10000-ctroRate)/10000.0))) + } + + ////统计参与游戏次数 + //if !sceneEx.Testing && !playerEx.IsRob { + // pack := &server.GWSceneEnd{ + // GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), + // Players: []*server.PlayerCtx{&server.PlayerCtx{SnId: proto.Int32(playerEx.SnId), Coin: proto.Int64(playerEx.Coin)}}, + // } + // proto.SetDefaults(pack) + // sceneEx.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENEEND), pack) + //} + } else { //免费次数时,不能改线改选线 + totalBetValue = 0 + } + + writeBlackTryTimes := 0 + WriteBlack: + slotData := make([]int, 0) + var spinRes CaiShenSpinResult + var slotDataIsOk bool + for { + var symbolType rule.Symbol + if gamePoolCoin < int64(coinPoolSetting.GetLowerLimit()) { // userInfo.prizeFund < limit * roomId + symbolType = rule.SYMBOL1 + } else { + symbolType = rule.SYMBOL2 + } + slotData, _ = rule.GenerateSlotsData_v2(symbolType) + spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) + + // 免费次数时 不允许爆奖 + if playerEx.freeTimes > 0 && spinRes.IsJackpot { + break + } + if spinRes.JackpotCnt > 1 { + break + } + if spinRes.IsJackpot { + if sceneEx.jackpot.Small < sceneEx.jackpot.VirtualJK { + break + } + } + spinCondition := prizeFund + prizeFundAdd - (spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue() + spinRes.TotalPrizeJackpot) + spinCondition += jackpotFundAdd + sceneEx.jackpot.VirtualJK - jackpotInit + win := spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue() + spinRes.TotalPrizeJackpot + // 现金池不足时 重新发牌 + if spinCondition < 0 && win > totalBetValue { + if !spinRes.IsJackpot { // 非爆奖 水池不足 不再进行黑白名单调控 + writeBlackTryTimes = 999 + } + break + } + + // 非爆奖时 不允许赢取太大的奖励 + var limitBigWin int64 = 50 + if spinCondition < int64(coinPoolSetting.GetLowerLimit()) { //现金池不足时 + limitBigWin = int64(jackpotParam[rule.CAISHEN_JACKPOT_LIMITWIN_PRIZELOW]) + } else { + limitBigWin = int64(jackpotParam[rule.CAISHEN_JACKPOT_LIMITWIN_PRIZEHIGH]) + } + if totalBetValue > 0 && !spinRes.IsJackpot && spinRes.TotalPrizeLine+spinRes.BonusGame.GetTotalPrizeValue() > totalBetValue*limitBigWin { + break + } + + // 小游戏次数限制 + // 爆奖次数限制 + + slotDataIsOk = true + + break + } + + if !slotDataIsOk { + slotData = rule.MissData[rand.Intn(len(rule.MissData))] + spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) + } + + // 黑白名单调控 防止异常循环,添加上限次数 + if writeBlackTryTimes < 100 && playerEx.CheckBlackWriteList(spinRes.TotalPrizeLine+spinRes.TotalPrizeJackpot+spinRes.BonusGame.GetTotalPrizeValue() > totalBetValue) { + writeBlackTryTimes++ + goto WriteBlack + } else if writeBlackTryTimes >= 100 && writeBlackTryTimes != 999 { + logger.Logger.Warnf("CaiShenWriteBlackTryTimesOver [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, gamePoolCoin, playerEx.BlackLevel, playerEx.WhiteLevel) + } + // 奖池水池处理 + if spinRes.IsJackpot { + sceneEx.jackpot.Small -= sceneEx.jackpot.VirtualJK + if sceneEx.jackpot.Small < 0 { + sceneEx.jackpot.Small = 0 + } + sceneEx.jackpot.VirtualJK = jackpotInit + } else { + sceneEx.jackpot.Small += jackpotFundAdd + sceneEx.jackpot.VirtualJK += jackpotFundAdd + } + + // 玩家赢钱 + totalWinScore := spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot + if totalWinScore > 0 || len(spinRes.BonusX) > 0 { + p.AddCoin(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue(), common.GainWay_HundredSceneWin, 0, "system", s.GetSceneName()) + //p.Statics(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore, true) + if !p.IsRob && !sceneEx.Testing { + sceneEx.PopCoinPool(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore, isFoolPlayer) + //base.CoinPoolMgr.PopCoin(sceneEx.GetGameFreeId(), sceneEx.GroupId, sceneEx.Platform, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore) + } + playerEx.taxCoin = spinRes.TotalTaxScore + playerEx.AddServiceFee(playerEx.taxCoin) + } + p.StaticsLaba(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, totalBetValue, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore) + + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Sucess, append(params[:1], playerEx.betLines...)) + + //免费次数 + var isFreeFlag bool + if playerEx.freeTimes > 0 { + playerEx.freeTimes-- + isFreeFlag = true + } + playerEx.freeTimes += spinRes.AddFreeTimes + + rule.SpinID++ + playerEx.spinID = rule.SpinID + playerEx.cards = spinRes.SlotsData + playerEx.winCoin = spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot + spinRes.BonusGame.GetTotalPrizeValue() + playerEx.taxCoin + playerEx.linesWinCoin = spinRes.TotalPrizeLine + playerEx.jackpotWinCoin = spinRes.TotalPrizeJackpot + playerEx.smallGameWinCoin = spinRes.BonusGame.GetTotalPrizeValue() + playerEx.CurrentBet = totalBetValue + playerEx.CurrentTax = playerEx.taxCoin + + // 小游戏超时处理 + if len(spinRes.BonusX) > 0 { + playerEx.totalPriceBonus = spinRes.BonusGame.GetTotalPrizeValue() + playerEx.bonusGame = &spinRes.BonusGame + playerEx.bonusX = spinRes.BonusX + logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) + // playerEx.bonusTimerHandle, _ = timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool { + // this.OnPlayerOp(s, p, CaiShenBonusGame, []int64{playerEx.spinID}) + // return true + // }), nil, CaiShenBonusGameTimeout, 1) + } + + playerEx.billedData = &caishen.GameBilledData{ + SpinID: proto.Int64(playerEx.spinID), + SlotsData: spinRes.SlotsData, + AddFreeSpin: proto.Int32(spinRes.AddFreeTimes), + IsJackpot: proto.Bool(spinRes.IsJackpot), + PrizeLines: spinRes.LinesInfo, + TotalPrizeValue: proto.Int64(totalWinScore), + TotalPaylinePrizeValue: proto.Int64(spinRes.TotalPrizeLine), + TotalJackpotValue: proto.Int64(spinRes.TotalPrizeJackpot), + Balance: proto.Int64(playerEx.Coin - spinRes.BonusGame.GetTotalPrizeValue()), + FreeSpins: proto.Int32(playerEx.freeTimes), + Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), + BonusX: spinRes.BonusX, + BonusGame: &spinRes.BonusGame, + } + pack := &caishen.SCCaiShenGameBilled{ + BilledData: playerEx.billedData, + } + proto.SetDefaults(pack) + logger.Logger.Infof("CaiShenPlayerOpStart %v", pack) + p.SendToClient(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_GAMEBILLED), pack) + + // 记录本次操作 + playerEx.RollGameType.BaseResult.WinTotal = pack.BilledData.GetTotalPrizeValue() + pack.BilledData.GetBonusGame().GetTotalPrizeValue() + playerEx.RollGameType.BaseResult.IsFree = isFreeFlag + playerEx.RollGameType.BaseResult.AllWinNum = int32(len(pack.BilledData.PrizeLines)) + playerEx.RollGameType.BaseResult.WinRate = spinRes.TotalWinRate + playerEx.RollGameType.BaseResult.Cards = pack.BilledData.GetSlotsData() + playerEx.RollGameType.WinLines = spinRes.WinLines + playerEx.RollGameType.BaseResult.WinLineScore = pack.BilledData.TotalPaylinePrizeValue + playerEx.RollGameType.BaseResult.WinJackpot = pack.BilledData.GetTotalJackpotValue() + playerEx.RollGameType.BaseResult.WinSmallGame = pack.BilledData.GetBonusGame().GetTotalPrizeValue() + playerEx.RollGameType.BaseResult.IsFoolPlayer = isFoolPlayer + CaiShenCheckAndSaveLog(sceneEx, playerEx) + + // 广播奖池 + if totalBetValue == 0 && !spinRes.IsJackpot { // 没改变奖池 + return true + } + // 添加进开奖记录里面 + if spinRes.IsJackpot { + sceneEx.RecordBurstLog(playerEx.Name, pack.BilledData.GetTotalJackpotValue(), playerEx.CurrentBet) + } + logger.Logger.Tracef("---caishen---当前奖池:真人[%v] 虚拟[%v]", sceneEx.jackpot.Small, sceneEx.jackpot.VirtualJK) + case CaiShenBurstHistory: + sceneEx.BurstHistory(playerEx) + case CaiShenPlayerHistory: + task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { + spinid := strconv.FormatInt(int64(playerEx.SnId), 10) + gpl := model.GetPlayerListByHallEx(p.SnId, p.Platform, 0, 80, 0, 0, 0, s.DbGameFree.GetGameClass(), s.GameId) + pack := &caishen.SCCaiShenPlayerHistory{} + for _, v := range gpl.Data { + //if v.GameDetailedLogId == "" { + // logger.Logger.Error("CaiShenPlayerHistory GameDetailedLogId is nil") + // break + //} + //gdl := model.GetPlayerHistory(p.Platform, v.GameDetailedLogId) + //if gdl == nil { + // logger.Logger.Error("CaiShenPlayerHistory gdl is nil") + // continue + //} + //data, err := UnMarshalCaiShenGameNote(gdl.GameDetailedNote) + //if err != nil { + // logger.Logger.Errorf("UnMarshalCaiShenGameNote error:%v", err) + //} + //gnd := data.(*GameResultLog) + player := &caishen.CaiShenPlayerHistoryInfo{ + SpinID: proto.String(spinid), + CreatedTime: proto.Int64(int64(v.Ts)), + TotalBetValue: proto.Int64(v.BetAmount), + TotalPriceValue: proto.Int64(v.WinTotal), + IsFree: proto.Bool(v.IsFree), + TotalBonusValue: proto.Int64(v.WinSmallGame), + } + pack.PlayerHistory = append(pack.PlayerHistory, player) + } + proto.SetDefaults(pack) + logger.Logger.Info("CaiShenPlayerHistory: ", pack) + return pack + + }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { + if data == nil { + logger.Logger.Error("CaiShenPlayerHistory data is nil") + return + } + p.SendToClient(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_PLAYERHISTORY), data) + }), "CSGetCaiShenPlayerHistoryHandler").Start() + case CaiShenBonusGame: + //params 参数0 spinID + //参数是否合法 + if len(params) < 1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + if playerEx.spinID != params[0] || playerEx.totalPriceBonus <= 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + if playerEx.bonusTimerHandle != timer.TimerHandle(0) { + timer.StopTimer(playerEx.bonusTimerHandle) + playerEx.bonusTimerHandle = timer.TimerHandle(0) + } + logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) + + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Sucess, []int64{playerEx.totalPriceBonus, playerEx.Coin}) + playerEx.CleanBonus() + case CaiShenBonusGameRecord: + // params[0] 小游戏阶段: 0 小游戏动画开始 1 小游戏界面1 2 切换小游戏界面2 + // params[1] 小游戏界面1时,选择奖项的界面位置信息 + if len(params) < 1 || params[0] < 0 || params[0] > 2 || playerEx.totalPriceBonus <= 0 || (params[0] == 1 && len(params) < 2) { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + if params[0] == 0 { + if playerEx.bonusStage > 0 || len(params) < 13 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + playerEx.bonusStage = 1 + playerEx.bonusStartTime = time.Now().Unix() + for i := 1; i < len(params); i++ { + playerEx.bonusGameIconData = append(playerEx.bonusGameIconData, int32(params[i])) + } + } else if params[0] == 2 { + if playerEx.bonusStage != 1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + playerEx.bonusStage = 2 + playerEx.bonusStartTime = time.Now().Unix() + } else if params[0] == 1 { + if params[1] < 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } else if playerEx.bonusGame != nil && len(playerEx.bonusOpRecord) >= len(playerEx.bonusGame.BonusData) { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Error, params) + return false + } + playerEx.bonusOpRecord = append(playerEx.bonusOpRecord, int32(params[1])) + } + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, caishen.OpResultCode_OPRC_Sucess, params) + } + return true +} + +func (this *SceneStateCaiShenStart) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { +} + +// 发送玩家操作情况 +func (this *SceneStateCaiShenStart) OnPlayerSToCOp(s *base.Scene, p *base.Player, pos int, opcode int, + opRetCode caishen.OpResultCode, params []int64) { + pack := &caishen.SCCaiShenOp{ + SnId: proto.Int32(p.SnId), + OpCode: proto.Int(opcode), + OpRetCode: opRetCode, + Params: params, + } + proto.SetDefaults(pack) + p.SendToClient(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_PLAYEROP), pack) +} + +var caiShenBenchTest bool +var caiShenBenchTestTimes int + +func (this *SceneStateCaiShenStart) BenchTest(s *base.Scene, p *base.Player) { + const BENCH_CNT = 10000 + setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) + oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + if caiShenBenchTestTimes == 0 { + defaultVal := int64(setting.GetLowerLimit()) + if oldPoolCoin != defaultVal { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) + } + } + caiShenBenchTestTimes++ + + fileName := fmt.Sprintf("caishen-%v-%d.csv", p.SnId, caiShenBenchTestTimes) + file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + defer file.Close() + if err != nil { + file, err = os.Create(fileName) + if err != nil { + return + } + } + file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,中线倍数,中线数,剩余免费次数\r\n") + + oldCoin := p.Coin + p.Coin = 10000000 + if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { + for i := 0; i < BENCH_CNT; i++ { + StartCoin := p.Coin + freeTimes := playerEx.freeTimes + poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + playerEx.UnmarkFlag(base.PlayerState_GameBreak) + suc := this.OnPlayerOp(s, p, CaiShenPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) + inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) + outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin + taxCoin := playerEx.RollGameType.BaseResult.Tax + + str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, StartCoin, p.Coin, inCoin, outCoin, taxCoin, + playerEx.RollGameType.BaseResult.WinSmallGame, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) + file.WriteString(str) + if !suc { + break + } + + if playerEx.totalPriceBonus > 0 { + this.OnPlayerOp(s, p, CaiShenBonusGame, []int64{playerEx.spinID}) + } + } + } + p.Coin = oldCoin +} +func (this *SceneStateCaiShenStart) WinTargetBenchTest(s *base.Scene, p *base.Player) { + const BENCH_CNT = 10000 + var once = sync.Once{} + once.Do(func() { + setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) + oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + if caiShenBenchTestTimes == 0 { + defaultVal := int64(setting.GetLowerLimit()) + if oldPoolCoin != defaultVal { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) + } + } + }) + caiShenBenchTestTimes++ + + fileName := fmt.Sprintf("caishen-win-%v-%d.csv", p.SnId, caiShenBenchTestTimes) + file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + defer file.Close() + if err != nil { + file, err = os.Create(fileName) + if err != nil { + return + } + } + file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,中线倍数,中线数,剩余免费次数\r\n") + oldCoin := p.Coin + switch s.DbGameFree.GetSceneType() { + case 1: + p.Coin = 100000 + case 2: + p.Coin = 500000 + case 3: + p.Coin = 1000000 + case 4: + p.Coin = 10000000 + default: + p.Coin = 100000 + } + var targetCoin = p.Coin + p.Coin/10 + if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { + for i := 0; p.Coin < targetCoin; i++ { + StartCoin := p.Coin + freeTimes := playerEx.freeTimes + poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + playerEx.UnmarkFlag(base.PlayerState_GameBreak) + suc := this.OnPlayerOp(s, p, CaiShenPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) + inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) + outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin + taxCoin := playerEx.RollGameType.BaseResult.Tax + + str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, StartCoin, p.Coin, inCoin, outCoin, taxCoin, + playerEx.RollGameType.BaseResult.WinSmallGame, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) + file.WriteString(str) + if !suc { + break + } + + if playerEx.totalPriceBonus > 0 { + this.OnPlayerOp(s, p, CaiShenBonusGame, []int64{playerEx.spinID}) + } + if i > BENCH_CNT { + break + } + } + } + p.Coin = oldCoin +} + +// MultiplayerBenchTest 多人同时测试 模拟正常环境 +func (this *SceneStateCaiShenStart) MultiplayerBenchTest(s *base.Scene) { + const BENCH_CNT = 10000 + var once = sync.Once{} + once.Do(func() { + setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) + oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + if caiShenBenchTestTimes == 0 { + defaultVal := int64(setting.GetLowerLimit()) + if oldPoolCoin != defaultVal { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) + } + } + }) + caiShenBenchTestTimes++ + + fileName := fmt.Sprintf("caishen-total-%v-%d.csv", s.DbGameFree.GetSceneType(), caiShenBenchTestTimes) + file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + defer file.Close() + if err != nil { + file, err = os.Create(fileName) + if err != nil { + return + } + } + file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,爆奖,中线倍数,中线数,剩余免费次数\r\n") + + playersFile := make(map[int32]*os.File) + oldCoins := make(map[int32]int64) + hasCoin := int64(1000 * s.DbGameFree.GetBaseScore()) + robots := make(map[int32]bool) + testPlayers := make(map[int32]*base.Player) + for _, p := range s.Players { + if p.IsRob { + p.IsRob = false + robots[p.SnId] = true + } + fileName := fmt.Sprintf("caishen-player%v-%v-%d.csv", p.SnId, s.DbGameFree.GetSceneType(), caiShenBenchTestTimes) + file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + if err != nil { + file, err = os.Create(fileName) + if err != nil { + return + } + } + file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,爆奖,中线倍数,中线数,剩余免费次数\r\n") + playersFile[p.SnId] = file + oldCoins[p.SnId] = p.Coin + p.Coin = hasCoin + hasCoin = int64(float64(hasCoin) * 1.6) + testPlayers[p.SnId] = p + } + defer func() { + for _, file := range playersFile { + file.Close() + } + for snid, Coin := range oldCoins { + if player := s.GetPlayer(snid); player != nil { + player.Coin = Coin + if robots[player.SnId] { + player.IsRob = true + } + } + } + }() + + totalBet := s.DbGameFree.GetBaseScore() * int32(len(rule.AllBetLines)) + for i := 0; i < BENCH_CNT; i++ { + for snid, p := range testPlayers { + if playerEx, ok := p.ExtraData.(*CaiShenPlayerData); ok { + StartCoin := p.Coin + if StartCoin < int64(totalBet) { + continue + } + freeTimes := playerEx.freeTimes + poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + playerEx.UnmarkFlag(base.PlayerState_GameBreak) + suc := this.OnPlayerOp(s, p, CaiShenPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) + inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) + outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin + taxCoin := playerEx.RollGameType.BaseResult.Tax + lineScore := float64(playerEx.RollGameType.BaseResult.WinRate*s.DbGameFree.GetBaseScore()) * float64(10000.0-s.DbGameFree.GetTaxRate()) / 10000.0 + jackpotScore := outCoin - playerEx.RollGameType.BaseResult.WinSmallGame - int64(lineScore+0.00001) + + str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, StartCoin, p.Coin, inCoin, outCoin, taxCoin, + playerEx.RollGameType.BaseResult.WinSmallGame, jackpotScore, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) + file.WriteString(str) + if pFile := playersFile[snid]; pFile != nil { + pFile.WriteString(str) + } + + if !suc { + continue + } + + if playerEx.totalPriceBonus > 0 { + this.OnPlayerOp(s, p, CaiShenBonusGame, []int64{playerEx.spinID}) + } + } + } + } +} + +func CaiShenCheckAndSaveLog(sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerData) { + //统计金币变动 + //log1 + logger.Logger.Trace("CaiShenCheckAndSaveLog Save ", playerEx.SnId) + //changeCoin := playerEx.Coin - playerEx.StartCoin + changeCoin := playerEx.winCoin - playerEx.taxCoin - playerEx.CurrentBet + startCoin := playerEx.Coin - changeCoin + playerEx.SaveSceneCoinLog(startCoin, changeCoin, + playerEx.Coin, playerEx.CurrentBet, playerEx.taxCoin, playerEx.winCoin, playerEx.jackpotWinCoin, playerEx.smallGameWinCoin) + + //log2 + playerEx.RollGameType.BaseResult.ChangeCoin = changeCoin + playerEx.RollGameType.BaseResult.BasicBet = sceneEx.DbGameFree.GetBaseScore() + playerEx.RollGameType.BaseResult.RoomId = int32(sceneEx.SceneId) + playerEx.RollGameType.BaseResult.AfterCoin = playerEx.Coin + playerEx.RollGameType.BaseResult.BeforeCoin = startCoin + playerEx.RollGameType.BaseResult.IsFirst = sceneEx.IsPlayerFirst(playerEx.Player) + playerEx.RollGameType.BaseResult.PlayerSnid = playerEx.SnId + playerEx.RollGameType.BaseResult.TotalBet = int32(playerEx.CurrentBet) + playerEx.RollGameType.AllLine = int32(len(playerEx.betLines)) + playerEx.RollGameType.BaseResult.FreeTimes = playerEx.freeTimes + playerEx.RollGameType.UserName = playerEx.Name + playerEx.RollGameType.BetLines = playerEx.betLines + playerEx.RollGameType.BaseResult.Tax = playerEx.taxCoin + playerEx.RollGameType.BaseResult.WBLevel = sceneEx.players[playerEx.SnId].WBLevel + if playerEx.score > 0 { + if !playerEx.IsRob { + info, err := model.MarshalGameNoteByROLL(playerEx.RollGameType) + if err == nil { + logid, _ := model.AutoIncGameLogId() + playerEx.currentLogId = logid + sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) + totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin + validFlow := totalin + totalout + validBet := common.AbsI64(totalin - totalout) + logParam := &base.SaveGamePlayerListLogParam{ + Platform: playerEx.Platform, + Channel: playerEx.Channel, + Promoter: playerEx.BeUnderAgentCode, + PackageTag: playerEx.PackageID, + InviterId: playerEx.InviterId, + LogId: logid, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: playerEx.taxCoin, + BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), + WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, + ValidBet: validBet, + ValidFlow: validFlow, + IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), + IsFree: playerEx.RollGameType.BaseResult.IsFree, + WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, + WinTotal: playerEx.RollGameType.BaseResult.WinTotal, + } + sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + } + } + } + + //统计输下注金币数 + if !sceneEx.Testing && !playerEx.IsRob { + playerBet := &server.PlayerData{ + SnId: proto.Int32(playerEx.SnId), + Bet: proto.Int64(playerEx.CurrentBet), + Gain: proto.Int64(playerEx.RollGameType.BaseResult.ChangeCoin), + Tax: proto.Int64(playerEx.taxCoin), + OtherTax: 0, + Coin: proto.Int64(playerEx.GetCoin()), + FlowCoin: 0, + Lottery: 0, + Kind: 0, + Card: nil, + GameCoinTs: proto.Int64(playerEx.GameCoinTs), + WBGain: 0, + WinState: 0, + } + gwPlayerBet := &server.GWPlayerData{ + SceneId: proto.Int(sceneEx.SceneId), + GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), + } + gwPlayerBet.Datas = append(gwPlayerBet.Datas, playerBet) + sceneEx.SyncPlayerDatas(&base.PlayerDataParam{ + HasRobotGaming: false, + Data: gwPlayerBet, + }) + } + + playerEx.taxCoin = 0 + playerEx.winCoin = 0 + playerEx.linesWinCoin = 0 + playerEx.jackpotWinCoin = 0 + playerEx.smallGameWinCoin = 0 + + if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { + sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) + } +} + +func init() { + ScenePolicyCaiShenSington.RegisteSceneState(&SceneStateCaiShenStart{}) + core.RegisteHook(core.HOOK_BEFORE_START, func() error { + base.RegisteScenePolicy(common.GameId_CaiShen, 0, ScenePolicyCaiShenSington) + return nil + }) +} diff --git a/gamesrv/easterisland/action_easterisland.go b/gamesrv/easterisland/action_easterisland.go new file mode 100644 index 0000000..98a9983 --- /dev/null +++ b/gamesrv/easterisland/action_easterisland.go @@ -0,0 +1,55 @@ +package easterisland + +import ( + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/netlib" + + "mongo.games.com/game/common" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/protocol/easterisland" +) + +// 复活岛的操作 +type CSEasterIslandOpPacketFactory struct { +} +type CSEasterIslandOpHandler struct { +} + +func (this *CSEasterIslandOpPacketFactory) CreatePacket() interface{} { + pack := &easterisland.CSEasterIslandOp{} + return pack +} +func (this *CSEasterIslandOpHandler) Process(s *netlib.Session, packetid int, data interface{}, sid int64) error { + logger.Logger.Trace("CSEasterIslandOpHandler Process recv ", data) + if csEasterIslandOp, ok := data.(*easterisland.CSEasterIslandOp); ok { + p := base.PlayerMgrSington.GetPlayer(sid) + if p == nil { + logger.Logger.Warn("CSEasterIslandOpHandler p == nil") + return nil + } + scene := p.GetScene() + if scene == nil { + logger.Logger.Warn("CSEasterIslandOpHandler p.scene == nil") + return nil + } + if scene.GameId != common.GameId_EasterIsland { + logger.Logger.Error("CSEasterIslandOpHandler gameId Error ", scene.GameId) + return nil + } + if !scene.HasPlayer(p) { + return nil + } + sp := scene.GetScenePolicy() + if sp != nil { + sp.OnPlayerOp(scene, p, int(csEasterIslandOp.GetOpCode()), csEasterIslandOp.GetParams()) + } + return nil + } + return nil +} + +func init() { + // 复活岛的操作 + common.RegisterHandler(int(easterisland.EasterIslandPacketID_PACKET_CS_EASTERISLAND_PLAYEROP), &CSEasterIslandOpHandler{}) + netlib.RegisterFactory(int(easterisland.EasterIslandPacketID_PACKET_CS_EASTERISLAND_PLAYEROP), &CSEasterIslandOpPacketFactory{}) +} diff --git a/gamesrv/easterisland/constant.go b/gamesrv/easterisland/constant.go new file mode 100644 index 0000000..41d199c --- /dev/null +++ b/gamesrv/easterisland/constant.go @@ -0,0 +1,133 @@ +package easterisland + +import ( + "encoding/json" + "time" + + "mongo.games.com/game/model" +) + +// 玩家游戏数据索引 +const ( + EasterIslandFreeTimes int = iota //0 当前剩余免费次数 + EasterIslandIndexMax +) + +// 通知奖池变化的时间间隔 +const jackpotNoticeInterval = time.Second + +// 场景状态 +const ( + EasterIslandSceneStateStart int = iota //开始游戏 + EasterIslandSceneStateMax +) + +// 玩家操作 +const ( + EasterIslandPlayerOpStart int = iota //游戏 + EasterIslandPlayerHistory //游戏记录 + EasterIslandBurstHistory //爆奖记录 + EasterIslandBonusGame //小游戏 + EasterIslandBonusGameRecord //小游戏操作记录 +) + +const ( + EasterIslandBonusGameTimeout = time.Second * 60 + EasterIslandBonusGameStageTimeout = 15 // 小游戏每阶段的超时时间 秒 +) + +type GameResultLog struct { + BaseResult *model.SlotBaseResultType + AllLine int32 //线路数 + UserName string //昵称 + WinLines []int //赢分的线 + BetLines []int64 //下注的线 +} + +// 复活岛解析的数据 +type EasterIslandGameNoteData struct { + Source int32 + Data *GameResultLog +} + +// 复活岛游戏记录 +func UnMarshalEasterIslandGameNote(data string) (roll interface{}, err error) { + gnd := &EasterIslandGameNoteData{} + if err := json.Unmarshal([]byte(data), gnd); err != nil { + return nil, err + } + roll = gnd.Data + return +} + +// {0, 6, 12, 8, 4}, //线条4 +// {10, 6, 2, 8, 14}, //线条5 +// {5, 1, 12, 3, 9}, //线条22 +// {5, 11, 2, 13, 9}, //线条23 +var DebugData = [][]int{ + { + 5, 8, 6, 8, 5, + 9, 5, 8, 5, 4, + 6, 7, 5, 9, 6, + }, + { + 6, 8, 5, 8, 6, + 9, 5, 8, 5, 4, + 5, 7, 6, 9, 5, + }, + { + 5, 8, 6, 8, 5, + 6, 7, 8, 9, 6, + 5, 6, 5, 6, 5, + }, + { + 5, 6, 5, 6, 5, + 6, 7, 8, 9, 6, + 5, 8, 6, 8, 5, + }, + //{ + // 3, 3, 3, 3, 3, + // 3, 3, 3, 3, 3, + // 3, 3, 3, 3, 3, + //}, + //{ + // 4, 4, 4, 4, 4, + // 4, 4, 4, 4, 4, + // 4, 4, 4, 4, 4, + //}, + //{ + // 5, 5, 5, 5, 5, + // 5, 5, 5, 5, 5, + // 5, 5, 5, 5, 5, + //}, + //{ + // 6, 6, 6, 6, 6, + // 6, 6, 6, 6, 6, + // 6, 6, 6, 6, 6, + //}, + //{ + // 7, 7, 7, 7, 7, + // 7, 7, 7, 7, 7, + // 7, 7, 7, 7, 7, + //}, + //{ + // 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, + //}, + //{ + // 9, 9, 9, 9, 9, + // 9, 9, 9, 9, 9, + // 9, 9, 9, 9, 9, + //}, + //{ + // 10, 10, 10, 10, 10, + // 10, 10, 10, 10, 10, + // 10, 10, 10, 10, 10, + //}, + //{ + // 11, 11, 11, 11, 11, + // 11, 11, 11, 11, 11, + // 11, 11, 11, 11, 11, + //}, +} diff --git a/gamesrv/easterisland/playerdata_easterisland.go b/gamesrv/easterisland/playerdata_easterisland.go new file mode 100644 index 0000000..747dee1 --- /dev/null +++ b/gamesrv/easterisland/playerdata_easterisland.go @@ -0,0 +1,155 @@ +package easterisland + +import ( + "encoding/json" + "math/rand" + + "mongo.games.com/goserver/core/timer" + + rule "mongo.games.com/game/gamerule/easterisland" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/protocol/easterisland" +) + +type EasterIslandPlayerData struct { + *base.Player + score int32 //单线押注数 + spinID int64 //当前旋转ID + freeTimes int32 //免费转动次数 + cards []int32 //15张牌 + //RollGameType *model.EasterIslandType //记录信息 + RollGameType *GameResultLog //记录信息 + enterGameCoin int64 //玩家进入老虎机初始金币 + taxCoin int64 //本局税收 + winCoin int64 //本局收税前赢的钱 + linesWinCoin int64 //本局中奖线赢得钱 + jackpotWinCoin int64 //本局奖池赢的钱 + smallGameWinCoin int64 //本局小游戏赢的钱 + betLines []int64 //下注的选线 + totalPriceBonus int64 //小游戏得分 + bonusTimerHandle timer.TimerHandle //托管handle + currentLogId string //爆奖玩家logid + leavetime int32 //用户离开时间 + bonusStage int32 //小游戏所处阶段 1选金额 2选倍率 + bonusStartTime int64 //小游戏阶段开始时间 + bonusOpRecord []int32 //小游戏操作记录 + bonusGame *easterisland.EasterIslandBonusGameInfo //小游戏 + bonusX []int32 //小游戏倍率选项 + billedData *easterisland.GameBilledData + DebugGame bool //测试 + TestNum int +} + +// 玩家初始化 +func (this *EasterIslandPlayerData) init(s *base.Scene) { + this.Clean() + this.score = 0 + this.freeTimes = 0 + //this.RollGameType = &model.EasterIslandType{} + this.RollGameType = &GameResultLog{} + this.RollGameType.BaseResult = &model.SlotBaseResultType{} + this.enterGameCoin = this.Coin + this.currentLogId = "" + this.billedData = &easterisland.GameBilledData{} + this.DebugGame = true + this.TestNum = 0 + + // 加载玩家游戏数据 + if this.GDatas == nil { + this.GDatas = make(map[string]*model.PlayerGameInfo) + } + + if d, exist := this.GDatas[s.KeyGamefreeId]; exist { + gLen := len(d.Data) + if gLen < EasterIslandIndexMax { + for i := gLen; i < EasterIslandIndexMax; i++ { + d.Data = append(d.Data, 0) + } + } + } else { + pgd := &model.PlayerGameInfo{ + Data: make([]int64, EasterIslandIndexMax, EasterIslandIndexMax), + } + this.GDatas[s.KeyGamefreeId] = pgd + } + this.LoadPlayerGameData(s.KeyGamefreeId) + //线条全选 + if len(this.betLines) == 0 { + this.betLines = rule.AllBetLines + } +} + +// 玩家清理数据 +func (this *EasterIslandPlayerData) Clean() { + for i := 0; i < len(this.cards); i++ { + this.cards[i] = -1 + } + this.winCoin = 0 + this.taxCoin = 0 + this.linesWinCoin = 0 + this.jackpotWinCoin = 0 + this.smallGameWinCoin = 0 + this.CleanBonus() +} + +// 清理小游戏数据 +func (this *EasterIslandPlayerData) CleanBonus() { + this.totalPriceBonus = 0 + this.bonusStage = 0 + this.bonusTimerHandle = timer.TimerHandle(0) + this.bonusStartTime = 0 + this.bonusOpRecord = make([]int32, 0) + this.bonusGame = nil + this.bonusX = nil +} + +// 加载玩家游戏数据 +func (this *EasterIslandPlayerData) LoadPlayerGameData(gameFreeId string) { + if d, exist := this.GDatas[gameFreeId]; exist { + this.freeTimes = int32(d.Data[EasterIslandFreeTimes]) + if this.freeTimes > 0 && len(d.DataEx) != 0 { + json.Unmarshal(d.DataEx, &this.betLines) + } + } +} + +// 存储玩家游戏数据 +func (this *EasterIslandPlayerData) SavePlayerGameData(gameFreeId string) { + if d, exist := this.GDatas[gameFreeId]; exist { + d.Data[EasterIslandFreeTimes] = int64(this.freeTimes) + d.DataEx, _ = json.Marshal(this.betLines) + } +} + +// 黑白名单的限制是否生效 +func (this *EasterIslandPlayerData) CheckBlackWriteList(isWin bool) bool { + if isWin && this.BlackLevel > 0 && this.BlackLevel <= 10 { + if rand.Int31n(100) < this.BlackLevel*10 { + return true + } + } else if !isWin && this.WhiteLevel > 0 && this.WhiteLevel <= 10 { + if rand.Int31n(100) < this.WhiteLevel*10 { + return true + } + } + return false +} + +// 玩家是否是新手 +func (this *EasterIslandPlayerData) IsFNovice(keyGameId string) { + if f, ok := this.IsFoolPlayer[keyGameId]; ok { + if !f { + return + } + } else { + this.IsFoolPlayer[keyGameId] = true + return + } + if data, ok := this.GDatas[keyGameId]; ok { + if data.Statics.GameTimes < 100 && data.Statics.TotalOut-data.Statics.TotalIn <= 2000000 { + return + } + this.IsFoolPlayer[keyGameId] = false + } +} diff --git a/gamesrv/easterisland/scenedata_easterisland.go b/gamesrv/easterisland/scenedata_easterisland.go new file mode 100644 index 0000000..48762ce --- /dev/null +++ b/gamesrv/easterisland/scenedata_easterisland.go @@ -0,0 +1,341 @@ +package easterisland + +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/easterisland" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/proto" + "mongo.games.com/game/protocol/easterisland" + "mongo.games.com/game/protocol/gamehall" +) + +type EasterIslandSceneData struct { + *base.Scene //房间信息 + players map[int32]*EasterIslandPlayerData //玩家信息 + jackpot *base.SlotJackpotPool //奖池 + lastJackpotValue int64 //上一次奖池变化时的值 + lastJackPot time.Time //增加奖池时间 + lastBurstJackPot map[int32]time.Time //爆池时间 +} + +type EasterIslandJackpot struct { + createdTime time.Time + userName string + priceValue int64 + roomID int64 + spinID string +} + +func NewEasterIslandSceneData(s *base.Scene) *EasterIslandSceneData { + return &EasterIslandSceneData{ + Scene: s, + players: make(map[int32]*EasterIslandPlayerData), + } +} + +func (this *EasterIslandSceneData) SaveData(force bool) { +} + +func (this *EasterIslandSceneData) OnPlayerLeave(p *base.Player, reason int) { + if p, exist := this.players[p.SnId]; exist { + delete(this.players, p.SnId) + } +} + +func (this *EasterIslandSceneData) init() bool { + if this.DbGameFree == nil { + return false + } + params := this.DbGameFree.GetJackpot() + this.jackpot = &base.SlotJackpotPool{} + if this.jackpot.Small <= 0 { + this.jackpot.Small = 0 + this.jackpot.VirtualJK = int64(params[rule.EL_JACKPOT_InitJackpot] * this.DbGameFree.GetBaseScore()) + } + str := base.SlotsPoolMgr.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 +} + +func (this *EasterIslandSceneData) SceneDestroy(force bool) { + //销毁房间 + this.Scene.Destroy(force) +} + +type EasterIslandSpinResult struct { + LinesInfo []*easterisland.EasterIslandLinesInfo + SlotsData []int32 + TotalPrizeLine int64 // 线条总金额 + TotalPrizeJackpot int64 // 爆奖总金额 + JackpotCnt int // 爆奖的次数 + AddFreeTimes int32 // 新增免费次数 + IsJackpot bool // 是否爆奖 + BonusGame easterisland.EasterIslandBonusGameInfo + BonusX []int32 + TotalWinRate int32 // 中奖总倍率 + TotalTaxScore int64 // 税收 + WinLines []int // 赢分的线 +} + +func (this *EasterIslandSceneData) CalcLinePrize(cards []int, betLines []int64, betValue int64) (spinRes EasterIslandSpinResult) { + taxRate := this.DbGameFree.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_EASTERISLAND && 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 := &easterisland.EasterIslandLinesInfo{ + 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, int64(value)) + } + spinRes.BonusGame = easterisland.EasterIslandBonusGameInfo{ + TotalPrizeValue: proto.Int64(totalBonusValue * int64(bonusGame.Mutiplier)), + Mutiplier: proto.Int32(int32(bonusGame.Mutiplier)), + DataMultiplier: proto.Int64(totalBonusValue), + BonusData: bonusData, + } + // 小游戏税收 + bonusTax := (bonusGame.DataMultiplier - totalBonusValue) * int64(bonusGame.Mutiplier) + spinRes.TotalTaxScore += bonusTax + } + + // add free + if countFree >= 3 { + if countFree > 5 { + countFree = 5 + } + spinRes.AddFreeTimes = int32(rule.FreeSpinTimesRate[countFree-1]) + } + + return +} + +func (this *EasterIslandSceneData) 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.DbGameFree.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 easterisland", pack) + base.PlayerMgrSington.BroadcastMessageToGroup(int(gamehall.HundredScenePacketID_PACKET_SC_GAMEJACKPOT), pack, tags) + } +} +func (this *EasterIslandSceneData) 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 *EasterIslandSceneData) 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 *EasterIslandSceneData) RecordBurstLog(name string, wincoin, totalbet int64) { + log := model.NewBurstJackpotLog(this.Platform, this.DbGameFree.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 *EasterIslandSceneData) BurstHistory(player *EasterIslandPlayerData) { + task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { + return model.GetBurstJackpotLog(this.Platform, this.DbGameFree.GameId) + }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { + var logsp []*easterisland.EasterIslandBurstHistoryInfo + if data != nil { + logs := data.([]model.BurstJackpotLog) + if len(logs) > 0 { + for _, log := range logs { + logsp = append(logsp, &easterisland.EasterIslandBurstHistoryInfo{ + UserName: log.Name, + PriceValue: log.WinCoin, + TotalBet: log.TotalBet, + Ts: log.Ts, + }) + } + } + } + pack := &easterisland.SCEasterIslandBurstHistory{ + BurstLog: logsp, + } + logger.Logger.Trace("SCEasterIslandBurstHistory:", pack) + player.SendToClient(int(easterisland.EasterIslandPacketID_PACKET_SC_EASTERISLAND_BURSTHISTORY), pack) + }), "BurstHistory").Start() +} +func (this *EasterIslandSceneData) GetLastBurstJackPot() time.Time { + return this.lastBurstJackPot[this.GetGameFreeId()] +} +func (this *EasterIslandSceneData) SetLastBurstJackPot() { + var randT = rand.Intn(25200-7200+1) + 7200 + switch this.DbGameFree.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 *EasterIslandSceneData) AIAddJackPot() { + if time.Now().Sub(this.lastJackPot) > 0 { + var randT = rand.Intn(3) + 1 + switch this.DbGameFree.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.DbGameFree.GetBaseScore()) * float64(rule.LINENUM) * float64(500) / 10000)) + this.jackpot.VirtualJK += val + } +} +func (this *EasterIslandSceneData) AIBurstJackPot() { + if time.Now().Sub(this.GetLastBurstJackPot()) > 0 { + this.SetLastBurstJackPot() + jackpotParams := this.DbGameFree.GetJackpot() + var jackpotInit = int64(jackpotParams[rule.EL_JACKPOT_InitJackpot] * this.DbGameFree.GetBaseScore()) //奖池初始值 + + //AI机器人爆奖 + val := this.jackpot.VirtualJK + this.jackpot.VirtualJK = jackpotInit + bet := this.DbGameFree.GetBaseScore() * int32(rule.LINENUM) + this.RecordBurstLog(this.RandNickName(), val, int64(bet)) + } +} +func (this *EasterIslandSceneData) 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.DbGameFree.GetId())) + // if !p.IsRob && + // todayGamefreeIDSceneData != nil && + // this.DbGameFree.GetPlayNumLimit() != 0 && + // todayGamefreeIDSceneData.GameTimes >= int64(this.DbGameFree.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) + } + } + } +} diff --git a/gamesrv/easterisland/scenepolicy_easterisland.go b/gamesrv/easterisland/scenepolicy_easterisland.go new file mode 100644 index 0000000..a57137c --- /dev/null +++ b/gamesrv/easterisland/scenepolicy_easterisland.go @@ -0,0 +1,958 @@ +package easterisland + +import ( + "fmt" + "math" + "math/rand" + "os" + "strconv" + "sync" + "time" + + "mongo.games.com/goserver/core" + "mongo.games.com/goserver/core/basic" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/task" + "mongo.games.com/goserver/core/timer" + + "mongo.games.com/game/common" + rule "mongo.games.com/game/gamerule/easterisland" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/proto" + "mongo.games.com/game/protocol/easterisland" + "mongo.games.com/game/protocol/server" +) + +//////////////////////////////////////////////////////////////////////////////// +//复活岛 +//////////////////////////////////////////////////////////////////////////////// + +// 房间内主要逻辑 +var ScenePolicyEasterIslandSington = &ScenePolicyEasterIsland{} + +type ScenePolicyEasterIsland struct { + base.BaseScenePolicy + states [EasterIslandSceneStateMax]base.SceneState +} + +// 创建场景扩展数据 +func (this *ScenePolicyEasterIsland) CreateSceneExData(s *base.Scene) interface{} { + sceneEx := NewEasterIslandSceneData(s) + if sceneEx != nil { + if sceneEx.init() { + s.ExtraData = sceneEx + } + } + return sceneEx +} + +// 创建玩家扩展数据 +func (this *ScenePolicyEasterIsland) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} { + playerEx := &EasterIslandPlayerData{Player: p} + if playerEx != nil { + p.ExtraData = playerEx + } + return playerEx +} + +// 场景开启事件 +func (this *ScenePolicyEasterIsland) OnStart(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyEasterIsland) OnStart, sceneId=", s.SceneId) + sceneEx := NewEasterIslandSceneData(s) + if sceneEx != nil { + if sceneEx.init() { + s.ExtraData = sceneEx + s.ChangeSceneState(EasterIslandSceneStateStart) //改变当前的玩家状态 + } + } +} + +// 场景关闭事件 +func (this *ScenePolicyEasterIsland) OnStop(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyEasterIsland) OnStop , sceneId=", s.SceneId) + if sceneEx, ok := s.ExtraData.(*EasterIslandSceneData); ok { + sceneEx.SaveData(true) + } +} + +// 场景心跳事件 +func (this *ScenePolicyEasterIsland) OnTick(s *base.Scene) { + if s == nil { + return + } + if s.SceneState != nil { + s.SceneState.OnTick(s) + } +} + +// 玩家进入事件 +func (this *ScenePolicyEasterIsland) OnPlayerEnter(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyEasterIsland) OnPlayerEnter, sceneId=", s.SceneId, " player=", p.SnId) + if sceneEx, ok := s.ExtraData.(*EasterIslandSceneData); ok { + playerEx := &EasterIslandPlayerData{Player: p} + playerEx.init(s) // 玩家当前信息初始化 + playerEx.score = sceneEx.DbGameFree.GetBaseScore() // 底注 + sceneEx.players[p.SnId] = playerEx + p.ExtraData = playerEx + EasterIslandSendRoomInfo(s, p, sceneEx, playerEx, nil) + s.FirePlayerEvent(p, base.PlayerEventEnter, nil) //回调会调取 onPlayerEvent事件 + } +} + +// 玩家离开事件 +func (this *ScenePolicyEasterIsland) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyEasterIsland) OnPlayerLeave, sceneId=", s.SceneId, " player=", p.SnId) + if sceneEx, ok := s.ExtraData.(*EasterIslandSceneData); ok { + if this.CanChangeCoinScene(s, p) { + if playerEx, ok := p.ExtraData.(*EasterIslandPlayerData); ok { + playerEx.SavePlayerGameData(s.KeyGamefreeId) + } + sceneEx.OnPlayerLeave(p, reason) + s.FirePlayerEvent(p, base.PlayerEventLeave, []int64{int64(reason)}) + } + } +} + +// 玩家掉线 +func (this *ScenePolicyEasterIsland) OnPlayerDropLine(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyEasterIsland) OnPlayerDropLine, sceneId=", s.SceneId, " player=", p.SnId) + s.FirePlayerEvent(p, base.PlayerEventDropLine, nil) + if sceneEx, ok := s.ExtraData.(*EasterIslandSceneData); ok { + if sceneEx.Gaming { + return + } + } +} + +// 玩家重连 +func (this *ScenePolicyEasterIsland) OnPlayerRehold(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyEasterIsland) OnPlayerRehold, sceneId=", s.SceneId, " player=", p.Name) + //if sceneEx, ok := s.ExtraData.(*EasterIslandSceneData); ok { + // if playerEx, ok := p.ExtraData.(*EasterIslandPlayerData); ok { + //发送房间信息给自己 + //EasterIslandSendRoomInfo(s, p, sceneEx, playerEx) + s.FirePlayerEvent(p, base.PlayerEventRehold, nil) + //} + //} +} + +// 玩家重连 +func (this *ScenePolicyEasterIsland) OnPlayerReturn(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyEasterIsland) OnPlayerReturn, sceneId=", s.SceneId, " player=", p.Name) + if sceneEx, ok := s.ExtraData.(*EasterIslandSceneData); ok { + if playerEx, ok := p.ExtraData.(*EasterIslandPlayerData); ok { + //发送房间信息给自己 + EasterIslandSendRoomInfo(s, p, sceneEx, playerEx, playerEx.billedData) + s.FirePlayerEvent(p, base.PlayerEventReturn, nil) + } + } +} + +// 玩家操作 +func (this *ScenePolicyEasterIsland) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + if s == nil || p == nil { + return false + } + if s.SceneState != nil { + return s.SceneState.OnPlayerOp(s, p, opcode, params) + } + return true +} + +// 玩家事件 +func (this *ScenePolicyEasterIsland) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { + if s == nil || p == nil { + return + } + if s.SceneState != nil { + s.SceneState.OnPlayerEvent(s, p, evtcode, params) + } +} + +// 是否完成了整个牌局 +func (this *ScenePolicyEasterIsland) IsCompleted(s *base.Scene) bool { return false } + +// 是否可以强制开始 +func (this *ScenePolicyEasterIsland) IsCanForceStart(s *base.Scene) bool { return true } + +// 当前状态能否换桌 +func (this *ScenePolicyEasterIsland) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if s == nil || p == nil { + return true + } + if s.SceneState != nil { + return s.SceneState.CanChangeCoinScene(s, p) + } + return true +} + +func (this *ScenePolicyEasterIsland) RegisteSceneState(state base.SceneState) { + if state == nil { + return + } + stateid := state.GetState() + if stateid < 0 || stateid >= EasterIslandSceneStateMax { + return + } + this.states[stateid] = state +} + +func (this *ScenePolicyEasterIsland) GetSceneState(s *base.Scene, stateid int) base.SceneState { + if stateid >= 0 && stateid < EasterIslandSceneStateMax { + return ScenePolicyEasterIslandSington.states[stateid] + } + return nil +} +func (this *ScenePolicyEasterIsland) GetJackPotVal(s *base.Scene) int64 { + if sceneEx, ok := s.ExtraData.(*EasterIslandSceneData); ok { + if sceneEx.lastJackpotValue != sceneEx.jackpot.VirtualJK { + return sceneEx.jackpot.VirtualJK + } + } + return 0 +} +func EasterIslandSendRoomInfo(s *base.Scene, p *base.Player, sceneEx *EasterIslandSceneData, playerEx *EasterIslandPlayerData, data *easterisland.GameBilledData) { + logger.Logger.Trace("-------------------发送房间消息 ", s.RoomId, p.SnId) + pack := &easterisland.SCEasterIslandRoomInfo{ + RoomId: proto.Int(s.SceneId), + Creator: proto.Int32(s.Creator), + GameId: proto.Int(s.GameId), + RoomMode: proto.Int(s.GameMode), + Params: s.Params, + State: proto.Int(s.SceneState.GetState()), + Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), + GameFreeId: proto.Int32(s.DbGameFree.Id), + BilledData: data, + } + if playerEx != nil { + pd := &easterisland.EasterIslandPlayerData{ + SnId: proto.Int32(playerEx.SnId), + Name: proto.String(playerEx.Name), + Head: proto.Int32(playerEx.Head), + Sex: proto.Int32(playerEx.Sex), + Coin: proto.Int64(playerEx.Coin), + HeadOutLine: proto.Int32(playerEx.HeadOutLine), + VIP: proto.Int32(playerEx.VIP), + } + pack.Players = append(pack.Players, pd) + //for _, value := range playerEx.cards { + // pack.Cards = append(pack.Cards, int32(value)) + //} + pack.BetLines = playerEx.betLines + pack.FreeTimes = proto.Int32(playerEx.freeTimes) + pack.Chip = proto.Int32(s.DbGameFree.BaseScore) + pack.SpinID = proto.Int64(playerEx.spinID) + if playerEx.totalPriceBonus > 0 { + switch playerEx.bonusStage { + case 0: + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + case 1: + if time.Now().Unix()-playerEx.bonusStartTime >= EasterIslandBonusGameStageTimeout*2 { + playerEx.CleanBonus() + } else if time.Now().Unix()-playerEx.bonusStartTime >= EasterIslandBonusGameStageTimeout { + playerEx.bonusStage = 2 + playerEx.bonusStartTime += EasterIslandBonusGameStageTimeout + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + leftTime := playerEx.bonusStartTime + EasterIslandBonusGameStageTimeout + 2 - time.Now().Unix() + pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) + } else { + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + leftTime := playerEx.bonusStartTime + EasterIslandBonusGameStageTimeout + 2 - time.Now().Unix() + pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusOpRecord...) + } + case 2: + if time.Now().Unix()-playerEx.bonusStartTime >= EasterIslandBonusGameStageTimeout { + playerEx.CleanBonus() + } else { + pack.ParamsEx = append(pack.ParamsEx, playerEx.bonusStage) + leftTime := playerEx.bonusStartTime + EasterIslandBonusGameStageTimeout + 2 - time.Now().Unix() + pack.ParamsEx = append(pack.ParamsEx, int32(leftTime)) + } + } + } + if playerEx.totalPriceBonus > 0 { + pack.TotalPriceBonus = proto.Int64(playerEx.totalPriceBonus) + pack.BonusGame = playerEx.bonusGame + pack.BonusX = playerEx.bonusX + } + } + proto.SetDefaults(pack) + p.SendToClient(int(easterisland.EasterIslandPacketID_PACKET_SC_EASTERISLAND_ROOMINFO), pack) +} + +type SceneStateEasterIslandStart struct { +} + +// 获取当前场景状态 +func (this *SceneStateEasterIslandStart) GetState() int { return EasterIslandSceneStateStart } + +// 是否可以切换状态到 +func (this *SceneStateEasterIslandStart) CanChangeTo(s base.SceneState) bool { return true } + +// 当前状态能否换桌 +func (this *SceneStateEasterIslandStart) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + return true +} + +func (this *SceneStateEasterIslandStart) GetTimeout(s *base.Scene) int { return 0 } + +func (this *SceneStateEasterIslandStart) OnEnter(s *base.Scene) { + if sceneEx, ok := s.ExtraData.(*EasterIslandSceneData); ok { + logger.Logger.Tracef("(this *Scene) [%v] 场景状态进入 %v", s.SceneId, len(sceneEx.players)) + sceneEx.StateStartTime = time.Now() + pack := &easterisland.SCEasterIslandRoomState{ + State: proto.Int(this.GetState()), + } + proto.SetDefaults(pack) + s.Broadcast(int(easterisland.EasterIslandPacketID_PACKET_SC_EASTERISLAND_ROOMSTATE), pack, 0) + } +} + +func (this *SceneStateEasterIslandStart) OnLeave(s *base.Scene) {} + +func (this *SceneStateEasterIslandStart) OnTick(s *base.Scene) { + if sceneEx, ok := s.ExtraData.(*EasterIslandSceneData); ok { + sceneEx.AIAddJackPot() + sceneEx.AIBurstJackPot() + sceneEx.KickPlayerByTime() + } +} + +func (this *SceneStateEasterIslandStart) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + playerEx, ok := p.ExtraData.(*EasterIslandPlayerData) + if !ok { + return false + } + sceneEx, ok := s.ExtraData.(*EasterIslandSceneData) + if !ok { + return false + } + if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { + //离开有统计 + sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) + return false + } + switch opcode { + case EasterIslandPlayerOpStart: //开始 + //if !easterIslandBenchTest { + // easterIslandBenchTest = true + // for i := 0; i < 10; i++ { + // //this.BenchTest(s, p) + // this.WinTargetBenchTest(s, p) + // } + // return true + //} + + //参数是否合法 + //params 参数0底注,后面跟客户端选择的线n条线(1<=n<=25),客户端线是从1开始算起1~25条线 + if len(params) < 2 || len(params) > rule.LINENUM+1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + //先做底注校验 + if sceneEx.DbGameFree.GetBaseScore() != int32(params[0]) { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + playerEx.score = int32(params[0]) // 单线押注数 + // 小游戏未结束 不能进行下一次旋转 + if playerEx.totalPriceBonus > 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + //判断线条是否重复,是否合法 + lineFlag := make(map[int64]bool) + lineParams := make([]int64, 0) + for i := 1; i < len(params); i++ { + lineNum := params[i] + if lineNum >= 1 && lineNum <= int64(rule.LINENUM) && !lineFlag[lineNum] { + lineParams = append(lineParams, lineNum) + lineFlag[lineNum] = true + } else { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + } + //没有选线参数 + if len(lineParams) == 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + + //获取总投注金额(所有线的总投注) | 校验玩家余额是否足够 + totalBetValue := (int64(len(lineParams))) * params[0] + if playerEx.freeTimes <= 0 && totalBetValue > playerEx.Coin { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_CoinNotEnough, params) + return false + } else if playerEx.freeTimes <= 0 && int64(sceneEx.DbGameFree.GetBetLimit()) > playerEx.Coin { //押注限制 + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_CoinNotEnough, params) + return false + } + + p.LastOPTimer = time.Now() + sceneEx.GameNowTime = time.Now() + sceneEx.NumOfGames++ + p.GameTimes++ + + //获取当前水池的上下文环境 + sceneEx.CpCtx = base.CoinPoolMgr.GetCoinPoolCtx(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) + taxRate := sceneEx.DbGameFree.GetTaxRate() + if taxRate < 0 || taxRate > 10000 { + logger.Logger.Warnf("EasterIslandErrorTaxRate [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate) + taxRate = 500 + } + coinPoolSetting := base.CoinPoolMgr.GetCoinPoolSetting(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) + ctroRate := 500 //调节赔率 暗税系数 + logger.Logger.Tracef("EasterIslandRates [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate, ctroRate) + + playerEx.IsFNovice(sceneEx.KeyGameId) + isFoolPlayer := false + var gamePoolCoin int64 + //if isFoolPlayer { + // gamePoolCoin = base.CoinPoolMgr.GetNoviceCoinPool(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} else { + gamePoolCoin = base.CoinPoolMgr.GetCoin(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} + prizeFund := gamePoolCoin - sceneEx.jackpot.VirtualJK // 除去奖池的水池剩余金额 + jackpotParams := sceneEx.DbGameFree.GetJackpot() // 奖池参数 + var jackpotInit = int64(jackpotParams[rule.EL_JACKPOT_InitJackpot] * sceneEx.DbGameFree.GetBaseScore()) //奖池初始值 + + var jackpotFundAdd, prizeFundAdd int64 + if playerEx.freeTimes <= 0 { //正常模式才能记录用户的押注变化,免费模式不能改变押注 + playerEx.betLines = lineParams // 选线记录 + jackpotFundAdd = int64(math.Floor(float64(totalBetValue) * (float64(ctroRate) / 10000.0))) //奖池要增加的金额 + prizeFundAdd = totalBetValue - jackpotFundAdd //现金池增加的金额 + //扣除投注金币 + p.AddCoin(-totalBetValue, common.GainWay_HundredSceneLost, base.SyncFlag_ToClient, "system", s.GetSceneName()) + if !p.IsRob && !sceneEx.Testing { + // 推送金币 + sceneEx.PushCoinPool(prizeFundAdd, isFoolPlayer) + } + + ////统计参与游戏次数 + //if !sceneEx.Testing && !playerEx.IsRob { + // pack := &server.GWSceneEnd{ + // GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), + // Players: []*server.PlayerCtx{&server.PlayerCtx{SnId: proto.Int32(playerEx.SnId), Coin: proto.Int64(playerEx.Coin)}}, + // } + // proto.SetDefaults(pack) + // sceneEx.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENEEND), pack) + //} + } else { + totalBetValue = 0 + } + + writeBlackTryTimes := 0 + WriteBlack: + slotData := make([]int, 0) + var spinRes EasterIslandSpinResult + var slotDataIsOk bool + for { + var symbolType rule.Symbol + if gamePoolCoin < int64(coinPoolSetting.GetLowerLimit()) { // userInfo.prizeFund < limit * roomId + symbolType = rule.SYMBOL1 + } else { + symbolType = rule.SYMBOL2 + } + slotData, _ = rule.GenerateSlotsData_v2(symbolType) + + spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) + + // 免费次数时 不允许爆奖 + if playerEx.freeTimes > 0 && spinRes.IsJackpot { + break + } + if spinRes.JackpotCnt > 1 { + break + } + if spinRes.IsJackpot { + if sceneEx.jackpot.Small < sceneEx.jackpot.VirtualJK { + continue + } + } + spinCondition := prizeFund + prizeFundAdd - (spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue() + spinRes.TotalPrizeJackpot) + spinCondition += jackpotFundAdd + sceneEx.jackpot.VirtualJK - jackpotInit + win := spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue() + spinRes.TotalPrizeJackpot + // 现金池不足时 重新发牌 + if spinCondition < 0 && win > totalBetValue { + if !spinRes.IsJackpot { // 非爆奖 水池不足 不再进行黑白名单调控 + writeBlackTryTimes = 999 + } + break + } + + // 非爆奖时 不允许赢取太大的奖励 + var limitBigWin int64 = 50 + if spinCondition < int64(coinPoolSetting.GetLowerLimit()) { //现金池不足时 + limitBigWin = int64(jackpotParams[rule.EL_JACKPOT_LIMITWIN_PRIZELOW]) + } else { + limitBigWin = int64(jackpotParams[rule.EL_JACKPOT_LIMITWIN_PRIZEHIGH]) + } + if totalBetValue > 0 && !spinRes.IsJackpot && spinRes.TotalPrizeLine+spinRes.BonusGame.GetTotalPrizeValue() > totalBetValue*limitBigWin { + break + } + + slotDataIsOk = true + break + } + + if !slotDataIsOk { + slotData = rule.MissData[rand.Intn(len(rule.MissData))] + spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) + } + + // 黑白名单调控 防止异常循环,添加上限次数 + if writeBlackTryTimes < 100 && playerEx.CheckBlackWriteList(spinRes.TotalPrizeLine+spinRes.TotalPrizeJackpot+spinRes.BonusGame.GetTotalPrizeValue() > totalBetValue) { + writeBlackTryTimes++ + goto WriteBlack + } else if writeBlackTryTimes >= 100 && writeBlackTryTimes != 999 { + logger.Logger.Warnf("EasterIslandWriteBlackTryTimesOver [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, gamePoolCoin, playerEx.BlackLevel, playerEx.WhiteLevel) + } + // 奖池水池处理 + if spinRes.IsJackpot { + sceneEx.jackpot.Small -= sceneEx.jackpot.VirtualJK + if sceneEx.jackpot.Small < 0 { + sceneEx.jackpot.Small = 0 + } + sceneEx.jackpot.VirtualJK = jackpotInit + } else { + sceneEx.jackpot.Small += jackpotFundAdd + sceneEx.jackpot.VirtualJK += jackpotFundAdd + } + + // 玩家赢钱 + totalWinScore := spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot + if totalWinScore > 0 || len(spinRes.BonusX) > 0 { + p.AddCoin(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue(), common.GainWay_HundredSceneWin, 0, "system", s.GetSceneName()) + if !p.IsRob && !sceneEx.Testing { + sceneEx.PopCoinPool(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore, isFoolPlayer) + } + playerEx.taxCoin = spinRes.TotalTaxScore + playerEx.AddServiceFee(playerEx.taxCoin) + } + p.StaticsLaba(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, totalBetValue, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore) + + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Sucess, append(params[:1], playerEx.betLines...)) + + var isFreeFlag bool + if playerEx.freeTimes > 0 { + playerEx.freeTimes-- + isFreeFlag = true + } + playerEx.freeTimes += spinRes.AddFreeTimes + + rule.SpinID++ + playerEx.spinID = rule.SpinID + playerEx.cards = spinRes.SlotsData + playerEx.winCoin = spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot + spinRes.BonusGame.GetTotalPrizeValue() + playerEx.taxCoin + playerEx.linesWinCoin = spinRes.TotalPrizeLine + playerEx.jackpotWinCoin = spinRes.TotalPrizeJackpot + playerEx.smallGameWinCoin = spinRes.BonusGame.GetTotalPrizeValue() + playerEx.CurrentBet = totalBetValue + playerEx.CurrentTax = playerEx.taxCoin + + // 小游戏超时处理 + if len(spinRes.BonusX) > 0 { + playerEx.totalPriceBonus = spinRes.BonusGame.GetTotalPrizeValue() + playerEx.bonusGame = &spinRes.BonusGame + playerEx.bonusX = spinRes.BonusX + logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) + } + + playerEx.billedData = &easterisland.GameBilledData{ + SpinID: proto.Int64(playerEx.spinID), + SlotsData: spinRes.SlotsData, + AddFreeSpin: proto.Int32(spinRes.AddFreeTimes), + IsJackpot: proto.Bool(spinRes.IsJackpot), + PrizeLines: spinRes.LinesInfo, + TotalPrizeValue: proto.Int64(spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot), + TotalPaylinePrizeValue: proto.Int64(spinRes.TotalPrizeLine), + TotalJackpotValue: proto.Int64(spinRes.TotalPrizeJackpot), + Balance: proto.Int64(playerEx.Coin - spinRes.BonusGame.GetTotalPrizeValue()), + FreeSpins: proto.Int32(playerEx.freeTimes), + Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), + BonusX: spinRes.BonusX, + BonusGame: &spinRes.BonusGame, + } + pack := &easterisland.SCEasterIslandGameBilled{ + BilledData: playerEx.billedData, + } + proto.SetDefaults(pack) + logger.Logger.Infof("EasterIslandPlayerOpStart %v", pack) + p.SendToClient(int(easterisland.EasterIslandPacketID_PACKET_SC_EASTERISLAND_GAMEBILLED), pack) + + // 记录本次操作 + playerEx.RollGameType.BaseResult.WinTotal = pack.BilledData.GetTotalPrizeValue() + pack.BilledData.GetBonusGame().GetTotalPrizeValue() + playerEx.RollGameType.BaseResult.IsFree = isFreeFlag + playerEx.RollGameType.BaseResult.WinSmallGame = pack.BilledData.BonusGame.GetTotalPrizeValue() + playerEx.RollGameType.BaseResult.AllWinNum = int32(len(pack.BilledData.PrizeLines)) + playerEx.RollGameType.BaseResult.WinRate = spinRes.TotalWinRate + playerEx.RollGameType.BaseResult.Cards = pack.BilledData.GetSlotsData() + playerEx.RollGameType.BaseResult.WinLineScore = pack.BilledData.TotalPaylinePrizeValue + playerEx.RollGameType.WinLines = spinRes.WinLines + playerEx.RollGameType.BaseResult.WinJackpot = pack.BilledData.GetTotalJackpotValue() + playerEx.RollGameType.BaseResult.IsFoolPlayer = isFoolPlayer + EasterIslandCheckAndSaveLog(sceneEx, playerEx) + + // 广播奖池 + if totalBetValue == 0 && !spinRes.IsJackpot { // 没改变奖池 + return true + } + // 添加进开奖记录里面 + if spinRes.IsJackpot { + sceneEx.RecordBurstLog(playerEx.Name, pack.BilledData.GetTotalJackpotValue(), playerEx.CurrentBet) + } + logger.Logger.Tracef("---easterisland---当前奖池:真人[%v] 虚拟[%v]", sceneEx.jackpot.Small, sceneEx.jackpot.VirtualJK) + case EasterIslandBurstHistory: + sceneEx.BurstHistory(playerEx) + case EasterIslandPlayerHistory: + task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { + spinid := strconv.FormatInt(int64(playerEx.SnId), 10) + gpl := model.GetPlayerListByHallEx(p.SnId, p.Platform, 0, 80, 0, 0, 0, s.DbGameFree.GetGameClass(), s.GameId) + pack := &easterisland.SCEasterIslandPlayerHistory{} + for _, v := range gpl.Data { + //if v.GameDetailedLogId == "" { + // logger.Logger.Error("EasterIslandPlayerHistory GameDetailedLogId is nil") + // break + //} + //gdl := model.GetPlayerHistory(p.Platform, v.GameDetailedLogId) + //if gdl == nil { + // logger.Logger.Error("EasterIslandPlayerHistory gdl is nil") + // continue + //} + //data, err := UnMarshalEasterIslandGameNote(gdl.GameDetailedNote) + //if err != nil { + // logger.Logger.Errorf("UnMarshalEasterIslandGameNote error:%v", err) + // continue + //} + //if gnd, ok := data.(*GameResultLog); ok { + // + //} + player := &easterisland.EasterIslandPlayerHistoryInfo{ + SpinID: proto.String(spinid), + CreatedTime: proto.Int64(int64(v.Ts)), + TotalBetValue: proto.Int64(v.BetAmount), + TotalPriceValue: proto.Int64(v.WinTotal), + IsFree: proto.Bool(v.IsFree), + TotalBonusValue: proto.Int64(v.WinSmallGame), + } + pack.PlayerHistory = append(pack.PlayerHistory, player) + } + proto.SetDefaults(pack) + logger.Logger.Info("EasterIslandPlayerHistory: ", pack) + return pack + + }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { + if data == nil { + logger.Logger.Error("EasterIslandPlayerHistory data is nil") + return + } + p.SendToClient(int(easterisland.EasterIslandPacketID_PACKET_SC_EASTERISLAND_PLAYERHISTORY), data) + }), "CSGetEasterIslandPlayerHistoryHandler").Start() + case EasterIslandBonusGame: + //参数是否合法 params 参数0 spinID + if len(params) < 1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + if playerEx.spinID != params[0] || playerEx.totalPriceBonus <= 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + if playerEx.bonusTimerHandle != timer.TimerHandle(0) { + timer.StopTimer(playerEx.bonusTimerHandle) + playerEx.bonusTimerHandle = timer.TimerHandle(0) + } + logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) + + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Sucess, []int64{playerEx.totalPriceBonus, playerEx.Coin}) + playerEx.CleanBonus() + case EasterIslandBonusGameRecord: + // params[0] 小游戏阶段: 0 小游戏动画开始 1 小游戏界面1 2 切换小游戏界面2 + // params[1] 小游戏界面1时,选择奖项的界面位置信息 + if len(params) < 1 || params[0] < 0 || params[0] > 2 || playerEx.totalPriceBonus <= 0 || (params[0] == 1 && len(params) < 2) { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + if params[0] == 0 { + if playerEx.bonusStage > 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + playerEx.bonusStage = 1 + playerEx.bonusStartTime = time.Now().Unix() + } else if params[0] == 2 { + if playerEx.bonusStage != 1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + playerEx.bonusStage = 2 + playerEx.bonusStartTime = time.Now().Unix() + } else if params[0] == 1 { + if params[1] < 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } else if playerEx.bonusGame != nil && len(playerEx.bonusOpRecord) >= len(playerEx.bonusGame.BonusData) { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Error, params) + return false + } + playerEx.bonusOpRecord = append(playerEx.bonusOpRecord, int32(params[1])) + } + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, easterisland.OpResultCode_OPRC_Sucess, params) + } + return true +} + +func (this *SceneStateEasterIslandStart) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { +} + +// 发送玩家操作情况 +func (this *SceneStateEasterIslandStart) OnPlayerSToCOp(s *base.Scene, p *base.Player, pos int, opcode int, + opRetCode easterisland.OpResultCode, params []int64) { + pack := &easterisland.SCEasterIslandOp{ + SnId: proto.Int32(p.SnId), + OpCode: proto.Int(opcode), + OpRetCode: opRetCode, + Params: params, + } + proto.SetDefaults(pack) + p.SendToClient(int(easterisland.EasterIslandPacketID_PACKET_SC_EASTERISLAND_PLAYEROP), pack) +} + +var easterIslandBenchTest bool +var easterIslandBenchTestTimes int + +func (this *SceneStateEasterIslandStart) BenchTest(s *base.Scene, p *base.Player) { + const BENCH_CNT = 10000 + setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) + oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + if easterIslandBenchTestTimes == 0 { + defaultVal := int64(setting.GetLowerLimit()) + if oldPoolCoin != defaultVal { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) + } + } + easterIslandBenchTestTimes++ + + fileName := fmt.Sprintf("easterisland-%v-%d.csv", p.SnId, easterIslandBenchTestTimes) + file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + defer file.Close() + if err != nil { + file, err = os.Create(fileName) + if err != nil { + return + } + } + file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,中线倍数,中线数,剩余免费次数\r\n") + + oldCoin := p.Coin + p.Coin = 100000000 + if playerEx, ok := p.ExtraData.(*EasterIslandPlayerData); ok { + for i := 0; i < BENCH_CNT; i++ { + startCoin := p.Coin + freeTimes := playerEx.freeTimes + poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + playerEx.UnmarkFlag(base.PlayerState_GameBreak) + suc := this.OnPlayerOp(s, p, EasterIslandPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) + inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) + outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin + taxCoin := playerEx.RollGameType.BaseResult.Tax + + str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, startCoin, p.Coin, inCoin, outCoin, taxCoin, + playerEx.RollGameType.BaseResult.WinSmallGame, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) + file.WriteString(str) + if !suc { + break + } + + if playerEx.totalPriceBonus > 0 { + this.OnPlayerOp(s, p, EasterIslandBonusGame, []int64{playerEx.spinID}) + } + } + } + p.Coin = oldCoin +} +func (this *SceneStateEasterIslandStart) WinTargetBenchTest(s *base.Scene, p *base.Player) { + const BENCH_CNT = 10000 + var once = sync.Once{} + once.Do(func() { + setting := base.CoinPoolMgr.GetCoinPoolSetting(s.Platform, s.GetGameFreeId(), s.GroupId) + oldPoolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + if easterIslandBenchTestTimes == 0 { + defaultVal := int64(setting.GetLowerLimit()) + if oldPoolCoin != defaultVal { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, defaultVal-oldPoolCoin) + } + } + }) + easterIslandBenchTestTimes++ + + fileName := fmt.Sprintf("easterisland-%v-%d.csv", p.SnId, easterIslandBenchTestTimes) + file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + defer file.Close() + if err != nil { + file, err = os.Create(fileName) + if err != nil { + return + } + } + file.WriteString("玩家id,当前水位,之前余额,之后余额,投入,产出,税收,小游戏,中线倍数,中线数,剩余免费次数\r\n") + oldCoin := p.Coin + switch s.DbGameFree.GetSceneType() { + case 1: + p.Coin = 100000 + case 2: + p.Coin = 500000 + case 3: + p.Coin = 1000000 + case 4: + p.Coin = 10000000 + default: + p.Coin = 100000 + } + var targetCoin = p.Coin + p.Coin/10 + if playerEx, ok := p.ExtraData.(*EasterIslandPlayerData); ok { + for i := 0; p.Coin < targetCoin; i++ { + startCoin := p.Coin + freeTimes := playerEx.freeTimes + poolCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + playerEx.UnmarkFlag(base.PlayerState_GameBreak) + suc := this.OnPlayerOp(s, p, EasterIslandPlayerOpStart, append([]int64{int64(playerEx.score)}, rule.AllBetLines...)) + inCoin := int64(playerEx.RollGameType.BaseResult.TotalBet) + outCoin := playerEx.RollGameType.BaseResult.ChangeCoin + inCoin + taxCoin := playerEx.RollGameType.BaseResult.Tax + + str := fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v\r\n", p.SnId, poolCoin, startCoin, p.Coin, inCoin, outCoin, taxCoin, + playerEx.RollGameType.BaseResult.WinSmallGame, playerEx.RollGameType.BaseResult.WinRate, playerEx.RollGameType.BaseResult.AllWinNum, freeTimes) + file.WriteString(str) + if !suc { + break + } + + if playerEx.totalPriceBonus > 0 { + this.OnPlayerOp(s, p, EasterIslandBonusGame, []int64{playerEx.spinID}) + } + if i > BENCH_CNT { + break + } + } + } + p.Coin = oldCoin +} + +func EasterIslandCheckAndSaveLog(sceneEx *EasterIslandSceneData, playerEx *EasterIslandPlayerData) { + //统计金币变动 + //log1 + logger.Logger.Trace("EasterIslandCheckAndSaveLog Save ", playerEx.SnId) + //changeCoin := playerEx.Coin - playerEx.StartCoin + changeCoin := playerEx.winCoin - playerEx.taxCoin - playerEx.CurrentBet + startCoin := playerEx.Coin - changeCoin + playerEx.SaveSceneCoinLog(startCoin, changeCoin, + playerEx.Coin, playerEx.CurrentBet, playerEx.taxCoin, playerEx.winCoin, playerEx.jackpotWinCoin, playerEx.smallGameWinCoin) + + //log2 + playerEx.RollGameType.BaseResult.ChangeCoin = changeCoin + playerEx.RollGameType.BaseResult.BasicBet = sceneEx.DbGameFree.GetBaseScore() + playerEx.RollGameType.BaseResult.RoomId = int32(sceneEx.SceneId) + playerEx.RollGameType.BaseResult.AfterCoin = playerEx.Coin + playerEx.RollGameType.BaseResult.BeforeCoin = startCoin + playerEx.RollGameType.BaseResult.IsFirst = sceneEx.IsPlayerFirst(playerEx.Player) + playerEx.RollGameType.BaseResult.PlayerSnid = playerEx.SnId + playerEx.RollGameType.BaseResult.TotalBet = int32(playerEx.CurrentBet) + playerEx.RollGameType.AllLine = int32(len(playerEx.betLines)) + playerEx.RollGameType.BaseResult.FreeTimes = playerEx.freeTimes + playerEx.RollGameType.UserName = playerEx.Name + playerEx.RollGameType.BetLines = playerEx.betLines + playerEx.RollGameType.BaseResult.Tax = playerEx.taxCoin + playerEx.RollGameType.BaseResult.WBLevel = sceneEx.players[playerEx.SnId].WBLevel + if playerEx.score > 0 { + if !playerEx.IsRob { + info, err := model.MarshalGameNoteByROLL(playerEx.RollGameType) + if err == nil { + logid, _ := model.AutoIncGameLogId() + playerEx.currentLogId = logid + sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) + totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin + validFlow := totalin + totalout + validBet := common.AbsI64(totalin - totalout) + logParam := &base.SaveGamePlayerListLogParam{ + Platform: playerEx.Platform, + Channel: playerEx.Channel, + Promoter: playerEx.BeUnderAgentCode, + PackageTag: playerEx.PackageID, + InviterId: playerEx.InviterId, + LogId: logid, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: playerEx.taxCoin, + BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), + WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, + ValidBet: validBet, + ValidFlow: validFlow, + IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), + IsFree: playerEx.RollGameType.BaseResult.IsFree, + WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, + WinTotal: playerEx.RollGameType.BaseResult.WinTotal, + } + sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + } + } + } + + //统计输下注金币数 + if !sceneEx.Testing && !playerEx.IsRob { + playerBet := &server.PlayerData{ + SnId: proto.Int32(playerEx.SnId), + Bet: proto.Int64(playerEx.CurrentBet), + Gain: proto.Int64(playerEx.RollGameType.BaseResult.ChangeCoin), + Tax: proto.Int64(playerEx.taxCoin), + Coin: proto.Int64(playerEx.GetCoin()), + GameCoinTs: proto.Int64(playerEx.GameCoinTs), + } + gwPlayerBet := &server.GWPlayerData{ + SceneId: proto.Int(sceneEx.SceneId), + GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), + } + gwPlayerBet.Datas = append(gwPlayerBet.Datas, playerBet) + sceneEx.SyncPlayerDatas(&base.PlayerDataParam{ + HasRobotGaming: false, + Data: gwPlayerBet, + }) + } + + playerEx.taxCoin = 0 + playerEx.winCoin = 0 + playerEx.linesWinCoin = 0 + playerEx.jackpotWinCoin = 0 + playerEx.smallGameWinCoin = 0 + + if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { + sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) + } +} + +func init() { + ScenePolicyEasterIslandSington.RegisteSceneState(&SceneStateEasterIslandStart{}) + core.RegisteHook(core.HOOK_BEFORE_START, func() error { + base.RegisteScenePolicy(common.GameId_EasterIsland, 0, ScenePolicyEasterIslandSington) + return nil + }) +} diff --git a/gamesrv/fruits/scenedata_fruits.go b/gamesrv/fruits/scenedata_fruits.go index 35ac3d6..d21bf4e 100644 --- a/gamesrv/fruits/scenedata_fruits.go +++ b/gamesrv/fruits/scenedata_fruits.go @@ -5,6 +5,8 @@ import ( "fmt" "math" "math/rand" + "time" + "mongo.games.com/game/common" "mongo.games.com/game/gamerule/fruits" "mongo.games.com/game/gamesrv/base" @@ -14,7 +16,6 @@ import ( "mongo.games.com/game/protocol/server" "mongo.games.com/game/srvdata" "mongo.games.com/goserver/core/logger" - "time" ) type FruitsSceneData struct { @@ -92,7 +93,7 @@ func (s *FruitsSceneData) OnPlayerLeave(p *base.Player, reason int) { //小玛丽 playerEx.winCoin = playerEx.winOutMaryCoin + playerEx.winMidMaryCoin + playerEx.winFreeCoin if playerEx.winCoin != 0 { - //SysProfitCoinMgr.PushBetAndSysOut(s.sysProfitCoinKey, 0, playerEx.winCoin) + //SysProfitCoinMgr.Add(s.sysProfitCoinKey, 0, playerEx.winCoin) p.Statics(s.KeyGameId, s.KeyGamefreeId, playerEx.winCoin, false) //tax := int64(math.Ceil(float64(playerEx.winCoin) * float64(s.DbGameFree.GetTaxRate()) / 10000)) //playerEx.taxCoin = tax @@ -137,7 +138,7 @@ func (s *FruitsSceneData) Win(p *FruitsPlayerData) { } if isBilled && p.winCoin != 0 { p.noWinTimes = 0 - //SysProfitCoinMgr.PushBetAndSysOut(s.sysProfitCoinKey, 0, p.winCoin) + //SysProfitCoinMgr.Add(s.sysProfitCoinKey, 0, p.winCoin) p.Statics(s.KeyGameId, s.KeyGamefreeId, p.winCoin, false) //tax := int64(math.Ceil(float64(p.winCoin) * float64(s.DbGameFree.GetTaxRate()) / 10000)) //p.taxCoin = tax @@ -364,23 +365,19 @@ func (s *FruitsSceneData) SendPlayerBet(p *FruitsPlayerData) { if p.gameState != fruits.Normal { betCoin = 0 } - + playerBet := &server.PlayerData{ + SnId: proto.Int32(p.SnId), + Bet: proto.Int64(betCoin), + Gain: proto.Int64(p.Coin - p.startCoin), + Tax: proto.Int64(p.taxCoin), + } + gwPlayerBet := &server.GWPlayerData{ + GameFreeId: proto.Int32(s.DbGameFree.GetId()), + } + gwPlayerBet.Datas = append(gwPlayerBet.Datas, playerBet) s.SyncPlayerDatas(&base.PlayerDataParam{ HasRobotGaming: false, - Data: &server.GWPlayerData{ - Datas: []*server.PlayerData{ - { - SnId: p.SnId, - Bet: betCoin, - Gain: p.Coin - p.startCoin, - Tax: p.taxCoin, - Coin: p.Coin, - GameCoinTs: p.GameCoinTs, - }, - }, - GameFreeId: s.GetGameFreeId(), - SceneId: int32(s.SceneId), - }, + Data: gwPlayerBet, }) } } @@ -443,7 +440,7 @@ func (s *FruitsSceneData) Regulation(p *FruitsPlayerData, n int) { // } // if regY == -1 { // if setting != nil { - // poolValue := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + // poolValue := base.CoinPoolMgr.LoadCoin(s.GetGameFreeId(), s.Platform, s.GroupId) // w := float64(s.slotRateWeight[0]) * (1 - float64(int32(poolValue)-setting.GetLowerLimit())/float64(setting.GetUpperLimit()-setting.GetLowerLimit()+1)) // if w < 0 { // regY = 0 diff --git a/gamesrv/fruits/scenepolicy_fruits.go b/gamesrv/fruits/scenepolicy_fruits.go index 50e69a2..65e1b34 100644 --- a/gamesrv/fruits/scenepolicy_fruits.go +++ b/gamesrv/fruits/scenepolicy_fruits.go @@ -326,7 +326,7 @@ func (this *SceneBaseStateFruits) OnTick(s *base.Scene) { // now := time.Now() // sceneEx.mqLogTime = now.Add(-time.Second * time.Duration(now.Second())) // - // waterVal := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + // waterVal := base.CoinPoolMgr.LoadCoin(s.GetGameFreeId(), s.Platform, s.GroupId) // waterVal = int64(math.Floor(float64(waterVal) / float64(fruits.NowByte))) // // jkVal1 := int64(math.Floor(float64(sceneEx.jackpot.GetTotalSmall()) / float64(fruits.NowByte))) @@ -444,7 +444,7 @@ func (this *SceneStateStartFruits) OnPlayerOp(s *base.Scene, p *base.Player, opc } playerEx.CurrentBet = playerEx.betCoin playerEx.CurrentTax = 0 - //SysProfitCoinMgr.PushBetAndSysOut(sceneEx.sysProfitCoinKey, playerEx.betCoin, -playerEx.betCoin) + //SysProfitCoinMgr.Add(sceneEx.sysProfitCoinKey, playerEx.betCoin, -playerEx.betCoin) //没有免费次数 扣钱 p.Statics(s.KeyGameId, s.KeyGamefreeId, -playerEx.betCoin, false) playerEx.AddCoin(-playerEx.betCoin, common.GainWay_HundredSceneLost, 0, "system", s.GetSceneName()) diff --git a/gamesrv/iceage/action_iceage.go b/gamesrv/iceage/action_iceage.go index fb02b54..866edbe 100644 --- a/gamesrv/iceage/action_iceage.go +++ b/gamesrv/iceage/action_iceage.go @@ -1,11 +1,12 @@ package iceage import ( + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/netlib" + "mongo.games.com/game/common" "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/protocol/iceage" - "mongo.games.com/goserver/core/logger" - "mongo.games.com/goserver/core/netlib" ) // 冰河世纪的操作 diff --git a/gamesrv/iceage/constant.go b/gamesrv/iceage/constant.go index df0aace..9da385e 100644 --- a/gamesrv/iceage/constant.go +++ b/gamesrv/iceage/constant.go @@ -2,8 +2,9 @@ package iceage import ( "encoding/json" - "mongo.games.com/game/model" "time" + + "mongo.games.com/game/model" ) // 玩家游戏数据索引 diff --git a/gamesrv/iceage/playerdata_iceage.go b/gamesrv/iceage/playerdata_iceage.go index acba5cf..ed48775 100644 --- a/gamesrv/iceage/playerdata_iceage.go +++ b/gamesrv/iceage/playerdata_iceage.go @@ -3,13 +3,14 @@ package iceage import ( "encoding/json" "math/rand" + "strconv" + + "mongo.games.com/goserver/core/timer" + rule "mongo.games.com/game/gamerule/iceage" - base "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/model" "mongo.games.com/game/protocol/iceage" - "mongo.games.com/goserver/core/timer" - "strconv" - //"mongo.games.com/game/common" ) type IceAgePlayerData struct { diff --git a/gamesrv/iceage/scenedata_iceage.go b/gamesrv/iceage/scenedata_iceage.go index d1d9a1e..26e449e 100644 --- a/gamesrv/iceage/scenedata_iceage.go +++ b/gamesrv/iceage/scenedata_iceage.go @@ -4,20 +4,21 @@ 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/goserver/core/basic" - "mongo.games.com/goserver/core/task" - "time" - - rule "mongo.games.com/game/gamerule/iceage" - "mongo.games.com/game/gamesrv/base" - "mongo.games.com/game/proto" "mongo.games.com/game/srvdata" - "mongo.games.com/goserver/core/logger" ) type IceAgeJackpot struct { @@ -323,14 +324,7 @@ func (this *IceAgeSceneData) AIAddJackPot() { randT = rand.Intn(3) + 1 } this.lastJackPot = time.Now().Add(time.Second * time.Duration(randT)) - //AI机器人 - setting := base.CoinPoolMgr.GetCoinPoolSetting(this.Platform, this.GetGameFreeId(), this.GroupId) - var ctroRate int32 - if setting != nil { - ctroRate = 9800 - } - var val int64 - val = int64(math.Floor(float64(this.DbGameFree.GetBaseScore()) * float64(rule.LINENUM) * float64(ctroRate) / 10000)) + val := int64(math.Floor(float64(this.DbGameFree.GetBaseScore()) * float64(rule.LINENUM) * float64(500) / 10000)) this.jackpot.VirtualJK += val } } diff --git a/gamesrv/iceage/scenepolicy_iceage.go b/gamesrv/iceage/scenepolicy_iceage.go index 5561bcc..d80e2b5 100644 --- a/gamesrv/iceage/scenepolicy_iceage.go +++ b/gamesrv/iceage/scenepolicy_iceage.go @@ -3,6 +3,17 @@ package iceage import ( "fmt" "math" + "os" + "strconv" + "sync" + "time" + + "mongo.games.com/goserver/core" + "mongo.games.com/goserver/core/basic" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/task" + "mongo.games.com/goserver/core/timer" + "mongo.games.com/game/common" rule "mongo.games.com/game/gamerule/iceage" "mongo.games.com/game/gamesrv/base" @@ -10,15 +21,6 @@ import ( "mongo.games.com/game/proto" "mongo.games.com/game/protocol/iceage" "mongo.games.com/game/protocol/server" - "mongo.games.com/goserver/core" - "mongo.games.com/goserver/core/basic" - "mongo.games.com/goserver/core/logger" - "mongo.games.com/goserver/core/task" - "mongo.games.com/goserver/core/timer" - "os" - "strconv" - "sync" - "time" ) //////////////////////////////////////////////////////////////////////////////// @@ -395,7 +397,7 @@ func (this *SceneStateIceAgeStart) OnPlayerOp(s *base.Scene, p *base.Player, opc //水池设置 coinPoolSetting := base.GetCoinPoolMgr().GetCoinPoolSetting(sceneEx.GetPlatform(), sceneEx.GetGameFreeId(), sceneEx.GetGroupId()) //baseRate := coinPoolSetting.GetBaseRate() //基础赔率 - ctroRate := 9800 //调节赔率 暗税系数 + ctroRate := 500 //调节赔率 暗税系数 //if baseRate >= 10000 || baseRate <= 0 || ctroRate < 0 || ctroRate >= 1000 || baseRate+ctroRate > 9900 { // logger.Logger.Warnf("IceAgeErrorBaseRate [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, baseRate, ctroRate) // baseRate = 9700 @@ -406,13 +408,13 @@ func (this *SceneStateIceAgeStart) OnPlayerOp(s *base.Scene, p *base.Player, opc logger.Logger.Tracef("IceAgeRates [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate, ctroRate) playerEx.IsFNovice(sceneEx.KeyGameId) - isFoolPlayer := playerEx.IsFoolPlayer[sceneEx.KeyGameId] + isFoolPlayer := false var gamePoolCoin int64 - if isFoolPlayer { - gamePoolCoin = base.CoinPoolMgr.GetNoviceCoin(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 - } else { - gamePoolCoin = base.CoinPoolMgr.GetCoin(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 - } + //if isFoolPlayer { + // gamePoolCoin = base.CoinPoolMgr.GetNoviceCoinPool(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} else { + gamePoolCoin = base.CoinPoolMgr.GetCoin(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} prizeFund := gamePoolCoin - sceneEx.jackpot.VirtualJK // 除去奖池的水池剩余金额 var jackpotParam = sceneEx.GetDBGameFree().GetJackpot() // 奖池参数 @@ -979,9 +981,10 @@ func IceAgeCheckAndSaveLog(sceneEx *IceAgeSceneData, playerEx *IceAgePlayerData) GameFreeId: proto.Int32(sceneEx.GetDBGameFree().GetId()), } gwPlayerBet.Datas = append(gwPlayerBet.Datas, playerBet) - proto.SetDefaults(gwPlayerBet) - sceneEx.SendToWorld(int(server.SSPacketID_PACKET_GW_PLAYERDATA), gwPlayerBet) - logger.Logger.Trace("Send msg gwPlayerBet ===>", gwPlayerBet) + sceneEx.SyncPlayerDatas(&base.PlayerDataParam{ + HasRobotGaming: false, + Data: gwPlayerBet, + }) } playerEx.taxCoin = 0 diff --git a/gamesrv/main.go b/gamesrv/main.go index f8cb9c9..1295456 100644 --- a/gamesrv/main.go +++ b/gamesrv/main.go @@ -20,8 +20,14 @@ import ( _ "mongo.games.com/game/gamesrv/thirteen" _ "mongo.games.com/game/gamesrv/tienlen" + // 拉霸 + _ "mongo.games.com/game/gamesrv/avengers" + _ "mongo.games.com/game/gamesrv/caishen" + _ "mongo.games.com/game/gamesrv/easterisland" _ "mongo.games.com/game/gamesrv/fruits" _ "mongo.games.com/game/gamesrv/iceage" + _ "mongo.games.com/game/gamesrv/richblessed" + _ "mongo.games.com/game/gamesrv/tamquoc" ) func main() { diff --git a/gamesrv/richblessed/action_richblessed.go b/gamesrv/richblessed/action_richblessed.go new file mode 100644 index 0000000..59f4b34 --- /dev/null +++ b/gamesrv/richblessed/action_richblessed.go @@ -0,0 +1,48 @@ +package richblessed + +import ( + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/netlib" + + "mongo.games.com/game/common" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/protocol/richblessed" +) + +type CSRichBlessedOpPacketFactory struct { +} +type CSRichBlessedOpHandler struct { +} + +func (this *CSRichBlessedOpPacketFactory) CreatePacket() interface{} { + pack := &richblessed.CSRichBlessedOp{} + return pack +} + +func (this *CSRichBlessedOpHandler) Process(s *netlib.Session, packetid int, data interface{}, sid int64) error { + if op, ok := data.(*richblessed.CSRichBlessedOp); ok { + p := base.PlayerMgrSington.GetPlayer(sid) + if p == nil { + logger.Logger.Warn("CSRichBlessedOpHandler p == nil") + return nil + } + scene := p.GetScene() + if scene == nil { + logger.Logger.Warn("CSRichBlessedOpHandler p.scene == nil") + return nil + } + if !scene.HasPlayer(p) { + return nil + } + if scene.GetScenePolicy() != nil { + scene.GetScenePolicy().OnPlayerOp(scene, p, int(op.GetOpCode()), op.GetParams()) + } + return nil + } + return nil +} +func init() { + //多财多福 + common.RegisterHandler(int(richblessed.RBPID_PACKET_RICHBLESSED_CSRichBlessedOp), &CSRichBlessedOpHandler{}) + netlib.RegisterFactory(int(richblessed.RBPID_PACKET_RICHBLESSED_CSRichBlessedOp), &CSRichBlessedOpPacketFactory{}) +} diff --git a/gamesrv/richblessed/playerdata_richblessed.go b/gamesrv/richblessed/playerdata_richblessed.go new file mode 100644 index 0000000..76417f8 --- /dev/null +++ b/gamesrv/richblessed/playerdata_richblessed.go @@ -0,0 +1,112 @@ +package richblessed + +import ( + "mongo.games.com/game/gamerule/richblessed" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" +) + +var ( + ElementsParams = [][]int32{} // 十三个元素 + FreeElementsParams = [][]int32{} + FreeLeElementsParams = []int32{0, 0, 60, 50, 50, 60, 50, 0, 0, 0, 0, 0, 0} + JACKPOTElementsParams = []int32{20, 30, 100, 150} +) + +// RichBlessed +type RichBlessedPlayerData struct { + *base.Player + roomid int32 //房间ID + result *richblessed.WinResult + betIdx int //下注索引 + betCoin int64 //下注金额 + maxbetCoin int64 //下注金额 + oneBetCoin int64 //单注 + cpCtx model.CoinPoolCtx //水池环境 + leaveTime int32 //离开时间 + winCoin int64 //本局输赢 + startCoin int64 //本局开始金币 + freewinCoin int64 //免费游戏总输赢 + JackwinCoin int64 //Jack奖励 + freeTimes int32 //免费游戏 + addfreeTimes int32 //新增免费游戏 + gameState int //当前游戏模式 + taxCoin int64 //税收 + noWinTimes int //没有中奖次数 + isFWinJackpot bool //是否中奖 + JackMidCards []int64 //掀开位置 + ///当局数值 + nowFreeTimes int //当前第几轮免费游戏 + winLineRate int64 //线倍率 + JackPotRate int64 //获取奖池的百分比 5% 10% 15% + freeWinTotalRate int64 //免费游戏赢的倍率 + // winNowJackPotCoin int64 //当局奖池爆奖 + winNowAllRate int64 //当局赢得倍率 + //测试 + isFTest int + isTestIdx int + isJk bool + // + weightPos int32 //当局权重 +} + +func (p *RichBlessedPlayerData) init() { + p.roomid = 0 + p.result = new(richblessed.WinResult) +} +func (p *RichBlessedPlayerData) Clear() { + p.gameState = richblessed.Normal + p.startCoin = p.Coin + p.winCoin = 0 + p.taxCoin = 0 + p.isFWinJackpot = false + p.addfreeTimes = 0 + p.result.AllRate = 0 + p.JackMidCards = p.JackMidCards[:0] + p.result.FreeNum = 0 + p.result.JackpotEle = -1 + p.result.JackpotRate = 0 + if p.freeTimes == 0 { + p.freewinCoin = 0 + p.nowFreeTimes = 0 + } + p.isJk = false + p.weightPos = 0 +} + +// 正常游戏 免费游戏 +func (p *RichBlessedPlayerData) TestCode(eleLineAppearRate [][]int32) { + if p.isFTest%5 == 0 && p.gameState == richblessed.Normal { + switch p.isTestIdx { + case 0: + //免费 + p.result.EleValue = []int32{ + 1, 1, 1, 1, 1, + 6, 2, 7, 7, 9, + 9, 7, 4, 8, 7, + } + p.isTestIdx = 1 + case 1: + //奖池 + p.result.EleValue = []int32{ + 5, 0, 0, 0, 1, + 6, 2, 7, 7, 9, + 9, 1, 4, 8, 7, + } + p.isTestIdx = 0 + p.isJk = true + } + } else { + p.result.CreateLine(eleLineAppearRate) + } +} + +func (p *RichBlessedPlayerData) CreateLevResult(eleLineAppearRate [][]int32) { + p.result.CreateLevLine(eleLineAppearRate) +} + +// 正常游戏 免费游戏 +func (p *RichBlessedPlayerData) CreateJACKPOT(eleRate []int32) { + p.result.CreateJACKPOT(eleRate) + +} diff --git a/gamesrv/richblessed/scenedata_richblessed.go b/gamesrv/richblessed/scenedata_richblessed.go new file mode 100644 index 0000000..b7ea258 --- /dev/null +++ b/gamesrv/richblessed/scenedata_richblessed.go @@ -0,0 +1,457 @@ +package richblessed + +import ( + "encoding/json" + "fmt" + "math" + "math/rand" + "time" + + "mongo.games.com/goserver/core/logger" + + "mongo.games.com/game/common" + "mongo.games.com/game/gamerule/richblessed" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/proto" + protocol "mongo.games.com/game/protocol/richblessed" + "mongo.games.com/game/protocol/server" + "mongo.games.com/game/srvdata" +) + +type RichBlessedSceneData struct { + *base.Scene //场景 + players map[int32]*RichBlessedPlayerData //玩家信息 + jackpot *base.SlotJackpotPool //奖池 + levelRate [][]int32 //调控概率区间 + slotRateWeight []int32 //调控权重 + sysProfitCoinKey string + mqLogTime time.Time +} + +func NewRichBlessedSceneData(s *base.Scene) *RichBlessedSceneData { + sceneEx := &RichBlessedSceneData{ + Scene: s, + players: make(map[int32]*RichBlessedPlayerData), + } + sceneEx.Init() + return sceneEx +} +func (s *RichBlessedSceneData) Init() { + s.LoadJackPotData() + //for _, data := range srvdata.PBDB_SlotRateMgr.Datas.Arr { + // if int(data.GetGameId()) == common.GameId_Fruits { + // s.levelRate = append(s.levelRate, data.RateSection) + // s.slotRateWeight = append(s.slotRateWeight, data.GetWeight()) + // } + //} + s.sysProfitCoinKey = fmt.Sprintf("%v_%v", s.Platform, s.GetGameFreeId()) + s.mqLogTime = time.Now() +} + +func (s *RichBlessedSceneData) Clear() { + +} +func (s *RichBlessedSceneData) SceneDestroy(force bool) { + //销毁房间 + s.Scene.Destroy(force) +} +func (s *RichBlessedSceneData) AddPrizeCoin(playerEx *RichBlessedPlayerData) { + val := playerEx.betCoin + tax := int64(math.Ceil(float64(val) * float64(s.DbGameFree.GetTaxRate()) / 10000)) + //playerEx.taxCoin = tax + //playerEx.AddServiceFee(tax) + val -= tax + + addPrizeCoin := val * richblessed.NowByte * int64(s.DbGameFree.GetJackpotRatio()) //扩大10000倍 + jk1 := int64(math.Floor(float64(addPrizeCoin) / 1000 / 4)) //千分之奖池比例 分四份 + s.jackpot.AddToGrand(playerEx.IsRob, jk1) + s.jackpot.AddToBig(playerEx.IsRob, jk1) + s.jackpot.AddToMiddle(playerEx.IsRob, jk1) + s.jackpot.AddToSmall(playerEx.IsRob, jk1) + logger.Logger.Tracef("[Rich] 奖池增加...AddPrizeCoin... %f", float64(jk1*4)/float64(richblessed.NowByte)) + base.SlotsPoolMgr.SetPool(s.GetGameFreeId(), s.Platform, s.jackpot) + if !s.Testing { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, val*richblessed.NowByte-jk1*4) + } +} +func (s *RichBlessedSceneData) DelPrizeCoin(isRob bool, win int64, jackpotEle int32) { + if win > 0 { + switch jackpotEle { + case richblessed.GoldBoy: + s.jackpot.AddToGrand(isRob, -win*richblessed.NowByte) + case richblessed.GoldGirl: + s.jackpot.AddToBig(isRob, -win*richblessed.NowByte) + case richblessed.BlueBoy: + s.jackpot.AddToMiddle(isRob, -win*richblessed.NowByte) + default: + s.jackpot.AddToSmall(isRob, -win*richblessed.NowByte) + } + logger.Logger.Tracef("[Rich] 奖池减少...DelPrizeCoin... %d", win) + base.SlotsPoolMgr.SetPool(s.GetGameFreeId(), s.Platform, s.jackpot) + } +} +func (s *RichBlessedSceneData) delPlayer(SnId int32) { + if _, exist := s.players[SnId]; exist { + delete(s.players, SnId) + } +} +func (s *RichBlessedSceneData) OnPlayerLeave(p *base.Player, reason int) { + if playerEx, ok := p.ExtraData.(*RichBlessedPlayerData); ok { + if playerEx.freeTimes > 0 || playerEx.isFWinJackpot { + if playerEx.isFWinJackpot { // 小游戏 + s.JACKPOTWin(playerEx) + + a1 := rand.Int63n(3) + a2 := rand.Int63n(3) + 3 + a3 := rand.Int63n(2) + 6 + playerEx.JackMidCards = append(playerEx.JackMidCards, a1, a2, a3) + + //发送结算 + //s.SendJACKPOTBilled(playerEx) + + s.SaveLog(playerEx, 1) + playerEx.Clear() + } + //freenum := playerEx.freeTimes + //for i := int32(0); i < freenum; i++ { + // playerEx.Clear() + // gameRand, _ := s.GetFreeWeight() + // playerEx.CreateLevResult(gameRand) // 没有铜锣概率 + // s.Win(playerEx) + // s.SaveLog(playerEx, 1) + //} + } + s.delPlayer(p.SnId) + } +} + +// 是否中奖 +func (s *RichBlessedSceneData) CanJACKPOT(p *RichBlessedPlayerData, bet int64, big int64, JACKRand []int32) bool { + ret := p.result.CanJACKPOT(bet, big) + logger.Logger.Tracef("RichBlessedSceneData CanJACKPOT %v %v", ret, p.result.EleValue) + if ret || p.isJk { + WinJackPot := int64(0) + ele := p.result.CreateJACKPOT(JACKRand) + if p.isJk { + ele = rand.Int31n(richblessed.JackMax) + p.result.JackpotEle = ele + } + switch ele { + case richblessed.GoldBoy: + WinJackPot = s.jackpot.GetTotalGrand() + case richblessed.GoldGirl: + WinJackPot = s.jackpot.GetTotalBig() + case richblessed.BlueBoy: + WinJackPot = s.jackpot.GetTotalMiddle() + case richblessed.BlueGirl: + WinJackPot = s.jackpot.GetTotalSmall() + } + if WinJackPot > 0 { + jkWin := int64(math.Floor(float64(WinJackPot) / float64(richblessed.NowByte))) + if jkWin > (richblessed.JkEleNumRate[int(ele)]*p.oneBetCoin) || p.isJk { + p.isFWinJackpot = true + return true + } + } + //不能中奖 + p.result.JackpotEle = -1 + p.result.JackpotRate = 0 + } + return false +} +func (s *RichBlessedSceneData) Win(p *RichBlessedPlayerData) { + p.result.Win(p.betCoin, p.maxbetCoin) + + if p.result.FreeNum != 0 { + p.addfreeTimes = p.result.FreeNum + p.freeTimes += p.addfreeTimes + } + + p.winLineRate = p.result.AllRate + p.winCoin += p.oneBetCoin * p.winLineRate + if p.gameState == richblessed.FreeGame { + p.freewinCoin += p.winCoin + } + if p.winCoin != 0 { + p.noWinTimes = 0 + //SysProfitCoinMgr.Add(s.sysProfitCoinKey, 0, p.winCoin) + p.Statics(s.KeyGameId, s.KeyGamefreeId, p.winCoin, false) + //tax := int64(math.Ceil(float64(p.winCoin) * float64(s.DbGameFree.GetTaxRate()) / 10000)) + //p.taxCoin = tax + //p.winCoin -= tax + //p.AddServiceFee(tax) + + p.AddCoin(p.winCoin, common.GainWay_HundredSceneWin, 0, "system", s.GetSceneName()) + if !s.Testing && p.winCoin != 0 { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, -(p.winCoin)*richblessed.NowByte) + } + //p.isReportGameEvent = true + } +} + +func (s *RichBlessedSceneData) JACKPOTWin(p *RichBlessedPlayerData) { + p.result.JACKPOTWin() + p.JackwinCoin = p.result.JackpotRate * p.oneBetCoin + if p.JackwinCoin > 0 { + s.DelPrizeCoin(p.IsRob, p.JackwinCoin, p.result.JackpotEle) + p.noWinTimes = 0 + //SysProfitCoinMgr.Add(s.sysProfitCoinKey, 0, p.JackwinCoin) + p.Statics(s.KeyGameId, s.KeyGamefreeId, p.JackwinCoin, false) + //tax := int64(math.Ceil(float64(p.JackwinCoin) * float64(s.DbGameFree.GetTaxRate()) / 10000)) + //p.taxCoin = tax + //p.JackwinCoin -= tax + //p.AddServiceFee(tax) + + p.AddCoin(p.JackwinCoin, common.GainWay_HundredSceneWin, 0, "system", s.GetSceneName()) + if !s.Testing && p.JackwinCoin != 0 { + base.CoinPoolMgr.PushCoin(s.GetGameFreeId(), s.GroupId, s.Platform, -(p.JackwinCoin)*richblessed.NowByte) + } + // p.JackpotEle = -1 + //p.isReportGameEvent = true + } +} + +func (s *RichBlessedSceneData) SendBilled(p *RichBlessedPlayerData) { + //正常游戏 免费游戏 + pack := &protocol.SCRBBilled{ + NowGameState: proto.Int(p.gameState), + BetIdx: proto.Int(p.betIdx), + Coin: proto.Int64(p.Coin), + Cards: p.result.EleValue, + FreeAllWin: proto.Int64(p.freewinCoin), // + //SmallJackpot: proto.Int64(s.jackpot.GetTotalSmall() / 10000), + //MiddleJackpot: proto.Int64(s.jackpot.GetTotalMiddle() / 10000), + //BigJackpot: proto.Int64(s.jackpot.GetTotalBig() / 10000), + //GrandJackpot: proto.Int64(s.jackpot.GetTotalGrand() / 10000), + WinEleCoin: proto.Int64(p.winCoin), + WinRate: proto.Int64(p.winLineRate), + FreeNum: proto.Int64(int64(p.freeTimes)), + AddFreeNum: proto.Int64(int64(p.addfreeTimes)), + JackpotEle: proto.Int32(p.result.JackpotEle), + WinFreeTimes: proto.Int32(int32(p.nowFreeTimes)), + } + var wl []*protocol.RichWinLine + for _, r := range p.result.WinLine { + wl = append(wl, &protocol.RichWinLine{ + Poss: r.Poss, + }) + } + pack.WinLines = wl + logger.Logger.Trace("SCRBBilled:", pack) + p.SendToClient(int(protocol.RBPID_PACKET_RICHBLESSED_SCRBBilled), pack) +} + +func (s *RichBlessedSceneData) SendJACKPOTBilled(p *RichBlessedPlayerData) { + + pack := &protocol.SCRBBilled{ + NowGameState: proto.Int(p.gameState), + BetIdx: proto.Int(p.betIdx), + Coin: proto.Int64(p.Coin), + //SmallJackpot: proto.Int64(s.jackpot.GetTotalSmall() / 10000), + //MiddleJackpot: proto.Int64(s.jackpot.GetTotalMiddle() / 10000), + //BigJackpot: proto.Int64(s.jackpot.GetTotalBig() / 10000), + //GrandJackpot: proto.Int64(s.jackpot.GetTotalGrand() / 10000), + WinJackpot: proto.Int64(p.JackwinCoin), + } + logger.Logger.Trace("SendJACKPOTBilled:", pack) + p.SendToClient(int(protocol.RBPID_PACKET_RICHBLESSED_SCRBJACKBilled), pack) +} + +func (s *RichBlessedSceneData) LoadJackPotData() { + str := base.SlotsPoolMgr.GetPool(s.GetGameFreeId(), s.Platform) + if str != "" { + jackpot := &base.SlotJackpotPool{} + err := json.Unmarshal([]byte(str), jackpot) + if err == nil { + s.jackpot = jackpot + } + } + if s.jackpot != nil { + base.SlotsPoolMgr.SetPool(s.GetGameFreeId(), s.Platform, s.jackpot) + } else { + s.jackpot = &base.SlotJackpotPool{} + jp := s.DbGameFree.GetJackpot() + if len(jp) > 0 { + s.jackpot.Small += int64(jp[0] * 10000) + } + } +} +func (s *RichBlessedSceneData) SaveLog(p *RichBlessedPlayerData, isOffline int) { + if s.Testing { + return + } + s.SendPlayerBet(p) + + var betCoin int64 + var nowNRound int + var nowGetCoin int64 + + if p.gameState == richblessed.Normal { + betCoin = p.betCoin + nowGetCoin = p.winCoin + + } else if p.gameState == richblessed.FreeGame { + nowNRound = p.nowFreeTimes + nowGetCoin = p.winCoin + + } else { + nowGetCoin = p.JackwinCoin + + } + RichBlessed := model.RichBlessedType{ + RoomId: s.SceneId, + BasicScore: int32(p.oneBetCoin), + PlayerSnId: p.SnId, + BeforeCoin: p.startCoin, + AfterCoin: p.Coin, + ChangeCoin: p.Coin - p.startCoin, + TotalBetCoin: betCoin, + TotalLine: 9, + TotalWinCoin: nowGetCoin, + NowGameState: p.gameState, + NowNRound: nowNRound, + IsOffline: isOffline, + FirstFreeTimes: int(p.freeTimes), + TaxCoin: p.taxCoin, + WBLevel: p.WBLevel, + RealCtrl: s.RealCtrl, + WBState: p.WBState, + WeightKey: p.weightPos + 1, + } + + var winLine []model.RichBlessedWinLine + if p.gameState == richblessed.JackGame { // jack小游戏 + RichBlessed.JackEleValue = p.result.JackpotEle + RichBlessed.JackMidCards = append(RichBlessed.JackMidCards, p.JackMidCards...) + } + + RichBlessed.Cards = p.result.EleValue + RichBlessed.WinLineNum = len(p.result.WinLine) + RichBlessed.WinLineRate = p.winLineRate + RichBlessed.WinLineCoin = p.winLineRate * p.oneBetCoin + for _, line := range p.result.WinLine { + if len(line.Lines) > 0 { + flag := line.Lines[0] + fw := model.RichBlessedWinLine{ + Id: line.LineId, + Num: len(line.Lines), + EleValue: flag, + Rate: line.Rate, + WinCoin: line.Rate * p.oneBetCoin, + } + winLine = append(winLine, fw) + } + } + + RichBlessed.WinLine = winLine + info, err := model.MarshalGameNoteByROLL(&RichBlessed) + if err == nil { + logId, _ := model.AutoIncGameLogId() + s.SaveGameDetailedLog(logId, info, &base.GameDetailedParam{}) + //水池上下文环境s + s.CpCtx = p.cpCtx + var totalIn, totalOut int64 + if betCoin > 0 { + totalIn = betCoin + } + if nowGetCoin > 0 { + totalOut = p.Coin - p.startCoin + betCoin /*+ p.taxCoin*/ + } + s.SaveGamePlayerListLog(p.SnId, + &base.SaveGamePlayerListLogParam{ + Platform: p.Platform, + Channel: p.Channel, + Promoter: p.BeUnderAgentCode, + PackageTag: p.PackageID, + InviterId: p.InviterId, + LogId: logId, + TotalIn: totalIn, + TotalOut: totalOut, + TaxCoin: p.taxCoin, + ClubPumpCoin: 0, + BetAmount: totalIn, + WinAmountNoAnyTax: p.Coin - p.startCoin, + IsFirstGame: s.IsPlayerFirst(p.Player), + }) + } + s.GameNowTime = time.Now() + if s.CheckNeedDestroy() && p.freeTimes == 0 { + s.PlayerLeave(p.Player, common.PlayerLeaveReason_OnDestroy, true) + } +} +func (s *RichBlessedSceneData) GetEleWeight(needpos int32) (norms, frees [][]int32, jk []int32, key int32) { + if needpos < 0 || needpos > 7 || !s.RealCtrl { + needpos = 0 + } + if needpos == 0 { + curCoin := base.CoinPoolMgr.GetCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + curCoin = int64(math.Floor(float64(curCoin) / float64(richblessed.NowByte))) + + for i := len(s.DbGameFree.BalanceLine) - 1; i >= 0; i-- { + balance := s.DbGameFree.BalanceLine[i] + if curCoin >= int64(balance) { + key = int32(i) + break + } + } + } else { + key = needpos - 1 + } + for _, ele := range srvdata.PBDB_SlotRateWeightMgr.Datas.GetArr() { + if ele.GameFreeId == s.GetGameFreeId() && ele.Pos == key { + norms = append(norms, ele.NormCol1) + norms = append(norms, ele.NormCol2) + norms = append(norms, ele.NormCol3) + norms = append(norms, ele.NormCol4) + norms = append(norms, ele.NormCol5) + + frees = append(frees, ele.FreeCol1) + frees = append(frees, ele.FreeCol2) + frees = append(frees, ele.FreeCol3) + frees = append(frees, ele.FreeCol4) + frees = append(frees, ele.FreeCol5) + + jk = ele.JackPot + break + } + } + if norms == nil { + norms = richblessed.EleWeight[:5] + frees = richblessed.EleWeight[5:10] + jk = richblessed.EleWeight[10] + key = 0 + } + return +} + +func (s *RichBlessedSceneData) CreateResult(eleLineAppearRate [][]int32, playerEx *RichBlessedPlayerData) { + //if s.DbGameFree.GetId() == 3070004 { + // playerEx.TestCode(eleLineAppearRate) + //} else { + playerEx.result.CreateLine(eleLineAppearRate) + //} +} +func (s *RichBlessedSceneData) SendPlayerBet(p *RichBlessedPlayerData) { + //统计输下注金币数 + if !p.IsRob && !s.Testing { + betCoin := p.betCoin + if p.gameState != richblessed.Normal { + betCoin = 0 + } + playerBet := &server.PlayerData{ + SnId: proto.Int32(p.SnId), + Bet: proto.Int64(betCoin), + Gain: proto.Int64(p.Coin - p.startCoin), + Tax: proto.Int64(p.taxCoin), + } + gwPlayerBet := &server.GWPlayerData{ + GameFreeId: proto.Int32(s.DbGameFree.GetId()), + } + gwPlayerBet.Datas = append(gwPlayerBet.Datas, playerBet) + s.SyncPlayerDatas(&base.PlayerDataParam{ + HasRobotGaming: false, + Data: gwPlayerBet, + }) + } +} diff --git a/gamesrv/richblessed/scenepolicy_richblessed.go b/gamesrv/richblessed/scenepolicy_richblessed.go new file mode 100644 index 0000000..cee9421 --- /dev/null +++ b/gamesrv/richblessed/scenepolicy_richblessed.go @@ -0,0 +1,585 @@ +package richblessed + +import ( + "time" + + "mongo.games.com/goserver/core" + "mongo.games.com/goserver/core/logger" + + "mongo.games.com/game/common" + "mongo.games.com/game/gamerule/richblessed" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/proto" + protocol "mongo.games.com/game/protocol/richblessed" +) + +// //////////////////////////////////////////////////////////// +var ScenePolicyRichBlessedSington = &ScenePolicyRichBlessed{} + +type ScenePolicyRichBlessed struct { + base.BaseScenePolicy + states [richblessed.RichBlessedStateMax]base.SceneState +} + +// 创建场景扩展数据 +func (this *ScenePolicyRichBlessed) CreateSceneExData(s *base.Scene) interface{} { + sceneEx := NewRichBlessedSceneData(s) + if sceneEx != nil { + if sceneEx.GetInit() { + s.SetExtraData(sceneEx) + } + } + return sceneEx +} + +// 创建玩家扩展数据 +func (this *ScenePolicyRichBlessed) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} { + playerEx := &RichBlessedPlayerData{Player: p} + p.SetExtraData(playerEx) + return playerEx +} + +// 场景开启事件 +func (this *ScenePolicyRichBlessed) OnStart(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyRichBlessed) OnStart, sceneId=", s.GetSceneId()) + sceneEx := NewRichBlessedSceneData(s) + if sceneEx != nil { + if sceneEx.GetInit() { + s.SetExtraData(sceneEx) + s.ChangeSceneState(richblessed.RichBlessedStateStart) + } + } +} + +// 场景关闭事件 +func (this *ScenePolicyRichBlessed) OnStop(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyRichBlessed) OnStop , sceneId=", s.GetSceneId()) +} + +// 场景心跳事件 +func (this *ScenePolicyRichBlessed) OnTick(s *base.Scene) { + if s == nil { + return + } + if s.GetSceneState() != nil { + s.GetSceneState().OnTick(s) + } +} + +// 玩家进入事件 +func (this *ScenePolicyRichBlessed) OnPlayerEnter(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyRichBlessed) OnPlayerEnter, sceneId=", s.GetSceneId(), " player=", p.Name, "bet:", s.DbGameFree.GetOtherIntParams()) + if sceneEx, ok := s.GetExtraData().(*RichBlessedSceneData); ok { + playerEx := &RichBlessedPlayerData{Player: p} + playerEx.init() + playerEx.Clear() + + sceneEx.players[p.SnId] = playerEx + + p.SetExtraData(playerEx) + + RichBlessedSendRoomInfo(s, sceneEx, playerEx) + + s.FirePlayerEvent(p, base.PlayerEventEnter, nil) + } +} + +// 玩家离开事件 +func (this *ScenePolicyRichBlessed) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyRichBlessed) OnPlayerLeave, sceneId=", s.GetSceneId(), " player=", p.SnId) + if sceneEx, ok := s.ExtraData.(*RichBlessedSceneData); ok { + s.FirePlayerEvent(p, base.PlayerEventLeave, nil) + sceneEx.OnPlayerLeave(p, reason) + } +} + +// 玩家掉线 +func (this *ScenePolicyRichBlessed) OnPlayerDropLine(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyRichBlessed) OnPlayerDropLine, sceneId=", s.GetSceneId(), " player=", p.SnId) + s.FirePlayerEvent(p, base.PlayerEventDropLine, nil) +} + +// 玩家重连 +func (this *ScenePolicyRichBlessed) OnPlayerRehold(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyRichBlessed) OnPlayerRehold, sceneId=", s.GetSceneId(), " player=", p.SnId) + if sceneEx, ok := s.GetExtraData().(*RichBlessedSceneData); ok { + if playerEx, ok := p.GetExtraData().(*RichBlessedPlayerData); ok { + RichBlessedSendRoomInfo(s, sceneEx, playerEx) + } + } +} + +// 返回房间 +func (this *ScenePolicyRichBlessed) OnPlayerReturn(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyRichBlessed) OnPlayerReturn, GetSceneId()=", s.GetSceneId(), " player=", p.Name) + if sceneEx, ok := s.GetExtraData().(*RichBlessedSceneData); ok { + if playerEx, ok := p.GetExtraData().(*RichBlessedPlayerData); ok { + //if p.IsMarkFlag(base.PlayerState_Auto) { + // p.UnmarkFlag(base.PlayerState_Auto) + // p.SyncFlag() + //} + //发送房间信息给自己 + RichBlessedSendRoomInfo(s, sceneEx, playerEx) + s.FirePlayerEvent(p, base.PlayerEventReturn, nil) + } + } +} + +func RichBlessedSendRoomInfo(s *base.Scene, sceneEx *RichBlessedSceneData, playerEx *RichBlessedPlayerData) { + pack := RichBlessedCreateRoomInfoPacket(s, sceneEx, playerEx) + logger.Logger.Trace("RoomInfo: ", pack) + playerEx.SendToClient(int(protocol.RBPID_PACKET_RICHBLESSED_SCRBRoomInfo), pack) +} +func RichBlessedCreateRoomInfoPacket(s *base.Scene, sceneEx *RichBlessedSceneData, playerEx *RichBlessedPlayerData) interface{} { + //房间信息 + pack := &protocol.SCRBRoomInfo{ + RoomId: proto.Int(s.SceneId), + GameId: proto.Int(s.GameId), + RoomMode: proto.Int(s.SceneMode), + SceneType: proto.Int(s.SceneType), + Params: s.Params, + NumOfGames: proto.Int(sceneEx.NumOfGames), + State: proto.Int(s.SceneState.GetState()), + ParamsEx: common.Int64ToInt32(s.DbGameFree.OtherIntParams), //s.GetParamsEx(), + //BetLimit: s.DbGameFree.BetLimit, + + NowGameState: proto.Int(playerEx.gameState), + BetIdx: proto.Int(playerEx.betIdx), + FreeAllWin: proto.Int64(playerEx.freewinCoin), + SmallJackpot: proto.Int64(playerEx.oneBetCoin * richblessed.JkEleNumRate[richblessed.BlueGirl]), + MiddleJackpot: proto.Int64(playerEx.oneBetCoin * richblessed.JkEleNumRate[richblessed.BlueBoy]), + BigJackpot: proto.Int64(playerEx.oneBetCoin * richblessed.JkEleNumRate[richblessed.GoldGirl]), + GrandJackpot: proto.Int64(playerEx.oneBetCoin * richblessed.JkEleNumRate[richblessed.GoldBoy]), + WinEleCoin: proto.Int64(playerEx.winCoin), + WinRate: proto.Int64(playerEx.winLineRate), + FreeNum: proto.Int64(int64(playerEx.freeTimes)), + AddFreeNum: proto.Int64(int64(playerEx.addfreeTimes)), + WinFreeTimes: proto.Int32(int32(playerEx.nowFreeTimes)), + JackpotEle: proto.Int32(playerEx.result.JackpotEle), + WinJackpot: proto.Int64(playerEx.JackwinCoin), + GameFreeId: proto.Int32(s.DbGameFree.Id), + } + + if playerEx.oneBetCoin == 0 && len(s.DbGameFree.GetOtherIntParams()) != 0 { // 初始化客户端jack显示 + oneBetCoin := int64(s.DbGameFree.GetOtherIntParams()[0] / richblessed.LineNum) + pack.SmallJackpot = oneBetCoin * richblessed.JkEleNumRate[richblessed.BlueGirl] + pack.MiddleJackpot = oneBetCoin * richblessed.JkEleNumRate[richblessed.BlueBoy] + pack.BigJackpot = oneBetCoin * richblessed.JkEleNumRate[richblessed.GoldGirl] + pack.GrandJackpot = oneBetCoin * richblessed.JkEleNumRate[richblessed.GoldBoy] + } + + //自己的信息 + if playerEx != nil { + pd := &protocol.RBPlayerData{ + SnId: proto.Int32(playerEx.SnId), + Name: proto.String(playerEx.Name), + Head: proto.Int32(playerEx.Head), + Sex: proto.Int32(playerEx.Sex), + Coin: proto.Int64(playerEx.Coin), + Pos: proto.Int(playerEx.Pos), + Flag: proto.Int(playerEx.GetFlag()), + City: proto.String(playerEx.City), + HeadOutLine: proto.Int32(playerEx.HeadOutLine), + VIP: proto.Int32(playerEx.VIP), + } + pack.Player = pd + } + if playerEx.result != nil { + pack.Cards = playerEx.result.EleValue + var wl []*protocol.RichWinLine + for _, r := range playerEx.result.WinLine { + wl = append(wl, &protocol.RichWinLine{ + Poss: r.Poss, + }) + } + pack.WinLines = wl + } + proto.SetDefaults(pack) + return pack +} +func (this *ScenePolicyRichBlessed) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + if s == nil || p == nil { + return false + } + logger.Logger.Trace("(this *ScenePolicyRichBlessed) OnPlayerOp, sceneId=", s.GetSceneId(), " player=", p.SnId, " opcode=", opcode, " params=", params) + if s.GetSceneState() != nil { + if s.GetSceneState().OnPlayerOp(s, p, opcode, params) { + p.SetLastOPTimer(time.Now()) + return true + } + return false + } + return true +} + +func (this *ScenePolicyRichBlessed) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyRichBlessed) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " eventcode=", evtcode, " params=", params) + if s.GetSceneState() != nil { + s.GetSceneState().OnPlayerEvent(s, p, evtcode, params) + } +} + +// 当前状态能否换桌 +func (this *ScenePolicyRichBlessed) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if s == nil || p == nil { + return false + } + if s.GetSceneState() != nil { + return s.GetSceneState().CanChangeCoinScene(s, p) + } + return false +} + +// 状态基类 +type SceneBaseStateRichBlessed struct { +} + +func (this *SceneBaseStateRichBlessed) GetTimeout(s *base.Scene) int { + if sceneEx, ok := s.GetExtraData().(*RichBlessedSceneData); ok { + return int(time.Now().Sub(sceneEx.GetStateStartTime()) / time.Second) + } + return 0 +} + +func (this *SceneBaseStateRichBlessed) CanChangeTo(s base.SceneState) bool { + return true +} + +// 当前状态能否换桌 +func (this *SceneBaseStateRichBlessed) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + return true +} +func (this *SceneBaseStateRichBlessed) OnEnter(s *base.Scene) { + if sceneEx, ok := s.GetExtraData().(*RichBlessedSceneData); ok { + sceneEx.SetStateStartTime(time.Now()) + } +} + +func (this *SceneBaseStateRichBlessed) OnLeave(s *base.Scene) {} +func (this *SceneBaseStateRichBlessed) OnTick(s *base.Scene) { + if time.Now().Sub(s.GameStartTime) > time.Second*3 { + if sceneEx, ok := s.ExtraData.(*RichBlessedSceneData); ok { + //pack := &protocol.SCRBPrize{ + // PrizePool: proto.Int64(sceneEx.jackpot.GetTotalSmall() / 10000), + //} + //proto.SetDefaults(pack) + ////logger.Logger.Trace("SCRBPrize: ", pack) + //s.Broadcast(int(protocol.RBPID_PACKET_RICHBLESSED_SCRBPrize), pack, 0) + for _, p := range sceneEx.players { + if p.IsOnLine() { + p.leaveTime = 0 + continue + } + + p.leaveTime++ + if p.leaveTime < 60*2 { + continue + } + //踢出玩家 + sceneEx.PlayerLeave(p.Player, common.PlayerLeaveReason_LongTimeNoOp, true) + } + } + s.GameStartTime = time.Now() + } + if sceneEx, ok := s.ExtraData.(*RichBlessedSceneData); ok { + //for _, p := range sceneEx.players { + // //游戏次数达到目标值 + // todayGamefreeIDSceneData, _ := p.GetDaliyGameData(int(sceneEx.DbGameFree.GetId())) + // if !p.IsRob && + // todayGamefreeIDSceneData != nil && + // sceneEx.DbGameFree.GetPlayNumLimit() != 0 && + // todayGamefreeIDSceneData.GameTimes >= int64(sceneEx.DbGameFree.GetPlayNumLimit()) { + // s.PlayerLeave(p.Player, common.PlayerLeaveReason_GameTimes, true) + // } + //} + if sceneEx.CheckNeedDestroy() { + for _, player := range sceneEx.players { + if !player.IsRob { + sceneEx.PlayerLeave(player.Player, common.PlayerLeaveReason_OnDestroy, true) + } + } + if s.GetRealPlayerCnt() == 0 { + sceneEx.SceneDestroy(true) + } + } + } + //if sceneEx, ok := s.GetExtraData().(*RichBlessedSceneData); ok { + // if time.Now().Sub(sceneEx.mqLogTime) >= time.Minute*1 { + // now := time.Now() + // sceneEx.mqLogTime = now.Add(-time.Second * time.Duration(now.Second())) + // + // waterVal := base.CoinPoolMgr.LoadCoin(s.GetGameFreeId(), s.Platform, s.GroupId) + // waterVal = int64(math.Floor(float64(waterVal) / float64(richblessed.NowByte))) + // + // jkVal1 := int64(math.Floor(float64(sceneEx.jackpot.GetTotalSmall()) / float64(richblessed.NowByte))) + // jkVal2 := int64(math.Floor(float64(sceneEx.jackpot.GetTotalMiddle()) / float64(richblessed.NowByte))) + // jkVal3 := int64(math.Floor(float64(sceneEx.jackpot.GetTotalBig()) / float64(richblessed.NowByte))) + // jkVal4 := int64(math.Floor(float64(sceneEx.jackpot.GetTotalGrand()) / float64(richblessed.NowByte))) + // + // base.JackPotMgr.WJackPotUpdate(sceneEx.GetGameFreeId(), sceneEx.Platform, waterVal, jkVal1, jkVal2, jkVal3, jkVal4) + // } + //} +} +func (this *SceneBaseStateRichBlessed) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + return false +} +func (this *SceneBaseStateRichBlessed) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { +} + +// //////////////////////////////////////////////////////////// +// 开始状态 +// //////////////////////////////////////////////////////////// +type SceneStateStartRichBlessed struct { + SceneBaseStateRichBlessed +} + +func (this *SceneStateStartRichBlessed) GetState() int { + return richblessed.RichBlessedStateStart +} + +func (this *SceneStateStartRichBlessed) CanChangeTo(s base.SceneState) bool { + return false +} + +// 当前状态能否换桌 +func (this *SceneStateStartRichBlessed) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if playerEx, ok := p.GetExtraData().(*RichBlessedPlayerData); ok { + if playerEx.IsOnLine() && playerEx.freeTimes > 0 { + return false + } + } + return true +} + +func (this *SceneStateStartRichBlessed) GetTimeout(s *base.Scene) int { + return 0 +} + +func (this *SceneStateStartRichBlessed) OnEnter(s *base.Scene) { + this.SceneBaseStateRichBlessed.OnEnter(s) + if sceneEx, ok := s.GetExtraData().(*RichBlessedSceneData); ok { + sceneEx.SetGameNowTime(time.Now()) + } +} + +// 状态离开时 +func (this *SceneStateStartRichBlessed) OnLeave(s *base.Scene) { + this.SceneBaseStateRichBlessed.OnLeave(s) + logger.Logger.Tracef("(this *SceneStateStartRichBlessed) OnLeave, sceneid=%v", s.GetSceneId()) +} + +// 玩家操作 +func (this *SceneStateStartRichBlessed) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + logger.Logger.Tracef("(this *SceneStateStartRichBlessed) OnPlayerOp, sceneid=%v params=%v", s.GetSceneId(), params) + if this.SceneBaseStateRichBlessed.OnPlayerOp(s, p, opcode, params) { + return true + } + if sceneEx, ok := s.GetExtraData().(*RichBlessedSceneData); ok { + if playerEx, ok := p.GetExtraData().(*RichBlessedPlayerData); ok { + switch opcode { + case richblessed.RichBlessedPlayerOpStart: + playerEx.Clear() + if len(params) > 0 { + //只有开始算操作 + p.LastOPTimer = time.Now() + idx := int(params[0]) + if len(sceneEx.DbGameFree.GetOtherIntParams()) <= idx { + pack := &protocol.SCRichBlessedOp{ + OpCode: proto.Int(opcode), + OpRetCode: proto.Int(3), + } + playerEx.SendToClient(int(protocol.RBPID_PACKET_RICHBLESSED_SCRichBlessedOp), pack) + return false + } + + if playerEx.freeTimes > 0 { + playerEx.gameState = richblessed.FreeGame + playerEx.freeTimes-- + playerEx.nowFreeTimes++ + } + //水池上下文环境 + playerEx.cpCtx = base.CoinPoolMgr.GetCoinPoolCtx(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) + + norms, frees, JACKRand, key := sceneEx.GetEleWeight(playerEx.WBState) + playerEx.weightPos = key + if playerEx.gameState == richblessed.Normal { + logger.Logger.Tracef("(this *SceneStateStartRichBlessed) OnPlayerOp, 下注 %v %v %v", playerEx.betCoin, playerEx.maxbetCoin, playerEx.oneBetCoin) + playerEx.betIdx = idx + playerEx.betCoin = int64(sceneEx.DbGameFree.GetOtherIntParams()[idx]) + maxidx := len(sceneEx.DbGameFree.GetOtherIntParams()) - 1 + playerEx.maxbetCoin = int64(sceneEx.DbGameFree.GetOtherIntParams()[maxidx]) + playerEx.oneBetCoin = playerEx.betCoin / richblessed.LineNum // 单注 + playerEx.noWinTimes++ + + if playerEx.Coin < int64(s.DbGameFree.GetBetLimit()) { + //押注限制(低于该值不能押注) + pack := &protocol.SCRichBlessedOp{ + OpCode: proto.Int(opcode), + OpRetCode: proto.Int(2), + } + playerEx.SendToClient(int(protocol.RBPID_PACKET_RICHBLESSED_SCRichBlessedOp), pack) + return false + } + if playerEx.betCoin > playerEx.Coin { + //金币不足 + pack := &protocol.SCRichBlessedOp{ + OpCode: proto.Int(opcode), + OpRetCode: proto.Int(1), + } + playerEx.SendToClient(int(protocol.RBPID_PACKET_RICHBLESSED_SCRichBlessedOp), pack) + return false + } + playerEx.CurrentBet = playerEx.betCoin + playerEx.CurrentTax = 0 + //SysProfitCoinMgr.Add(sceneEx.sysProfitCoinKey, playerEx.betCoin, -playerEx.betCoin) + //没有免费次数 扣钱 + p.Statics(s.KeyGameId, s.KeyGamefreeId, -playerEx.betCoin, false) + playerEx.AddCoin(-playerEx.betCoin, common.GainWay_HundredSceneLost, 0, "system", s.GetSceneName()) + sceneEx.AddPrizeCoin(playerEx) // 12%jack + + sceneEx.CreateResult(norms, playerEx) + + playerEx.isFTest++ + if playerEx.isFTest >= 100000 { + playerEx.isFTest = 0 + } + + //if !playerEx.nottest { + // playerEx.result.EleValue = []int32{1, 0, 1, 0, 5, 6, 2, 7, 7, 9, 9, 7, 4, 8, 7} //三锣免费 + //} + } else { + // 免费游戏 + if playerEx.freeTimes >= 100 { + playerEx.CreateLevResult(frees) // 没有铜锣概率 + playerEx.freeTimes = 0 + } else { + sceneEx.CreateResult(frees, playerEx) + } + + //if playerEx.freeTimes == 3 && !playerEx.nottest1 { // 免费在中一次 + // playerEx.result.EleValue = []int32{1, 0, 1, 0, 5, 6, 2, 7, 7, 9, 9, 7, 4, 8, 7} //三锣免费 + // playerEx.nottest1 = true + //} + } + + sceneEx.Win(playerEx) + + if sceneEx.CanJACKPOT(playerEx, playerEx.betCoin, playerEx.maxbetCoin, JACKRand) { // 中奖 包含CreateJACKPOT 下注不存在越界问题 + playerEx.gameState = richblessed.JackGame + // sceneEx.JACKPOTWin(playerEx) + } + //发送结算 + sceneEx.SendBilled(playerEx) + if !playerEx.isFWinJackpot { + sceneEx.SaveLog(playerEx, 0) + } + } + case richblessed.RichBlessedPlayerOpSwitch: + if len(params) > 0 && playerEx.freeTimes == 0 { + idx := int(params[0]) + if len(sceneEx.DbGameFree.GetOtherIntParams()) > idx { + playerEx.betIdx = idx + playerEx.betCoin = int64(sceneEx.DbGameFree.GetOtherIntParams()[idx]) + playerEx.oneBetCoin = playerEx.betCoin / richblessed.LineNum + pack := &protocol.SCRichBlessedOp{ + OpCode: proto.Int(opcode), + OpRetCode: proto.Int(4), + } + for i := int32(0); i != richblessed.JackMax; i++ { + pack.Params = append(pack.Params, playerEx.oneBetCoin*richblessed.JkEleNumRate[i]) + } + playerEx.SendToClient(int(protocol.RBPID_PACKET_RICHBLESSED_SCRichBlessedOp), pack) + logger.Logger.Tracef("(this *SceneStateStartRichBlessed) OnPlayerOp, sceneid=%v pack=%v", s.GetSceneId(), pack) + } + } + case richblessed.RichBlessedPlayerOpJack: // jack领奖 注意不要再次结算wincoin + if !playerEx.isFWinJackpot { + pack := &protocol.SCRichBlessedOp{ + OpCode: proto.Int(opcode), + OpRetCode: proto.Int(3), + } + playerEx.SendToClient(int(protocol.RBPID_PACKET_RICHBLESSED_SCRichBlessedOp), pack) + return false + } + playerEx.JackMidCards = append(playerEx.JackMidCards, params...) + sceneEx.JACKPOTWin(playerEx) + //发送结算 + sceneEx.SendJACKPOTBilled(playerEx) + + sceneEx.SaveLog(playerEx, 0) + + playerEx.Clear() // 小游戏模式结束 + } + } + } + return true +} + +// 玩家事件 +func (this *SceneStateStartRichBlessed) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { + logger.Logger.Trace("(this *SceneStateStartRichBlessed) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " evtcode=", evtcode) + this.SceneBaseStateRichBlessed.OnPlayerEvent(s, p, evtcode, params) + if _, ok := s.GetExtraData().(*RichBlessedSceneData); ok { + switch evtcode { + case base.PlayerEventEnter: + /* + pack := &protocol.SCRBPrize{ + PrizePool: proto.Int64(sceneEx.jackpot.GetTotalSmall() / 10000), + } + proto.SetDefaults(pack) + //logger.Logger.Trace("SCRBPrize: ", pack) + p.SendToClient(int(protocol.RBPID_PACKET_RICHBLESSED_SCRBPrize), pack) + */ + } + } +} + +func (this *SceneStateStartRichBlessed) OnTick(s *base.Scene) { + this.SceneBaseStateRichBlessed.OnTick(s) +} + +// ////////////////////////////////////////////////////////////////////////////// +func (this *ScenePolicyRichBlessed) RegisteSceneState(state base.SceneState) { + if state == nil { + return + } + stateid := state.GetState() + if stateid < 0 || stateid >= richblessed.RichBlessedStateMax { + return + } + this.states[stateid] = state +} + +func (this *ScenePolicyRichBlessed) GetSceneState(s *base.Scene, stateid int) base.SceneState { + if stateid >= 0 && stateid < richblessed.RichBlessedStateMax { + return this.states[stateid] + } + return nil +} + +func init() { + //主状态 + ScenePolicyRichBlessedSington.RegisteSceneState(&SceneStateStartRichBlessed{}) + core.RegisteHook(core.HOOK_BEFORE_START, func() error { + base.RegisteScenePolicy(common.GameId_Richblessed, richblessed.RoomMode_Classic, ScenePolicyRichBlessedSington) + return nil + }) +} diff --git a/gamesrv/tamquoc/action_tamquoc.go b/gamesrv/tamquoc/action_tamquoc.go new file mode 100644 index 0000000..2ef6c60 --- /dev/null +++ b/gamesrv/tamquoc/action_tamquoc.go @@ -0,0 +1,55 @@ +package tamquoc + +import ( + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/netlib" + + "mongo.games.com/game/common" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/protocol/tamquoc" +) + +// 百战成神的操作 +type CSTamQuocOpPacketFactory struct { +} +type CSTamQuocOpHandler struct { +} + +func (this *CSTamQuocOpPacketFactory) CreatePacket() interface{} { + pack := &tamquoc.CSTamQuocOp{} + return pack +} +func (this *CSTamQuocOpHandler) Process(s *netlib.Session, packetid int, data interface{}, sid int64) error { + logger.Logger.Trace("CSTamQuocOpHandler Process recv ", data) + if csTamQuocOp, ok := data.(*tamquoc.CSTamQuocOp); ok { + p := base.PlayerMgrSington.GetPlayer(sid) + if p == nil { + logger.Logger.Warn("CSTamQuocOpHandler p == nil") + return nil + } + scene := p.GetScene() + if scene == nil { + logger.Logger.Warn("CSTamQuocOpHandler p.scene == nil") + return nil + } + if scene.GameId != common.GameId_TamQuoc { + logger.Logger.Error("CSTamQuocOpHandler gameId Error ", scene.GameId) + return nil + } + if !scene.HasPlayer(p) { + return nil + } + sp := scene.GetScenePolicy() + if sp != nil { + sp.OnPlayerOp(scene, p, int(csTamQuocOp.GetOpCode()), csTamQuocOp.GetParams()) + } + return nil + } + return nil +} + +func init() { + // 百战成神的操作 + common.RegisterHandler(int(tamquoc.TamQuocPacketID_PACKET_CS_TAMQUOC_PLAYEROP), &CSTamQuocOpHandler{}) + netlib.RegisterFactory(int(tamquoc.TamQuocPacketID_PACKET_CS_TAMQUOC_PLAYEROP), &CSTamQuocOpPacketFactory{}) +} diff --git a/gamesrv/tamquoc/constant.go b/gamesrv/tamquoc/constant.go new file mode 100644 index 0000000..1a02763 --- /dev/null +++ b/gamesrv/tamquoc/constant.go @@ -0,0 +1,112 @@ +package tamquoc + +import ( + "encoding/json" + "time" + + "mongo.games.com/game/model" +) + +// 玩家游戏数据索引 +const ( + TamQuocFreeTimes int = iota //0 当前剩余免费次数 + TamQuocBonusTime //1 上一次小游戏的时间 + TamQuocIndexMax +) + +// 通知奖池变化的时间间隔 +const jackpotNoticeInterval = time.Second + +// 场景状态 +const ( + TamQuocSceneStateStart int = iota //开始游戏 + TamQuocSceneStateMax +) + +// 玩家操作 +const ( + TamQuocPlayerOpStart int = iota //游戏 + TamQuocPlayerHistory // 游戏记录 + TamQuocBurstHistory // 爆奖记录 + TamQuocBonusGame // 小游戏 + TamQuocBonusGameRecord // 小游戏重连 +) + +// 小游戏超时时间 +const TamQuocBonusGameTimeout = time.Second * 60 + +// 小游戏操作时间 +const TamQuocBonusGamePickTime = time.Second * 15 + +type GameResultLog struct { + BaseResult *model.SlotBaseResultType + AllLine int32 //线路数 + UserName string //昵称 + BetLines []int64 //下注的线 + //Cards [][]int32 // 消除前后的牌(消除前15张,消除后15张...) + WinLines []int // 赢分的线 +} + +// 百战成神解析的数据 +type TamQuocGameNoteData struct { + Source int32 + Data *GameResultLog +} + +// 百战成神游戏记录 +func UnMarshalTamQuocGameNote(data string) (roll interface{}, err error) { + gnd := &TamQuocGameNoteData{} + if err := json.Unmarshal([]byte(data), gnd); err != nil { + return nil, err + } + roll = gnd.Data + return +} + +var DebugData = [][]int{ + { + 1, 1, 1, 5, 5, + 1, 1, 1, 3, 4, + 6, 7, 2, 3, 5, + }, + { + 1, 1, 1, 1, 5, + 1, 1, 1, 1, 4, + 6, 7, 2, 3, 5, + }, + { + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 6, 7, 2, 3, 5, + }, + { + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, + }, + { + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, + }, + { + 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, + }, + { + 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, + }, + { + 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, + }, + { + 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, + }, +} diff --git a/gamesrv/tamquoc/playerdata_tamquoc.go b/gamesrv/tamquoc/playerdata_tamquoc.go new file mode 100644 index 0000000..7d66450 --- /dev/null +++ b/gamesrv/tamquoc/playerdata_tamquoc.go @@ -0,0 +1,152 @@ +package tamquoc + +import ( + "encoding/json" + "math/rand" + "time" + + "mongo.games.com/goserver/core/timer" + + rule "mongo.games.com/game/gamerule/tamquoc" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/protocol/tamquoc" +) + +type TamQuocPlayerData struct { + *base.Player + spinID int64 //当前旋转ID + score int32 //单线押注数 + freeTimes int32 //免费转动次数 + cards []int32 //15张牌 + totalPriceBonus int64 //小游戏奖金 + bonusTimerHandle timer.TimerHandle //托管handle + //RollGameType *model.TamQuocType //记录信息 + RollGameType *GameResultLog //记录信息 + enterGameCoin int64 //玩家进入初始金币 + betLines []int64 //下注的选线 + taxCoin int64 //本局税收 + winCoin int64 //本局收税前赢的钱 + linesWinCoin int64 //本局中奖线赢得钱 + jackpotWinCoin int64 //本局奖池赢的钱 + smallGameWinCoin int64 //本局小游戏赢的钱 + currentLogId string //爆奖玩家logid + leavetime int32 //用户离开时间 + bonusGameTime int64 //上一次小游戏的时间 + bonusGameStartTime time.Time // 小游戏开始时间 + bonusGamePickPos []int32 // 小游戏位置 + bonusGameCanPickNum int // 小游戏点击次数 + bonusGame tamquoc.TamQuocBonusGameInfo + billedData *tamquoc.GameBilledData + DebugGame bool //测试 + TestNum int +} + +// 玩家初始化 +func (this *TamQuocPlayerData) init(s *base.Scene) { + this.Clean() + this.score = 0 + this.freeTimes = 0 + //this.RollGameType = &model.TamQuocType{} + this.RollGameType = &GameResultLog{} + this.RollGameType.BaseResult = &model.SlotBaseResultType{} + this.enterGameCoin = this.Coin + this.currentLogId = "" + this.billedData = &tamquoc.GameBilledData{} + this.DebugGame = true + this.TestNum = 0 + + initCards := rule.GenerateSlotsData_v2(rule.SYMBOL2) + for _, card := range initCards { + this.cards = append(this.cards, int32(card)) + } + + // 加载玩家游戏数据 + if this.GDatas == nil { + this.GDatas = make(map[string]*model.PlayerGameInfo) + } + + if d, exist := this.GDatas[s.KeyGamefreeId]; exist { + gLen := len(d.Data) + if gLen < TamQuocIndexMax { + for i := gLen; i < TamQuocIndexMax; i++ { + d.Data = append(d.Data, 0) + } + } + } else { + pgd := &model.PlayerGameInfo{ + Data: make([]int64, TamQuocIndexMax, TamQuocIndexMax), + } + this.GDatas[s.KeyGamefreeId] = pgd + } + this.LoadPlayerGameData(s.KeyGamefreeId) + //线条全选 + if len(this.betLines) == 0 { + this.betLines = rule.AllBetLines + } + this.bonusGamePickPos = make([]int32, 2) +} + +// 玩家清理数据 +func (this *TamQuocPlayerData) Clean() { + for i := 0; i < len(this.cards); i++ { + this.cards[i] = -1 + } + this.winCoin = 0 + this.taxCoin = 0 + this.linesWinCoin = 0 + this.jackpotWinCoin = 0 + this.smallGameWinCoin = 0 +} + +// 加载玩家游戏数据 +func (this *TamQuocPlayerData) LoadPlayerGameData(gameFreeId string) { + if d, exist := this.GDatas[gameFreeId]; exist { + this.freeTimes = int32(d.Data[TamQuocFreeTimes]) + this.bonusGameTime = d.Data[TamQuocBonusTime] + if this.freeTimes > 0 && len(d.DataEx) != 0 { + json.Unmarshal(d.DataEx, &this.betLines) + } + } +} + +// 存储玩家游戏数据 +func (this *TamQuocPlayerData) SavePlayerGameData(gameFreeId string) { + if d, exist := this.GDatas[gameFreeId]; exist { + d.Data[TamQuocFreeTimes] = int64(this.freeTimes) + d.Data[TamQuocBonusTime] = this.bonusGameTime + d.DataEx, _ = json.Marshal(this.betLines) + } +} + +// 黑白名单的限制是否生效 +func (this *TamQuocPlayerData) CheckBlackWriteList(isWin bool) bool { + if isWin && this.BlackLevel > 0 && this.BlackLevel <= 10 { + if rand.Int31n(100) < this.BlackLevel*10 { + return true + } + } else if !isWin && this.WhiteLevel > 0 && this.WhiteLevel <= 10 { + if rand.Int31n(100) < this.WhiteLevel*10 { + return true + } + } + return false +} + +// 玩家是否是新手 +func (this *TamQuocPlayerData) IsFNovice(keyGameId string) { + if f, ok := this.IsFoolPlayer[keyGameId]; ok { + if !f { + return + } + } else { + this.IsFoolPlayer[keyGameId] = true + return + } + if data, ok := this.GDatas[keyGameId]; ok { + if data.Statics.GameTimes < 100 && data.Statics.TotalOut-data.Statics.TotalIn <= 2000000 { + return + } + this.IsFoolPlayer[keyGameId] = false + } +} diff --git a/gamesrv/tamquoc/scenedata_tamquoc.go b/gamesrv/tamquoc/scenedata_tamquoc.go new file mode 100644 index 0000000..db474ea --- /dev/null +++ b/gamesrv/tamquoc/scenedata_tamquoc.go @@ -0,0 +1,324 @@ +package tamquoc + +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/tamquoc" + "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/tamquoc" +) + +type TamQuocSceneData struct { + *base.Scene //房间信息 + players map[int32]*TamQuocPlayerData //玩家信息 + rooms map[int][]*TamQuocPlayerData //房间 + jackpot *base.SlotJackpotPool //奖池 + lastJackpotValue int64 //上一次奖池变化时的值 + lastJackPot time.Time //增加奖池时间 + lastBurstJackPot map[int32]time.Time //爆池时间 +} + +func NewTamQuocSceneData(s *base.Scene) *TamQuocSceneData { + return &TamQuocSceneData{ + Scene: s, + players: make(map[int32]*TamQuocPlayerData), + rooms: make(map[int][]*TamQuocPlayerData), + } +} + +func (this *TamQuocSceneData) SaveData(force bool) { +} + +func (this *TamQuocSceneData) OnPlayerLeave(p *base.Player, reason int) { + if p, exist := this.players[p.SnId]; exist { + delete(this.players, p.SnId) + } +} + +func (this *TamQuocSceneData) SceneDestroy(force bool) { + //销毁房间 + this.Scene.Destroy(force) +} + +func (this *TamQuocSceneData) init() bool { + if this.DbGameFree == nil { + return false + } + params := this.DbGameFree.GetJackpot() + this.jackpot = &base.SlotJackpotPool{} + if this.jackpot.Small <= 0 { + this.jackpot.Small = 0 + this.jackpot.VirtualJK = int64(params[rule.TAMQUOC_JACKPOT_InitJackpot] * this.DbGameFree.GetBaseScore()) + } + str := base.SlotsPoolMgr.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 TamQuocSpinResult struct { + LinesInfo []*tamquoc.TamQuocLinesInfo + SlotsData []int32 + TotalPrizeLine int64 // 线条总金额 + TotalPrizeJackpot int64 // 爆奖总金额 + JackpotCnt int // 爆奖的次数 + AddFreeTimes int32 // 新增免费次数 + IsJackpot bool // 是否爆奖 + BonusGame tamquoc.TamQuocBonusGameInfo + TotalWinRate int32 // 中奖总倍率 + TotalTaxScore int64 // 税收 + IsBonusGame bool // 是否进小游戏标志 + WinLines []int // 赢分的线 +} + +func (this *TamQuocSceneData) CalcLinePrize(cards []int, betLines []int64, betValue int64) (spinRes TamQuocSpinResult) { + taxRate := this.DbGameFree.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 + } + + var startBonus int + 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++ + var prizeJackpot int64 + if spinRes.TotalPrizeJackpot == 0 { // 第一个爆奖 获取当前奖池所有 + prizeJackpot = this.jackpot.VirtualJK + } else { // 之后的爆奖 奖励为奖池初值 + prizeJackpot = int64(this.DbGameFree.GetJackpot()[rule.TAMQUOC_JACKPOT_InitJackpot] * this.DbGameFree.GetBaseScore()) + } + prizeJackpot = calcTaxScore(prizeJackpot, &spinRes.TotalTaxScore) + spinRes.TotalPrizeJackpot += prizeJackpot + } + + curScore := betValue * int64(line.Score) + curScore = calcTaxScore(curScore, &spinRes.TotalTaxScore) + spinRes.TotalPrizeLine += curScore + spinRes.TotalWinRate += int32(line.Score) + + lineInfo := &tamquoc.TamQuocLinesInfo{ + 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())) + + // bonus game + if line.BonusElementCnt == 3 || line.BonusElementCnt == 4 { + startBonus += rule.LineScore[rule.Element_BONUS][line.BonusElementCnt-1] + spinRes.IsBonusGame = true + } + + // add free + if line.FreeElementCnt >= 3 { + spinRes.AddFreeTimes += int32(rule.FreeSpinTimesRate[line.FreeElementCnt-1]) + } + } + + if spinRes.IsBonusGame && startBonus > 0 { + bonusGame := rule.GenerateBonusGame(int(betValue), startBonus) + + var totalBonusValue int64 + bonusData := make([]int64, 0) + for _, value := range bonusGame.BonusData { + value = calcTaxScore(value, nil) + totalBonusValue += value + bonusData = append(bonusData, value) + } + + spinRes.BonusGame = tamquoc.TamQuocBonusGameInfo{ + TotalPrizeValue: proto.Int64(totalBonusValue * int64(bonusGame.Mutiplier)), + Mutiplier: proto.Int32(int32(bonusGame.Mutiplier)), + DataMultiplier: proto.Int64(totalBonusValue), + BonusData: bonusData, + } + // 小游戏税收 + bonusTax := (bonusGame.DataMultiplier - totalBonusValue) * int64(bonusGame.Mutiplier) + spinRes.TotalTaxScore += bonusTax + } + + for _, card := range cards { + spinRes.SlotsData = append(spinRes.SlotsData, int32(card)) + } + return +} +func (this *TamQuocSceneData) 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.DbGameFree.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 tamquoc", pack) + base.PlayerMgrSington.BroadcastMessageToGroup(int(gamehall.HundredScenePacketID_PACKET_SC_GAMEJACKPOT), pack, tags) + } +} + +func (this *TamQuocSceneData) 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 *TamQuocSceneData) 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 *TamQuocSceneData) RecordBurstLog(name string, wincoin, totalbet int64) { + log := model.NewBurstJackpotLog(this.Platform, this.DbGameFree.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 *TamQuocSceneData) BurstHistory(player *TamQuocPlayerData) { + task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { + return model.GetBurstJackpotLog(this.Platform, this.DbGameFree.GameId) + }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { + var logsp []*tamquoc.TamQuocBurstHistoryInfo + if data != nil { + logs := data.([]model.BurstJackpotLog) + if len(logs) > 0 { + for _, log := range logs { + logsp = append(logsp, &tamquoc.TamQuocBurstHistoryInfo{ + UserName: log.Name, + PriceValue: log.WinCoin, + TotalBet: log.TotalBet, + Ts: log.Ts, + }) + } + } + } + pack := &tamquoc.SCTamQuocBurstHistory{ + BurstLog: logsp, + } + logger.Logger.Trace("SCTamQuocBurstHistory:", pack) + player.SendToClient(int(tamquoc.TamQuocPacketID_PACKET_SC_TAMQUOC_BURSTHISTORY), pack) + }), "BurstHistory").Start() +} +func (this *TamQuocSceneData) GetLastBurstJackPot() time.Time { + return this.lastBurstJackPot[this.GetGameFreeId()] +} +func (this *TamQuocSceneData) SetLastBurstJackPot() { + var randT = rand.Intn(25200-7200+1) + 7200 + switch this.DbGameFree.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 *TamQuocSceneData) AIAddJackPot() { + if time.Now().Sub(this.lastJackPot) > 0 { + var randT = rand.Intn(3) + 1 + switch this.DbGameFree.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.DbGameFree.GetBaseScore()) * float64(rule.LINENUM) * float64(500) / 10000)) + this.jackpot.VirtualJK += val + } +} +func (this *TamQuocSceneData) AIBurstJackPot() { + if time.Now().Sub(this.GetLastBurstJackPot()) > 0 { + this.SetLastBurstJackPot() + jackpotParams := this.DbGameFree.GetJackpot() + var jackpotInit = int64(jackpotParams[rule.TAMQUOC_JACKPOT_InitJackpot] * this.DbGameFree.GetBaseScore()) //奖池初始值 + + //AI机器人爆奖 + val := this.jackpot.VirtualJK + this.jackpot.VirtualJK = jackpotInit + bet := this.DbGameFree.GetBaseScore() * int32(rule.LINENUM) + this.RecordBurstLog(this.RandNickName(), val, int64(bet)) + } +} +func (this *TamQuocSceneData) 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.DbGameFree.GetId())) + // if !p.IsRob && + // todayGamefreeIDSceneData != nil && + // this.DbGameFree.GetPlayNumLimit() != 0 && + // todayGamefreeIDSceneData.GameTimes >= int64(this.DbGameFree.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) + } + } + } +} diff --git a/gamesrv/tamquoc/scenepolicy_tamquoc.go b/gamesrv/tamquoc/scenepolicy_tamquoc.go new file mode 100644 index 0000000..deed427 --- /dev/null +++ b/gamesrv/tamquoc/scenepolicy_tamquoc.go @@ -0,0 +1,843 @@ +package tamquoc + +import ( + "math" + "strconv" + "time" + + "mongo.games.com/goserver/core" + "mongo.games.com/goserver/core/basic" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/task" + "mongo.games.com/goserver/core/timer" + + "mongo.games.com/game/common" + rule "mongo.games.com/game/gamerule/tamquoc" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/model" + "mongo.games.com/game/proto" + "mongo.games.com/game/protocol/server" + "mongo.games.com/game/protocol/tamquoc" +) + +//////////////////////////////////////////////////////////////////////////////// +//百战成神 +//////////////////////////////////////////////////////////////////////////////// + +// 房间内主要逻辑 +var ScenePolicyTamQuocSington = &ScenePolicyTamQuoc{} + +type ScenePolicyTamQuoc struct { + base.BaseScenePolicy + states [TamQuocSceneStateMax]base.SceneState +} + +// 创建场景扩展数据 +func (this *ScenePolicyTamQuoc) CreateSceneExData(s *base.Scene) interface{} { + sceneEx := NewTamQuocSceneData(s) + if sceneEx != nil { + if sceneEx.init() { + s.ExtraData = sceneEx + } + } + return sceneEx +} + +// 创建玩家扩展数据 +func (this *ScenePolicyTamQuoc) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} { + playerEx := &TamQuocPlayerData{Player: p} + if playerEx != nil { + p.ExtraData = playerEx + } + return playerEx +} + +// 场景开启事件 +func (this *ScenePolicyTamQuoc) OnStart(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyTamQuoc) OnStart, sceneId=", s.SceneId) + sceneEx := NewTamQuocSceneData(s) + if sceneEx != nil { + if sceneEx.init() { + s.ExtraData = sceneEx + s.ChangeSceneState(TamQuocSceneStateStart) //改变当前的玩家状态 + } + } +} + +// 场景关闭事件 +func (this *ScenePolicyTamQuoc) OnStop(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyTamQuoc) OnStop , sceneId=", s.SceneId) + if sceneEx, ok := s.ExtraData.(*TamQuocSceneData); ok { + sceneEx.SaveData(true) + } +} + +// 场景心跳事件 +func (this *ScenePolicyTamQuoc) OnTick(s *base.Scene) { + if s == nil { + return + } + if s.SceneState != nil { + s.SceneState.OnTick(s) + } +} + +// 玩家进入事件 +func (this *ScenePolicyTamQuoc) OnPlayerEnter(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyTamQuoc) OnPlayerEnter, sceneId=", s.SceneId, " player=", p.SnId) + if sceneEx, ok := s.ExtraData.(*TamQuocSceneData); ok { + playerEx := &TamQuocPlayerData{Player: p} + playerEx.init(s) // 玩家当前信息初始化 + playerEx.score = sceneEx.DbGameFree.GetBaseScore() // 底注 + sceneEx.players[p.SnId] = playerEx + p.ExtraData = playerEx + TamQuocSendRoomInfo(s, p, sceneEx, playerEx, nil) + s.FirePlayerEvent(p, base.PlayerEventEnter, nil) //回调会调取 onPlayerEvent事件 + } +} + +// 玩家离开事件 +func (this *ScenePolicyTamQuoc) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyTamQuoc) OnPlayerLeave, sceneId=", s.SceneId, " player=", p.SnId) + if sceneEx, ok := s.ExtraData.(*TamQuocSceneData); ok { + if this.CanChangeCoinScene(s, p) { + if playerEx, ok := p.ExtraData.(*TamQuocPlayerData); ok { + playerEx.SavePlayerGameData(strconv.Itoa(int(s.GetGameFreeId()))) + } + sceneEx.OnPlayerLeave(p, reason) + s.FirePlayerEvent(p, base.PlayerEventLeave, []int64{int64(reason)}) + } + } +} + +// 玩家掉线 +func (this *ScenePolicyTamQuoc) OnPlayerDropLine(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyTamQuoc) OnPlayerDropLine, sceneId=", s.SceneId, " player=", p.SnId) + s.FirePlayerEvent(p, base.PlayerEventDropLine, nil) + if sceneEx, ok := s.ExtraData.(*TamQuocSceneData); ok { + if sceneEx.Gaming { + return + } + } +} + +// 玩家重连 +func (this *ScenePolicyTamQuoc) OnPlayerRehold(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyTamQuoc) OnPlayerRehold, sceneId=", s.SceneId, " player=", p.Name) + //if sceneEx, ok := s.ExtraData.(*TamQuocSceneData); ok { + // if playerEx, ok := p.ExtraData.(*TamQuocPlayerData); ok { + // //发送房间信息给自己 + // TamQuocSendRoomInfo(s, p, sceneEx, playerEx) + s.FirePlayerEvent(p, base.PlayerEventRehold, nil) + // } + //} +} + +// 玩家重连 +func (this *ScenePolicyTamQuoc) OnPlayerReturn(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyTamQuoc) OnPlayerReturn, sceneId=", s.SceneId, " player=", p.Name) + if sceneEx, ok := s.ExtraData.(*TamQuocSceneData); ok { + if playerEx, ok := p.ExtraData.(*TamQuocPlayerData); ok { + //发送房间信息给自己 + TamQuocSendRoomInfo(s, p, sceneEx, playerEx, playerEx.billedData) + s.FirePlayerEvent(p, base.PlayerEventReturn, nil) + } + } +} + +// 玩家操作 +func (this *ScenePolicyTamQuoc) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + if s == nil || p == nil { + return false + } + if s.SceneState != nil { + return s.SceneState.OnPlayerOp(s, p, opcode, params) + } + return true +} + +// 玩家事件 +func (this *ScenePolicyTamQuoc) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { + if s == nil || p == nil { + return + } + if s.SceneState != nil { + s.SceneState.OnPlayerEvent(s, p, evtcode, params) + } +} + +// 是否完成了整个牌局 +func (this *ScenePolicyTamQuoc) IsCompleted(s *base.Scene) bool { return false } + +// 是否可以强制开始 +func (this *ScenePolicyTamQuoc) IsCanForceStart(s *base.Scene) bool { return true } + +// 当前状态能否换桌 +func (this *ScenePolicyTamQuoc) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if s == nil || p == nil { + return true + } + if s.SceneState != nil { + return s.SceneState.CanChangeCoinScene(s, p) + } + return true +} + +func (this *ScenePolicyTamQuoc) RegisteSceneState(state base.SceneState) { + if state == nil { + return + } + stateid := state.GetState() + if stateid < 0 || stateid >= TamQuocSceneStateMax { + return + } + this.states[stateid] = state +} + +func (this *ScenePolicyTamQuoc) GetSceneState(s *base.Scene, stateid int) base.SceneState { + if stateid >= 0 && stateid < TamQuocSceneStateMax { + return ScenePolicyTamQuocSington.states[stateid] + } + return nil +} +func (this *ScenePolicyTamQuoc) GetJackPotVal(s *base.Scene) int64 { + if sceneEx, ok := s.ExtraData.(*TamQuocSceneData); ok { + if sceneEx.lastJackpotValue != sceneEx.jackpot.VirtualJK { + return sceneEx.jackpot.VirtualJK + } + } + return 0 +} +func TamQuocSendRoomInfo(s *base.Scene, p *base.Player, sceneEx *TamQuocSceneData, playerEx *TamQuocPlayerData, data *tamquoc.GameBilledData) { + logger.Logger.Trace("-------------------发送房间消息 ", s.RoomId, p.SnId) + pack := &tamquoc.SCTamQuocRoomInfo{ + RoomId: proto.Int(s.SceneId), + Creator: proto.Int32(s.Creator), + GameId: proto.Int(s.GameId), + RoomMode: proto.Int(s.GameMode), + Params: s.Params, + State: proto.Int(s.SceneState.GetState()), + Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), + GameFreeId: proto.Int32(s.GetDBGameFree().GetId()), + BilledData: data, + } + if playerEx != nil { + pd := &tamquoc.TamQuocPlayerData{ + SnId: proto.Int32(playerEx.SnId), + Name: proto.String(playerEx.Name), + Head: proto.Int32(playerEx.Head), + Sex: proto.Int32(playerEx.Sex), + Coin: proto.Int64(playerEx.Coin), + HeadOutLine: proto.Int32(playerEx.HeadOutLine), + VIP: proto.Int32(playerEx.VIP), + } + pack.Players = append(pack.Players, pd) + //for _, value := range playerEx.cards { + // pack.Cards = append(pack.Cards, int32(value)) + //} + pack.BetLines = playerEx.betLines + pack.FreeTimes = proto.Int32(playerEx.freeTimes) + pack.Chip = proto.Int32(s.DbGameFree.BaseScore) + pack.SpinID = proto.Int64(playerEx.spinID) + if playerEx.totalPriceBonus > 0 && playerEx.bonusGameStartTime.Add(TamQuocBonusGamePickTime).Before(time.Now()) { + playerEx.totalPriceBonus = 0 + playerEx.bonusGamePickPos = make([]int32, 2) + // 取消定时器 + if playerEx.bonusTimerHandle != timer.TimerHandle(0) { + timer.StopTimer(playerEx.bonusTimerHandle) + playerEx.bonusTimerHandle = timer.TimerHandle(0) + } + } + if playerEx.totalPriceBonus > 0 { + pack.TotalPriceBonus = proto.Int64(playerEx.totalPriceBonus) + playerEx.bonusGamePickPos[1] = int32(playerEx.bonusGameStartTime.Add(TamQuocBonusGamePickTime).Unix() - time.Now().Unix()) + pack.ParamsEx = playerEx.bonusGamePickPos + pack.BonusGame = &playerEx.bonusGame + } + } + proto.SetDefaults(pack) + p.SendToClient(int(tamquoc.TamQuocPacketID_PACKET_SC_TAMQUOC_ROOMINFO), pack) +} + +type SceneStateTamQuocStart struct { +} + +// 获取当前场景状态 +func (this *SceneStateTamQuocStart) GetState() int { return TamQuocSceneStateStart } + +// 是否可以切换状态到 +func (this *SceneStateTamQuocStart) CanChangeTo(s base.SceneState) bool { return true } + +// 当前状态能否换桌 +func (this *SceneStateTamQuocStart) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if _, ok := p.ExtraData.(*TamQuocPlayerData); ok { + return true + } + return true +} + +func (this *SceneStateTamQuocStart) GetTimeout(s *base.Scene) int { return 0 } + +func (this *SceneStateTamQuocStart) OnEnter(s *base.Scene) { + if sceneEx, ok := s.ExtraData.(*TamQuocSceneData); ok { + logger.Logger.Tracef("(this *base.Scene) [%v] 场景状态进入 %v", s.SceneId, len(sceneEx.players)) + sceneEx.StateStartTime = time.Now() + pack := &tamquoc.SCTamQuocRoomState{ + State: proto.Int(this.GetState()), + } + proto.SetDefaults(pack) + s.Broadcast(int(tamquoc.TamQuocPacketID_PACKET_SC_TAMQUOC_ROOMSTATE), pack, 0) + } +} + +func (this *SceneStateTamQuocStart) OnLeave(s *base.Scene) {} + +func (this *SceneStateTamQuocStart) OnTick(s *base.Scene) { + if sceneEx, ok := s.ExtraData.(*TamQuocSceneData); ok { + sceneEx.AIAddJackPot() + sceneEx.AIBurstJackPot() + sceneEx.KickPlayerByTime() + } +} + +func (this *SceneStateTamQuocStart) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + playerEx, ok := p.ExtraData.(*TamQuocPlayerData) + if !ok { + return false + } + sceneEx, ok := s.ExtraData.(*TamQuocSceneData) + if !ok { + return false + } + if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { + //离开有统计 + sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) + return false + } + switch opcode { + case TamQuocPlayerOpStart: //开始 + + //参数是否合法 + //params 参数0底注,后面跟客户端选择的线n条线(1<=n<=20),客户端线是从1开始算起1~20条线 + if len(params) < 2 || len(params) > rule.LINENUM+1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Error, params) + return false + } + //先做底注校验 + if sceneEx.DbGameFree.GetBaseScore() != int32(params[0]) { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Error, params) + return false + } + playerEx.score = int32(params[0]) // 单线押注数 + // 小游戏未结束 不能进行下一次旋转 + if playerEx.totalPriceBonus > 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Error, params) + return false + } + //判断线条是否重复,是否合法 + lineFlag := make(map[int64]bool) + lineParams := make([]int64, 0) + for i := 1; i < len(params); i++ { + lineNum := params[i] + if lineNum >= 1 && lineNum <= int64(rule.LINENUM) && !lineFlag[lineNum] { + lineParams = append(lineParams, lineNum) + lineFlag[lineNum] = true + } else { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Error, params) + return false + } + } + //没有选线参数 + if len(lineParams) == 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Error, params) + return false + } + + //获取总投注金额(所有线的总投注) | 校验玩家余额是否足够 + totalBetValue := (int64(len(lineParams))) * params[0] + if playerEx.freeTimes <= 0 && totalBetValue > playerEx.Coin { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_CoinNotEnough, params) + return false + } else if playerEx.freeTimes <= 0 && int64(sceneEx.DbGameFree.GetBetLimit()) > playerEx.Coin { //押注限制 + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_CoinNotEnough, params) + return false + } + + p.LastOPTimer = time.Now() + sceneEx.GameNowTime = time.Now() + sceneEx.NumOfGames++ + p.GameTimes++ + //playerEx.StartCoin = playerEx.Coin + + //获取当前水池的上下文环境 + sceneEx.CpCtx = base.CoinPoolMgr.GetCoinPoolCtx(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) + + //税收比例 + taxRate := sceneEx.DbGameFree.GetTaxRate() + if taxRate < 0 || taxRate > 10000 { + logger.Logger.Tracef("TamQuocErrorTaxRate [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate) + taxRate = 500 + } + //水池设置 + coinPoolSetting := base.CoinPoolMgr.GetCoinPoolSetting(sceneEx.Platform, sceneEx.GetGameFreeId(), sceneEx.GroupId) + ctroRate := 500 //调节赔率 暗税系数 + jackpotRate := ctroRate //奖池系数 + logger.Logger.Tracef("TamQuocRates [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, taxRate, ctroRate) + + playerEx.IsFNovice(sceneEx.KeyGameId) + isFoolPlayer := false + var gamePoolCoin int64 + //if isFoolPlayer { + // gamePoolCoin = base.CoinPoolMgr.GetNoviceCoinPool(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} else { + gamePoolCoin = base.CoinPoolMgr.GetCoin(sceneEx.GetGameFreeId(), sceneEx.Platform, sceneEx.GroupId) // 当前水池金额 + //} + prizeFund := gamePoolCoin - sceneEx.jackpot.VirtualJK // 除去奖池的水池剩余金额 + + // 奖池参数 + var jackpotParam = sceneEx.DbGameFree.GetJackpot() + var jackpotInit = int64(jackpotParam[rule.TAMQUOC_JACKPOT_InitJackpot] * sceneEx.DbGameFree.GetBaseScore()) //奖池初始值 + + var jackpotFundAdd, prizeFundAdd int64 + if playerEx.freeTimes <= 0 { //正常模式才能记录用户的押注变化,免费模式不能改变押注 + playerEx.betLines = lineParams // 选线记录 + jackpotFundAdd = int64(math.Floor(float64(totalBetValue) * (float64(jackpotRate) / 10000.0))) //奖池要增加的金额 + prizeFundAdd = totalBetValue - jackpotFundAdd + playerEx.TotalBet += totalBetValue //总下注额(从进房间开始,包含多局游戏的下注) + //扣除投注金币 + p.AddCoin(-totalBetValue, common.GainWay_HundredSceneLost, base.SyncFlag_ToClient, "system", s.GetSceneName()) + //p.Statics(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, -totalBetValue, true) + if !p.IsRob && !sceneEx.Testing { + // 推送金币 + sceneEx.PushCoinPool(prizeFundAdd, isFoolPlayer) + //base.CoinPoolMgr.PushCoin(sceneEx.GetGameFreeId(), sceneEx.GroupId, sceneEx.Platform, int64(float64(totalBetValue)*(float64(10000-ctroRate)/10000.0))) + } + + //统计参与游戏次数 + //if !sceneEx.Testing && !playerEx.IsRob { + // pack := &server.GWSceneEnd{ + // GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), + // Players: []*server.PlayerCtx{&server.PlayerCtx{SnId: proto.Int32(playerEx.SnId), Coin: proto.Int64(playerEx.Coin)}}, + // } + // proto.SetDefaults(pack) + // sceneEx.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENEEND), pack) + //} + } else { //免费次数时,不能改线改选线 + totalBetValue = 0 + } + + var symbolType rule.Symbol + if gamePoolCoin <= int64(coinPoolSetting.GetLowerLimit()) { // 水池不足 + symbolType = rule.SYMBOL1 + } else { + symbolType = rule.SYMBOL2 + } + writeBlackTryTimes := 0 + WriteBlack: + slotData := make([]int, 0) + var spinRes TamQuocSpinResult + var slotDataIsOk bool + for i := 0; i < 3; i++ { + slotData = rule.GenerateSlotsData_v2(symbolType) + //if sceneEx.DbGameFree.GetSceneType() == 1 { + // slotData = []int{1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7} + //} + spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) + //if sceneEx.DbGameFree.GetSceneType() == 1 { + // slotDataIsOk = true + // break + //} + if spinRes.AddFreeTimes > 0 && len(playerEx.betLines) < 15 { + continue + } + + // 免费次数时 不允许爆奖 + if playerEx.freeTimes > 0 && spinRes.IsJackpot { + continue + } + + // 水池不足以支付玩家 + if spinRes.IsJackpot { + if sceneEx.jackpot.Small < sceneEx.jackpot.VirtualJK { + continue + } + } + spinCondition := prizeFund + prizeFundAdd - (spinRes.TotalPrizeJackpot + spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue()) + spinCondition += sceneEx.jackpot.VirtualJK - jackpotInit + win := spinRes.TotalPrizeJackpot + spinRes.TotalPrizeLine + spinRes.BonusGame.GetTotalPrizeValue() + if spinCondition < 0 && win > totalBetValue { + if !spinRes.IsJackpot { + writeBlackTryTimes = 999 + } + continue + } + + // 非爆奖时 大奖限制 + var limitBigWin int64 + if symbolType == rule.SYMBOL1 { + limitBigWin = int64(jackpotParam[rule.TAMQUOC_JACKPOT_LIMITWIN_PRIZELOW]) + } else { + limitBigWin = int64(jackpotParam[rule.TAMQUOC_JACKPOT_LIMITWIN_PRIZEHIGH]) + } + if totalBetValue > 0 && !spinRes.IsJackpot && spinRes.TotalPrizeLine > totalBetValue*limitBigWin { + continue + } + + if spinRes.BonusGame.GetTotalPrizeValue() > 0 { + if len(playerEx.betLines) < 20 { + continue + } + + // 小游戏最小时间间隔限制 + lastBonusGameTimeInterval := time.Now().Unix() - playerEx.bonusGameTime + if symbolType == rule.SYMBOL1 && lastBonusGameTimeInterval < int64(jackpotParam[rule.TAMQUOC_JACKPOT_BonusMinTimeInterval_Low]) { + continue + } else if symbolType == rule.SYMBOL2 && lastBonusGameTimeInterval < int64(jackpotParam[rule.TAMQUOC_JACKPOT_BonusMinTimeInterval_High]) { + continue + } + } + + slotDataIsOk = true + break + } + + if !slotDataIsOk { + slotData = rule.GenerateSlotsData_v3(rule.DEFALUTROOMMODEL) + spinRes = sceneEx.CalcLinePrize(slotData, playerEx.betLines, params[0]) + } + + // 黑白名单调控 防止异常循环,添加上限次数 + if writeBlackTryTimes < 100 && playerEx.CheckBlackWriteList(spinRes.TotalPrizeLine+spinRes.TotalPrizeJackpot+spinRes.BonusGame.GetTotalPrizeValue() > totalBetValue) { + writeBlackTryTimes++ + goto WriteBlack + } else if writeBlackTryTimes >= 100 && writeBlackTryTimes != 999 { + logger.Logger.Warnf("TamquocWriteBlackTryTimesOver [%v][%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, gamePoolCoin, playerEx.BlackLevel, playerEx.WhiteLevel) + } + // 奖池水池处理 + + if spinRes.IsJackpot { + sceneEx.jackpot.Small -= sceneEx.jackpot.VirtualJK + if sceneEx.jackpot.Small < 0 { + sceneEx.jackpot.Small = 0 + } + sceneEx.jackpot.VirtualJK = jackpotInit + } else { + sceneEx.jackpot.Small += jackpotFundAdd + sceneEx.jackpot.VirtualJK += jackpotFundAdd + } + + // 玩家赢钱 + totalWinScore := spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot + if totalWinScore > 0 || spinRes.BonusGame.GetTotalPrizeValue() > 0 { + p.AddCoin(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue(), common.GainWay_HundredSceneWin, 0, "system", s.GetSceneName()) + //p.Statics(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore, true) + if !p.IsRob && !sceneEx.Testing { + sceneEx.PopCoinPool(totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore, isFoolPlayer) + //base.CoinPoolMgr.PopCoin(sceneEx.GetGameFreeId(), sceneEx.GroupId, sceneEx.Platform, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore) + } + playerEx.taxCoin = spinRes.TotalTaxScore + playerEx.AddServiceFee(playerEx.taxCoin) + } + p.StaticsLaba(sceneEx.KeyGameId, sceneEx.KeyGamefreeId, totalBetValue, totalWinScore+spinRes.BonusGame.GetTotalPrizeValue()+spinRes.TotalTaxScore) + + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Sucess, append(params[:1], playerEx.betLines...)) + + //免费次数 + var isFreeFlag bool + if playerEx.freeTimes > 0 { + playerEx.freeTimes-- + isFreeFlag = true + } + playerEx.freeTimes += spinRes.AddFreeTimes + + rule.SpinID++ + playerEx.spinID = rule.SpinID + playerEx.cards = spinRes.SlotsData + playerEx.winCoin = spinRes.TotalPrizeLine + spinRes.TotalPrizeJackpot + spinRes.BonusGame.GetTotalPrizeValue() + playerEx.taxCoin + playerEx.linesWinCoin = spinRes.TotalPrizeLine + playerEx.jackpotWinCoin = spinRes.TotalPrizeJackpot + playerEx.smallGameWinCoin = spinRes.BonusGame.GetTotalPrizeValue() + playerEx.CurrentBet = totalBetValue + playerEx.CurrentTax = playerEx.taxCoin + + // 小游戏超时处理 + if spinRes.IsBonusGame { + playerEx.totalPriceBonus = spinRes.BonusGame.GetTotalPrizeValue() + playerEx.bonusGameTime = time.Now().Unix() + logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) + playerEx.bonusTimerHandle, _ = timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool { + this.OnPlayerOp(s, p, TamQuocBonusGame, []int64{playerEx.spinID}) + return true + }), nil, TamQuocBonusGameTimeout, 1) + playerEx.bonusGameCanPickNum = len(spinRes.BonusGame.BonusData) + playerEx.bonusGame = spinRes.BonusGame + } + + playerEx.billedData = &tamquoc.GameBilledData{ + SpinID: proto.Int64(playerEx.spinID), + SlotsData: spinRes.SlotsData, + AddFreeSpin: proto.Int32(spinRes.AddFreeTimes), + IsJackpot: proto.Bool(spinRes.IsJackpot), + PrizeLines: spinRes.LinesInfo, + TotalPrizeValue: proto.Int64(totalWinScore), + TotalPaylinePrizeValue: proto.Int64(spinRes.TotalPrizeLine), + TotalJackpotValue: proto.Int64(spinRes.TotalPrizeJackpot), + Balance: proto.Int64(playerEx.Coin - spinRes.BonusGame.GetTotalPrizeValue()), + FreeSpins: proto.Int32(playerEx.freeTimes), + Jackpot: proto.Int64(sceneEx.jackpot.VirtualJK), + BonusGame: &spinRes.BonusGame, + } + pack := &tamquoc.SCTamQuocGameBilled{ + BilledData: playerEx.billedData, + } + proto.SetDefaults(pack) + logger.Logger.Infof("TamQuocPlayerOpStart %v", pack) + p.SendToClient(int(tamquoc.TamQuocPacketID_PACKET_SC_TAMQUOC_GAMEBILLED), pack) + + // 记录本次操作this + playerEx.RollGameType.BaseResult.WinTotal = pack.BilledData.GetTotalPrizeValue() + pack.BilledData.GetBonusGame().GetTotalPrizeValue() + playerEx.RollGameType.BaseResult.IsFree = isFreeFlag + playerEx.RollGameType.BaseResult.WinSmallGame = pack.BilledData.BonusGame.GetTotalPrizeValue() + playerEx.RollGameType.BaseResult.AllWinNum = int32(len(pack.BilledData.PrizeLines)) + playerEx.RollGameType.BaseResult.WinRate = spinRes.TotalWinRate + playerEx.RollGameType.BaseResult.Cards = pack.BilledData.GetSlotsData() + playerEx.RollGameType.WinLines = spinRes.WinLines + playerEx.RollGameType.BaseResult.WinJackpot = pack.BilledData.GetTotalJackpotValue() + playerEx.RollGameType.BaseResult.WinLineScore = pack.BilledData.TotalPaylinePrizeValue + playerEx.RollGameType.BaseResult.IsFoolPlayer = isFoolPlayer + TamQuocCheckAndSaveLog(sceneEx, playerEx) + + // 广播奖池 + if totalBetValue == 0 && !spinRes.IsJackpot { // 没改变奖池 + return true + } + // 添加进开奖记录里面 + if spinRes.IsJackpot { + sceneEx.RecordBurstLog(playerEx.Name, pack.BilledData.GetTotalJackpotValue(), playerEx.CurrentBet) + } + logger.Logger.Tracef("---tamquoc---当前奖池:真人[%v] 虚拟[%v]", sceneEx.jackpot.Small, sceneEx.jackpot.VirtualJK) + case TamQuocBurstHistory: + sceneEx.BurstHistory(playerEx) + case TamQuocPlayerHistory: + task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { + spinid := strconv.FormatInt(int64(playerEx.SnId), 10) + gpl := model.GetPlayerListByHallEx(p.SnId, p.Platform, 0, 80, 0, 0, 0, s.DbGameFree.GetGameClass(), s.GameId) + pack := &tamquoc.SCTamQuocPlayerHistory{} + for _, v := range gpl.Data { + //if v.GameDetailedLogId == "" { + // logger.Logger.Error("TamQuocPlayerHistory GameDetailedLogId is nil") + // break + //} + //gdl := model.GetPlayerHistory(p.Platform, v.GameDetailedLogId) + //if gdl == nil { + // logger.Logger.Error("TamQuocPlayerHistory gdl is nil") + // continue + //} + //data, err := UnMarshalTamQuocGameNote(gdl.GameDetailedNote) + //if err != nil { + // logger.Logger.Errorf("UnMarshalTamQuoccGameNote error:%v", err) + //} + //gnd := data.(*GameResultLog) + player := &tamquoc.TamQuocPlayerHistoryInfo{ + SpinID: proto.String(spinid), + CreatedTime: proto.Int64(int64(v.Ts)), + TotalBetValue: proto.Int64(v.BetAmount), + TotalPriceValue: proto.Int64(v.WinTotal), + IsFree: proto.Bool(v.IsFree), + TotalBonusValue: proto.Int64(v.WinSmallGame), + } + pack.PlayerHistory = append(pack.PlayerHistory, player) + } + proto.SetDefaults(pack) + logger.Logger.Info("TamQuocPlayerHistory: ", pack) + return pack + + }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { + if data == nil { + logger.Logger.Error("TamQuocPlayerHistory data is nil") + return + } + p.SendToClient(int(tamquoc.TamQuocPacketID_PACKET_SC_TAMQUOC_PLAYERHISTORY), data) + }), "CSGetTamQuocPlayerHistoryHandler").Start() + case TamQuocBonusGame: + //params 参数0 spinID + //参数是否合法 + if len(params) < 1 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Error, params) + return false + } + if playerEx.spinID != params[0] || playerEx.totalPriceBonus <= 0 { + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Error, params) + return false + } + if playerEx.bonusTimerHandle != timer.TimerHandle(0) { + timer.StopTimer(playerEx.bonusTimerHandle) + playerEx.bonusTimerHandle = timer.TimerHandle(0) + } + logger.Logger.Tracef("BonusGame Start [%v][%v][%v][%v]", sceneEx.GetGameFreeId(), playerEx.SnId, playerEx.spinID, playerEx.totalPriceBonus) + + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Sucess, []int64{playerEx.totalPriceBonus, playerEx.Coin}) + playerEx.totalPriceBonus = 0 + playerEx.bonusGamePickPos = make([]int32, 2) + case TamQuocBonusGameRecord: + // params + // 参数下标0 0表示进小游戏 1表示选图标界面 + // 参数下标1 玩家当前点击位置 + if (len(params) == 1 && params[0] != 0) || + (len(params) == 2 && (params[0] != 1 || params[1] < 1 || params[1] > 24)) { + logger.Logger.Errorf("Invalid parameter") + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Error, params) + return true + } + switch params[0] { + case 0: + if playerEx.bonusGamePickPos[0] < 1 { + // 记录进入小游戏时间 + playerEx.bonusGameStartTime = time.Now() + playerEx.bonusGamePickPos[0] = 1 + } + case 1: + if len(playerEx.bonusGamePickPos) > playerEx.bonusGameCanPickNum { + logger.Logger.Errorf("too many pickPos") + this.OnPlayerSToCOp(s, p, playerEx.Pos, opcode, tamquoc.OpResultCode_OPRC_Error, params) + return true + } + playerEx.bonusGamePickPos = append(playerEx.bonusGamePickPos, int32(params[1])) + default: + logger.Logger.Errorf("Invalid parameter, params[0]") + } + + } + return true +} + +func (this *SceneStateTamQuocStart) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { +} + +// 发送玩家操作情况 +func (this *SceneStateTamQuocStart) OnPlayerSToCOp(s *base.Scene, p *base.Player, pos int, opcode int, + opRetCode tamquoc.OpResultCode, params []int64) { + pack := &tamquoc.SCTamQuocOp{ + SnId: proto.Int32(p.SnId), + OpCode: proto.Int(opcode), + OpRetCode: opRetCode, + Params: params, + } + proto.SetDefaults(pack) + p.SendToClient(int(tamquoc.TamQuocPacketID_PACKET_SC_TAMQUOC_PLAYEROP), pack) +} + +func TamQuocCheckAndSaveLog(sceneEx *TamQuocSceneData, playerEx *TamQuocPlayerData) { + //统计金币变动 + //log1 + logger.Logger.Trace("TamQuocCheckAndSaveLog Save ", playerEx.SnId) + //changeCoin := playerEx.Coin - playerEx.StartCoin + changeCoin := playerEx.winCoin - playerEx.taxCoin - playerEx.CurrentBet + startCoin := playerEx.Coin - changeCoin + playerEx.SaveSceneCoinLog(startCoin, changeCoin, + playerEx.Coin, playerEx.CurrentBet, playerEx.taxCoin, playerEx.winCoin, playerEx.jackpotWinCoin, playerEx.smallGameWinCoin) + + //log2 + playerEx.RollGameType.BaseResult.ChangeCoin = changeCoin + playerEx.RollGameType.BaseResult.BasicBet = sceneEx.DbGameFree.GetBaseScore() + playerEx.RollGameType.BaseResult.RoomId = int32(sceneEx.SceneId) + playerEx.RollGameType.BaseResult.AfterCoin = playerEx.Coin + playerEx.RollGameType.BaseResult.BeforeCoin = startCoin + playerEx.RollGameType.BaseResult.IsFirst = sceneEx.IsPlayerFirst(playerEx.Player) + playerEx.RollGameType.BaseResult.PlayerSnid = playerEx.SnId + playerEx.RollGameType.BaseResult.TotalBet = int32(playerEx.CurrentBet) + playerEx.RollGameType.AllLine = int32(len(playerEx.betLines)) + playerEx.RollGameType.BaseResult.FreeTimes = playerEx.freeTimes + playerEx.RollGameType.UserName = playerEx.Name + playerEx.RollGameType.BetLines = playerEx.betLines + playerEx.RollGameType.BaseResult.Tax = playerEx.taxCoin + playerEx.RollGameType.BaseResult.WBLevel = sceneEx.players[playerEx.SnId].WBLevel + if playerEx.score > 0 { + if !playerEx.IsRob { + info, err := model.MarshalGameNoteByROLL(playerEx.RollGameType) + if err == nil { + logid, _ := model.AutoIncGameLogId() + playerEx.currentLogId = logid + sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) + totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin + validFlow := totalin + totalout + validBet := common.AbsI64(totalin - totalout) + logParam := &base.SaveGamePlayerListLogParam{ + Platform: playerEx.Platform, + Channel: playerEx.Channel, + Promoter: playerEx.BeUnderAgentCode, + PackageTag: playerEx.PackageID, + InviterId: playerEx.InviterId, + LogId: logid, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: playerEx.taxCoin, + BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), + WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, + ValidBet: validBet, + ValidFlow: validFlow, + IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), + IsFree: playerEx.RollGameType.BaseResult.IsFree, + WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, + WinTotal: playerEx.RollGameType.BaseResult.WinTotal, + } + sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + } + } + } + + //统计输下注金币数 + if !sceneEx.Testing && !playerEx.IsRob { + playerBet := &server.PlayerData{ + SnId: proto.Int32(playerEx.SnId), + Bet: proto.Int64(playerEx.CurrentBet), + Gain: proto.Int64(playerEx.RollGameType.BaseResult.ChangeCoin), + Tax: proto.Int64(playerEx.taxCoin), + Coin: proto.Int64(playerEx.GetCoin()), + GameCoinTs: proto.Int64(playerEx.GameCoinTs), + } + gwPlayerBet := &server.GWPlayerData{ + SceneId: proto.Int(sceneEx.SceneId), + GameFreeId: proto.Int32(sceneEx.DbGameFree.GetId()), + } + gwPlayerBet.Datas = append(gwPlayerBet.Datas, playerBet) + sceneEx.SyncPlayerDatas(&base.PlayerDataParam{ + HasRobotGaming: false, + Data: gwPlayerBet, + }) + } + + playerEx.taxCoin = 0 + playerEx.winCoin = 0 + playerEx.linesWinCoin = 0 + playerEx.jackpotWinCoin = 0 + playerEx.smallGameWinCoin = 0 + + if sceneEx.CheckNeedDestroy() && playerEx.freeTimes <= 0 { + sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_OnDestroy, true) + } +} + +func init() { + ScenePolicyTamQuocSington.RegisteSceneState(&SceneStateTamQuocStart{}) + core.RegisteHook(core.HOOK_BEFORE_START, func() error { + base.RegisteScenePolicy(common.GameId_TamQuoc, 0, ScenePolicyTamQuocSington) + return nil + }) +} diff --git a/xlsx/DB_GameFree.xlsx b/xlsx/DB_GameFree.xlsx index 70ca23a..3afc904 100644 Binary files a/xlsx/DB_GameFree.xlsx and b/xlsx/DB_GameFree.xlsx differ diff --git a/xlsx/DB_GameRule.xlsx b/xlsx/DB_GameRule.xlsx index 636ca79..31ead19 100644 Binary files a/xlsx/DB_GameRule.xlsx and b/xlsx/DB_GameRule.xlsx differ