class FishPlayerBuffer(object): """回馈赛的buffer""" def __init__(self, player, bufferId): self.player = player self.bufferId = bufferId self._state = BUFFER_STATE.NOEFFECT self.startTime = 0 self.bufferConf = config.getPlayerBufferConf(bufferId) self.checkTimer = FTLoopTimer(self.bufferConf["delayTime"], -1, self._bufferStart) self.checkTimer.start() self.sendMsgTimer = None def getBufferId(self): return self.bufferId def isStart(self): return self._state == BUFFER_STATE.START def _bufferStart(self): if self.checkTimer: self.checkTimer.cancel() self._state = BUFFER_STATE.START self.startTime = int(time.time()) pass
class MultipleFishGroup(object): """ 倍率鱼群(回馈赛专用) """ def __init__(self, table): self.table = table self._tableRank = 0 self._nextGroupTimer = None def clearTimer(self): if self._nextGroupTimer: self._nextGroupTimer.cancel() self._nextGroupTimer = None def initGroup(self, tableRank): """初始化倍率鱼群""" self._tableRank = tableRank self._setNextGroupTimer() def _setNextGroupTimer(self): """启动倍率鱼定时器""" self.clearTimer() interval = random.randint(25, int((1 - self._tableRank) * 30 + 30)) self._nextGroupTimer = FTLoopTimer(interval, 0, self._addMultipleFishGroup) self._nextGroupTimer.start() def _addMultipleFishGroup(self): """添加倍率鱼群""" randomNum = random.randint(1, 10000) for multipleFishMap in config.getRandomMultipleFishConf( self.table.runConfig.fishPool): probb = multipleFishMap["probb"] if probb[0] <= randomNum <= probb[-1]: fishType = multipleFishMap["fishType"] allMultipleGroupIds = self.table.runConfig.allMultipleGroupIds groupId = random.choice(allMultipleGroupIds[fishType]) if ftlog.is_debug(): ftlog.debug("_addMultipleFishGroup", fishType, allMultipleGroupIds, groupId) self.table.insertFishGroup(groupId) self._setNextGroupTimer() break def cancelNextGroupTimer(self): """取消定时器""" if self._nextGroupTimer: self._nextGroupTimer.cancel() self._nextGroupTimer = None
class SportOdds(object): '''欧指筛选''' ODDS = ['17', '308', '255', '256', '254'] def __init__(self, sportlottery): self.sportlottery = sportlottery self.timer = FTLoopTimer(10, -1, self._getHttpOdds) self.timer.start() if ftlog.is_debug(): ftlog.debug('SportOdds', 'sportObj=', self.sportlottery.toDict()) def _getHttpOdds(self): if ftlog.is_debug(): ftlog.debug('SportOdds', '_getHttpOdds=', self.sportlottery.toDict()) contents = http7Mgethdaoddsinfo(self.sportlottery.matchId) if not contents or len(contents) == 0: return if contents.get('GameId') != str(self.sportlottery.matchId): ftlog.warn('SportOdds httpOdds GameId not match', 'matchId=', self.sportlottery.matchId, 'GameId=', contents.get('GameId')) return Datas = contents.get('Datas') if not Datas or len(Datas) == 0: ftlog.warn('SportOdds httpOdds Datas empty', 'Datas=', Datas, 'contents=', contents) return tag = 0 for data in Datas: if data.get('Cid') in self.ODDS: odds = data.get('Data', []) if odds and len(odds) >= 3: self.sportlottery.odds = odds[:3] self.sportlottery.save() if self.timer: self.timer.cancel() tag = 1 break if self.sportlottery and tag == 1: self.sportlottery.clearSportOdds()
class ScriptBase(object): @classmethod def createScript(cls, player): script = None fishPool = player.table.runConfig.fishPool conf = config.getRobotConf("robotScript").get(str(fishPool), {}) scriptsConf = conf.get("scripts", []) if conf.get("enable", 0) == 1 and len(scriptsConf) > 0: level = 0 fireRange = [] idleRange = [] leaveRange = [] probb = random.randint(0, 10000) for script in scriptsConf: if script.get("probb", 0) == 0: continue if probb > script.get("probb", 0) > 0: probb -= script["probb"] else: level = script["level"] fireRange = script["fireRange"] idleRange = script["idleRange"] leaveRange = script["leaveRange"] if level == 1: from newfish.script.script_easy import ScriptEasy1 script = ScriptEasy1(player, fireRange, idleRange, leaveRange)#Script%s%d % ("Easy", level) ftlog.debug("createScript", player.userId, fishPool, scriptsConf, (script is not None)) return script def __init__(self, player, fireRange, idleRange, leaveRange): self.player = player self.userId = player.userId self.player.table.clip_add(player.userId, player.seatId) ftlog.debug("__init__", player.userId, player.chip, player.clip) self.fireInterval = config.getGunLevelConf(self.nowGunLevel, self.player.table.gameMode).get("interval", 0.3) self.updateTimer = None self.updateTimer = FTLoopTimer(5, -1, self._update) self.updateTimer.start() self.fireTimer = None self.fireTargetPos = [0, 0] self.bulletId = 0 # 空闲次数 self.idleCount = 0 # 开火次数 self.fireCount = 0 # 等待离开 self.waitLeaveCount = 0 # 表情 self.exp = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] self.fireRange = fireRange self.idleRange = idleRange self.leaveRange = leaveRange self.updateCount = 0 self.needClear = False # 全是机器人的计数 self.allRobotCount = 0 @property def table(self): return self.player.table # @property # def userId(self): # return self.player.userId @property def seatId(self): return self.player.seatId @property def nowGunLevel(self): return self.player.nowGunLevel @property def clip(self): return self.player.clip def clear(self): self._clearData() def _clearData(self): ftlog.debug("_clearData", self.userId, self.table.tableId) if self.updateTimer: self.updateTimer.cancel() self.updateTimer = None else: return if self.fireTimer: self.fireTimer.cancel() self.bulletId = 1 self.fireCount = 0 self.idleCount = 0 self.waitLeaveCount = 0 robotutil.sendRobotNotifyShutDownByUserId(self.table, self.userId) self.table.clearPlayer(self.player) def _update(self): pass def _updateFireTarget(self): pass def _fire(self): self.bulletId += 1 self.bulletId %= 90 if self.bulletId == 0: self.bulletId += 1 self.player.lastActionTime = int(time.time()) canFire = self.table.fire(self.userId, self.seatId, self.fireTargetPos, self.nowGunLevel, self.bulletId, 0, self.player.lastActionTime, 0) self.fireCount -= 1 if canFire and self.fireCount > 0: self.fireTimer = FTLoopTimer(self.fireInterval, 0, self._fire) self.fireTimer.start() else: self.fireCount = 0 self.fireTimer = None if canFire: self.idleCount = random.randint(self.idleRange[0], self.idleRange[1]) ftlog.debug("_fire, idle", self.userId, self.idleCount) else: self.waitLeaveCount = random.randint(self.leaveRange[0], self.leaveRange[1]) ftlog.debug("_fire, wait leave", self.userId, self.waitLeaveCount) # ftlog.debug("_update", self.userId, self.seatId, self.nowGunLevel, self.bulletId, # self.chip, self.fireCount, self.fireTargetPos) def _isNeedCancelTimer(self): if self.updateTimer and (self.userId == 0 or self.clip == 0 or self.needClear or self.allRobotCount == 12): ftlog.debug("_isNeedCancelTimer", self.userId, self.clip, self.needClear, self.allRobotCount) self._clearData() return True self.updateCount += 1 if self.updateCount % 12 == 0: conf = config.getRobotConf("robotScript").get(str(self.table.runConfig.fishPool), {}) # 关闭机器人 if conf.get("enable", 0) == 0: self.needClear = True return True for player in self.table.players: if player and player.isRobotUser is not True: self.allRobotCount = 0 break else: self.allRobotCount += 1 return False def _isWaitLeave(self): if self.waitLeaveCount > 0: self.waitLeaveCount -= 1 if self.waitLeaveCount == 0: ftlog.debug("_isWaitLeave", self.userId) self._clearData() return True return False def _isIdle(self): if self.idleCount > 0: self.idleCount -= 1 return True return False def _chat(self, isFace=1): chatMsg = random.choice(self.exp) mo = MsgPack() mo.setCmd("table_chat") mo.setResult("gameId", FISH_GAMEID) mo.setResult("userId", self.userId) mo.setResult("seatId", self.seatId) mo.setResult("isFace", isFace) mo.setResult("chatMsg", chatMsg) GameMsg.sendMsg(mo, self.table.getBroadcastUids()) def _setFireTimer(self): ftlog.debug("_setFireTimer", self.userId, (self.fireTimer is not None), self.fireCount, self.fireInterval) if self.fireTimer is None: self.fireCount = random.randint(self.fireRange[0], self.fireRange[1]) self.fireTimer = FTLoopTimer(self.fireInterval, 0, self._fire) self.fireTimer.start()
class MajiangQuickTable(TYTable): """ 1)负责框架桌子资源的管理,对接赛制/自建桌 2)负责处理用户的上行消息处理 3)麻将的具体逻辑,在逻辑类中处理 4)负责联网玩法用户准备情况的管理,条件合适的时候开始游戏 5)MajiangTable就是核心玩法里联网的action_handler """ def __init__(self, tableId, room): super(MajiangQuickTable, self).__init__(room, tableId) self._owner = room self._players = [] self.__actionHandler = ActionHandlerFactory.getActionHandler(MRunMode.LONGNET) # 初始化seat for seat in range(self.maxSeatN): self.seats[seat] = TYSeat(self) # 牌桌配置 self._roomConf = self.room.roomConf ftlog.debug('MajiangQuickTable.init roomConf->', self._roomConf) self._tableConf = copy.deepcopy(self._roomConf.get('tableConf', {})) self._tableConf[MFTDefine.IS_CREATE] = self.getRoomConfig(MFTDefine.IS_CREATE, 0) ftlog.debug('MajiangQuickTable.init tableConf->', self._tableConf) # 创建逻辑配桌类 self.__tableType = self.getRoomConfig('tableType', 'normal') self.__playMode = self.getRoomConfig('playMode', 'guobiao') ftlog.debug('MajiangQuickTable.init playMode:', self.playMode) # 逻辑牌桌 self.__table_observer = None # 下面这部分代码改为在具体的麻将工程里执行,以实现不同牌桌逻辑的拆分 # self.logic_table = MajiangTableLogic(self.maxSeatN, self.playMode, MRunMode.LONGNET) # self.logic_table.setTableConfig(self._tableConf) # # 设置牌桌公共信息,tableId & roomId # self.logic_table.msgProcessor.setInfo(self.gameId, self.roomId, self.tableId, self.playMode, self.tableType, self.maxSeatN) # self.logic_table.msgProcessor.setRoomInfo(self._roomConf, self._tableConf) # # 给action handler设置table # self.__actionHandler.setTable(self.logic_table) # 初始化定时器,个数是座位数加1 self.__timer = MajiangTableTimer(self.maxSeatN + 1, self) # 循环定时器,用于处理牌桌托管状态 self.__looper_timer = None ftlog.debug('MajiangQuickTable create ok, roomId:', self.roomId, ' tableId:', self.tableId) @property def tableObserver(self): return self.__table_observer def setTableObserver(self, observer): """设置牌桌观察者""" self.__table_observer = observer self.logic_table.setTableObserver(self.tableObserver) @property def tableTimer(self): return self.__timer @property def tableLooperTimer(self): return self.__looper_timer @property def actionHander(self): """行为解析处理器""" return self.__actionHandler @property def playMode(self): """玩法""" return self.__playMode @property def tableType(self): """牌桌类型""" return self.__tableType def changeFrameSeatToMJSeatId(self, frameSeat): """将框架的seatId转化为麻将的座位号 获取座位号时,框架返回的是1,2,3,内部存储的索引是0,1,2 麻将的座位号是0,1,2 """ return frameSeat - 1 def changeMJSeatToFrameSeat(self, mjSeat): """将麻将的座位号转化为框架的座位号""" return mjSeat + 1 def getRoomConfig(self, name, defaultValue): """获取房间配置""" return self._roomConf.get(name, defaultValue) def getTableConfig(self, name, defaultValue): """获取table配置""" return self._tableConf.get(name, defaultValue) def CheckSeatId(self, seatId, userId=None): """校验座位号""" seatValid = (seatId >= 0) and (seatId < self.maxSeatN) if not seatValid: return False if not userId: return seatValid if self.seats[seatId][TYSeat.INDEX_SEATE_USERID] != userId: return False return True def doTableChat(self, userId, seatId, isFace, voiceIdx, chatMsg): """doTableChat非父类的接口,可以抽象至麻将的table基类中""" ftlog.debug('MajiangQuickTable.doTableChat userId:', userId, ' seatId:', seatId, ' ifFace:', isFace if isFace else "1", ' voiceIdx:', voiceIdx if voiceIdx else "1", ' chatMsg:', chatMsg if chatMsg else "1") if 'type' in chatMsg and chatMsg['type'] == 2: # 表情 if not self.process_interactive_expression(userId, seatId, chatMsg): return # 语音/文字 self._doTableChat(userId, seatId, isFace, voiceIdx, chatMsg) def _doTableChat(self, userId, seatId, isFace, voiceIdx, chatMsg): """ 聊天的逻辑 1)文字聊天 { "cmd": "table_chat", "params": { "roomId": 7108021001, "tableId": 71080210010100, "seatId": 1, "isFace": 0, "msg": { "seatId": 1, "type": 0, "content": "abc" }, "gameId": 710, "userId": 10856, "clientId": "IOS_3.91_tuyoo.appStore,weixinPay,alipay.0-hall6.appStore.huanle" } } 2)语音聊天 { "cmd": "table_chat", "params": { "roomId": 7108021001, "tableId": 71080210010100, "seatId": 1, "isFace": 0, "msg": { "seatId": 1, "type": 2, "emoId": 1, "targetSeatId": 0 }, "gameId": 710, "userId": 10856, "clientId": " IOS_3.91_tuyoo.appStore,weixinPay,alipay.0-hall6.appStore.huanle" } } """ if not chatMsg: return if isFace == 0 and 'type' in chatMsg and chatMsg['type'] == 0: # 麻将文字聊天消息 content = chatMsg['content'] filterContent = keywords.replace(content) chatMsg['content'] = filterContent if isFace == 0: users = self.logic_table.getBroadCastUIDs() self.logic_table.msgProcessor.table_chat_broadcast(userId, self.gameId, voiceIdx, chatMsg, users) else: for seat in self.maxSeatN: player = self.logic_table.getPlayer(seat) self.logic_table.msgProcessor.table_chat_to_face(userId, self.gameId, voiceIdx, chatMsg, player) def process_interactive_expression(self, uid, seatId, chat_msg): """处理消费金币的表情""" targetSeatId = chat_msg.get('targetSeatId', -1) if not self.CheckSeatId(targetSeatId, None): return False target_player_uid = self.seats[targetSeatId][TYSeat.INDEX_SEATE_USERID] return MTableExpression.process_interactive_expression(uid , self.gameId , seatId , chat_msg , target_player_uid , self.getTableConfig('base_chip', 0)) def _doSit(self, msg, userId, seatId, clientId): '''玩家操作, 尝试再当前的某个座位上坐下''' ftlog.debug('==_doSit=msg=', msg, ' seatId:', seatId, 'tableId:', self.tableId) seatId = self.changeFrameSeatToMJSeatId(seatId) self.doSitDown(userId, seatId, msg, clientId) def doSitDown(self, userId, seatId, msg, clientId): """ 用户坐到某个桌子上,逻辑处理:如果是非重连用户,将用户坐下的消息广播给 其它已经坐下的用户,然后将当前的桌子信息发送给新来用户 继承自table类 这是的seatId为游戏的座位号 返回值: 1)是否做下 2)是否断线重连 """ ftlog.debug('>>MajiangQuickTable.doSitDown seatId =', seatId, ', userId = ', userId, ' tableId:', self.tableId) if (seatId != -1) and (userId != self.seats[seatId][TYSeat.INDEX_SEATE_USERID]): onlinedata.removeOnlineLoc(userId, self.roomId, self.tableId) ftlog.warn('reconnecting user id is not matched', 'seats =', self.seats, ' tableId:', self.tableId) return False frameSeatId = self.findIdleSeat(userId) ftlog.debug('MajiangQuickTable.doSitDown userId:', userId, ' findSeatId:', frameSeatId) sitRe = True if 0 == frameSeatId: ftlog.debug('MajiangQuickTable.doSitDown now seats:', self.seats) sendPopTipMsg(userId, '对不起,该房间已满员') self.logic_table.msgProcessor.quick_start_err(userId) sitRe = False elif 0 > frameSeatId: # 补发tableInfo seatId = self.getSeatIdByUserId(userId) if seatId < 0: onlinedata.removeOnlineLoc(userId, self.roomId, self.tableId) else: self.sendMsgTableInfo(msg, userId, seatId, True) elif frameSeatId > 0: isReady = self.getTableConfig(MTDefine.READY_AFTER_SIT, 0) gameSeatId = self.changeFrameSeatToMJSeatId(frameSeatId) # 设置座位的状态 self.seats[gameSeatId][TYSeat.INDEX_SEATE_USERID] = userId # 快速桌用户坐下就是准备状态 self.seats[gameSeatId][ TYSeat.INDEX_SEATE_STATE] = TYSeat.SEAT_STATE_READY if isReady else TYSeat.SEAT_STATE_WAIT # 添加玩家 tPlayer = TYPlayer(self, gameSeatId) self.players[gameSeatId] = tPlayer ftlog.debug('MajiangQuickTable.doSitDown user:'******' seat in:', gameSeatId , ' now seats:', self.seats , ' now playersNum:', self.playersNum) # 向牌桌添加用户:联网/机器人 if TYPlayer.isHuman(userId): locResult = onlinedata.addOnlineLoc(userId, self.roomId, self.tableId, frameSeatId) ftlog.info('MajiangQuickTable.doSitDown, add online loc userId:', userId , ' roomId:', self.roomId , ' tableId:', self.tableId , ' frameSeatId:', frameSeatId , ' locResult:', locResult) _name, _purl, _sex, _coin = userdata.getAttrs(userId, ['name', 'purl', 'sex', 'coin']) player = MPlayer(_name, _sex, userId, 0, _purl, _coin, clientId) # 快速桌 默认坐下就是准备状态 默认非托管状态 self.logic_table.addPlayer(player, gameSeatId, isReady, False) # 发送location消息 self.logic_table.msgProcessor.send_location_message(gameSeatId, userId) else: from difang.majiang2.resource import resource robot = resource.getRobotByUserId(userId) if robot: player = MPlayer(robot['name'], robot['sex'], userId, 0, robot['purl'], robot['coin']) # 机器人默认准备 默认托管状态 self.logic_table.addPlayer(player, gameSeatId, True, True) # 座位号调整,框架返回时进行了加1的操作,调整还原 self.room.updateTableScore(self.getTableScore(), self.tableId) self.sendMsgTableInfo(msg, userId, self.getSeatIdByUserId(userId), False) if self.playersNum != self.maxSeatN: # 一次召唤一个机器人 self.setTimerOfDispatchRobot() uids = self.logic_table.getBroadCastUIDs() self.logic_table.msgProcessor.sendTableEvent(self.playersNum, userId, gameSeatId, uids) else: # 人满了,启动定时器 self.setTimerHandleAutoDecideAction() return sitRe def sendMsgTableInfo(self, message, userId, seatId, isReconnect, isHost=False): """玩家坐下后,给玩家发送table_info,拉进游戏""" self.logic_table.sendMsgTableInfo(seatId, isReconnect) if isReconnect: self.logic_table.msgProcessor.table_call_latest_msg(seatId) self.logic_table.setPlayerLeave(seatId, False) self.logic_table.sendEnterMessage() self.logic_table.msgProcessor.broadcastUserSit(seatId, userId, isReconnect, isHost, self.logic_table.getBroadCastUIDs()) def setTimerHandleAutoDecideAction(self): """定时器,处理托管的行为""" ftlog.debug('MajiangQuickTable.setTimerHandleAutoDecideAction tableId:', self.tableId) if not self.__looper_timer: self.__looper_timer = FTLoopTimer(1, -1, self.handle_auto_decide_action) self.__looper_timer.start() def setTimerOfDispatchRobot(self): """设置定时器加派机器人""" ftlog.debug('MajiangQuickTable.setTimerOfDispatchRobot tableId:', self.tableId) robotMode = self.getRoomConfig('hasrobot', 1) if robotMode != 1: return message = self.logic_table.msgProcessor.getMsgDispatchRobot(self.playersNum) robot_interval = majiang_conf.getRobotInterval(self.gameId) self.__timer.setupTimer(self.maxSeatN # 调用的定时器编号 , robot_interval # 定时时间 , message) # 定时回调的消息 def _handle_dispatch_virtual_player(self): """处理分派机器人""" self.__timer.cancelTimer(self.maxSeatN) playerCount = runcmd.getMsgPack().getParam('player_count') if (self.playersNum == playerCount): ftlog.debug("dispatch_virtual_player", playerCount) robotRandom = random.randint(1, 9999) from difang.majiang2.resource import resource robot = resource.getRobot(robotRandom) self.doSitDown(robot['userId'], -1, None, 'robot_3.7_-hall6-robot') else: ftlog.debug('player_count is changed, no need to dispacth virtual player') @locked def handle_auto_decide_action(self): """处理托管""" ftlog.debug('$$$$$$$$$$$$$$$$$MajiangQuickTable.handle_auto_decide_action') if self.logic_table.isGameOver(): """游戏结束,通知玩家离开,站起,重置牌桌""" ftlog.debug('MajiangQuickTable.handle_auto_decide_action gameOver, clearTable... tableId:', self.tableId) self.clearTable(True) return self.actionHander.updateTimeOut(-1) self.actionHander.doAutoAction() def _doTableCall(self, msg, userId, seatId, action, clientId): """ 继承父类,处理table_call消息 """ try: ftlog.debug('MajiangQuickTable handle table_call message, tableId:', self.tableId, ' seatId:', seatId, ' action:', action) if not self.CheckSeatId(seatId, userId): ftlog.warn("handle table_call, seatId is invalid,", action, seatId) return if action == 'play': # 出牌 self.actionHander.handleTableCallPlay(userId, seatId, msg) elif action == 'chi': # 吃牌 self.actionHander.handleTableCallChi(userId, seatId, msg) elif action == 'peng': # 碰牌 self.actionHander.handleTableCallPeng(userId, seatId, msg) elif action == 'gang': # 杠牌 self.actionHander.handleTableCallGang(userId, seatId, msg) elif action == 'grabTing': # 抢听 self.actionHander.handleTableCallGrabTing(userId, seatId, msg) elif action == 'win': # 和牌 self.actionHander.handleTableCallWin(userId, seatId, msg) elif action == 'pass': # 过牌 self.actionHander.handleTableCallpass(userId, seatId, msg) elif action == 'dispatch_virtual_player': # 分配机器人 self._handle_dispatch_virtual_player() elif action == 'grabHuGang': # 抢杠和 self.actionHander.handleTableCallGrabHuGang(userId, seatId, msg) elif action == 'fanpigu': self.actionHander.handleTableCallFanpigu(userId, seatId, msg) elif action == 'ping': # 获取网速 self.actionHander.handleTableCallPing(userId, seatId, msg) elif action == 'exchange': # 换牌 self.actionHander.handleTableCallExchange(userId, seatId, msg) else: ftlog.debug('MajiangQuickTable._doTableCall unprocessed message:', msg) except: ftlog.error("_doTableCall error clear table") self.clearTable(True) def kickOffUser(self, userId, seatId, sendLeave): """让一个玩家leave""" ftlog.debug('MajiangQuickTable.kickOffUser userId:', userId, ' seatId:', seatId) onlinedata.removeOnlineLoc(userId, self.roomId, self.tableId) # uids = self.logic_table.getBroadCastUIDs() # 临时注释掉 待整体确认 taoxc # self.logic_table.msgProcessor.table_leave(userId, seatId, uids) # 游戏开始之后的退出,客户端不需要再收到退出消息 客户端的退出由其自身控制 sendLeave = False # 游戏未开始时房主解散了房间才需要向客户端发消息 sendLeave = True if sendLeave: uids = self.logic_table.getBroadCastUIDs() self.logic_table.msgProcessor.create_table_dissolve(userId, seatId, 'dissolve', uids) self.logic_table.removePlayer(seatId) self.seats[seatId] = TYSeat(self) self.players[seatId] = None def _doLeave(self, msg, userId, clientId): reason = msg.getParam("reason", TYRoom.LEAVE_ROOM_REASON_ACTIVE) ftlog.debug("majiang_quick_table_doLeave msg:", msg) if reason == TYRoom.LEAVE_ROOM_REASON_LOST_CONNECTION: self.logic_table.sendLeaveMessage(userId) return {"isOK": False, "reason": reason} def _doStandUp(self, msg, userId, seatId, reason, clientId): ''' 玩家操作, 尝试离开当前的座位 子类需要自行判定userId和seatId是否吻合 快速麻将桌的站起比较简单 牌局没开始,站起 牌局已开始,不处理,超时托管 ''' if self.logic_table.isPlaying(): # 用户托管 ftlog.debug('MajiangQuickTable.standup, user stand up, set trustTee...') self.logic_table.setAutoDecideValue(seatId, True) else: ftlog.info('MajiangQuickTable.standup removeOnlineLoc userId:', userId , ' roomId:', self.roomId , ' tableId:', self.tableId , ' seatId:', seatId , ' reason:', reason) self.kickOffUser(userId, seatId, True) def _doTableManage(self, msg, action): '''桌子内部处理所有的table_manage命令''' ftlog.debug("majiang_quick_table_doTableManage msg:", msg, "action", action) result = {'isOK': True} if action == 'leave': userId = msg.getParam('userId') self.logic_table.sendLeaveMessage(userId) seatId = self.getSeatIdByUserId(userId) if seatId >= 0: self.logic_table.setPlayerLeave(seatId, True) self._doStandUp(None, userId, seatId, -1, '') elif action == 'clear_table': self.clearTable(True) elif action == 'tableTiles': if self.logic_table.isPlaying(): self.logic_table.printTableTiles() return result def getSeatIdByUserId(self, userId): """根据userId获取座位号""" for index in range(self.maxSeatN): if self.seats[index][TYSeat.INDEX_SEATE_USERID] == userId: return index return -1 def clearTable(self, sendLeave): """清理桌子""" ftlog.debug('MajiangQuickTable.clearTable tableId:', self.tableId , ' now seats: ', self.seats) self.__timer.cancelTimerAll() if self.__looper_timer: self.__looper_timer.cancel() self.__looper_timer = None # 清理用户座位 for seatId in range(self.maxSeatN): if self.seats[seatId][TYSeat.INDEX_SEATE_USERID] != 0: self.kickOffUser(self.seats[seatId][TYSeat.INDEX_SEATE_USERID], seatId, sendLeave) # 结束游戏 self.logic_table.reset() # 释放桌子 self.room.updateTableScore(self.getTableScore(), self.tableId) def saveRecordAfterClear(self, score): """score为每盘的分的数组,形如[[-1,0,1,0],[2,1,1,0]]""" scoreInfo = {} ftlog.debug("saveRecordAfterClear score:", score) playerCount = self.logic_table.playerCount sendScore = [[] for _ in range(playerCount)] for roundScore in score: for i in range(0, playerCount): sendScore[i].append(roundScore[i]) ftlog.debug("saveRecordAfterClear sendScore:", sendScore) ftId = self.logic_table.tableConfig[MFTDefine.FTID] for i in range(0, playerCount): cp = self.logic_table.player[i] if cp: if 'budget' not in scoreInfo: scoreInfo['budget'] = {} import time if 'time' not in scoreInfo: scoreInfo['time'] = int(time.time()) if 'playMode' not in scoreInfo: scoreInfo['playMode'] = self.playMode if 'tableId' not in scoreInfo: scoreInfo['tableId'] = self.tableId if 'tableNo' not in scoreInfo: scoreInfo['tableNo'] = ftId if 'defaultScore' not in scoreInfo: scoreInfo['defaultScore'] = 1 if 'recordUrls' not in scoreInfo: scoreInfo['recordUrls'] = self.logic_table.recordUrls if cp.userId not in scoreInfo['budget']: scoreInfo['budget'][cp.userId] = {} scoreInfo['budget'][cp.userId]['uid'] = cp.userId scoreInfo['budget'][cp.userId]['name'] = cp.name scoreInfo['budget'][cp.userId]['score'] = sendScore[i] if self.logic_table.tableResult: if self.logic_table.tableResult.score: scoreInfo['budget'][cp.userId]['deltaScoreList'] = \ self.logic_table.tableResult.score[i] else: scoreInfo['budget'][cp.userId]['deltaScoreList'] = 0 else: scoreInfo['budget'][cp.userId]['deltaScoreList'] = 0 MJCreateTableRecord.saveRecord(scoreInfo, ftId, self.gameId)
class Heartbeat(object): """心跳的类""" ST_IDLE = 0 ST_START = 1 ST_STOP = 2 def __init__(self, target, interval): self._target = target self._state = Heartbeat.ST_IDLE self._count = 0 self._postTaskList = [] self._timer = None self._interval = interval self._init = False def start(self): assert (self._state == Heartbeat.ST_IDLE) self._state = Heartbeat.ST_START self._timer = FTLoopTimer(0, 0, self._onInit) self._timer.start() def stop(self): """停止定时器""" if self._state != Heartbeat.ST_STOP: self._state = Heartbeat.ST_STOP if self._timer: self._timer.cancel() self._timer = None @property def count(self): """次数""" return self._count def postCall(self, func, *args, **kwargs): """处理回调用""" self.postTask(functools.partial(func, *args, **kwargs)) def postTask(self, task): """添加任务""" if self._state != Heartbeat.ST_STOP: self._postTaskList.append(task) if self._init and self._timer: self._timer.cancel() self._timer = FTLoopTimer(0, 0, self._onTimeout) self._timer.start() def _onInit(self): """启动定时器""" try: self._timer = None interval = self._target.onInit() # 上层类函数初始化 if interval: self._interval = interval # 间隔时间 self._scheduleTimer() except: ftlog.error("Heartbeat._onInit") def _onTimeout(self): """时间到点的定时器""" try: self._timer = None self._count += 1 # 执行次数 self._processPostTaskList() # 处理任务集合list interval = self._target.onHeartbeat() # 上层函数的心跳 if interval is not None: self._interval = interval except: self._interval = 1 ftlog.error("Heartbeat._onTimeout") self._scheduleTimer() def _scheduleTimer(self): """设置特定时间的定时器""" if self._state == Heartbeat.ST_START: interval = 0 if self._postTaskList else self._interval self._timer = FTLoopTimer(interval, 0, self._onTimeout) self._timer.start() def _processPostTaskList(self): """处理任务函数""" taskList = self._postTaskList self._postTaskList = [] for task in taskList: try: task() except: ftlog.error("task=", task)
class TaskBase(object): def __init__(self, player, taskConf, taskSystem, taskData=None): self.player = player self.userId = player.userId self.taskId = taskConf["taskId"] self.taskConfig = taskConf self.taskSystem = taskSystem self.taskData = taskData or self._getInitMainData() self.taskInterval = taskConf["timeLong"] self.helpProgress = taskData.get("helpProgress", 0) if taskData else 0 self.waitTime = taskData.get("waitTime", 0) if taskData else taskConf["waitTime"] self.taskActivateTimer = None # 任务激活 self.sendTaskInfoTimer = None # 发送任务信息 self.updateTaskInfoTimer = None # 刷新任务进度 self.userEndTaskTimer = None # 任务结束倒计时 self.isSendMsg = False self.receiveRewards = None self.catchBetNum = taskData.get("catchBetNum", 0) if taskData else 0 self._reload() def clear(self): """清理定时器""" if self.taskActivateTimer: self.taskActivateTimer.cancel() if self.sendTaskInfoTimer: self.sendTaskInfoTimer.cancel() if self.updateTaskInfoTimer: self.updateTaskInfoTimer.cancel() if self.userEndTaskTimer: self.userEndTaskTimer.cancel() def _reload(self): self.recordStartTime = 0 if not self.isTaskOver(): if self.taskData.get("type", 0) and self.taskData.get("type", 0) != self.taskConfig["type"]: self.taskData = self._getInitMainData() return if self.taskConfig["target"] != self.taskData["target"]: # 未完成的任务任务目标发生变化后重置存档 self.taskData = self._getInitMainData() return if self.taskConfig["targetNum"] != self.taskData["targetNum"] and self.taskData.get("type", 0) not in [0, TaskType.HoldCoin]: self.taskData = self._getInitMainData() return def _getInitMainData(self): """获取初始化主线数据""" targetNum = self.taskConfig["targetNum"] if util.isNewbieRoom(self.player.table.typeName) and self.taskConfig["type"] == TaskType.HoldCoin: targetNum += self.player.allChip // 100 * 100 return { "type": self.taskConfig["type"], "progress": 0, "state": TaskState.NotOpen, "failTime": 0, "targetNum": targetNum, "target": self.taskConfig["target"] } def _addProgress(self, value, isMe, progress=0, isTargetAddition=False): """增加任务进度""" assert (self.taskData) if value == 0 or self.taskData["state"] != TaskState.Update: # value return if ftlog.is_debug(): ftlog.debug("_addProgress1", "value =", value, "isMe =", isMe, "progress =", progress, "isTargetAddition =", isTargetAddition, "helpProgress =", self.helpProgress) if isMe: value *= self.taskSystem.taskExpedite progress_ = min(self.taskData["progress"] + value, 999999999999) self._updateProgress(progress_, isMe) else: if progress > 0 or isTargetAddition: if progress: self.helpProgress += progress else: self.helpProgress += value progress_ = min(self.taskData["progress"] + value, 999999999999) self._updateProgress(progress_, isMe) if ftlog.is_debug(): ftlog.debug("_addProgress2", "helpProgress =", self.helpProgress, "totalProgress =", progress_) def _updateProgress(self, value, isMe): """ 更新任务进度 """ if self.taskData["progress"] != value: self.taskData["progress"] = value self.taskData["time"] = int(time.time()) if self._isComplete(): self.taskEnd() else: if isMe: self.sendUserTaskInfo() else: # 好友助力任务进度延迟刷新 self.isSendMsg = True def _receiveTaskReward(self): """领取奖励""" assert (self.taskData) if self.isTaskOver(): # 已领取 return 1, None targetCount = self.taskData["targetNum"] if self.taskData["progress"] < targetCount: # 未达成 return 1, None _rewards = self._getDropItems() if not _rewards: _rewards = self.taskConfig["rewards"] # 普通奖励 if _rewards and util.isChestRewardId(_rewards[0]["name"]): # 宝箱奖励(新手宝箱奖励固定) if util.isNewbieRoom(self.player.table.typeName): _rewards = [ {"name": 101, "count": 500}, {"name": 1145, "count": 1}, {"name": 1149, "count": 1} # {"name": 1137, "count": 3} ] else: from newfish.entity.chest import chest_system _rewards = chest_system.getChestRewards(self.userId, _rewards[0]["name"]) rewards = [] for _, reward in enumerate(_rewards): if reward["name"] <= 0: continue rwDict = {} rwDict["name"] = reward["name"] rwDict["count"] = reward["count"] rewards.append(rwDict) code = 0 self.taskData["state"] = TaskState.Success # 改变状态 if rewards: code = util.addRewards(self.userId, rewards, "BI_NFISH_TABLE_TASK_REWARDS", int(self.taskId)) return code, rewards def _getDropItems(self): """获取掉落的道具""" realRewards = [] rewards = self.taskConfig["rewards"] for reward in rewards: dropId = reward["name"] dropConf = config.getDropConf(dropId) if dropConf: _, rds = drop_system.getDropItem(dropId) realRewards.append(rds) return realRewards def _getCatchFishCoin(self, event, target=0): """获取捕鱼的金币""" totalCoin = 0 # 总金币数不包括招财珠 gunSkinMul = event.gunSkinMul fishCoins = {} outCoinsNum = 0 for gainMap in event.gain: fishType = int(gainMap["fishType"]) itemId = gainMap["itemId"] itemCount = gainMap["count"] / gunSkinMul if itemId == config.CHIP_KINDID: # 金币 totalCoin += itemCount if fishType // 1000 == 14: fishType = fishType % 14000 + 11000 fishCoins[str(fishType)] = fishCoins.setdefault(str(fishType), 0) + itemCount if target and itemCount >= target: outCoinsNum += 1 return totalCoin, fishCoins, outCoinsNum def dealCatchEvent(self, event, tableMultiple, coinAddition, playersNum): """ 处理捕鱼事件 :param event: 捕获事件详情 :param tableMultiple: 房间倍率 :param coinAddition: 当处于累计捕获金币任务时的进度加成 :param playersNum: 当前桌内玩家数量 :return: """ if self.taskConfig["type"] in [TaskType.UseSkillNum, TaskType.ComboNum]: return if self.taskData["state"] != TaskState.Update: return isMe = event.userId == self.userId fishTypes = event.fishTypes # 鱼种类 wpId = event.wpId gunSkinMul = event.gunSkinMul target = self.taskConfig["target"] progress = 0 isTargetAddition = False if self.taskConfig["type"] in [TaskType.CatchFishCoin, TaskType.UseSkillCatchFishCoin]: progress = coinAddition elif self.taskConfig["type"] in [TaskType.CatchFishNum, TaskType.CatchBossNum, TaskType.FishNumCoinHigh, TaskType.BetFishNum, TaskType.CatchRainbowFishNum, TaskType.CatchRedPacketFishNum]: friendHelpPlayerMultiple = config.getCommonValueByKey("friendHelpPlayerMultiple", {}).get(str(playersNum - 1), 0) probb = (friendHelpPlayerMultiple * (self.taskData["targetNum"] + 5) / self.taskData["targetNum"]) * 10000 randInt = random.randint(1, 10000) if randInt <= probb: isTargetAddition = True if self.taskConfig["type"] == TaskType.CatchFishCoin: # 1捕获xx鱼达金币数 totalCoin, fishCoins, _ = self._getCatchFishCoin(event) if target: self._addProgress(fishCoins.get(str(target), 0), isMe, progress=progress, isTargetAddition=isTargetAddition) else: self._addProgress(totalCoin, isMe, progress=progress, isTargetAddition=isTargetAddition) elif self.taskConfig["type"] == TaskType.CatchFishNum: # 2捕获鱼个数 if target: betTarget = 14000 + int(target) % 11000 fishNum = fishTypes.count(target) + fishTypes.count(betTarget) self._addProgress(fishNum, isMe, progress=progress, isTargetAddition=isTargetAddition) else: self._addProgress(len(fishTypes), isMe, progress=progress, isTargetAddition=isTargetAddition) return elif self.taskConfig["type"] == TaskType.CatchBossNum: # 3捕获boss个数 bossNum = 0 # boss个数 for fishType in fishTypes: fishConf = config.getFishConf(fishType, self.taskSystem.table.typeName, tableMultiple) if fishConf["type"] in config.BOSS_FISH_TYPE: bossNum += 1 self._addProgress(bossNum, isMe, progress=progress, isTargetAddition=isTargetAddition) return elif self.taskConfig["type"] == TaskType.FishNumCoinHigh: # 4多少金币以上的鱼 _, _, num = self._getCatchFishCoin(event, target) self._addProgress(num, isMe, progress=progress, isTargetAddition=isTargetAddition) return elif self.taskConfig["type"] == TaskType.BetFishNum: # 5--多少只倍率鱼 betFishMap = {} for gainMap in event.gain: fishConf = config.getFishConf(gainMap["fishType"], self.taskSystem.table.typeName, tableMultiple) itemId = gainMap["itemId"] itemCount = gainMap["count"] if fishConf["type"] in config.MULTIPLE_FISH_TYPE: if itemId == config.CHIP_KINDID: # 金币 bet = itemCount / fishConf["score"] / tableMultiple / gunSkinMul betFishMap[str(bet)] = betFishMap.get(str(bet), 0) + 1 betNum = 0 for bet in betFishMap: if int(bet) >= target: betNum += betFishMap[bet] self._addProgress(betNum, isMe, progress=progress, isTargetAddition=isTargetAddition) elif self.taskConfig["type"] == TaskType.UseSkillCatchFishNum: # 8 使用技能捕获鱼数 wpType = util.getWeaponType(wpId) if wpType in [config.SKILL_WEAPON_TYPE, config.RB_FIRE_WEAPON_TYPE, config.RB_BOMB_WEAPON_TYPE]: if target: self._addProgress(fishTypes.count(target), isMe, progress=progress, isTargetAddition=isTargetAddition) else: self._addProgress(len(fishTypes), isMe, progress=progress, isTargetAddition=isTargetAddition) elif self.taskConfig["type"] == TaskType.UseSkillCatchFishCoin: # 9 使用技能捕获XX金币类型的鱼数 totalCoin, fishCoins, _ = self._getCatchFishCoin(event) # 总金币数不包括招财珠 wpType = util.getWeaponType(wpId) if wpType in [config.SKILL_WEAPON_TYPE, config.RB_FIRE_WEAPON_TYPE, config.RB_BOMB_WEAPON_TYPE]: if target: self._addProgress(fishCoins.get(str(target), 0), isMe, progress=progress, isTargetAddition=isTargetAddition) else: self._addProgress(totalCoin, isMe, progress=progress, isTargetAddition=isTargetAddition) elif self.taskConfig["type"] == TaskType.CatchFishNumByOneFire: # 10 1网捕获多少鱼 if len(fishTypes) >= target: value = 1 if not isMe: return self._addProgress(value, isMe, progress=progress, isTargetAddition=isTargetAddition) elif self.taskConfig["type"] == TaskType.CatchRainbowFishNum: # 捕获彩虹鱼 rainbowNum = 0 for fishType in fishTypes: fishConf = config.getFishConf(fishType, self.taskSystem.table.typeName, tableMultiple) if fishConf["type"] in config.RAINBOW_FISH_TYPE: rainbowNum += 1 self._addProgress(rainbowNum, isMe, progress=progress, isTargetAddition=isTargetAddition) elif self.taskConfig["type"] == TaskType.CatchRedPacketFishNum: # 捕获红包券鱼 redPacketNum = 0 for fishType in fishTypes: fishConf = config.getFishConf(fishType, self.taskSystem.table.typeName, tableMultiple) if fishConf["type"] == 4: redPacketNum += 1 self._addProgress(redPacketNum, isMe, progress=progress, isTargetAddition=isTargetAddition) def dealUseSkillEvent(self, event): """使用技能事件""" if self.taskData["state"] != TaskState.Update: return if self.taskConfig["type"] == TaskType.UseSkillNum: target = self.taskConfig["target"] if target == 0: self._addProgress(1, event.userId == self.userId) else: if event.skillId == target: self._addProgress(1, event.userId == self.userId) def dealUseSkillItem(self, event): """使用技能道具""" if self.taskData["state"] != TaskState.Update: return if self.taskConfig["type"] == TaskType.UserSkillItem: self._addProgress(1, event.userId == self.userId) def dealGetPearl(self, pearl): """获得珍珠""" if self.taskData["state"] != TaskState.Update: return if self.taskConfig["type"] == TaskType.CatchPearlNum: self._addProgress(pearl, True) def dealCommboEvent(self, event): """处理连击事件""" if self.taskData["state"] != TaskState.Update: return if self.taskConfig["type"] == TaskType.ComboNum: if event.comboNum >= self.taskConfig["target"]: self._addProgress(1, event.userId == self.userId) def refreshHoldCoin(self, coin): """刷新持有金币数量""" if self.taskData["state"] != TaskState.Update: return if ftlog.is_debug(): ftlog.debug("refreshHoldCoin", self.userId, coin) if self.taskConfig["type"] == TaskType.HoldCoin: self._updateProgress(coin, True) def refreshLevel(self, level): """刷新等级""" if self.taskData["state"] != TaskState.Update: return ftlog.debug("refreshLevel", self.userId, level) if self.taskConfig["type"] == TaskType.UpgradeLevel: self._updateProgress(level, True) def getTaskId(self): """ 获取任务Id """ return self.taskId def taskStart(self, interval=0, delay=0): """ 任务开始 """ if ftlog.is_debug(): ftlog.debug("taskBase_______taskStart", self.taskId) if self.taskActivateTimer: self.taskActivateTimer.cancel() if delay > 0: taskActivateInterval = max(interval, Task_Delay_Ready_Time) self.taskActivateTimer = FTLoopTimer(taskActivateInterval, 0, self._taskActivate, delay) self.taskActivateTimer.start() elif self.taskConfig["timeLong"] > 0: if util.isNewbieRoom(self.player.table.typeName) and self.taskSystem.taskModel == TaskModel.Main: time_ = Task_Red_Ready_Time else: time_ = Task_Normal_Ready_Time taskActivateInterval = max(interval, time_) taskInfoInterval = max(interval - time_, 0) self.delaySendUserTaskInfo(taskInfoInterval) self.taskActivateTimer = FTLoopTimer(taskActivateInterval, 0, self._taskActivate) self.taskActivateTimer.start() else: self.taskActivateTimer = FTLoopTimer(interval, 0, self._taskActivate) self.taskActivateTimer.start() from newfish.game import TGFish from newfish.entity.event import TableTaskStartEvent event = TableTaskStartEvent(self.userId, FISH_GAMEID, self.taskSystem.table.tableId, self.getTaskId()) TGFish.getEventBus().publishEvent(event) def _taskActivate(self, delay=0): """任务激活""" # 未完成前3个中期目标时不触发渔场任务. if self.taskSystem.needCheckMidTermTargetStates: if not self.taskSystem.top3MidTermTargetFinished: self.taskSystem.top3MidTermTargetFinished = True for taskClass in self.player.achieveSystem.holdAssetTasks: if taskClass.taskId < 1003 or (taskClass.taskId == 1003 and not taskClass.isComplete()): self.taskSystem.top3MidTermTargetFinished = False break if not self.taskSystem.top3MidTermTargetFinished: if self.taskActivateTimer: self.taskActivateTimer.cancel() self.taskActivateTimer = FTLoopTimer(60, 0, self._taskActivate) self.taskActivateTimer.start() if ftlog.is_debug(): ftlog.debug("_taskActivate, need delay !", self.player.userId, self.taskId) return if ftlog.is_debug(): ftlog.debug("_taskActivate->", delay, self.waitTime) self.taskData["state"] = TaskState.Start if delay > 0: self.taskData["state"] = TaskState.Update self.taskInterval = delay self.recordStartTime = int(time.time()) self.clear() if self.taskInterval != 0: self.userEndTaskTimer = FTLoopTimer(self.taskInterval, 0, self.taskEnd) self.userEndTaskTimer.start() if self.taskSystem.isFriendRoom(): self.updateTaskInfoTimer = FTLoopTimer(1, -1, self.sendTimerUpdate) self.updateTaskInfoTimer.start() self.sendUserTaskInfo() self.taskData["state"] = TaskState.Update def getTaskFailTime(self): """ 当前任务已经失败多少次 """ return self.taskData["failTime"] def getTaskInfo(self): """ 获取返回给客户端的任务数据 """ progress = min(self.taskData["progress"], self.taskData["targetNum"]) progress = int(progress) if progress - int(progress) == 0 else progress meProgress = progress - self.helpProgress meProgress = int(meProgress) if meProgress - int(meProgress) == 0 else meProgress taskInfo = {} taskInfo["taskId"] = self.taskConfig["taskId"] taskInfo["isLimitTime"] = self.isLimitTime() taskInfo["shareMode"] = 1 # 1 if not self.isLimitTime() or util.isLocationLimit(self.userId) else 0 taskInfo["progress"] = [int(progress), int(meProgress), self.taskData["targetNum"]] taskInfo["state"] = self.taskData["state"] taskInfodescId = self.taskConfig["desc"] taskInfo["desc"] = config.getMultiLangTextConf(str(taskInfodescId), lang=util.getLanguage(self.userId)) taskInfo["reward"] = self.taskConfig["rewards"] if self.receiveRewards: taskInfo["realReward"] = self.receiveRewards taskInfo["target"] = self.taskConfig["target"] taskInfo["suggestTarget"] = self.taskConfig["suggestTarget"] timeLeft = self.recordStartTime + self.taskInterval - int(time.time()) taskInfo["timeLeft"] = timeLeft if timeLeft >= 0 else self.taskInterval taskInfo["timeLong"] = self.taskInterval taskInfo["failTimeConf"] = self.taskConfig["failTime"] taskInfo["failTime"] = self.taskData["failTime"] # 失败次数 taskInfo["isNextLimitTime"] = self.taskSystem.isNextLimitTime(self.getTaskId()) taskInfo["model"] = TaskModel.Red if util.isNewbieRoom(self.player.table.typeName) and self.taskSystem.taskModel == TaskModel.Main else self.taskSystem.taskModel taskInfo["type"] = self.taskConfig["type"] if self.taskSystem.taskModel in [TaskModel.Red, TaskModel.Main]: taskInfo["index"] = self.taskSystem.allMainTaskIds.index(self.taskId) return taskInfo def getTaskData(self): """ 获取存储的任务数据 """ saveData = {} saveData["type"] = self.taskConfig["type"] saveData["taskId"] = self.taskId saveData["progress"] = self.taskData["progress"] saveData["helpProgress"] = self.helpProgress saveData["state"] = self.taskData["state"] saveData["target"] = self.taskConfig["target"] saveData["targetNum"] = self.taskData["targetNum"] saveData["failTime"] = self.taskData["failTime"] saveData["waitTime"] = int(self.taskActivateTimer.getTimeOut()) if self.taskActivateTimer else 0 if self.catchBetNum: saveData["catchBetNum"] = self.catchBetNum return saveData def taskEnd(self): """ 任务结束 """ if ftlog.is_debug(): ftlog.debug("taskBase_______taskEnd", self.taskId, self.userId, self.taskData["state"]) beforeState = self.taskData["state"] self.clear() if beforeState == TaskState.Update: isComplete = self._isComplete() if isComplete: _, rewards = self._receiveTaskReward() self.receiveRewards = rewards self.taskSystem.saveRedState() # 保存红包 else: self.taskSystem.taskExpedite = 1 self.taskData["state"] = TaskState.Fail if self.isLimitTime(): self.taskData["failTime"] += 1 from newfish.game import TGFish from newfish.entity.event import TableTaskEndEvent event = TableTaskEndEvent(self.userId, FISH_GAMEID, self.taskSystem.table.tableId, self.getTaskId(), isComplete, self.isLimitTime(), self.receiveRewards) TGFish.getEventBus().publishEvent(event) # 上传当前完成任务进度 if self.taskSystem.taskModel == TaskModel.Main and self.taskSystem.isRedRoom(): ftlog.debug("BI_NFISH_THOUSAND_RED_TASK_PROGRESS--->000", self.getTaskId()) bireport.reportGameEvent("BI_NFISH_GE_THOUSAND_RED_TASK", self.userId,FISH_GAMEID, self.taskSystem.table.roomId, self.taskSystem.table.tableId, self.getTaskId(), int(isComplete), 0, 0, [], config.CLIENTID_ROBOT) # 新手引导步骤完成 if self.taskConfig["type"] == TaskType.UpgradeLevel: util.addGuideStep(self.player.userId, config.NEWBIE_GUIDE_GUN_UP, self.player.clientId) self.sendUserTaskInfo() def sendTimerUpdate(self): """ 任务进度刷新 """ if self.taskConfig["type"] == TaskType.HoldCoin: self.taskSystem.refreshHoldCoin(self.player.holdCoin) elif self.taskConfig["type"] == TaskType.UpgradeLevel: gunLevel = self.player.gunLevel - 2100 self.taskSystem.refreshLevel(gunLevel) if self.isSendMsg: self.sendUserTaskInfo() def delaySendUserTaskInfo(self, interval=0): """ 延时发送任务信息 """ if self.sendTaskInfoTimer: self.sendTaskInfoTimer.cancel() self.sendTaskInfoTimer = FTLoopTimer(interval, 0, self.sendUserTaskInfo) self.sendTaskInfoTimer.start() def sendUserTaskInfo(self): """ 发送任务信息 """ self.isSendMsg = False message = MsgPack() message.setCmd("table_task_info") message.setResult("gameId", FISH_GAMEID) message.setResult("userId", self.userId) taskInfo = self.getTaskInfo() message.setResult("taskInfo", taskInfo) router.sendToUser(message, self.userId) def _isComplete(self): """ 任务是否完成 """ assert (self.taskData) targetCount = self.taskData["targetNum"] return self.taskData["progress"] >= targetCount def isTaskSuccess(self): """ 任务成功 """ return self.taskData["state"] == TaskState.Success def getTaskConf(self): assert (self.taskConfig) return self.taskConfig def isTaskOver(self): """任务结束""" return self.taskData["state"] in [TaskState.Success, TaskState.Fail] def getTaskState(self): return self.taskData["state"] def getTaskTargets(self): if self.taskData["state"] != TaskState.Update: return [] if self.taskConfig["type"] in [TaskType.CatchFishNum, TaskType.CatchFishCoin, TaskType.UseSkillCatchFishNum, TaskType.UseSkillCatchFishCoin]: if self.taskConfig["target"] != 0: return [self.taskConfig["target"]] return [] def isLimitTime(self): """是否限制了时间""" if not self.taskConfig: return 0 return 1 if self.taskConfig.get("timeLong", 0) != 0 else 0
class HttpGetNdayAfterMatchs(object): '''N日后的比赛列表''' def __init__(self, interval, ndays, callback): self.httpContents = [] self.callback = callback self.now = datetime.datetime.now() self._afterday = (self.now + datetime.timedelta(days=ndays)).strftime('%Y-%m-%d') self.timer = FTLoopTimer(interval, -1, self._checkResult) self.timer.start() def __str__(self): return '%s:%s' % (self.now, self._afterday) def __repr__(self): return self.__str__() @property def key(self): return self.__str__() def _checkDate(self): return self.now.date() == datetime.datetime.now().date() def _checkResult(self): if ftlog.is_debug(): ftlog.debug('HttpGetNdayAfterMatchs', 'now=', self.now, '_afterday=', self._afterday) if not self._checkDate(): ftlog.info('hallsportlottery.HttpNdayAfterMatchList', '_checkDate=', self.now.date(), 'nowDate=', datetime.datetime.now().date()) if self.timer: self.timer.cancel() if self.callback: self.callback(self) return contents = http7Mgetschedulebydate(self._afterday) if contents and len(contents) > 0: if self.timer: self.timer.cancel() self.doContents(contents) if self.callback: self.callback(self) def doContents(self, contents): leagues = SportlotteryConf.leaguekeys() teams = SportlotteryConf.teamskeys() focusTeams = SportlotteryConf.focusTeamskeys() schedule = contents.get('Schedule') if schedule and len(schedule) > 0: for matchDict in schedule: match = matchDict['Id'] if match and len(match) >= 4: if match[1] not in leagues: continue if match[2] not in teams or match[3] not in teams: continue if match[2] not in focusTeams and match[ 3] not in focusTeams: continue d = { 'matchId': match[0], 'leagueId': match[1], 'homeTeamId': match[2], 'awayTeamId': match[3], 'timestamp': matchDict['Date'] / 1000 } self.httpContents.append(d)
class FishTimeMatchTable(FishMultipleTable): def __init__(self, room, tableId): super(FishTimeMatchTable, self).__init__(room, tableId) self.clearTableData() # 用户离线等待时间 self._offlineWaitSeconds = 600 # 用户空闲超时时间 self._idleTimeOutSeconds = 600 # 用户无子弹时超时时间 self._inactiveTimeOutSeconds = 600 # 准备倒计时 self._readySeconds = 5 # 排名刷新间隔 self._loopSeconds = 5 # 初始化定时器 self._readyTimer = None self._startTimer = None self._loopTimer = None # 比赛技能 self._matchSkills = None # 可用action self.actionMap = { "robot_leave": self._robotLeave, "catch": self._verifyCatch, "skill_use": self._skill_use, "skill_install": self._skill_install, "skill_replace": self._skill_replace, "smile": self.doTableSmilies, "honor_push": self._honor_push, "honor_replace": self._honor_replace, "guns_list": self._guns_list, "guns_pool": self._guns_pool, "treasure_rewards": self._getTreasureRewards, "item_use": self.item_use, # 使用道具技能 } self._logger = Logger() self._logger.add("cls=", self.__class__.__name__) self._logger.add("gameId", self.gameId) self._logger.add("roomId", room.roomId) self._logger.add("tableId", tableId) self._logger.add("matchId", room.bigmatchId) def clearTableData(self): """ 清理桌子数据和状态 """ # 比赛状态 self._matchState = MatchState.DEFAULT # 比赛桌详情 self._match_table_info = None # 比赛任务数据 self._usersData = {} def clearAllTimer(self): """ 清理所有定时器 """ if self._logger.isDebug(): self._logger.debug("clearAllTimer, tableId =", self.tableId) if self._readyTimer: self._readyTimer.cancel() self._readyTimer = None if self._startTimer: self._startTimer.cancel() self._startTimer = None if self._loopTimer: self._loopTimer.cancel() self._loopTimer = None if self.bufferFishGroup: self.bufferFishGroup.cancelNextGroupTimer() if self.multipleFishGroup: self.multipleFishGroup.cancelNextGroupTimer() def startFishGroup(self): """ 启动鱼阵 """ if self.runConfig.allNormalGroupIds: self.normalFishGroup = NormalFishGroup(self) # buffer鱼初始化 if self.runConfig.allBufferGroupIds: self.bufferFishGroup = BufferFishGroup(self) # 随机倍率鱼初始化 if self.runConfig.allMultipleGroupIds: self.multipleFishGroup = MultipleFishGroup(self) def createPlayer(self, table, seatIndex, clientId): """ 新创建Player对象 """ return FishTimeMatchPlayer(table, seatIndex, clientId) def _doTableManage(self, msg, action): """ 处理来自大比赛的table_manage命令 """ if action == "m_table_start": self.doMatchTableStart(msg) elif action == "m_table_info": self.doUpdateMatchTableInfo(msg) elif action == "m_table_update": self.doUpdateMatchRankInfo(msg) elif action == "m_table_clear": self.doMatchTableClear(msg) elif action == "m_table_over": self.doMatchOver(msg) elif action == "m_user_giveup": self.doUserGiveup(msg) else: super(FishTimeMatchTable, self)._doTableManage(msg, action) def doMatchTableStart(self, msg): """开始比赛桌子启动""" if self._logger.isDebug(): self._logger.debug("doMatchTableStart", "msg=", msg) table_info = msg.getKey("params") self._doUpdateTableInfo(table_info) self._doMatchQuickStart() # 开始 self.bufferFishGroup and self.bufferFishGroup.initGroup( self._match_table_info["tableRankRatio"]) self.multipleFishGroup and self.multipleFishGroup.initGroup( self._match_table_info["tableRankRatio"]) if self._logger.isDebug(): self._logger.debug("doMatchTableStart, tableId =", self.tableId, "readyTimer =", self._readyTimer) if not self._readyTimer: self._matchState = MatchState.READY self._readyTimer = FTLoopTimer(self._readySeconds, 0, self._matchStartTime) self._readyTimer.start() if self._logger.isDebug(): self._logger.debug("doMatchTableStart OK", "msg=", msg) def doUpdateMatchTableInfo(self, msg): """更新比赛桌子信息""" if self._logger.isDebug(): self._logger.debug("doUpdateMatchTableInfo", "msg=", msg) table_info = msg.getKey("params") self._doUpdateTableInfo(table_info) def doUpdateMatchRankInfo(self, msg): """更新排行榜信息""" if self._logger.isDebug(): self._logger.debug("doUpdateMatchRankInfo", "msg=", msg) rank_info = msg.getKey("params") self._doUpdateRankInfo(rank_info) def doMatchTableClear(self, msg): """清理比赛桌子""" if self._logger.isDebug(): self._logger.debug("doMatchTableClear", "msg=", msg) params = msg.getKey("params") matchId = params.get("matchId", -1) if matchId != self.room.bigmatchId: self._logger.error("doMatchTableClear", "msg=", msg, "err=", "DiffMatchId") return self._doMatchTableClear() def _doMatchTableClear(self): # 清理本桌玩家的在线状态 for player in self.players: if player and player.userId > 0: self._clearPlayer(None, player.userId, player.seatId) self.clearTableData() self.clearAllTimer() def doMatchOver(self, msg): """比赛完成""" if self._logger.isDebug(): self._logger.debug("doMatchOver", "msg=", msg) params = msg.getKey("params") matchId = params.get("matchId", -1) if matchId != self.room.bigmatchId: self._logger.error("doMatchOver", "msg=", msg, "err=", "DiffMatchId") return self._doMatchTableClear() def doUserGiveup(self, msg): """放弃比赛""" if self._logger.isDebug(): self._logger.debug("doUserGiveup", "msg=", msg) params = msg.getKey("params") userId = params.get("userId", -1) matchId = params.get("matchId", -1) if matchId != self.room.bigmatchId: self._logger.error("doUserGiveup", "msg=", msg, "err=", "DiffMatchId") player = self.getPlayer(userId) from newfish.entity.event import MatchGiveUpEvent from newfish.game import TGFish event = MatchGiveUpEvent(userId, FISH_GAMEID, self.room.bigmatchId) TGFish.getEventBus().publishEvent(event) if player: self._clearPlayer(None, player.userId, player.seatId) if self.playersNum == 0: self._doMatchTableClear() def _doSit(self, msg, userId, seatId, clientId): """ 玩家操作, 尝试再当前的某个座位上坐下 """ ret = self._doSitDown(msg, userId, seatId, clientId) return ret def _doSitDown(self, msg, userId, seatId, clientId): """ 比赛牌桌只有玩家断线重连时才会触发坐下操作,既重新坐回牌桌 """ if seatId != 0: if self.seats[seatId - 1].userId == 0: onlinedata.removeOnlineLoc(userId, self.roomId, self.tableId) ftlog.warn("reconnect user is cleaned from table", "seats =", self.seats) return False elif userId != self.seats[seatId - 1].userId: onlinedata.removeOnlineLoc(userId, self.roomId, self.tableId) ftlog.warn("reconnect user id is not matched", "seats =", self.seats) return False else: ftlog.info("user reconect, userId:", userId) onlinedata.addOnlineLoc(userId, self.roomId, self.tableId, seatId) self.players[seatId - 1].offline = 1 self.players[seatId - 1].clientId = clientId self.players[seatId - 1].lang = util.getLanguage( userId, clientId) self.players[seatId - 1].refreshGunSkin() self._sendTableInfo(userId, seatId) self._updateMatchInfo(userId) self._updateMatchRank(userId) self._updateMatchTask(userId) self.players[seatId - 1].dealEnterTable() self.players[seatId - 1].enterTime = int(time.time()) self.players[seatId - 1].offline = 0 from newfish.game import TGFish event = EnterTableEvent(userId, FISH_GAMEID, self.roomId, self.tableId, seatId, 1) TGFish.getEventBus().publishEvent(event) return True else: for i in range(len(self.seats)): if self.seats[i].userId == userId: ftlog.info("lost user reconect, userId:", userId, "i =", i) onlinedata.addOnlineLoc(userId, self.roomId, self.tableId, i + 1) self.players[i].offline = 1 self.players[i].clientId = clientId self.players[i].lang = util.getLanguage(userId, clientId) self.players[i].refreshGunSkin() self._sendTableInfo(userId, i + 1) self._updateMatchInfo(userId) self._updateMatchRank(userId) self._updateMatchTask(userId) self.players[i].dealEnterTable() self.players[i].enterTime = int(time.time()) self.players[i].offline = 0 from newfish.game import TGFish event = EnterTableEvent(userId, FISH_GAMEID, self.roomId, self.tableId, seatId, 1) TGFish.getEventBus().publishEvent(event) return True def _doUpdateTableInfo(self, tableInfo): """比赛参数|获取比赛技能""" self._match_table_info = tableInfo self._matchSkills = self._match_table_info.get("skills") def _doUpdateRankInfo(self, rankInfo): """更新排名信息""" seats = rankInfo["seats"] for seat in seats: userId = seat["userId"] rank = seat["rank"] player = self.getPlayer(userId) if player: player.rank = rank self._updateMatchRank(userId) def _doMatchQuickStart(self): """比赛快速开始""" seats = self._match_table_info["seats"] for seat in seats: userId = seat["userId"] seatId = seat["seatId"] clientId = util.getClientId(userId) player = self.getPlayer(userId) if not player: self.doMatchSitDown(userId, seatId, clientId) player = self.getPlayer(userId) if player: player.currentTask = [ "time_match", self.roomId, 1, copy.deepcopy(self._match_table_info["targets"]) ] self._usersData[userId] = { "uid": userId, "targets": copy.deepcopy(self._match_table_info["targets"]), "results": {} } def doMatchSitDown(self, userId, seatId, clientId): """比赛入座""" self.seats[seatId - 1].userId = userId self.players[seatId - 1] = self.createPlayer(self, seatId - 1, clientId) # 创建玩家 self.players[seatId - 1].clip = self._match_table_info["bullet"] # 玩家子弹 onlinedata.addOnlineLoc(userId, self.roomId, self.tableId, seatId) self._sendTableInfo(userId, seatId) # 发送table_info self._broadcastPlayerSit(userId, seatId) # 广播玩家坐下 self.players[seatId - 1].enterTime = int(time.time()) self.players[seatId - 1].offline = 0 from newfish.game import TGFish event = EnterTableEvent(userId, FISH_GAMEID, self.roomId, self.tableId, seatId) TGFish.getEventBus().publishEvent(event) bireport.reportGameEvent("BI_NFISH_TABLE_ENTER", userId, FISH_GAMEID, self.roomId, self.tableId, self.players[seatId - 1].level, 0, 0, 0, [], clientId) def getCostBullet(self, gunId, gunLevel, wpConf, clientId): """获取消耗的子弹""" costBullet = 1 return costBullet def _broadcastPlayerLeave(self, userId, seatId): """广播玩家离开""" msg = MsgPack() msg.setCmd("leave") msg.setResult("gameId", FISH_GAMEID) msg.setResult("userId", userId) msg.setResult("seatId", seatId) GameMsg.sendMsg(msg, self.getBroadcastUids(userId)) def _matchStartTime(self): """ 比赛开始,设置比赛结束时间点和更新排名机制 """ self._matchState = MatchState.START for player in self.players: if player: self._updateMatchInfo(player.userId) self._updateMatchRank(player.userId) if self._logger.isDebug(): self._logger.debug("_matchStartTime, tableId =", self.tableId, "startTimer =", self._startTimer, "loopTimer =", self._loopTimer) self._startTimer = FTLoopTimer(self.runConfig.playingTime, 0, self._matchTimeUp) self._startTimer.start() self._loopTimer = FTLoopTimer(self._loopSeconds, -1, self._matchUpdateRank) self._loopTimer.start() def _matchTimeUp(self): """ 比赛结束,处理结果,清理玩家 """ if self._loopTimer: self._loopTimer.cancel() self._matchState = MatchState.END FTLoopTimer(0.5, 0, self.room.matchPlugin.doWinLose, self.room, self).start() for player in self.players: if player and player.userId: player.clearTimer() def _matchUpdateRank(self): """ 定时更新排名机制 """ if self.getRobotUserCount() == self.playersNum: for player in self.players: if player and player.userId <= config.ROBOT_MAX_USER_ID: maxScore = int(self._match_table_info["bullet"] * 1.2) score = random.randint(maxScore / 2, maxScore) gainChip = score / (self.runConfig.playingTime / 5) player.catchBudget(gainChip, 0, []) self.room.matchPlugin.doUpdate(self.room, self) if int(self._startTimer.getTimeOut()) <= self._loopSeconds: self._loopTimer.cancel() def _updateMatchInfo(self, userId): """更新比赛信息""" player = self.getPlayer(userId) if player and player.userId: msg = MsgPack() msg.setCmd("m_info") msg.setResult("gameId", FISH_GAMEID) msg.setResult("roomId", self.roomId) msg.setResult("tableId", self.tableId) msg.setResult("seatId", player.seatId) msg.setResult("userId", player.userId) msg.setResult("timeLong", self.runConfig.playingTime) msg.setResult( "timeLeft", int(self._startTimer.getTimeOut()) if self._startTimer else self.runConfig.playingTime) msg.setResult("targets", self._match_table_info["targets"]) GameMsg.sendMsg(msg, player.userId) def _updateMatchRank(self, userId): """比赛排名""" player = self.getPlayer(userId) if player and player.userId and self._match_table_info: msg = MsgPack() msg.setCmd("m_update") msg.setResult("gameId", FISH_GAMEID) msg.setResult("roomId", self.roomId) msg.setResult("tableId", self.tableId) msg.setResult("seatId", player.seatId) msg.setResult("userId", player.userId) msg.setResult("rank", [player.rank, self._match_table_info["playerCount"]]) GameMsg.sendMsg(msg, player.userId) def _updateMatchTask(self, userId): """更新比赛任务""" player = self.getPlayer(userId) usersData = self._usersData.get(userId, {}) if player and usersData and usersData["results"]: msg = MsgPack() msg.setCmd("m_task") msg.setResult("gameId", FISH_GAMEID) msg.setResult("roomId", self.roomId) msg.setResult("tableId", self.tableId) msg.setResult("seatId", player.seatId) msg.setResult("userId", player.userId) msg.setResult("targets", usersData["results"]) GameMsg.sendMsg(msg, player.userId) def getProbbCoefficient(self, player, fishInfo): """概率基数""" if fishInfo["type"] in [3, 21] or fishInfo["multiple"] > 1: j1 = player.matchLuckyValue / 7500.0 + 1.0 / 3 c = self._match_table_info["realPlayerCount"] k = float(4 * c) / (3 * c - 1) b = 1 - float(2 * c) / (3 * c - 1) j2 = 1 #k * min(player.rank, c) / c + b j = (j1 + j2) * 0.5 if ftlog.is_debug(): ftlog.debug("getProbbCoefficient", player, fishInfo, "luckyValue =", player.matchLuckyValue, "rank =", player.rank, "j1 =", j1, "c =", c, "k =", k, "b =", b, "j2 =", j2, "j =", j) return j return 1 def dealKillFishGain(self, fId, player, fpMultiple, gunMultiple=1, bufferCoinAdd=1, wpType=None, extends=None, gunX=1): """ 处理打死鱼获得的奖励 :param fId: 被捕获鱼的ID :param player: 捕鱼者 :param fpMultiple: 渔场倍率 :param gunMultiple: 炮的倍率 :param bufferCoinAdd: buffer加成金币系数 :param wpType: 武器类型 :param extends: 扩展数据 :param gunX: 炮的倍数 """ gainChip = 0 gain = [] gainMap = {} fishType = self.fishMap[fId]["fishType"] fixedMultiple = self.fishMap[fId]["multiple"] fishConf = config.getMatchFishConf(fishType) if fishConf["score"] > 0: gainMap["fId"] = fId gainMap["fishType"] = fishType taskMultiple = 1 target1 = self._match_table_info["targets"].get("target1", 0) target2 = self._match_table_info["targets"].get("target2", 0) multipleTarget1 = 14000 + target1 % 11000 multipleTarget2 = 14000 + target2 % 11000 if fishType == target1 or fishType == target2 or \ fishType == multipleTarget1 or fishType == multipleTarget2: taskMultiple = fishConf.get("multiple", 1) if fishConf["type"] in config.MULTIPLE_FISH_TYPE: multiple = self.getMultipleFishMultiple( player, fishConf, fpMultiple, gunMultiple, gunX) gainMap["itemId"] = CHIP_KINDID gainMap["count"] = int(fishConf["score"] * fpMultiple * gunX * taskMultiple * multiple * bufferCoinAdd) gainMap["fishMultiple"] = multiple gainChip = int(gainMap["count"]) gain.append(gainMap) else: gainMap["itemId"] = CHIP_KINDID gainMap["count"] = int(fishConf["score"] * fpMultiple * gunX * taskMultiple * fixedMultiple * bufferCoinAdd) gainChip = int(gainMap["count"]) gain.append(gainMap) else: if fishConf["type"] in config.BUFFER_FISH_TYPE: # 捕获buffer鱼 bufferId = player.getCatchBufferId(fishConf["itemId"]) if bufferId > 0: gainMap["fId"] = fId gainMap["fishType"] = fishType gainMap["itemId"] = bufferId gainMap["count"] = 1 gain.append(gainMap) return gainChip, gain, 0 def getMultipleFishMultiple(self, player, fishConf, fpMultiple, gunMultiple, gunX): """ 获得倍率鱼的倍率 """ randInt = random.randint(1, 10000) for multipleMap in config.getMatchMultipleFishConf( self.runConfig.fishPool, player.matchLuckyValue): probb = multipleMap["probb"] if probb[0] <= randInt <= probb[-1]: return multipleMap["multiple"] return 1 def _verifyCatch(self, msg, userId, seatId): if self._matchState == MatchState.END: return super(FishTimeMatchTable, self)._verifyCatch(msg, userId, seatId) def dealCatch(self, bulletId, wpId, player, catch, gain, gainChip, exp, fpMultiple, extends=None, skillId=0, stageId=0, isFraud=False, skillType=0): """处理捕获""" if self._matchState == MatchState.END: return self._retVerifyCatch(player, bulletId, catch, gain, extends, skillId, stageId, fpMultiple, isFraud=isFraud, skillType=skillType) gainCoupon = 0 items = [] for gainMap in gain: fishConf = config.getFishConf(gainMap["fishType"], self.typeName, fpMultiple) if fishConf["type"] in config.BUFFER_FISH_TYPE: player.addOneBufferId(gainMap["itemId"]) if fishConf["type"] in config.LOG_OUTPUT_FISH_TYPE: ftlog.info("dealCatch->fishType", "userId =", player.userId, "fishType =", fishConf["type"], "wpId =", wpId, "gainMap =", gainMap, "gainChip =", gainChip) player.catchBudget(gainChip, gainCoupon, items, wpId=wpId) self._afterCatch(bulletId, wpId, player, catch, gain, gainChip, fpMultiple, extends, skillType=skillType) def _afterCatch(self, bulletId, wpId, player, catch, gain, gainChip, fpMultiple, extends=None, skillId=0, isFraud=False, skillType=0, catchFishMultiple=None): """捕获之后""" fishTypes = [] for catchMap in catch: if catchMap["reason"] == 0: fId = catchMap["fId"] self.setFishDied(fId) fishType = self.fishMap[fId]["fishType"] fishTypes.append(fishType) event = CatchEvent(player.userId, FISH_GAMEID, self.roomId, self.tableId, fishTypes, wpId, gainChip, fpMultiple) self._dealCatchEvent(event) def _dealCatchEvent(self, event): """处理捕获事件""" if event.tableId == self.tableId: usersData = self._usersData.get(event.userId, {}) if not usersData: ftlog.debug("_dealCatchEvent->invalid userId", event.userId) return fishTypes = event.fishTypes targets = usersData["targets"] target1 = targets.get("target1", 0) multipleTarget1 = 14000 + target1 % 11000 target2 = targets.get("target2", 0) multipleTarget2 = 14000 + target2 % 11000 if (target1 in fishTypes or multipleTarget1 in fishTypes) and target1 not in usersData["results"]: usersData["results"][target1] = 0 if (target2 in fishTypes or multipleTarget2 in fishTypes) and target2 not in usersData["results"]: usersData["results"][target2] = 0 if target1 in fishTypes or multipleTarget1 in fishTypes: score = fishTypes.count(target1) + fishTypes.count( multipleTarget1) usersData["results"][target1] += score if target2 in fishTypes or multipleTarget2 in fishTypes: score = fishTypes.count(target2) + fishTypes.count( multipleTarget2) usersData["results"][target2] += score self._updateMatchTask(event.userId)
class ShareFishGroup(object): """ 分享宝箱鱼群 """ def __init__(self, table): self.table = table self._interval = 60 # 间隔 self._totalTime = 0 self.checkTimer = FTLoopTimer(self._interval, -1, self._checkCondition) self.checkTimer.start() def clearTimer(self): if self.checkTimer: self.checkTimer.cancel() self.checkTimer = None def _checkCondition(self): """检查条件""" self._totalTime += self._interval # 所有人可见的宝箱出现时间600s if self._totalTime % 600 == 0: groupId = self._getFishGroupId() if groupId: self._addShareFishGroup(groupId) else: # 玩家个人宝箱出现时间 for player in self.table.players: if player: appearCount, playTime, expiresTime, state = self._getShareData(player.userId) if ftlog.is_debug(): ftlog.debug("ShareFishGroup_checkCondition", player.userId, appearCount, playTime, expiresTime) appearMinTime = 180 + 120 * appearCount appearMaxTime = 240 + 120 * appearCount groupId = self._getFishGroupId() if (appearMinTime <= playTime * 60 <= appearMaxTime and time.time() > expiresTime and state == share_system.ShareRewardState.Unavailable and groupId): self._addShareFishGroup(groupId, player.userId) def _getShareData(self, userId): """获取分享宝箱鱼的数据""" shareClass = RandomChest(userId) return shareClass.shareData[share_system.INDEX_OTHER_DATA].get("appearCount", 0), \ shareClass.shareData[share_system.INDEX_OTHER_DATA].get("playTime", 0), \ shareClass.shareData[share_system.INDEX_OTHER_DATA].get("expiresTime", 0), \ shareClass.shareData[share_system.INDEX_OTHER_DATA].get("state", 0) def addAppearCount(self, userId=None): """添加分享鱼出现的次数""" if userId: shareClass = RandomChest(userId) # 随机分享宝箱 appearCount = shareClass.shareData[share_system.INDEX_OTHER_DATA].get("appearCount", 0) + 1 shareClass.shareData[share_system.INDEX_OTHER_DATA]["appearCount"] = appearCount shareClass.shareData[share_system.INDEX_OTHER_DATA]["playTime"] = 0 shareClass.saveData() def _getFishGroupId(self): """获取鱼群Id""" shareFishConf = config.getShareFishConf(self.table.runConfig.fishPool) # 获取分享宝箱鱼配置 randInt = random.randint(1, 10000) for fish in shareFishConf["fishes"]: probb = fish["probb"] if probb[0] <= randInt <= probb[1]: fishType = fish["fishType"] allShareGroupIds = self.table.runConfig.allShareGroupIds groupId = random.choice(allShareGroupIds[fishType]) return groupId return None def _addShareFishGroup(self, groupId, userId=None): """添加分享宝箱鱼群""" if ftlog.is_debug(): ftlog.debug("_addShareFishGroup", groupId, userId) self.table.insertFishGroup(groupId, userId=userId, sendUserId=userId) self.addAppearCount(userId)
class FishGroup(object): """ 鱼群对象 """ def __init__(self, conf, enterTime, serverGroupId, startFishId, position=None, gameResolution=None, deadCallback=None): """ :param conf: 鱼阵配置文件 {"id": "autofill_11092_21_3", "fishes": [{"fishType": 11092, "enterTime": 0.0, "exitTime": 25.0}], "totalTime": 25.0} :param enterTime: 该鱼群入场时间(渔场运行后的第n秒) :param serverGroupId: 鱼群ID(每新增一个鱼群自增加1) :param startFishId: 该鱼群第一条鱼的鱼ID :param position: 指定出现位置 :param gameResolution: 召唤该鱼群的玩家的游戏分辨率 :param deadCallback: 鱼群死亡回调函数 """ self.position = position if position else [0, 0] self.gameResolution = gameResolution if gameResolution else [] self.enterTime = enterTime self.startFishId = startFishId # 鱼群文件名字 self.id = conf.get("id") # 鱼群自增ID self.serverGroupId = serverGroupId # 鱼群类型 self.type = self.id.split("_")[1] if self.id.startswith( "call_") else self.id.split("_")[0] # 鱼群存活时间 self.totalTime = conf.get("totalTime") # 鱼群中的所有鱼 self.fishes = conf.get("fishes") # 鱼群中鱼的数量 self.fishCount = len(self.fishes) # 该鱼群的出场时间 self.exitTime = self.enterTime + self.totalTime # 该鱼群最后一条鱼的鱼ID self.endFishId = startFishId + self.fishCount - 1 self.maxEnterTime = self._getMaxEnterTime() # 该鱼群是否已被清除 self.isClear = False # 鱼群被冰冻后延长的存活时间 self.addTime = 0 # Boss鱼群延迟出现时间 self.extendGroupTime = 0 # 鱼群死亡定时器 self.deadTimer = None # 鱼群死亡回调 self.deadCallback = deadCallback if self.deadCallback: self.deadTimer = FTLoopTimer(self.totalTime, 0, self.deadCallback, self) self.deadTimer.start() def clear(self): """ 清除定时器等数据 """ if self.deadTimer: self.deadTimer.cancel() self.deadTimer = None self.isClear = True def isExist(self, nowTableTime): """ 该鱼群在当前时刻是否存在 """ return self.enterTime <= nowTableTime <= self.exitTime + self.addTime def fishExist(self, nowTableTime, fishId): """ 该鱼群中是否存在某条鱼 """ fish = self.fishes[fishId - self.startFishId] enterTime = self.enterTime + fish["enterTime"] exitTime = self.enterTime + fish["exitTime"] + self.addTime return enterTime <= nowTableTime <= exitTime def isAlive(self, nowTableTime, table=None): """ 该鱼群是否存活(包含特殊鱼及已生成但即将出现的鱼群) """ # 客户端特殊处理的鱼群且鱼群中鱼的数量不多时,判断鱼群是否存活看其中鱼的存活状态 if table and self.type in SPECIAL_ALIVE_TYPE: for fId in xrange(self.startFishId, self.endFishId + 1): isOK = table.findFish(fId) if isOK: return isOK return False # 一般鱼群,判断鱼群是否存活看鱼群的整体退出时间,因为其中鱼的数量过多,避免循环查找 return nowTableTime < self.exitTime + self.addTime def isVisible(self, table, userId): """ 该鱼群对某玩家是否可见 """ # 新手任务期间玩家自己可见的鱼. if self.type == "share" or self.type == "newbie" or self.type == "coupon" \ or self.id.startswith("tuition_44499") or self.id.startswith("autofill_72025"): for fId in xrange(self.startFishId, self.endFishId + 1): if fId in table.fishMap: if table.fishMap[fId]["owner"] is None or table.fishMap[ fId]["owner"] == userId: sendUsersList = table.fishMap[fId].get("sendUsersList") if not sendUsersList or userId in sendUsersList: return True break return False return True def isCleared(self): """ 该鱼群是否已被清除 """ return self.isClear def _getMaxEnterTime(self): """ 获得该鱼群最后一条鱼在该鱼阵文件中的入场时间 """ fishEnterTimes = [] for fish in self.fishes: fishEnterTimes.append(fish.get("enterTime")) fishEnterTimes.sort() return fishEnterTimes[-1] def getNextGroupTime(self): """ 获得下个鱼群的入场时间 """ return round(self.maxEnterTime + self.enterTime, 2) def desc(self): """ 鱼群详情 """ info = [ str(self.id), "enter:", str(self.enterTime), "exit:", str(self.exitTime), "startfishId:", str(self.startFishId), "endFishId:", str(self.endFishId), "addTime:", str(self.addTime) ] info = " ".join(info) return info def adjust(self, addTime): """ 调整鱼群存活时间 """ self.addTime += addTime self.extendGroupTime += addTime if self.deadTimer: interval = self.deadTimer.getTimeOut() + self.addTime if interval > 0: self.deadTimer.reset(interval) def getFishExitTime(self, fishType): """ 获取指定一条鱼的离场时间 """ for fish in self.fishes: if fishType == fish["fishType"]: return fish["exitTime"] return 0
class BoxFishGroup(SuperBossFishGroup): """ 宝箱怪鱼阵 """ def __init__(self, table): super(BoxFishGroup, self).__init__(table) self._interval = 300 # 宝箱怪出生间隔. 600 5分钟 self._bBossFishType = 71201 # 宝箱儿子 self._mBossFishType = 71202 # 宝箱妈妈 self._fBossFishType = 71203 # 宝箱爸爸 self._startTS = 0 # 宝箱怪出现的时间戳. self._fBossAppearTS = 0 # 宝箱爸爸出现的最晚时间戳. self._isBossShowTimeStage = 0 # showtime是boss出现前30秒(stage=0x1000), bBoss(0x1), mBoss(0x10), fBoss(0x100). 暂停状态(-0x1) self._hasBorned = [] # 已经出生的宝箱boss self._initConfTimer = None # 初始化配置定时器 self._nextTimer = None # 下次填充鱼的时间戳 self._autofillTimer = {} # 自动填充的时间 self._clearTimer = None # 清理宝箱的定时器. self._group = {} # 渔群信息 self._initConf() def _initConf(self): if self._initConfTimer: self._initConfTimer.cancel() self._initConfTimer = None self.boxConf = self.table.room.roomConf.get("boxConf") self._cron = FTCron(self.boxConf["cronTime"]) self._interval = self._cron.getNextLater() if self._interval >= 0: self._setTimer() # 启动定时器 self._initConfTimer = FTLoopTimer(self._interval + 1, 0, self._initConf) self._initConfTimer.start() else: ftlog.error("BoxFishGroup initConf error", self._cron.getTimeList()) def _addBossShowTimeStage(self, val): """添加boss展示的阶段""" self._isBossShowTimeStage |= val def _removeBossShowTimeStage(self, val): """移除boss展示阶段""" self._isBossShowTimeStage &= ~val if ftlog.is_debug(): ftlog.debug("BoxFishGroup._removeBossShowTimeStage =", self.table.tableId, self._isBossShowTimeStage) def _clearData(self, isSendMsg=True, fishType=0, isEnd=0.0): """ boss出生前清理相关数据 """ self._isBossShowTimeStage = 0 self._hasBorned = [] for _timer in self._autofillTimer.values(): if _timer: _timer.cancel() _timer = None self._autofillTimer = {} if self._clearTimer: self._clearTimer.cancel() self._clearTimer = None # 清理鱼阵. for _group in self._group.values(): if _group and self.table.fishGroupSystem: self.table.deleteFishGroup(_group) self._group = {} if isEnd: self.addTideFishGroup(isEnd) if isSendMsg: msg = MsgPack() msg.setCmd("superboss_end") msg.setResult("gameId", config.FISH_GAMEID) msg.setResult("roomId", self.table.roomId) msg.setResult("tableId", self.table.tableId) msg.setResult("type", "box") # 宝箱 msg.setResult("fishType", fishType) # 鱼Id GameMsg.sendMsg(msg, self.table.getBroadcastUids()) def isAppear(self): """ boss即将出现或已经出现 """ if ftlog.is_debug(): ftlog.debug("BoxFishGroup", self.table.tableId, self._isBossShowTimeStage) return self._isBossShowTimeStage & 0x1000 > 0 or self._isBossShowTimeStage & 0x111 > 0 def _setTimer(self): """ 设置boss出现时的计时器 """ if self._nextTimer: self._nextTimer.cancel() self._nextTimer = None if self._interval >= 0: self._nextTimer = FTLoopTimer(self._interval, 0, self._addFishGroup) self._nextTimer.start() self.appear() FTLoopTimer(max(self._interval - self.boxConf["tipTime"], 0), 0, self._addBossShowTimeStage, 0x1000).start() # 提示的时间 def _addFishGroup(self): """ 添加boss鱼阵 """ self._clearData(False) # 渔场内人数不满足时不出生宝箱怪. if self.table.playersNum < self.table.room.roomConf[ "superBossMinSeatN"]: return self._startTS = int(time.time()) # 宝箱怪出现的时间 self._fBossAppearTS = self._startTS + 90 # 宝箱爸爸出现的时间 for fishType in [self._bBossFishType, self._mBossFishType]: self._addBoss(fishType) # 宝箱儿子 宝箱妈妈 # 超出boss存活时间后清理boss. if self.boxConf["maxAliveTime"] > 0: # 最大的存活时长 self._clearTimer = FTLoopTimer(self.boxConf["maxAliveTime"] + 2, 0, self._clearData, True, 0, 0.1) self._clearTimer.start() def _addBoss(self, fishType, isSysTimerCall=True): """ 添加宝箱boss """ if self._isBossShowTimeStage == -0x1: self._isBossShowTimeStage = 0 if self._autofillTimer.get(fishType): self._autofillTimer[fishType].cancel() self._autofillTimer[fishType] = None # 处理冰冻自动填充时机延后逻辑. if self._group.get( fishType) and not isSysTimerCall and self._group[ fishType].extendGroupTime > 0: self._autofillTimer[fishType] = FTLoopTimer( self._group[fishType].extendGroupTime, 0, self._addBoss, fishType, False) self._autofillTimer[fishType].start() self._group[fishType].extendGroupTime = 0 return # boss超出最大存在时间后不再出现. if int(time.time()) >= self._startTS + self.boxConf["maxAliveTime"]: if fishType == self._bBossFishType: self._removeBossShowTimeStage(0x1) elif fishType == self._mBossFishType: self._removeBossShowTimeStage(0x10) else: self._removeBossShowTimeStage(0x100) return self._group[fishType] = None # 使用出生路径. if fishType not in self._hasBorned: self._hasBorned.append(fishType) _bossGroupIds = self.table.runConfig.allSuperBossBornGroupIds[ fishType] elif self._isBossShowTimeStage & 0x11 != 0x11: # bBoss或mBoss只有一个存在,则使用加速鱼阵. _bossGroupIds = self.table.runConfig.allSuperBossFastMoveGroupIds.get( fishType) if not _bossGroupIds: _bossGroupIds = self.table.runConfig.allSuperBossGroupIds[ fishType] else: _bossGroupIds = self.table.runConfig.allSuperBossGroupIds[fishType] if _bossGroupIds: _bossGroupId = random.choice(_bossGroupIds) self._group[fishType] = self.table.insertFishGroup(_bossGroupId) if self._group[fishType]: self._autofillTimer[fishType] = FTLoopTimer( self._group[fishType].totalTime + 1, 0, self._addBoss, fishType, False) self._autofillTimer[fishType].start() if fishType == self._bBossFishType: self._addBossShowTimeStage(0x1) elif fishType == self._mBossFishType: self._addBossShowTimeStage(0x10) else: self._addBossShowTimeStage(0x100) return self._group[fishType] ftlog.error("superboss_fish_group.BoxFishGroup, error, tableId =", self.table.tableId, fishType, self._hasBorned) return def triggerCatchFishEvent(self, event): """ 处理捕获事件 """ _fishType = 0 isBoxBossCatched = False if self._bBossFishType in event.fishTypes and self._group.get( self._bBossFishType): if ftlog.is_debug(): ftlog.debug("superboss_fish_group.BoxFishGroup, tableId =", self.table.tableId, "ft =", self._bBossFishType, self._isBossShowTimeStage) isBoxBossCatched = True _fishType = self._bBossFishType self._group[self._bBossFishType] = None self._removeBossShowTimeStage(0x1) if self._mBossFishType in event.fishTypes and self._group.get( self._mBossFishType): if ftlog.is_debug(): ftlog.debug("superboss_fish_group.BoxFishGroup, tableId =", self.table.tableId, "ft =", self._mBossFishType, self._isBossShowTimeStage) isBoxBossCatched = True _fishType = self._mBossFishType self._group[self._mBossFishType] = None self._removeBossShowTimeStage(0x10) if isBoxBossCatched: if self._autofillTimer.get(_fishType): self._autofillTimer[_fishType].cancel() self._autofillTimer[_fishType] = None if isBoxBossCatched and self._isBossShowTimeStage == 0: # 捕获宝箱宝宝和宝箱妈妈后,如果时间充裕就出生宝箱爸爸. if int(time.time()) < self._fBossAppearTS: self._isBossShowTimeStage = -0x1 FTLoopTimer(self.boxConf["fDelayTime"], 0, self._addBoss, self._fBossFishType).start() # 宝箱爸爸 else: # 时间不够则结束boss状态. self._clearData(isSendMsg=True, fishType=_fishType, isEnd=5.0) if self._fBossFishType in event.fishTypes: if not self._group.get( self._fBossFishType): # 宝箱爸爸被捕获时可能刚好超时,所以此时就不要再爆炸了. return stageCount = 0 for catchMap in event.catch: fishInfo = self.table.fishMap[catchMap["fId"]] fishType = fishInfo["fishType"] if catchMap["reason"] == 0 and fishType == self._fBossFishType: stageCount = catchMap.get("stageCount") break self._group[self._fBossFishType] = None self._removeBossShowTimeStage(0x100) if self._autofillTimer.get(self._fBossFishType): self._autofillTimer[self._fBossFishType].cancel() self._autofillTimer[self._fBossFishType] = None if self._clearTimer: self._clearTimer.cancel() self._clearTimer = None if stageCount > 1: msg = MsgPack() msg.setCmd("superboss_explosion_info") # 爆炸信息 msg.setResult("gameId", config.FISH_GAMEID) msg.setResult("roomId", self.table.roomId) msg.setResult("tableId", self.table.tableId) explosionPos = range(1, 5) # 选择狂暴落点索引. [1,2,3,4] random.shuffle(explosionPos) explosionPos.insert(0, 0) explosionPos.extend(random.sample(explosionPos[:-1], 1)) msg.setResult("explosionPos", explosionPos[:stageCount]) GameMsg.sendMsg(msg, self.table.getBroadcastUids()) FTLoopTimer( stageCount * self.boxConf["stageTime"] + self.boxConf["endDelayTime"], 0, self._clearData, True, self._fBossFishType, self.boxConf["tideDelayTime"]).start() def addTideFishGroup(self, delayTime=0.1): """添加鱼潮""" if delayTime > 0: FTLoopTimer(delayTime, 0, self.leave).start() # 鱼潮延迟出来的时间 def dealEnterTable(self, userId): """ 玩家进入渔场时发送 """ # 当前阶段boss开始出现的时间戳. startTS = 0 if self._isBossShowTimeStage & 0x111 != 0: startTS = self._startTS msg = MsgPack() msg.setCmd("box_info") msg.setResult("gameId", config.FISH_GAMEID) msg.setResult("roomId", self.table.roomId) msg.setResult("tableId", self.table.tableId) msg.setResult("startTS", startTS) GameMsg.sendMsg(msg, userId)
class CouponFishGroup(object): """ 奖券鱼鱼群 """ def __init__(self, table): self.table = table self._lastUtilAppearTime = int(time.time()) # 上一次添加所有人可见红包奖券出现的事件 self.checkTimer = FTLoopTimer(10, -1, self._checkCondition) # 检查条件 self.checkTimer.start() self._clearUserCouponFishData() # 清理用户奖券数据 self._registerEvent() # 注册事件 def clearTimer(self): """清理定时器""" if self.checkTimer: self.checkTimer.cancel() self.checkTimer = None for player in self.table.players: if player and player.userId: self._clearPlayerTimer(player.userId) # 清理玩家定时器 def _clearUserCouponFishData(self): """ 初始化个人可见奖券鱼相关数据 """ self._playerCouponTimerDict = {} # 玩家奖券定时器 for player in self.table.players: if player and player.userId: self._clearPlayerTimer(player.userId) def _clearPlayerTimer(self, userId): """ 清除与player相关的定时器和鱼阵 """ timer = self._playerCouponTimerDict.get(userId) if timer: timer.cancel() self._playerCouponTimerDict.pop(userId) def _checkCondition(self): """ 定时器条件检查 """ self._checkUtilConditionNew() def _checkUtilConditionNew(self): """ 检查定时的奖券鱼 """ couponFishConf = config.getCouponFishConf( self.table.runConfig.fishPool) if not couponFishConf: return interval = time.time() - self._lastUtilAppearTime couponRange = couponFishConf.get("couponRange") if interval >= couponFishConf["maxSecond"]: if ftlog.is_debug(): ftlog.debug("_checkUtilConditionNew, interval =", interval, couponRange, self.table.tableId) randInt = random.randint(1, 10000) for fish in couponFishConf["fishes"]: probb = fish["probb"] if probb[0] <= randInt <= probb[1]: fishType = fish["fishType"] allCouponGroupIds = self.table.runConfig.allCouponGroupIds groupId = random.choice(allCouponGroupIds[fishType]) self._addUtilCouponFishGroupNew(groupId, couponRange) break def _addUtilCouponFishGroupNew(self, groupId, couponRange): """ 添加定时出生的奖券鱼 """ self._lastUtilAppearTime = time.time() if not couponRange: if ftlog.is_debug(): ftlog.debug("_addUtilCouponFishGroupNew, groupId =", groupId, "tableId =", self.table.tableId) self.table.insertFishGroup(groupId) return sendUserList = [] for player in self.table.players: if player and player.userId > 0: totalEntityAmount = gamedata.getGameAttr( player.userId, FISH_GAMEID, GameData.totalEntityAmount) totalEntityAmount = float( totalEntityAmount) if totalEntityAmount else 0 if couponRange[0] <= totalEntityAmount < couponRange[1]: sendUserList.append(player.userId) if ftlog.is_debug(): ftlog.debug("_addUtilCouponFishGroupNew, groupId =", groupId, "couponRange =", couponRange, "sendUserList =", sendUserList, "tableId =", self.table.tableId) if sendUserList: self.table.insertFishGroup(groupId, sendUserId=sendUserList) def _checkUserConditionNew(self, userId): """ 检查个人可见奖券鱼出现条件是否满足 """ userCouponFishConf = config.getUserCouponFishConf( self.table.runConfig.fishPool) groupId, interval, totalBullet = self._isAppearUserCouponFishNew( userId, userCouponFishConf) if groupId: timer = FTLoopTimer(interval, 0, self._addUserCouponFishGroupNew, groupId, userId, totalBullet) timer.start() self._playerCouponTimerDict[userId] = timer if ftlog.is_debug(): ftlog.debug("_checkUserConditionNew->userId =", userId, "groupId =", groupId, "interval =", interval, "totalBullet =", totalBullet, "tableId =", self.table.tableId) def _isAppearUserCouponFishNew(self, userId, userCouponFishConf): """ 个人奖券鱼是否出现 """ groupId = None interval = 0 totalBullet = 0 if not userCouponFishConf: return groupId, interval, totalBullet catchCountDict = gamedata.getGameAttrJson( userId, FISH_GAMEID, GameData.catchUserCouponFishCount, {}) catchCount = catchCountDict.get(str(self.table.runConfig.fishPool), 0) rechargeAmount = hallvip.userVipSystem.getUserVip(userId).vipExp // 10 totalEntityAmount = gamedata.getGameAttr(userId, FISH_GAMEID, GameData.totalEntityAmount) totalEntityAmount = float( totalEntityAmount) if totalEntityAmount else 0 for conf in userCouponFishConf: if catchCount >= conf["limitCount"]: continue section = conf["sections"] if ftlog.is_debug(): ftlog.debug("_isAppearUserCouponFishNew->tabId=", self.table.tableId, "userId =", userId, "groupId =", groupId, "section =", section) # 充值金额大于等于指定值,获得金额小于指定值 if len(section) == 3 and rechargeAmount >= section[0] and section[ 1] <= totalEntityAmount < section[2]: randInt = random.randint(1, 10000) for fish in conf["fishes"]: probb = fish["probb"] if probb[0] <= randInt <= probb[1]: fishType = fish["fishType"] allCouponGroupIds = self.table.runConfig.allCouponGroupIds groupId = random.choice(allCouponGroupIds[fishType]) interval = random.randint(conf["minSecond"], conf["maxSecond"]) totalBullet = conf["totalBullet"] break if ftlog.is_debug(): ftlog.debug("_isAppearUserCouponFishNew->tabId=", self.table.tableId, "userId =", userId, "groupId =", groupId, "catchCountDict =", catchCountDict, "rechargeAmount =", rechargeAmount, "totalEntityAmount =", totalEntityAmount, "interval =", interval, "totalBullet =", totalBullet) return groupId, interval, totalBullet def _addUserCouponFishGroupNew(self, groupId, userId, totalBullet): """ 添加个人可见的奖券鱼 """ player = self.table.getPlayer(userId) self._clearPlayerTimer(userId) if player: playerBullet = player.couponConsumeClip if playerBullet < totalBullet: timer = FTLoopTimer(10, 0, self._addUserCouponFishGroupNew, groupId, userId, totalBullet) timer.start() self._playerCouponTimerDict[userId] = timer if ftlog.is_debug(): ftlog.debug( "_addUserCouponFishGroupNew, check later, tableId =", self.table.tableId, "userId =", userId, "playerBullet =", playerBullet, "totalBullet =", totalBullet) else: player.resetCouponConsumeClip() if ftlog.is_debug(): ftlog.debug("_addUserCouponFishGroupNew, tabId =", self.table.tableId, "userId =", userId, "groupId =", groupId) self.table.insertFishGroup(groupId, userId=userId, sendUserId=userId) self._checkUserConditionNew(userId) def _dealEnterTable(self, event): """ 处理进入事件 """ if event.tableId == self.table.tableId and not event.reconnect: self._checkUserConditionNew(event.userId) def _dealLeaveTable(self, event): """ 处理离开事件 """ if event.tableId == self.table.tableId: self._clearPlayerTimer(event.userId) def _registerEvent(self): """ 注册监听事件 """ from newfish.game import TGFish TGFish.getEventBus().subscribe(EnterTableEvent, self._dealEnterTable) TGFish.getEventBus().subscribe(LeaveTableEvent, self._dealLeaveTable)
class QueenFishGroup(SuperBossFishGroup): """ 龙女王鱼阵 """ def __init__(self, table): super(QueenFishGroup, self).__init__(table) self._interval = 300 # boss出生间隔 self._maskFishType = 74215 # 女王保护罩 self._fishType = 74207 # 龙女王 self._idx = 0 # 阶段boss的索引 3、4、5、1、2 self._startTS = 0 # boss出现的时间戳 self._nextTimer = None # 下一个boss出生的定时器 self._isBossShowTimeStage = 0 # showtime是boss出现前30秒 有保护罩(stage=0x1000) 第一阶段(0x1), 受伤阶段(0x10), 没有保护罩(0x100) self._initConfTimer = None # 初始化配置定时器 self._autofillTimer = None # boss被捕获后是否自动填充 self._clearTimer = None # 清理鱼阵的定时器. self._modQuitTimer = None # 120s内没有打掉保护罩、龙女王退场 self._group = None # 鱼群对象 self._initConf() def _initConf(self): if self._initConfTimer: self._initConfTimer.cancel() self._initConfTimer = None self.queenConf = self.table.room.roomConf.get("queenConf") self._cron = FTCron(self.queenConf["cronTime"]) self._interval = self._cron.getNextLater() if self._interval > 0: self._setTimer() # 启动定时器 self._initConfTimer = FTLoopTimer(self._interval + 1, 0, self._initConf) self._initConfTimer.start() else: ftlog.error("QueenFishGroup initConf error", self._cron.getTimeList()) def _addBossShowTimeStage(self, val): """展示boss的状态""" self._isBossShowTimeStage |= val def _removeBossShowTimeStage(self, val): """删除boss状态""" self._isBossShowTimeStage &= ~val def _clearData(self, isSendMsg=True, fishType=0, isEnd=0.0): """ boss出生前清理相关数据 """ self._isBossShowTimeStage = 0 if self._autofillTimer: self._autofillTimer.cancel() self._autofillTimer = None if self._clearTimer: self._clearTimer.cancel() self._clearTimer = None if self._modQuitTimer: self._modQuitTimer.cancel() self._modQuitTimer = None # 清理鱼阵. if self._group and self.table.fishGroupSystem: self.table.deleteFishGroup(self._group) self._group = None if isEnd: self.addTideFishGroup(isEnd) if isSendMsg: msg = MsgPack() msg.setCmd("queen_end") msg.setResult("gameId", config.FISH_GAMEID) msg.setResult("roomId", self.table.roomId) msg.setResult("tableId", self.table.tableId) msg.setResult("type", "queen") msg.setResult("fishType", fishType) GameMsg.sendMsg(msg, self.table.getBroadcastUids()) def isAppear(self): """ boss即将出现或已经出现 """ return self._isBossShowTimeStage & 0x1000 > 0 or self._isBossShowTimeStage & 0x111 > 0 def _setTimer(self): """ 设置boss出现时的计时器 """ if self._nextTimer: self._nextTimer.cancel() self._nextTimer = None if self._interval >= 0: self._nextTimer = FTLoopTimer(self._interval, 0, self._addFishGroup) # 添加初始化鱼群 self._nextTimer.start() self.appear() FTLoopTimer(max(self._interval - self.queenConf["tipTime"], 0), 0, self._addBossShowTimeStage, 0x1000).start() # boss即将出现 1次 def _addFishGroup(self): """ 添加boss鱼阵 """ self._clearData(False) # 清理数据 self._startTS = int(time.time()) # boss出现的时间戳 self._addBoss() # 添加boss if self.queenConf["addHurtTime"] > 0: self._modQuitTimer = FTLoopTimer(self.queenConf["addHurtTime"], 0, self._clearData, True, self._maskFishType, 0.1) # 2分钟后没有打掉保护罩,自动退场 self._modQuitTimer.start() # 超出boss存活时间后清理boss. if self.queenConf["maxAliveTime"] > 0: self._clearTimer = FTLoopTimer(self.queenConf["maxAliveTime"], 0, self._clearData, True, self._fishType, 0.1) self._clearTimer.start() def _addBoss(self, isSysTimerCall=True, nextStage=0x1000): """ 添加宝箱boss """ if nextStage != self._isBossShowTimeStage: self._removeBossShowTimeStage(self._isBossShowTimeStage) self._addBossShowTimeStage(nextStage) stage = 0x1000 if self._isBossShowTimeStage == 0x1000: # 出生鱼阵 有保护罩. fishType = self._maskFishType _bossGroupIds = self.table.runConfig.allSuperBossBornGroupIds[ fishType] stage = 0x1 elif self._isBossShowTimeStage == 0x1: # 第一阶段 有保护罩. fishType = self._maskFishType _bossGroupIds = self.random_boss_groupid(fishType) if not isSysTimerCall: stage = 0x1 else: stage = 0x10 elif self._isBossShowTimeStage == 0x10: # 受伤鱼阵 无保护罩. fishType = self._fishType _bossGroupIds = self.table.runConfig.allSuperBossBornGroupIds[ fishType] stage = 0x100 elif self._isBossShowTimeStage == 0x100: # 第二阶段 无保护罩. fishType = self._fishType _bossGroupIds = self.random_boss_groupid(fishType) stage = 0x100 else: return # nowTime = int(time.time()) # boss超出最大存在时间后不再出现. # if nowTime >= self._startTS + self.queenConf["maxAliveTime"]: # self._removeBossShowTimeStage(self._isBossShowTimeStage) # return if self._autofillTimer: self._autofillTimer.cancel() self._autofillTimer = None # 处理冰冻自动填充时机延后逻辑. if self._group and not isSysTimerCall and self._group.extendGroupTime > 0: # 该鱼群冰冻延长的时间 self._autofillTimer = FTLoopTimer(self._group.extendGroupTime, 0, self._addBoss, False, stage) self._autofillTimer.start() self._group.extendGroupTime = 0 return _bossGroupId = random.choice(_bossGroupIds) if not _bossGroupId: return self._group = self.table.insertFishGroup(_bossGroupId) if self._group: # 龙女王的离场时间 interval = self._group.getFishExitTime(fishType) self._autofillTimer = FTLoopTimer(interval, 0, self._addBoss, False, stage) # 自动填充下一阶段的鱼阵 self._autofillTimer.start() if ftlog.is_debug(): ftlog.debug("QueenFishGroup _addBoss", self.table.tableId, _bossGroupId, stage, interval) else: ftlog.error("QueenFishGroup _addBoss error", _bossGroupId) def random_boss_groupid(self, fishType): """ 第一阶段和第二阶段随机一类鱼群 在再该类鱼群中随机一个鱼群 统计一类鱼1、2、3、4、5 出现顺序为3、4、5、1、2 4、5、1、2、3 """ groupMap = {} _bossGroupIds = self.table.runConfig.allSuperBossGroupIds[fishType] for group_name in _bossGroupIds: group = int(group_name.rsplit("_")[-2]) if group not in groupMap: groupMap[group] = [group_name] else: groupMap[group].append(group_name) if not self._idx: num = random.randint(1, len(groupMap.keys())) self._idx = num else: if self._idx + 1 in groupMap.keys(): self._idx += 1 else: self._idx = min(groupMap.keys()) _bossGroupIds = groupMap[self._idx] return _bossGroupIds def triggerCatchFishEvent(self, event): """ 处理捕获事件 """ if self._maskFishType in event.fishTypes and self._isBossShowTimeStage in [ 0x1000, 0x1 ] and self._group: if self._autofillTimer: # 女王保护罩 出生鱼阵 第一鱼阵 self._autofillTimer.cancel() self._autofillTimer = None if self._modQuitTimer: self._modQuitTimer.cancel() self._modQuitTimer = None self._addBoss(False, 0x10) return # boss被捕获时可能刚好超时, 所以此时就不要再爆炸了. if self._fishType in event.fishTypes and self._isBossShowTimeStage in [ 0x10, 0x100 ] and self._group: # 龙女王不带保护罩 第二阶段 if self._autofillTimer: # 女王保护罩 出生鱼阵 第一鱼阵 self._autofillTimer.cancel() self._autofillTimer = None if self._clearTimer: self._clearTimer.cancel() self._clearTimer = None stageCount = 0 for catchMap in event.catch: fishInfo = self.table.fishMap[catchMap["fId"]] fishType = fishInfo["fishType"] if catchMap["reason"] == 0 and fishType == self._fishType: stageCount = catchMap.get("stageCount") break FTLoopTimer( stageCount * self.queenConf["stageTime"] + self.queenConf["endDelayTime"], 0, self._clearData, True, self._fishType, self.queenConf["tideDelayTime"]).start() def addTideFishGroup(self, delayTime=0.1): """ 添加鱼潮 """ if delayTime > 0: FTLoopTimer(delayTime, 0, self.leave).start() def dealEnterTable(self, userId): """ 玩家进入渔场时发送 """ # 当前阶段boss开始出现的时间戳. startTS = 0 if self._isBossShowTimeStage & 0x111 != 0: startTS = self._startTS msg = MsgPack() msg.setCmd("queen_info") msg.setResult("gameId", config.FISH_GAMEID) msg.setResult("roomId", self.table.roomId) msg.setResult("tableId", self.table.tableId) msg.setResult("startTS", startTS) GameMsg.sendMsg(msg, userId)
class MainQuest(object): """ 渔场内主线任务 """ def __init__(self, player): self.player = player self.holdCoin = player.holdCoin self.refreshCoinTimer = None self.refreshTaskTimer = None self.currTask = getCurrTaskInfo(self.player.userId) self.allHoldCoinTask = config.getMainQuestTasksConfByType( self.player.clientId, QuestType.HoldCoin) self.isFinishHoldCoinTask = isFinishAllTask(self.player.userId, QuestType.HoldCoin) if not self.isFinishHoldCoinTask: # 刷新持有金币任务 self.refreshCoinTimer = FTLoopTimer(1, -1, self.refreshaHoldCoin) self.refreshCoinTimer.start() # 刷新任务状态 self.refreshTaskTimer = FTLoopTimer(60, -1, self.refreshTaskState) self.refreshTaskTimer.start() def clear(self): if self.refreshCoinTimer: self.refreshCoinTimer.cancel() self.refreshCoinTimer = None if self.refreshTaskTimer: self.refreshTaskTimer.cancel() self.refreshTaskTimer = None def dealEnterTable(self, isReconnect): """ 进入渔场 """ self.refreshTaskState() pushCurrTask(self.player.userId) def dealLeaveTable(self): """ 离开渔场 """ self.syncTaskData() self.clear() def syncTaskData(self): """ 同步任务数据 """ setQuestTypeData(self.player.userId, QuestType.HoldCoin, self.holdCoin, True) def refreshTaskState(self): """ 刷新任务状态 """ self.syncTaskData() self.currTask = getCurrTaskInfo(self.player.userId) self.isFinishHoldCoinTask = isFinishAllTask(self.player.userId, QuestType.HoldCoin) if self.isFinishHoldCoinTask: self.clear() def refreshaHoldCoin(self): """ 刷新持有金币任务数据 """ if self.holdCoin != self.player.holdCoin: self.holdCoin = self.player.holdCoin finishTask = None for taskConf in self.allHoldCoinTask: if self.holdCoin >= taskConf["num"]: finishTask = taskConf if finishTask: self.syncTaskData() self.allHoldCoinTask.remove(finishTask) if self.currTask and self.currTask[ "type"] == QuestType.HoldCoin and self.currTask[ "state"] == QuestState.Default: taskConf = config.getMainQuestTaskConf(self.player.clientId, self.currTask["taskId"]) self.currTask["progress"] = [ min(self.holdCoin, taskConf["num"]), taskConf["num"] ] pushCurrTask(self.player.userId, task=self.currTask) def getQuestRewardsInTable(self, taskId): """ 在渔场内领取主线任务奖励 """ getQuestRewards(self.player.userId, self.player.clientId, taskId) self.refreshTaskState()
class SportResult(object): '''赛果''' def __init__(self, sportlottery): self.sportlottery = sportlottery self.date = datetime.datetime.fromtimestamp( self.sportlottery.timestamp).strftime('%Y-%m-%d') interval = self.sportlottery.timestamp - int(time.time()) if interval > 0: FTLoopTimer(interval + (45 + 15 + 45 + 5) * 60, 0, self._startTimer).start() else: if interval + (45 + 15 + 45 + 5) * 60 <= 0: self._startTimer() else: FTLoopTimer(interval + (45 + 15 + 45 + 5) * 60, 0, self._startTimer).start() if ftlog.is_debug(): ftlog.debug('SportResult', 'sportObj=', self.sportlottery.toDict()) def _startTimer(self): self.timer = FTLoopTimer(60, -1, self._getHttp) self.timer.start() def _getHttp(self): if ftlog.is_debug(): ftlog.debug('SportResult', '_getHttp=', self.sportlottery.toDict()) contents = http7Mgetschedulebydate(self.date) if not contents or len(contents) == 0: return tag = 0 schedule = contents.get('Schedule') if not schedule or len(schedule) == 0: return for matchDict in schedule: match = matchDict.get('Id') if not match or len(match) < 4: continue if match[0] == int(self.sportlottery.matchId): if 'Score' in matchDict: self.sportlottery.score = matchDict['Score'] if self.sportlottery.score and len( self.sportlottery.score ) > 0 and self.sportlottery.status not in RESULTS: self.sportlottery.status = 4 self.sportlottery.save() if self.sportlottery.isResult: if self.timer: self.timer.cancel() tag = 1 break if self.sportlottery and tag == 1: self.sportlottery.clearSportResult()
class Sportlottery(object): '''体育竞猜一场比赛实例''' def __init__(self): # 比赛id self.matchId = None # 联赛id self.leagueId = None # 主队id self.homeTeamId = None # 客队id self.awayTeamId = None # 比赛时间戳 self.timestamp = None # 比赛状态 self.status = None # 定时器 self.timer = None # 比分 self.score = None # 欧盘指数 self.sportOdds = None # 赛果 self.sportResult = None def fromDict(self, d): self.matchId = d['matchId'] self.leagueId = d['leagueId'] self.homeTeamId = d['homeTeamId'] self.awayTeamId = d['awayTeamId'] self.timestamp = d['timestamp'] self.status = d.get('status', 0) # 未开始 self.score = d.get('score', [0, 0]) # 比分 self.odds = d.get('odds', ['0', '0', '0']) def toDict(self): return { 'matchId': self.matchId, 'leagueId': self.leagueId, 'homeTeamId': self.homeTeamId, 'awayTeamId': self.awayTeamId, 'timestamp': self.timestamp, 'status': self.status, 'score': self.score, 'odds': self.odds } def save(self): date = datetime.datetime.fromtimestamp( self.timestamp).strftime('%Y-%m-%d') daobase.executeMixCmd('hset', leagueDaykey % date, self.matchId, strutil.dumps(self.toDict())) if ftlog.is_debug(): ftlog.debug('Sportlottery save', 'date=', date, 'matchId=', self.matchId, 'toDict=', self.toDict()) def clearSportOdds(self): if self.sportOdds: del self.sportOdds self.sportOdds = None def clearSportResult(self): if self.sportResult: del self.sportResult self.sportResult = None def start(self): if self.isResult: return if ftlog.is_debug(): ftlog.debug('Sportlottery start', 'toDict=', self.toDict()) if self.odds == ['0', '0', '0']: self.sportOdds = SportOdds(self) self.sportResult = SportResult(self) interval = self.timestamp - int(time.time()) if interval > 0: FTLoopTimer(interval, 0, self._startTimer).start() else: self._startTimer() def _startTimer(self): self.timer = FTLoopTimer(5 * 60, -1, self._getHttpStatus) self.timer.start() @property def isResult(self): return self.status in RESULTS def _getHttpStatus(self): contents = http7Mgetlivedata() if ftlog.is_debug(): ftlog.debug('Sportlottery _getHttpStatus', 'toDict=', self.toDict()) if not contents or len(contents) == 0: ftlog.info('Sportlottery._getHttpStatus', 'http7Mgetlivedata contents empty', contents) return liveData = contents.get('LiveData') if not liveData or len(liveData) == 0: ftlog.info('Sportlottery._getHttpStatus', 'http7Mgetlivedata LiveData empty', liveData) return matchD = liveData.get(str(self.matchId)) if matchD: self.score = matchD.get('Score', [0, 0]) self.status = matchD.get('Status', 0) if self.status != 0: self.save() if self.status in RESULTS: if self.timer: self.timer.cancel() else: ftlog.warn('Sportlottery._getHttpStatus', 'liveData havenot matchId=', self.matchId, 'obj=', self) def __str__(self): return '%s:%s:%s:%s:%s' % (self.matchId, self.leagueId, self.homeTeamId, self.awayTeamId, self.timestamp) def __repr__(self): return self.__str__() def destructor(self): if self.timer: self.timer.cancel() ftlog.info('Sportlottery=', self)
class Tentacle(object): """ 触手 """ ST_IDLE = -1 ST_SWING = 0 ST_RETRACT = 1 ST_FINAL = 2 def __init__(self, table, octopus): self.table = table self.octopus = octopus self._state = None self._idleTimer = None self._swingTimer = None self._retractTimer = None self.clear() @property def state(self): return self._state def clear(self): if self._idleTimer: self._idleTimer.cancel() self._idleTimer = None if self._swingTimer: self._swingTimer.cancel() self._swingTimer = None if self._retractTimer: self._retractTimer.cancel() self._retractTimer = None self._state = None self.posId = 0 self.fishId = 0 self.fishType = 0 self.delayTime = 0 self.frozenTime = 0 def init(self, posId, fishType, delayTime): """初始化章鱼boss的触手""" self.tentacleConf = self.table.room.roomConf["tentacleConf"] self.posId = posId self.fishType = fishType self.delayTime = delayTime self.idleTime = self.calcIdleTime() self.swingTime = self.calcSwingTime() self.retractTime = self.calcRetractTime() self.finalTime = self.calcFinalTime() self.createTentacleFish() if self.fishId > 0: if self.delayTime > 0: self._doIdle() else: self._doSwing() def _doIdle(self): """ 空闲等待 """ self._state = Tentacle.ST_IDLE stageTime = self.getCurrentStateStageTime() interval = stageTime[1] - stageTime[0] self._idleTimer = FTLoopTimer(interval, 0, self._doSwing) self._idleTimer.start() def _doSwing(self): """ 摆动触手 """ self._state = Tentacle.ST_SWING if self.delayTime > 0: self.octopus.syncTentacleState(self) stageTime = self.getCurrentStateStageTime() interval = stageTime[1] - stageTime[0] self._swingTimer = FTLoopTimer(interval, 0, self._doRetract) self._swingTimer.start() def _doRetract(self): """ 触手到时间正常收回 """ if self._state == Tentacle.ST_SWING: self._state = Tentacle.ST_RETRACT self.octopus.syncTentacleState(self) stageTime = self.getCurrentStateStageTime() interval = stageTime[1] - stageTime[0] self._retractTimer = FTLoopTimer(interval, 0, self._doFinal) self._retractTimer.start() def _doFinal(self, isCatch=False): """ 触手已收回 """ self._retractTimer and self._retractTimer.cancel() if self.octopus.state == Octopus.ST_APPEARED and isCatch is False: # 正常收回,增加剩余可出现触手数量 self.octopus.surplusTentaclesCount[str(self.fishType)] += 1 self.disappear() def disappear(self): """ 触手消失 """ self._state = Tentacle.ST_FINAL self.table.setFishDied(self.fishId) posId, fishType, delayTime = self.octopus.generateNewTentacleConf( self.posId) self.clear() if self.octopus.state == Octopus.ST_APPEARED: if fishType and posId: if ftlog.is_debug(): ftlog.debug("disappear init", self.table.tableId, posId, fishType, delayTime) self.init(posId, fishType, delayTime) def catch(self): """ 摆动状态下触手被捕获 """ if self._state == Tentacle.ST_SWING: self._state = Tentacle.ST_RETRACT self._swingTimer and self._swingTimer.cancel() self._retractTimer = FTLoopTimer(self.tentacleConf["retractTime"], 0, self._doFinal, isCatch=True) self._retractTimer.start() def calcIdleTime(self): """ 计算空闲状态开始时间戳 """ return pktimestamp.getCurrentTimestamp() + 1 def calcSwingTime(self): """ 计算摆动状态开始时间戳 """ return self.idleTime + self.delayTime def calcRetractTime(self): """ 计算收回状态开始时间戳 """ return self.swingTime + random.randint( *self.tentacleConf["swingTimeRange"]) + self.frozenTime def calcFinalTime(self): """ 计算结束状态开始时间戳 """ return self.retractTime + self.tentacleConf["retractTime"] def getCurrentStateStageTime(self): """ 获取当前状态开始结束时间 """ stateTime = { Tentacle.ST_IDLE: self.idleTime, Tentacle.ST_SWING: self.swingTime, Tentacle.ST_RETRACT: self.retractTime, Tentacle.ST_FINAL: self.finalTime } return stateTime[self._state], stateTime[self._state + 1] def createTentacleFish(self): """ 创建触手对应的鱼阵 """ groupIds = self.table.runConfig.allSuperBossGroupIds[self.fishType] if groupIds: groupIds = random.choice(groupIds) group = self.table.insertFishGroup(groupIds) self.fishId = group.startFishId self.octopus.surplusTentaclesCount[str(self.fishType)] -= 1 def frozenTentacleFish(self, frozenTime): """ 触手被冻住 """ self.frozenTime += frozenTime # 刷新触手收回动画开始和结束时间 self.retractTime = self.calcRetractTime() self.finalTime = self.calcFinalTime() stageTime = self.getCurrentStateStageTime() interval = stageTime[1] - pktimestamp.getCurrentTimestamp() if ftlog.is_debug(): ftlog.debug("frozenTentacleFish", self.frozenTime, self.retractTime, interval) self._swingTimer and self._swingTimer.cancel() self._swingTimer = FTLoopTimer(interval, 0, self._doRetract) self._swingTimer.start() def toDict(self): if Tentacle.ST_IDLE < self._state < Tentacle.ST_FINAL: return { "posId": self.posId, "fishId": self.fishId, "fishType": self.fishType, "state": self.state, "progress": self.getCurrentStateStageTime() } return {}
class Heartbeat(object): ST_IDLE = 0 ST_START = 1 ST_STOP = 2 def __init__(self, target, interval): self._target = target self._state = Heartbeat.ST_IDLE self._count = 0 self._postTaskList = [] self._timer = None self._interval = interval self._logger = Logger() self._init = False def start(self): assert (self._state == Heartbeat.ST_IDLE) self._state = Heartbeat.ST_START self._timer = FTLoopTimer(0, 0, self._onInit) self._timer.start() def stop(self): if self._state != Heartbeat.ST_STOP: self._state = Heartbeat.ST_STOP if self._timer: self._timer.cancel() self._timer = None @property def count(self): return self._count def postCall(self, func, *args, **kwargs): self.postTask(functools.partial(func, *args, **kwargs)) def postTask(self, task): if self._state != Heartbeat.ST_STOP: self._postTaskList.append(task) if self._init and self._timer: self._timer.cancel() self._timer = FTLoopTimer(0, 0, self._onTimeout) self._timer.start() def _onInit(self): try: self._timer = None interval = self._target.onInit() if interval: self._interval = interval self._scheduleTimer() except: self._logger.error("Heartbeat._onInit") def _onTimeout(self): try: self._timer = None self._count += 1 self._processPostTaskList() interval = self._target.onHeartbeat() if interval is not None: self._interval = interval except: self._interval = 1 self._logger.error("Heartbeat._onTimeout") self._scheduleTimer() def _scheduleTimer(self): if self._state == Heartbeat.ST_START: interval = 0 if self._postTaskList else self._interval self._timer = FTLoopTimer(interval, 0, self._onTimeout) self._timer.start() def _processPostTaskList(self): taskList = self._postTaskList self._postTaskList = [] for task in taskList: try: task() except: self._logger.error("task=", task)
class AutofillFishGroup(object): """ 千炮模式自动填充鱼群 """ def __init__(self, table): self.table = table # 自动填充鱼配置 self.autofillFishConf = {} # 各鱼种类别下鱼组index self._categoryGroupConf = {} # 各鱼种类别定时器 self._checkCategoryTimerList = [] # 各鱼种类别下的鱼群定时器 self._checkShoalTimerList = [] # 刷新分组配置定时器 self._refreshGroupConfTimer = None self.startDefaultAutofillFish() # 大奖赛间隔5分钟刷新分组配置 if self.table.typeName == config.FISH_GRAND_PRIX: self._refreshGroupConfTimer = FTLoopTimer(300, -1, self.refreshCategoryGroupConf) self._refreshGroupConfTimer.start() def clearTimer(self): """ 清理所有定时器 """ self.clearCategoryTimer() self.clearShoalTimer() if self._refreshGroupConfTimer: self._refreshGroupConfTimer.cancel() self._refreshGroupConfTimer = None if ftlog.is_debug(): ftlog.debug("AutofillFishGroup clearTimer", self.table.tableId) def clearCategoryTimer(self): """ 清理鱼种类别定时器 """ for _timer in self._checkCategoryTimerList: if _timer: _timer.cancel() _timer = None self._checkCategoryTimerList = [] def clearShoalTimer(self): """ 清理鱼种类别下的鱼群定时器 """ for _timer in self._checkShoalTimerList: if _timer: _timer.cancel() _timer = None self._checkShoalTimerList = [] def startDefaultAutofillFish(self): """ 默认状态下的自动填充鱼 """ self.defaultConf = config.getAutofillFishConf_m("default", self.table.runConfig.fishPool) if self.defaultConf: self._generalCategoryGroupConf(self.defaultConf) self._generalCategoryTimer() self._generalShoalTimer() def startSuperBossAutofillFish(self): """ 超级Boss期间的自动填充鱼 """ self.superBossConf = config.getAutofillFishConf_m("superBoss", self.table.runConfig.fishPool) if self.superBossConf: self._generalCategoryGroupConf(self.superBossConf) self._generalCategoryTimer() self._generalShoalTimer() def refreshCategoryGroupConf(self): """ 刷新各类鱼的分组数据(重新随机分组) """ self._generalCategoryGroupConf() def _generalCategoryGroupConf(self, autofillFishConf=None): """ 生成并记录各类鱼的分组数据 """ self.autofillFishConf = autofillFishConf or self.autofillFishConf for categoryId, categoryConf in self.autofillFishConf.iteritems(): self._categoryGroupConf[categoryId] = random.choice(categoryConf["groups"]) if ftlog.is_debug(): ftlog.debug("_generalCategoryGroupConf", self.table.tableId, self._categoryGroupConf) def _generalCategoryTimer(self): """ 生成并存储各类鱼的定时器 """ self.clearCategoryTimer() for categoryId, categoryConf in self.autofillFishConf.iteritems(): interval = categoryConf["cSupplyInterval"] checkTimer = FTLoopTimer(interval, -1, self._checkCategoryAutoFillFish, categoryId) checkTimer.start() self._checkCategoryTimerList.append(checkTimer) def _checkCategoryAutoFillFish(self, categoryId): """ 检测该类鱼是否需要填充鱼 """ if self.table.hasTideFishGroup(): # 当前渔场存在鱼潮 return group = self._categoryGroupConf[categoryId] groupType = group["groupType"] if groupType == 1: for fishConf in group["fishes"]: fillCount, totalCount = self._getAutoFillCount([fishConf]) self._addAutoFillFishGroup(categoryId, fishConf, fillCount, totalCount) elif groupType == 2: fillCount, totalCount = self._getAutoFillCount(group["fishes"]) for _ in xrange(fillCount): fishConf = util.getOneResultByWeight(group["fishes"]) self._addAutoFillFishGroup(categoryId, fishConf, 1, totalCount) def _getAutoFillCount(self, fishConfList): """ 统计某类鱼的存活数量,再计算某条鱼所需填充数量 @return: 需要填充数量, 该类鱼存活数量 """ aliveCount = 0 fishConf = None for fishConf in fishConfList: aliveCount += self.table.fishCountMap.get(fishConf["fishType"], 0) if aliveCount <= fishConf["minCount"]: randInt = random.randint(fishConf["minCount"], fishConf["maxCount"]) return int(math.ceil(float(randInt - aliveCount) / max(fishConf["fishCount"], 1))), aliveCount return 0, aliveCount def _addAutoFillFishGroup(self, categoryId, fishConf, fillCount, aliveCount): """ 添加填充鱼 """ if fillCount > 0: if fishConf["fishType"] not in self.table.runConfig.allAutofillGroupIds: ftlog.error("_addAutoFillFishGroup error", self.table.tableId, fishConf["fishType"]) return if ftlog.is_debug(): ftlog.debug("_addAutoFillFishGroup tableId =", self.table.tableId, "categoryId =", categoryId, "fishType =", fishConf["fishType"], "aliveCount =", aliveCount, "fillCount =", fillCount, "maxCount =", fishConf["maxCount"]) autofillGroupIds = self.table.runConfig.allAutofillGroupIds[fishConf["fishType"]] if autofillGroupIds: groupNames = random.sample(autofillGroupIds, min(len(autofillGroupIds), fillCount)) groupNames and self.table.insertFishGroup(groupNames) def _generalShoalTimer(self): """ 生成并存储各类鱼的鱼群定时器 """ self.clearShoalTimer() for categoryId, categoryConf in self.autofillFishConf.iteritems(): interval = categoryConf["sSupplyInterval"] if interval > 0: checkTimer = FTLoopTimer(interval, -1, self._checkAutoFillFishShoal, categoryId) checkTimer.start() self._checkShoalTimerList.append(checkTimer) def _checkAutoFillFishShoal(self, categoryId): """ 检测该类鱼的鱼群是否需要填充 """ if self.table.hasTideFishGroup(): # 当前渔场存在鱼潮 return group = self._categoryGroupConf[categoryId] fishConf = random.choice(group["fishes"]) self._addAutoFillFishShoal(fishConf) def _addAutoFillFishShoal(self, fishConf): """ 添加填充鱼群 """ autofillGroupIds = self.table.runConfig.allAutofillShoalGroupIds[fishConf["fishType"]] if autofillGroupIds: groupNames = random.sample(autofillGroupIds, 1) groupNames and self.table.insertFishGroup(groupNames)
class FishGrandPrixPlayer(FishMultiplePlayer): def _loadUserData(self): super(FishGrandPrixPlayer, self)._loadUserData() # 捕鱼积分 self.grandPrixFishPoint = weakdata.getDayFishData( self.userId, WeakData.grandPrix_fishPoint, 0) # 大奖赛剩余开火次数 self.grandPrixFireCount = weakdata.getDayFishData( self.userId, WeakData.grandPrix_fireCount, 0) # 大奖赛剩余技能使用次数 self.grandPrixUseSkillTimes = weakdata.getDayFishData( self.userId, WeakData.grandPrix_useSkillTimes, []) # 大奖赛目标鱼捕获数量 self.grandPrixTargetFish = weakdata.getDayFishData( self.userId, WeakData.grandPrix_targetFish, {}) # 大奖赛火炮等级和倍率 # self.grandPrixLevelFpMultiple = weakdata.getDayFishData(self.userId, WeakData.grandPrix_levelFpMultiple) # 大奖赛开始的时间戳 self.grandPrixStartTS = weakdata.getDayFishData( self.userId, WeakData.grandPrix_startTS, 0) # 大奖赛结束定时器 self.grandPrixEndTimer = None # 大奖赛提示定时器 self.grandPrixTipTimer = None # 大奖赛阶段奖励 self.grandPrixGetPointsInfo = weakdata.getDayFishData( self.userId, WeakData.grandPrix_getPointsInfo, []) self._freeTimes = weakdata.getDayFishData(self.userId, WeakData.grandPrix_freeTimes, 0) self.multipleList = [] # 10、50、200、500 for v in gdata.roomIdDefineMap().values(): roomConf = v.configure if roomConf.get("typeName") not in [config.FISH_FRIEND]: continue self.multipleList.append(roomConf.get("multiple", 1)) self.multipleList.sort() self._rankListCache = [] # 超越玩家的集合 self._surpassUser = {} self.grandPrixSurpassCount = weakdata.getDayFishData( self.userId, WeakData.grandPrix_surpassCount, 0) # 大奖赛超越自己次数 self.bestPoint = weakdata.getDayFishData(self.userId, WeakData.grandPrix_point, 0) self.inGameTimes = 0 # 游戏时长(分钟) def _incrGameTimer(self): """增加游戏时长""" if self.userId <= 0: return super(FishGrandPrixPlayer, self)._incrGameTimer() self.inGameTimes += 1 def _checkSkillCondition(self, skillId, select, skillType=0): """ 检测技能使用条件 """ if self.isGrandPrixMode() and select: # 大奖赛模式限制技能槽的使用次数 for idx, val in enumerate(self.grandPrixUseSkillTimes): if val.get("skillId") == skillId and val.get("skillType", 0) == skillType: if val.get("count") <= 0: return 7 break return super(FishGrandPrixPlayer, self)._checkSkillCondition(skillId, select, skillType) def addFire(self, bulletId, wpId, sendTimestamp, fpMultiple, gunMultiple=1, gunX=1, skill=None, power=None, clientFire=True, targetPos=None, fishType=None, costChip=0, superBullet=None): """添加开火信息""" super(FishGrandPrixPlayer, self).addFire(bulletId, wpId, sendTimestamp, fpMultiple, gunMultiple, gunX, skill, power, clientFire, targetPos, fishType, costChip, superBullet) if clientFire and skill is None and self.isGrandPrixMode(): self.grandPrixFireCount -= 1 # 开火次数减少 if self.grandPrixFireCount == 0: # 结束比赛 self.endGrandPrix() def _refreshSkillSlots(self, skillType=0): """ 刷新技能数据 安装技能槽 """ if skillType == 0: self.skillSlots = {} if self.grandPrixUseSkillTimes: for val in self.grandPrixUseSkillTimes: if isinstance(val, dict) and val.get("skillId"): if val.get("skillType", 0) == skillType: if skillType == 0: self.skillSlots[val["skillId"]] = [ val["state"], val["star"], val["grade"] ] else: super(FishGrandPrixPlayer, self)._refreshSkillSlots(skillType) def clearTimer(self): """清理提示和结束的定时器""" super(FishGrandPrixPlayer, self).clearTimer() if self.grandPrixEndTimer: self.grandPrixEndTimer.cancel() self.grandPrixEndTimer = None if self.grandPrixTipTimer: self.grandPrixTipTimer.cancel() self.grandPrixTipTimer = None if self.inGameTimes: bireport.reportGameEvent("BI_NFISH_GRAND_PRIX_INGAMETIMES", self.userId, FISH_GAMEID, 0, 0, self.grandPrixStartTS, self.inGameTimes, 0, 0, [], util.getClientId(self.userId)) def checkCanFire(self, fPos, wpId, bulletId, skillId, skillType): """ 检测玩家是否可以开火 """ canFire, reason, clip, costBullet, extends, skill = \ super(FishGrandPrixPlayer, self).checkCanFire(fPos, wpId, bulletId, skillId, skillType) if canFire and self.isGrandPrixMode() and self.grandPrixFireCount <= 0: canFire, reason = False, 8 return canFire, reason, clip, costBullet, extends, skill def sendFireMsg(self, userId, seatId, extends, params): """ 发送开火确认消息 """ fPos = params.get("fPos") wpId = params.get("wpId") bulletId = params.get("bulletId") skillId = params.get("skillId") timestamp = params.get("timestamp") canFire = params.get("canFire") reason = params.get("reason") clip = params.get("clip") skillType = params.get("skillType", 0) lockFId = params.get("lockFId", 0) fPosx, fPosy = fPos retMsg = MsgPack() retMsg.setCmd("fire") retMsg.setResult("gameId", FISH_GAMEID) retMsg.setResult("userId", userId) retMsg.setResult("wpId", wpId) retMsg.setResult("bulletId", bulletId) retMsg.setResult("skillId", skillId) retMsg.setResult("skillType", skillType) retMsg.setResult("extends", extends) retMsg.setResult("timestamp", timestamp) retMsg.setResult("reason", reason) retMsg.setResult("grandPrixFireCount", self.grandPrixFireCount) # 大奖赛剩余开火次数 retMsg.setResult("clip", clip) retMsg.setResult("lockFId", lockFId) superBullet = self.getFire(bulletId).get( "superBullet", {}) # self.isSuperBullet(bulletId) retMsg.setResult("superBullet", 1 if superBullet else 0) # 测试代码 GameMsg.sendMsg(retMsg, userId) if canFire: retMsg.setResult("fPosx", fPosx) retMsg.setResult("fPosy", fPosy) retMsg.setResult("seatId", seatId) GameMsg.sendMsg(retMsg, self.table.getBroadcastUids(userId)) def saveUserData(self): """保存用户数据""" super(FishGrandPrixPlayer, self).saveUserData() self.saveGrandPrixPoint() # 保存大奖赛积分 def getTargetFishs(self): """ 返回目标鱼(魔术炮技能召唤使用) """ fishes = super(FishGrandPrixPlayer, self).getTargetFishs() targetFish = [ int(ft) for ft, val in self.grandPrixTargetFish.iteritems() if val[0] < val[1] ] # 0 < 5目标鱼数量 if targetFish: fishes.extend(targetFish) return fishes def getMatchingFpMultiple(self, fpMultiple): """ 获取玩家渔场倍率对应的基础倍率 """ multiple = self.table.runConfig.multiple for mul in self.multipleList: if fpMultiple >= mul: multiple = mul return multiple def isGrandPrixMode(self): """ 大奖赛比赛模式 """ return self.grandPrixStartTS > 0 def _calcuCatchFishGrandPrixPoint(self, fishPoint, gunX): """ 计算捕鱼积分 炮倍和vip的加成 """ if ftlog.is_debug(): ftlog.debug('calcuCatchFishGrandPrixPoint', fishPoint, gunX) vipAddition = config.getVipConf(self.vipLevel).get( "grandPrixAddition", 0.) gunXAddition = self.getGunXAddition(gunX) if ftlog.is_debug(): ftlog.debug('calcuCatchFishGrandPrixPoint1', vipAddition, gunXAddition) point = fishPoint * 100 points = point * (1 + vipAddition) * (1 + gunXAddition) return int(points) def getGunXAddition(self, gunX): """ 根据开火时候[炮倍 * 炮(单倍率|双倍率)]确定 加成值 """ gunMInfo = config.getGrandPrixConf("gunMultiAddition") for info in gunMInfo: if info["rangeList"][0] <= gunX <= info["rangeList"][1]: return info["addition"] return 0 def saveGrandPrixPoint(self): """ 保存大奖赛积分 """ if not self.isGrandPrixMode(): return 0, 0 grandPrixFinalPoint = self.grandPrixFishPoint # 计入排行榜 if grandPrixFinalPoint: ranking_system.refreshGrandPrixPoint(self.userId, grandPrixFinalPoint) # 保存大奖赛数据 self._saveGrandPrixData() return int(grandPrixFinalPoint) # 最后的积分 def cancelUsingSkills(self): """ 取消处于使用中的技能 """ if not self.usingSkill: # 有之前技能记录 return lastSkillId = self.usingSkill[-1].get("skillId") lastSkillType = self.usingSkill[-1].get("skillType", 0) lastSkill = self.getSkill(lastSkillId, lastSkillType) if not lastSkill: return if lastSkill.state == 1: lastSkill.use(0) else: self.removeUsingSkill(lastSkillId, lastSkillType) orgState = lastSkill.state lastSkill.state = 0 self.table.broadcastSkillUse(lastSkill, 0, self.userId, orgState) # 广播选中/取消技能消息 self.table.broadcastGunChange(self) # 广播玩家现在的火炮等级 def unloadSkills(self): """ 下载所有技能 """ for _skillId in self.skills.keys(): _skill = self.getSkill(_skillId, 0) if not _skill: continue _skill.clear() del _skill def startGrandPrix(self): """ 大奖赛开始 grandPrixStartTS=0 报名大奖赛/ grandPrixStartTS > 0 直接进入渔场 """ curTime = int(time.time()) dayStartTimestamp = util.getDayStartTimestamp(curTime) remainGrandPrixTimeSeconds = util.timeStrToInt( config.getGrandPrixConf("openTimeRange")[1]) - ( curTime - dayStartTimestamp) # 大奖赛剩余时间 # 当局进入大奖赛 if self.grandPrixStartTS == 0: event = JoinGrandPrixEvent(self.userId, FISH_GAMEID, self.table.bigRoomId) # 参加大奖赛事件 TGFish.getEventBus().publishEvent(event) # 距离大奖赛结束不足10秒不可参赛 if not grand_prix.isGrandPrixOpenTime( ) or remainGrandPrixTimeSeconds < 10: code = SignupCode.SC_NOT_OPEN elif config.getVipConf(self.vipLevel).get( "grandPrixFreeTimes", 0) > self._freeTimes: # 用免费次数报名 self._freeTimes = weakdata.incrDayFishData( self.userId, WeakData.grandPrix_freeTimes, 1) code = SignupCode.SC_SUCC else: # 扣除报名费 fee = config.getGrandPrixConf("fee")[0] _consume = [{ "name": fee.get("name"), "count": fee.get("count") }] _ret = util.consumeItems(self.userId, _consume, "ITEM_USE", self.table.roomId) if _ret: code = SignupCode.SC_SUCC else: code = SignupCode.SC_FEE_NOT_ENOUGH if code == SignupCode.SC_SUCC: # 选择目标鱼 for _val in config.getGrandPrixConf( "group").values(): # 1、2、3个组 idx = random.randint(0, len(_val) - 1) # 一组鱼 _cnt = config.getGrandPrixConf("target").get( str(_val[idx]), {}).get("count", 999) # 某一种鱼 捕获数量 _point = config.getGrandPrixConf("target").get( str(_val[idx]), {}).get("point", 0) # 某一种鱼 获得的积分 self.grandPrixTargetFish[str( _val[idx])] = [0, _cnt, _point] # 备份技能数据. self.grandPrixUseSkillTimes = [] for i in range(skill_system.MAX_INSTALL_NUM - 1): self.grandPrixUseSkillTimes.append({ "skillId": 0, "state": 0, "star": 0, "grade": 0, "count": config.getGrandPrixConf("fireCount")[1], # 技能使用次数3 "skillType": 0 if i < skill_system.MAX_INSTALL_NUM else 1 # 0主技能 1辅助技能 }) for idx, _skillId in enumerate(self.skillSlots): _skill = self.getSkill(_skillId, 0) self.grandPrixUseSkillTimes[idx]["skillId"] = _skillId self.grandPrixUseSkillTimes[idx][ "state"] = _skill.skillState self.grandPrixUseSkillTimes[idx]["star"] = _skill.skillStar self.grandPrixUseSkillTimes[idx][ "grade"] = _skill.skillGrade if self.inGameTimes: bireport.reportGameEvent("BI_NFISH_GRAND_PRIX_INGAMETIMES", self.userId, FISH_GAMEID, 0, 0, self.grandPrixStartTS, self.inGameTimes, 0, 0, [], util.getClientId(self.userId)) self.inGameTimes = 0 self.grandPrixFishPoint = 0 self.grandPrixSurpassCount = 0 self.grandPrixStartTS = curTime # 大奖赛开始的时间戳 self.grandPrixFireCount = config.getGrandPrixConf( "fireCount")[0] self._saveGrandPrixData() # 保存大奖赛数据 else: if not grand_prix.isGrandPrixOpenTime(): # 现在不可参赛 code = SignupCode.SC_NOT_OPEN elif not self.isGrandPrixMode(): code = SignupCode.SC_SUCC else: code = SignupCode.SC_UNFINISH if code in [SignupCode.SC_SUCC, SignupCode.SC_UNFINISH]: interval = max(0.1, remainGrandPrixTimeSeconds) if self.grandPrixFireCount == 0: # 3秒之后结束大奖赛 interval = 0.1 if self.grandPrixEndTimer: self.grandPrixEndTimer.cancel() self.grandPrixEndTimer = None self.grandPrixEndTimer = FTLoopTimer(interval, 0, self.endGrandPrix) # 启动结束定时器 self.grandPrixEndTimer.start() # 取消处于使用中的技能,以免干扰技能使用次数计数 if self.offline == 0: # 玩家在线 self.cancelUsingSkills() self.unloadSkills() self.loadAllSkillData() self.syncSkillSlots() elif code == SignupCode.SC_NOT_OPEN: # 没开启 self._resetGrandPrixData() # 重置大奖赛相关数据 self._getSurpassTarget() # 获取要超越的玩家数据 mo = MsgPack() mo.setCmd("start_grand_prix") mo.setResult("gameId", FISH_GAMEID) mo.setResult("userId", self.userId) mo.setResult("seatId", self.seatId) mo.setResult("fireCount", self.grandPrixFireCount) mo.setResult("fishPoint", self.grandPrixFishPoint) mo.setResult("targetFish", self.grandPrixTargetFish) mo.setResult( "useSkillTimes", { val.get("skillId", 0): val.get("count", 0) for val in self.grandPrixUseSkillTimes }) mo.setResult("pointsInfo", grand_prix.getPointInfo( self.userId)) # 奖励积分 道具Id、道具数量、是否领取了奖励0|1 mo.setResult("todayMaxPoints", weakdata.getDayFishData(self.userId, WeakData.grandPrix_point, 0)) # 今日最高积分 GameMsg.sendMsg(mo, self.userId) def endGrandPrix(self): """ 大奖赛结束 """ if self.userId == 0: return if self.grandPrixEndTimer: self.grandPrixEndTimer.cancel() self.grandPrixEndTimer = None if not self.isGrandPrixMode(): return grandPrixFinalPoint = self.saveGrandPrixPoint() # 完成大奖赛事件 event = FinishGrandPrixEvent(self.userId, FISH_GAMEID, self.table.bigRoomId, grandPrixFinalPoint) TGFish.getEventBus().publishEvent(event) bireport.reportGameEvent("BI_NFISH_GRAND_PRIX_END", self.userId, FISH_GAMEID, 0, 0, grandPrixFinalPoint, 0, 0, 0, [], util.getClientId(self.userId)) if self.inGameTimes: bireport.reportGameEvent("BI_NFISH_GRAND_PRIX_INGAMETIMES", self.userId, FISH_GAMEID, 0, 0, self.grandPrixStartTS, self.inGameTimes, 0, 0, [], util.getClientId(self.userId)) self.inGameTimes = 0 self.cancelUsingSkills() # 恢复技能数据 取消处于使用中的技能 self.unloadSkills() # 下载所有技能 self._resetGrandPrixData() # 重置数据存档 self.loadAllSkillData() # 重新加载技能 读取并初始化所有技能数据 self.syncSkillSlots() # 同步技能槽消息 rank, rankRewards = ranking_system.getUserRankAndRewards( RankType.TodayGrandPrix, self.userId) if ftlog.is_debug(): ftlog.debug("endGrandPrix", self.grandPrixStartTS, self.grandPrixFireCount, self.grandPrixFishPoint) mo = MsgPack() mo.setCmd("end_grand_prix") mo.setResult("gameId", FISH_GAMEID) mo.setResult("userId", self.userId) mo.setResult("seatId", self.seatId) mo.setResult("fishPoint", grandPrixFinalPoint) mo.setResult("rank", rank) mo.setResult("rankRewards", rankRewards) mo.setResult("fee", config.getGrandPrixConf("fee")) mo.setResult( "tabs", ranking_system.getRankingTabs(self.userId, util.getClientId(self.userId), RankType.TodayGrandPrix, rankDetail=True)) GameMsg.sendMsg(mo, self.userId) self.sendGrandPrixInfo() self.table.clearPlayer(self) # 从桌子中踢掉玩家 def _resetGrandPrixData(self): """ 重置大奖赛相关数据 """ self.grandPrixStartTS = 0 # 大奖赛开始的时间戳 self.grandPrixFireCount = 0 # 大奖赛剩余开火次数 self.grandPrixTargetFish = {} # 大奖赛目标鱼捕获数量 self.grandPrixUseSkillTimes = [] # 大奖赛剩余技能使用次数 self.grandPrixFishPoint = 0 # 捕鱼积分 self.grandPrixSurpassCount = 0 # 大奖赛超越自己次数 # self.grandPrixLevelFpMultiple = None # 大奖赛火炮等级和倍率 self._rankListCache = [] # 要超越的玩家缓存 self._surpassUser = {} # 要超越玩家数据 self._saveGrandPrixData() # 保存大奖赛信息 weakdata.setDayFishData(self.userId, WeakData.grandPrix_surpassCount, 0) # 大奖赛超越自己次数 def _saveGrandPrixData(self): """ 保存大奖赛数据 """ weakdata.setDayFishData(self.userId, WeakData.grandPrix_startTS, self.grandPrixStartTS) weakdata.setDayFishData(self.userId, WeakData.grandPrix_fireCount, self.grandPrixFireCount) weakdata.setDayFishData(self.userId, WeakData.grandPrix_fishPoint, self.grandPrixFishPoint) weakdata.setDayFishData(self.userId, WeakData.grandPrix_surpassCount, self.grandPrixSurpassCount) weakdata.setDayFishData(self.userId, WeakData.grandPrix_useSkillTimes, json.dumps(self.grandPrixUseSkillTimes)) weakdata.setDayFishData(self.userId, WeakData.grandPrix_targetFish, json.dumps(self.grandPrixTargetFish)) # weakdata.setDayFishData(self.userId, WeakData.grandPrix_levelFpMultiple, json.dumps(self.grandPrixLevelFpMultiple)) def sendGrandPrixInfo(self): """ 发送大奖赛信息 大奖赛相关信息(进入渔场后服务器主动推送) """ if not grand_prix.isGrandPrixOpenTime(): # 是否为大奖赛开放时段 00:00 —— 23:00 self._resetGrandPrixData() self._freeTimes = 0 # 免费次数 weakdata.setDayFishData(self.userId, WeakData.grandPrix_getPointsInfo, json.dumps([])) weakdata.setDayFishData(self.userId, WeakData.grandPrix_freeTimes, self._freeTimes) if ftlog.is_debug(): ftlog.debug("sendGrandPrixInfo", self.grandPrixStartTS, self.isGrandPrixMode()) signUpState = 1 if self.isGrandPrixMode() else 0 # 是否已经报名 remainFreeTimes = config.getVipConf(self.vipLevel).get( "grandPrixFreeTimes", 0) - self._freeTimes # 剩余免费次数 openTime = "-".join(config.getGrandPrixConf("openTimeRange")) # 时间范围 mo = MsgPack() mo.setCmd("grand_prix_info") mo.setResult("gameId", FISH_GAMEID) mo.setResult("userId", self.userId) mo.setResult("seatId", self.seatId) mo.setResult("remainFreeTimes", remainFreeTimes) mo.setResult("fee", config.getGrandPrixConf("fee")) # 报名费 mo.setResult("openTime", openTime) # 00:00 - 23:00 mo.setResult( "isInOpenTime", 1 if grand_prix.isGrandPrixOpenTime() else 0) # 大奖在是否在开放时间段 mo.setResult("signUpState", signUpState) # 是否已报名大奖赛 mo.setResult( "todayRankType", RankType.TodayGrandPrix) # 今日榜Type,使用fish_ranking获取排行榜数据,下同 mo.setResult("todayDate", util.timestampToStr(int(time.time()), "%m/%d")) # 今日榜时间 mo.setResult("yesterdayRankType", RankType.LastGrandPrix) mo.setResult("yesterdayDate", util.timestampToStr(int(time.time() - 86400), "%m/%d")) mo.setResult( "des", config.getMultiLangTextConf( config.getGrandPrixConf("info").get("des"), lang=self.lang)) # 每日积分超过2400送100珍珠,今日榜单每10分钟刷新1次,最终排名00:00公布 mo.setResult("pointsInfo", grand_prix.getPointInfo( self.userId)) # 奖励积分 道具Id、道具数量、是否领取了奖励0|1 mo.setResult("todayMaxPoints", weakdata.getDayFishData(self.userId, WeakData.grandPrix_point, 0)) # 今日最高积分 GameMsg.sendMsg(mo, self.userId) if ftlog.is_debug(): ftlog.debug("FishGrandPrixPlayer, userId =", self.userId, "mo =", mo) def addGrandPrixFishPoint(self, fishPoint, fishType, gunX): """ 添加大奖赛捕鱼积分 """ if self.isGrandPrixMode(): fishPoint = self._calcuCatchFishGrandPrixPoint( fishPoint, gunX) # 计算捕获 vip加成 + 火炮倍率加成 self.grandPrixFishPoint += fishPoint fishType = int(fishType) % 100 for ft, val in self.grandPrixTargetFish.iteritems(): # 添加目标鱼积分 if fishType == int(ft) % 100 and val[0] < val[1]: self.grandPrixTargetFish[ft][0] += 1 if self.grandPrixTargetFish[ft][0] == val[1]: self.grandPrixFishPoint += val[2] break if self.grandPrixFishPoint > self.bestPoint: # 最好的积分 self.grandPrixSurpassCount += 1 # 大奖赛超越自己次数 self._surpassTarget() else: fishPoint = 0 return fishPoint def getPointReward(self, userId): """ 是否获取积分阶段奖励 """ rewards = [] for info in config.getGrandPrixConf("stageInfo"): point = info["point"] reward = info["rewards"] if self.grandPrixFishPoint >= point and point not in self.grandPrixGetPointsInfo: rewards.extend(reward) self.grandPrixGetPointsInfo.append(point) if rewards: util.addRewards(userId, rewards, "BI_GRAND_PRIX_POINT_REWARD") # 添加奖励 weakdata.setDayFishData(userId, WeakData.grandPrix_getPointsInfo, json.dumps(self.grandPrixGetPointsInfo)) return rewards def sendGrandPrixCatch(self, catchFishPoints): """ 大奖赛捕获消息 """ mo = MsgPack() mo.setCmd("catch_grand_prix") mo.setResult("gameId", FISH_GAMEID) mo.setResult("userId", self.userId) mo.setResult("seatId", self.seatId) mo.setResult("catchFishPoints", catchFishPoints) # [{"fId": 10010, "point": 5},], # 捕鱼积分 mo.setResult("fishPoint", self.grandPrixFishPoint) # 捕鱼积分 mo.setResult("targetFish", self.grandPrixTargetFish ) # {"11011": [0, 10],}, # 大奖赛目标鱼:[捕获数量, 目标数量] mo.setResult( "rewards", self.getPointReward(self.userId) ) # [{"name": 101, "count": 1000}, {"name": 101, "count": 2000}], # 大奖赛积分奖励 mo.setResult("pointsInfo", grand_prix.getPointInfo( self.userId)) # 奖励积分 道具Id、道具数量、是否领取了奖励0|1 GameMsg.sendMsg(mo, self.userId) def setTipTimer(self): """ 设置比赛开始和结束的通知消息 """ if self.grandPrixTipTimer: self.grandPrixTipTimer.cancel() self.grandPrixTipTimer = None self.sendGrandPrixInfo() # 发送大奖赛信息 curTime = int(time.time()) dayStartTS = util.getDayStartTimestamp(curTime) openTimeRange = config.getGrandPrixConf("openTimeRange") pastTime = curTime - dayStartTS # 03:00|23:10 beginTime = util.timeStrToInt(openTimeRange[0]) # 00:00 endTime = util.timeStrToInt(openTimeRange[1]) # 23:00 if pastTime < beginTime: interval = beginTime - pastTime + 5 # 开始的通知 elif beginTime <= pastTime <= endTime: interval = endTime - pastTime + 5 # 结束的通知 else: interval = 86400 + beginTime - pastTime + 5 # 开始的通知 self.grandPrixTipTimer = FTLoopTimer(interval, 0, self.setTipTimer) # 死循环 self.grandPrixTipTimer.start() def _getSurpassTarget(self): """ 获取要超越的玩家数据 """ timestamp = pktimestamp.getCurrentTimestamp() rankClass = RankingBase(self.userId, RankType.TodayGrandPrix, RankDefineIndex.GrandPrix, clientId=None, httpRequest=False) if rankClass: rankingList = rankClass.getTopNRankUsers(timestamp) surpassTarget = config.getGrandPrixConf( "surpassTarget") # [100、80、... 3、2、1] masterSurpassTargets = [] for rank in surpassTarget: idx = rank - 1 if 0 <= idx < len(rankingList.rankingUserList): player = rankingList.rankingUserList[idx] name = util.getNickname(player.userId) avatar = userdata.getAttr(player.userId, "purl") masterSurpassTargets.append({ "userId": player.userId, "name": name, "score": player.score, "rank": player.rank + 1, "avatar": avatar }) self._rankListCache = masterSurpassTargets def _surpassTarget(self): """请求大奖赛中超越玩家数据""" if self.userId: msg = MsgPack() msg.setCmd("g_surpass") msg.setResult("gameId", FISH_GAMEID) msg.setResult("roomId", self.table.roomId) msg.setResult("tableId", self.table.tableId) msg.setResult("userId", self.userId) if self.grandPrixSurpassCount <= 1 and self.bestPoint != 0: msg.setResult("bestScore", self.grandPrixFishPoint) if self._surpassUser.get(self.userId, None): if self.grandPrixFishPoint > self._surpassUser.get( self.userId).get("score"): msg.setResult("target", self._surpassUser.get(self.userId)) if self.grandPrixSurpassCount <= 1 or self._surpassUser.get( self.userId, None): GameMsg.sendMsg(msg, self.userId) self._updateSurpassUser() def _updateSurpassUser(self): """更新要超越的目标用户""" newTarget = None maxScore = max(self.grandPrixFishPoint, self.bestPoint) for tar in self._rankListCache: if maxScore < tar["score"] and tar["userId"] != self.userId: newTarget = tar break self._surpassUser[self.userId] = newTarget
class BufferFishGroup(object): """ buffer鱼群(比赛场专用) """ def __init__(self, table): self.table = table self._initData() self._tableRank = 0 self._bufferGroupId = None self._nextBufferTimer = None def clearTimer(self): if self._nextBufferTimer: self._nextBufferTimer.cancel() self._nextBufferTimer = None def initGroup(self, tableRank): """初始化""" self._tableRank = tableRank self._setBufferTimer() def _initData(self): """初始化数据""" self.fishes = {} for bufferFishMap in config.getBufferFishConf( self.table.runConfig.fishPool, self.table.runConfig.gameMode): fishType = bufferFishMap["fishType"] self.fishes.setdefault(fishType, []) for groupId in self.table.runConfig.allBufferGroupIds: if fishType and str(fishType) in groupId: self.fishes[fishType].append(groupId) self.fishes[fishType].sort(cmp=cmpGroupId) def _setBufferTimer(self): """设置buffer定时器""" if self._nextBufferTimer: self._nextBufferTimer.cancel() self._nextBufferTimer = None interval_ = random.randint(int(25 + (1 - self._tableRank) * 20), int((1 - self._tableRank) * 40 + 35)) if ftlog.is_debug(): ftlog.debug("_setBufferTimer========>", self.table.tableId, interval_, self._tableRank) self._nextBufferTimer = FTLoopTimer(interval_, 0, self._addBufferFishGroup) self._nextBufferTimer.start() def _addBufferFishGroup(self): """添加buffer鱼群""" fishType = 0 randomNum = random.randint(1, 10000) for bufferFishMap in config.getBufferFishConf( self.table.runConfig.fishPool, self.table.runConfig.gameMode): probb = bufferFishMap["probb"] if probb[0] <= randomNum <= probb[-1]: fishType = bufferFishMap["fishType"] break allBufferGroupIds = self.fishes[fishType] if ftlog.is_debug(): ftlog.debug("_addBufferFishGroup", fishType, allBufferGroupIds, self.fishes) # 选择一个鱼阵 if allBufferGroupIds: self._bufferGroupId = allBufferGroupIds[self.chooseOneGroup()] self.table.insertFishGroup(self._bufferGroupId) self._setBufferTimer() def chooseOneGroup(self): """选择一个鱼群""" luckyNums = [] for player_ in self.table.players: if player_: luckyNums.append(abs(player_.matchLuckyValue)) w1 = 0.25 * 10000 w2 = 0.5 * 10000 w3 = 0.25 * 10000 divisionNum = sum(luckyNums) if len(luckyNums) > 1 and divisionNum != 0: k1 = luckyNums[0] * 1.0 / (divisionNum) k1 = min(max(k1, 0.1), 0.9) # k1 和 k3的值最小是0.1 k3 = 1 - k1 k2 = k3 / k1 if k1 >= k3 else k1 / k3 w1 = int(k1 / (k1 + k2 + k3) * 10000) w2 = int(k2 / (k1 + k2 + k3) * 10000) w3 = int(k3 / (k1 + k2 + k3) * 10000) randomNum = random.randint(1, w1 + w2 + w3) if ftlog.is_debug(): ftlog.debug("chooseOneBufferGroup========>", self.table.runConfig.fishPool, luckyNums, w1, w2, w3, randomNum) if 1 <= randomNum <= w1: return random.choice([0, 1]) elif w1 + 1 <= randomNum <= w1 + w2: return random.choice([2, 3]) elif w1 + w2 + 1 <= randomNum <= w1 + w2 + w3: return random.choice([4, 5]) else: return random.choice([2, 3]) def cancelNextGroupTimer(self): """取消定时器""" if self._nextBufferTimer: self._nextBufferTimer.cancel() self._nextBufferTimer = None