go_dreamfactory/modules/entertainment/room.go
2023-11-01 10:01:11 +08:00

638 lines
18 KiB
Go

package entertainment
import (
"errors"
"fmt"
"go_dreamfactory/comm"
"go_dreamfactory/lego/sys/timewheel"
"go_dreamfactory/pb"
cfg "go_dreamfactory/sys/configure/structs"
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
"google.golang.org/protobuf/proto"
)
const (
MaxPs = 2 // 最大体力
//MaxRound = 7 // 最大回合数
MaxTime = 1800 // 游戏操作时间
)
//游戏房间
type Room struct {
Id string // 房间id
szSession []comm.IUserSession
player1 *pb.PlayerData // 玩家1
player2 *pb.PlayerData // 玩家2
chessboard *MapData
module *Entertainment
round int32 // 轮数
operatetimer *timewheel.Task //操作倒计时定时器
curPower string // 当前操作的玩家
NexPower string // 下一个操作的玩家
MaxRound int32
rd1 bool // 玩家1 是否准备
rd2 bool // 玩家2 是否准备
Status int32 //房间游戏状态 0未开始 1 已开始 2 已结束
RoomType int32 // 房间类型 1 是好友创房
}
func (this *Room) operateTimeOut(task *timewheel.Task, args ...interface{}) {
if this.player1.Userinfo.Uid == this.curPower { // 给玩家2
this.player1.Ps--
if this.player1.Ps <= 0 { // 体力消耗完权限给下一个人
this.NexPower = this.player2.Userinfo.Uid
this.player2.Ps = MaxPs // 恢复体力
}
} else { // 权限给1号玩家
this.player2.Ps--
if this.player2.Ps <= 0 {
this.curPower = this.player1.Userinfo.Uid
this.player1.Ps = MaxPs // 恢复体力
this.round++
if this.operatetimer != nil {
timewheel.Remove(this.operatetimer)
} // 回合+1
this.operatetimer = timewheel.Add(time.Second*MaxTime, this.operateTimeOut) // 开启新的定时器
}
}
var szMap []*pb.MapData
szMap = append(szMap, &pb.MapData{
Data: this.chessboard.Plat,
})
if err := this.module.SendMsgSyncToSession(string(this.module.GetType()), "operatorrst", &pb.EntertainOperatorRstPush{
Mpadata: szMap,
Power: this.NexPower,
Curpower: this.curPower,
Score: 0,
Round: this.round,
User1: this.player1,
User2: this.player2,
Itype: 0,
Curid: 0,
Targetid: 0,
}, this.szSession...); err != nil {
this.module.Errorln(err)
}
// 变更权限
this.curPower = this.NexPower
if this.round > this.MaxRound { // 游戏结束
if this.player1.Score == this.player2.Score {
this.MaxRound += 1 // 增加一回合
} else {
this.GameOver()
}
return
}
}
func (this *Room) InitRoom(module *Entertainment, p1 *pb.PlayerData, p2 *pb.PlayerData) *Room {
var room *Room
this.module = module
this.chessboard = new(MapData)
this.chessboard.InitMap(module) // 初始化棋盘
if s1, ok := this.module.GetUserSession(p1.Userinfo.Uid); !ok {
this.module.PutUserSession(s1)
} else {
this.szSession = append(this.szSession, s1.Clone())
}
if p2.Userinfo.Uid != "999" { // 是否是机器人
if s2, ok := this.module.GetUserSession(p2.Userinfo.Uid); !ok {
this.module.PutUserSession(s2)
} else {
this.szSession = append(this.szSession, s2.Clone())
}
}
this.MaxRound = module.ModuleTools.GetGlobalConf().ConsumeRounds
room = &Room{
Id: primitive.NewObjectID().Hex(),
szSession: this.szSession,
player1: p1,
player2: p2,
chessboard: this.chessboard,
module: module,
round: 1,
MaxRound: this.MaxRound,
Status: 0,
}
if err := this.module.SendMsgSyncToSession(string(this.module.GetType()), "enterroom", &pb.EntertainEnterRoomPush{
Rooid: room.Id,
Servepath: fmt.Sprintf("%s/%s", this.module.service.GetType(), this.module.service.GetId()),
User1: room.player1,
User2: room.player2,
}, this.szSession...); err != nil {
this.module.Errorln(err)
}
return room
}
// AI 操作了
func (this *Room) AiOperator() {
var (
curScore int32
szMap []*pb.MapData
bAddPs bool
oid1 int32
oid2 int32
)
this.player2.Ps--
// 交换元素
szMap, oid1, oid2, bAddPs = this.chessboard.AiSwapGirde()
for _, v := range szMap { //
this.player2.Energy += v.CurEnergy
v.CurEnergy = this.player2.Energy
curScore += v.CurSocre
this.player2.Score += v.CurSocre
v.CurSocre = this.player2.Score
}
if bAddPs {
this.player2.Ps++
if this.player2.Ps > MaxPs {
this.player2.Ps = MaxPs
}
}
if this.player2.Ps <= 0 { // 权限给下一个人
this.NexPower = this.player1.Userinfo.Uid
this.player1.Ps = MaxPs
this.round++
}
// 校验下次是不是消除
if this.chessboard.CheckAndRefreshPlat() {
this.chessboard.RedsetPlatData()
szMap = append(szMap, &pb.MapData{
Data: this.chessboard.GetPalatData(),
ChangeType: 1,
})
}
for _, v := range szMap { //
curScore += v.CurSocre
this.player2.Score += v.CurSocre
v.CurSocre = this.player2.Score
this.player2.Energy += v.CurEnergy
v.CurEnergy = this.player2.Energy
}
// 广播消息
if err := this.module.SendMsgSyncToSession(string(this.module.GetType()), "operatorrst", &pb.EntertainOperatorRstPush{
Mpadata: szMap,
Power: this.NexPower,
Curpower: this.curPower,
Score: curScore,
Round: this.round,
User1: this.player1,
User2: this.player2,
Itype: 0,
Curid: oid1,
Targetid: oid2,
}, this.szSession...); err != nil {
this.module.Errorln(err)
}
if this.round > this.MaxRound { // 游戏结束
if this.player1.Score == this.player2.Score {
this.MaxRound += 1 // 增加一回合
} else {
this.GameOver()
}
return
}
this.curPower = this.NexPower
if len(this.szSession) == 1 && this.curPower == this.player2.Userinfo.Uid {
this.AiOperator()
}
}
func (this *Room) ReceiveMessage(session comm.IUserSession, stype string, msg proto.Message) (errdata *pb.ErrorData) {
switch stype {
case "operator": // 操作消息
var (
curScore int32 // 该次操作的得分
AIOperator bool
oid1 int32 // 唯一id
oid2 int32
color int32 // 校验消除的颜色
bAddPs bool
)
var szMap []*pb.MapData
req := msg.(*pb.EntertainOperatorReq)
if session.GetUserId() != this.curPower { // 校验是不是你的权限
errdata = &pb.ErrorData{
Code: pb.ErrorCode_EntertainNoPower,
Title: pb.ErrorCode_EntertainNoPower.ToString(),
}
return
}
if this.curPower == this.player1.Userinfo.Uid {
color = 1
} else {
color = 2
}
if req.Itype == 1 { //释放技能
// 能量校验
if color == 1 { // 玩家1 放技能
conf, err := this.module.configure.GetGameConsumeHero(this.player1.Cardid)
if err != nil {
errdata = &pb.ErrorData{
Code: pb.ErrorCode_EntertainNoHeroSkill,
Title: pb.ErrorCode_EntertainNoHeroSkill.ToString(),
}
return
}
if this.player1.Energy >= conf.Skillload {
this.player1.Energy = 0 // 清零
if _, m := this.chessboard.SkillUp(conf.Skilleffect, conf.Skillvalue, true); len(m) > 0 {
szMap = append(szMap, m...)
} else {
szMap = append(szMap, &pb.MapData{
Data: this.chessboard.GetPalatData(),
})
}
for _, v := range szMap {
curScore += v.CurSocre
this.player1.Score += v.CurSocre
v.CurSocre = this.player1.Score
}
} else {
errdata = &pb.ErrorData{
Code: pb.ErrorCode_EntertainNoEnergy,
Title: pb.ErrorCode_EntertainNoEnergy.ToString(),
}
return
}
this.NexPower = this.curPower
} else {
conf, err := this.module.configure.GetGameConsumeHero(this.player2.Cardid)
if err != nil {
errdata = &pb.ErrorData{
Code: pb.ErrorCode_EntertainNoHeroSkill,
Title: pb.ErrorCode_EntertainNoHeroSkill.ToString(),
}
return
}
if this.player2.Energy >= conf.Skillload {
this.player2.Energy = 0 // 清零
if _, m := this.chessboard.SkillUp(conf.Skilleffect, conf.Skillvalue, true); len(m) > 0 {
szMap = append(szMap, m...)
} else {
szMap = append(szMap, &pb.MapData{
Data: this.chessboard.GetPalatData(),
})
}
for _, v := range szMap {
curScore += v.CurSocre
this.player2.Score += v.CurSocre
v.CurSocre = this.player2.Score
}
} else {
errdata = &pb.ErrorData{
Code: pb.ErrorCode_EntertainNoEnergy,
Title: pb.ErrorCode_EntertainNoEnergy.ToString(),
}
return
}
this.NexPower = this.curPower
}
if err := this.module.SendMsgSyncToSession(string(this.module.GetType()), "operatorrst", &pb.EntertainOperatorRstPush{
Mpadata: szMap,
Power: this.NexPower,
Curpower: this.curPower,
Score: curScore,
Round: this.round,
User1: this.player1,
User2: this.player2,
Itype: req.Itype,
Curid: oid1,
Targetid: oid2,
}, this.szSession...); err != nil {
this.module.Errorln(err)
}
return
}
oid1 = this.chessboard.Plat[req.Curid].Oid
oid2 = this.chessboard.Plat[req.Targetid].Oid
// 交换元素
if b := this.chessboard.SwapGirde(req.Curid, req.Targetid); !b { // 交换格子
errdata = &pb.ErrorData{
Code: pb.ErrorCode_EntertainCantSwap, // 不能交换 直接返回
Title: pb.ErrorCode_EntertainCantSwap.ToString(),
}
return
}
if m, b := this.chessboard.CheckMap(color, true); len(m) > 0 {
// curScore += score
szMap = append(szMap, m...)
bAddPs = b
} else { // 不能消除
this.chessboard.SwapGirde(req.Targetid, req.Curid) // 换到原来的位置
errdata = &pb.ErrorData{
Code: pb.ErrorCode_EntertainCantSwap, // 不能交换 直接返回
Title: pb.ErrorCode_EntertainCantSwap.ToString(),
}
return
}
// 校验下次是不是消除
if this.chessboard.CheckAndRefreshPlat() {
this.chessboard.RedsetPlatData()
szMap = append(szMap, &pb.MapData{
Data: this.chessboard.GetPalatData(),
ChangeType: 1,
})
}
if this.curPower == this.player1.Userinfo.Uid { //权限校验
this.player1.Score += curScore
this.player1.Ps--
if bAddPs {
this.player1.Ps++
if this.player1.Ps > MaxPs {
this.player1.Ps = MaxPs
}
}
if this.player1.Ps <= 0 {
this.NexPower = this.player2.Userinfo.Uid
if len(this.szSession) == 1 { // 校验2号玩家是不是AI
AIOperator = true
}
this.player2.Ps = MaxPs
}
} else { // this.curPower == this.player2.Uid
this.player2.Score += curScore
this.player2.Ps--
if bAddPs {
this.player2.Ps++
if this.player2.Ps > MaxPs {
this.player2.Ps = MaxPs
}
}
if this.player2.Ps <= 0 {
this.NexPower = this.player1.Userinfo.Uid
this.player1.Ps = MaxPs
this.round++
if this.operatetimer != nil {
timewheel.Remove(this.operatetimer)
this.operatetimer = timewheel.Add(time.Second*MaxTime, this.operateTimeOut) // 开启新的定时器
}
}
}
for _, v := range szMap { //
curScore += v.CurSocre
if color == 1 {
this.player1.Score += v.CurSocre
v.CurSocre = this.player1.Score
this.player1.Energy += v.CurEnergy
v.CurEnergy = this.player1.Energy
} else {
this.player2.Score += v.CurSocre
v.CurSocre = this.player2.Score
this.player2.Energy += v.CurEnergy
v.CurEnergy = this.player2.Energy
}
}
// 广播消息
if err := this.module.SendMsgSyncToSession(string(this.module.GetType()), "operatorrst", &pb.EntertainOperatorRstPush{
Mpadata: szMap,
Power: this.NexPower,
Curpower: this.curPower,
Score: curScore,
Round: this.round,
User1: this.player1,
User2: this.player2,
Itype: req.Itype,
Curid: oid1,
Targetid: oid2,
}, this.szSession...); err != nil {
this.module.Errorln(err)
}
if this.round > this.MaxRound { // 游戏结束
if this.player1.Score == this.player2.Score {
this.MaxRound += 1 // 增加一回合
} else {
this.GameOver()
}
return
}
// 变更权限
this.curPower = this.NexPower
if AIOperator { // AI操作
this.AiOperator()
}
case "ready":
var bStartGame bool // 可以开始游戏
if len(this.szSession) == 1 { // AI对战的话直接开始游戏
this.NexPower = this.player1.Userinfo.Uid
this.curPower = this.player1.Userinfo.Uid
this.player1.Ps = MaxPs
this.player2.Ps = 0
bStartGame = true
} else {
if this.player1.Userinfo.Uid == session.GetUserId() {
this.rd1 = true
} else if this.player2.Userinfo.Uid == session.GetUserId() {
this.rd2 = true
}
if this.player1.Userinfo.Uid != session.GetUserId() || this.RoomType != 1 { // 房主
if err := this.module.SendMsgSyncToSession(string(this.module.GetType()), "gameready", &pb.EntertainGameReadyPush{
P1Ready: this.rd1,
P2Ready: this.rd2,
}, this.szSession...); err != nil {
this.module.Errorln(err)
}
}
if this.rd1 && this.rd2 { // 两个玩家都准备好了 那么就开始游戏
bStartGame = true
}
}
if bStartGame {
var weight []int32 // 权重
// 开始随机玩法
list := this.module.configure.GetGameConsumeIntegral()
for _, v := range list {
weight = append(weight, v.Weight)
}
this.Status = 1
this.round = 1
if err := this.module.SendMsgSyncToSession(string(this.module.GetType()), "startgame", &pb.EntertainStartGamePush{
User1: this.player1,
User2: this.player2,
Mpadata: &pb.MapData{Data: this.chessboard.Plat},
Power: this.NexPower,
Round: this.round,
Roomid: this.Id, // 房间ID
Playtype: list[comm.GetRandW(weight)].Key, // 通过权重随机一个玩法
}, this.szSession...); err != nil {
this.module.Errorln(err)
}
this.operatetimer = timewheel.Add(time.Second*MaxTime, this.operateTimeOut)
}
case "reconnect": // 重连
session.SendMsg(string(this.module.GetType()), "reconnect", &pb.EntertainReconnectResp{
Roomid: this.Id,
Mpadata: &pb.MapData{
Data: this.chessboard.GetPalatData(),
CurSocre: 0,
CurEnergy: 0,
},
Power: this.NexPower,
Curpower: this.curPower,
Score: 0,
Round: this.round,
User1: this.player1,
User2: this.player2,
})
case "dissolve": // 房主解散房间
req := msg.(*pb.EntertainDissolveRoomReq)
if this.player1.Userinfo.Uid != req.Roomid {
errdata = &pb.ErrorData{
Code: pb.ErrorCode_EntertainNotMaster, // 不是房主
Title: pb.ErrorCode_EntertainNotMaster.ToString(),
}
return
}
// 游戏中不允许解散
if this.Status == 1 {
errdata = &pb.ErrorData{
Code: pb.ErrorCode_EntertainDissolveFailed, // 游戏中不能解散
Title: pb.ErrorCode_EntertainDissolveFailed.ToString(),
}
return
}
if err := this.module.SendMsgSyncToSession(string(this.module.GetType()), "dissolvemasterroom", &pb.EntertainDissolveMasterRoomPush{
Roomid: this.Id,
}, this.szSession...); err != nil {
this.module.Errorln(err)
}
}
return
}
// 游戏结束
func (this *Room) GameOver() (errdata *pb.ErrorData) {
var (
atno []*pb.UserAtno
winindex int32
bReward bool
res []*cfg.Gameatn
winner string
lostPlayer *pb.PlayerData // 输的玩家
)
if this.operatetimer != nil {
timewheel.Remove(this.operatetimer)
}
winner = this.player1.Userinfo.Uid
bReward = true
if this.player1.Score < this.player2.Score {
winner = this.player2.Userinfo.Uid
winindex = 1
if len(this.szSession) == 1 { // 赢家是AI 的话不发奖
bReward = false
}
}
if bReward { // 发奖
if user, err := this.module.ModuleUser.GetUser(winner); err == nil {
if conf, err := this.module.configure.GetGameConsumeintegral(user.Consumeexp); err == nil {
//res = append(res, conf.Onereward...) 这奖励手动领取
res = append(res, conf.Rewards...)
if errdata, atno = this.module.DispenseAtno(this.szSession[winindex], res, true); errdata != nil {
return
}
}
}
}
// 失败的一方扣除卡
if this.player1.Userinfo.Uid != winner {
lostPlayer = this.player1
} else {
lostPlayer = this.player2
}
// 失败卡类型
if conf, err := this.module.configure.GetGameConsumeHero(lostPlayer.Cardid); err == nil && lostPlayer.Userinfo.Uid != "999" {
if conf.Type != 1 { //卡片类型不为1
if list, err := this.module.model.getEntertainmList(lostPlayer.Userinfo.Uid); err == nil {
if list.Card[lostPlayer.Cardid] > 1 {
list.Card[lostPlayer.Cardid] -= 1
this.module.model.modifyEntertainmList(lostPlayer.Userinfo.Uid, map[string]interface{}{
"card": list.Card,
})
}
}
}
}
// 修改房间状态
this.Status = 2
this.module.SendMsgSyncToSession(string(this.module.GetType()), "gameover", &pb.EntertainGameOverPush{
User1: this.player1,
User2: this.player2,
Mpadata: &pb.MapData{
Data: this.chessboard.Plat,
},
Power: "", // 清理权限
Round: this.round,
Win: winner,
Reward: atno,
}, this.szSession...)
return
}
// 加入房间
func (this *Room) JoinRoom(module *Entertainment, p *pb.PlayerData) (room *Room, err error) {
// 该房间是个空的
if this.player1 == nil {
this.player1 = p
this.module = module
this.chessboard = new(MapData)
this.chessboard.InitMap(module) // 初始化棋盘
if s1, ok := this.module.GetUserSession(p.Userinfo.Uid); !ok {
this.module.PutUserSession(s1)
} else {
this.szSession = append(this.szSession, s1.Clone())
}
this.Id = p.Userinfo.Uid // 房主ID 作为房间id
this.RoomType = 1
this.MaxRound = this.module.ModuleTools.GetGlobalConf().ConsumeRounds
room = this
} else if this.player2 == nil {
//异常处理
if this.player1.Userinfo.Uid == p.Userinfo.Uid {
err = errors.New("重复加入")
}
this.player2 = p // 玩家2 赋值
if s1, ok := this.module.GetUserSession(p.Userinfo.Uid); !ok {
this.module.PutUserSession(s1)
} else {
this.szSession = append(this.szSession, s1.Clone())
}
// 推送消息
if err := this.module.SendMsgSyncToSession(string(this.module.GetType()), "joincreateroom", &pb.EntertainJoinCreateRoomPush{
Roomid: this.Id,
User1: this.player1,
User2: this.player2,
}, this.szSession...); err != nil {
this.module.Errorln(err)
}
} else { // 房间满了 加不进来
err = errors.New("房间已满")
return
}
return
}