File indexing completed on 2024-04-28 07:51:12
0001 # -*- coding: utf-8 -*- 0002 0003 """ 0004 Copyright (C) 2013-2016 Wolfgang Rohdewald <wolfgang@rohdewald.de> 0005 0006 SPDX-License-Identifier: GPL-2.0 0007 0008 """ 0009 0010 from qt import Qt 0011 0012 from mi18n import i18nc 0013 from message import Message 0014 from common import Internal, isAlive 0015 from player import Player, PlayingPlayer 0016 from game import PlayingGame 0017 from tile import Tile 0018 from handboard import PlayingHandBoard 0019 from animation import AnimationSpeed 0020 from uiwall import UIWall, SideText 0021 from wind import Wind 0022 0023 0024 class VisiblePlayer(Player): 0025 0026 """Mixin for VisiblePlayingPlayer and ScoringPlayer""" 0027 0028 def __init__(self): 0029 # pylint: disable=super-init-not-called 0030 self.__front = self.game.wall[self.idx] 0031 self.sideText = SideText() 0032 self.sideText.board = self.__front 0033 0034 def hide(self): 0035 """clear visible data and hide""" 0036 self.clearHand() 0037 self.handBoard.hide() 0038 0039 @property 0040 def idx(self): 0041 """our index in the player list""" 0042 if self not in self.game.players: 0043 # we will be added next 0044 return len(self.game.players) 0045 return self.game.players.index(self) 0046 0047 @property 0048 def front(self): 0049 """front""" 0050 return self.__front 0051 0052 @front.setter 0053 def front(self, value): 0054 """also assign handBoard to front""" 0055 self.__front = value 0056 if value and self.handBoard: 0057 self.handBoard.setParentItem(value) 0058 0059 def syncHandBoard(self, adding=None): 0060 """update display of handBoard. Set Focus to tileName.""" 0061 self.handBoard.sync(adding) 0062 0063 def showInfo(self): 0064 """show player info on the wall""" 0065 side = self.front 0066 self.sideText.text = '{} - {}'.format(self.localName, self.explainHand().total()) 0067 self.colorizeName() 0068 side.windTile = Wind.all4[self.wind].marker 0069 side.windTile.prevailing = self.game.roundsFinished 0070 side.windTile.board = self.front 0071 0072 0073 class VisiblePlayingPlayer(VisiblePlayer, PlayingPlayer): 0074 0075 """this player instance has a visual representation""" 0076 # pylint: disable=too-many-public-methods 0077 0078 def __init__(self, game, name): 0079 assert game 0080 self.handBoard = None # because Player.init calls clearHand() 0081 PlayingPlayer.__init__(self, game, name) 0082 VisiblePlayer.__init__(self) 0083 self.handBoard = PlayingHandBoard(self) 0084 self.voice = None 0085 0086 def clearHand(self): 0087 """clears attributes related to current hand""" 0088 super().clearHand() 0089 if self.game and self.game.wall: 0090 # is None while __del__ 0091 self.front = self.game.wall[self.idx] 0092 if self.handBoard: 0093 self.handBoard.setEnabled( 0094 self.game and self.game.belongsToHumanPlayer( 0095 ) and self == self.game.myself) 0096 0097 def explainHand(self): 0098 """return the hand to be explained. Same as current unless we need to discard. 0099 In that case, make an educated guess about the discard. 0100 For player==game.myself, use the focused tile.""" 0101 hand = self.hand 0102 if hand and hand.tiles and self._concealedTiles: 0103 if hand.lenOffset == 1 and not hand.won: 0104 if any(not x.isKnown for x in self._concealedTiles): 0105 hand -= Tile.unknown 0106 elif self.handBoard.focusTile: 0107 hand -= self.handBoard.focusTile.tile 0108 return hand 0109 0110 def colorizeName(self): 0111 """set the color to be used for showing the player name on the wall""" 0112 if not isAlive(self.sideText): 0113 return 0114 if self == self.game.activePlayer and self.game.client: 0115 color = Qt.blue 0116 elif Internal.Preferences.tilesetName == 'jade': 0117 color = Qt.white 0118 else: 0119 color = Qt.black 0120 self.sideText.color = color 0121 0122 def getsFocus(self, unusedResults=None): 0123 """give this player focus on his handBoard""" 0124 self.handBoard.setEnabled(True) 0125 self.handBoard.hasLogicalFocus = True 0126 0127 def popupMsg(self, msg): 0128 """shows a yellow message from player""" 0129 if msg != Message.NoClaim: 0130 self.speak(msg.name.lower()) 0131 yellow = self.front.message 0132 yellow.setText('{} {}'.format(yellow.msg, i18nc('kajongg', msg.name))) 0133 yellow.setVisible(True) 0134 0135 def hidePopup(self): 0136 """hide the yellow message from player""" 0137 if isAlive(self.front.message): 0138 self.front.message.msg = '' 0139 self.front.message.setVisible(False) 0140 0141 def speak(self, txt): 0142 """speak if we have a voice""" 0143 if self.voice: 0144 self.voice.speak(txt, self.front.rotation()) 0145 0146 def robTileFrom(self, tile): 0147 """used for robbing the kong from this player""" 0148 PlayingPlayer.robTileFrom(self, tile) 0149 tile = tile.exposed 0150 hbTiles = self.handBoard.uiTiles 0151 lastDiscard = [x for x in hbTiles if x.tile == tile][-1] 0152 lastDiscard.tile = lastDiscard.tile.concealed 0153 Internal.scene.discardBoard.lastDiscarded = lastDiscard 0154 # remove from board of robbed player, otherwise syncHandBoard would 0155 # not fix display for the robbed player 0156 lastDiscard.setBoard(None) 0157 assert lastDiscard.tile.isConcealed 0158 self.syncHandBoard() 0159 0160 def addConcealedTiles(self, tiles, animated=True): 0161 """add to my tiles and sync the hand board""" 0162 with AnimationSpeed(speed=Internal.Preferences.animationSpeed if animated else 99): 0163 PlayingPlayer.addConcealedTiles(self, [x.tile for x in tiles]) 0164 self.syncHandBoard(tiles) 0165 0166 def declaredMahJongg(self, concealed, withDiscard, lastTile, lastMeld): 0167 """player declared mah jongg. Determine last meld, show 0168 concealed tiles grouped to melds""" 0169 PlayingPlayer.declaredMahJongg( 0170 self, 0171 concealed, 0172 withDiscard, 0173 lastTile, 0174 lastMeld) 0175 if withDiscard: 0176 # withDiscard is a Tile, we need the UITile 0177 discardTile = Internal.scene.discardBoard.lastDiscarded 0178 if discardTile.tile is not withDiscard: 0179 self.game.debug( 0180 '%s is not %s' % 0181 (discardTile.tile, withDiscard)) 0182 assert False 0183 self.syncHandBoard([discardTile]) 0184 else: 0185 # show concealed tiles 0186 self.syncHandBoard() 0187 0188 def removeTile(self, tile): 0189 """remove from my melds or tiles""" 0190 PlayingPlayer.removeTile(self, tile) 0191 self.syncHandBoard() 0192 0193 def makeTileKnown(self, tile): 0194 """give an unknown tileItem a name""" 0195 PlayingPlayer.makeTileKnown(self, tile) 0196 assert tile.isKnown 0197 matchingTiles = sorted( 0198 self.handBoard.tilesByElement(Tile.unknown), 0199 key=lambda x: x.xoffset) 0200 matchingTiles[-1].tile = tile 0201 0202 def exposeMeld(self, meldTiles, calledTile=None): 0203 result = PlayingPlayer.exposeMeld( 0204 self, 0205 meldTiles, 0206 calledTile.tile if calledTile else None) 0207 adding = [calledTile] if calledTile else None 0208 self.syncHandBoard(adding=adding) 0209 return result 0210 0211 0212 class VisiblePlayingGame(PlayingGame): 0213 0214 """for the client""" 0215 # pylint: disable=too-many-arguments, too-many-public-methods 0216 playerClass = VisiblePlayingPlayer 0217 wallClass = UIWall 0218 0219 def __init__(self, names, ruleset, gameid=None, 0220 wantedGame=None, client=None, playOpen=False, autoPlay=False): 0221 PlayingGame.__init__( 0222 self, names, ruleset, gameid, wantedGame=wantedGame, 0223 client=client, playOpen=playOpen, autoPlay=autoPlay) 0224 # Internal.mainWindow.adjustMainView() 0225 # Internal.mainWindow.updateGUI() 0226 self.wall.decorate4() 0227 0228 def close(self): 0229 """close the game""" 0230 scene = Internal.scene 0231 scene.discardBoard.hide() 0232 if isAlive(scene): 0233 scene.removeTiles() 0234 scene.clientDialog = None 0235 for player in self.players: 0236 player.hide() 0237 if self.wall: 0238 self.wall.hide() 0239 if isAlive(scene.mainWindow): 0240 scene.mainWindow.actionAutoPlay.setChecked(False) 0241 scene.startingGame = False 0242 scene.game = None 0243 SideText.removeAll() 0244 scene.mainWindow.updateGUI() 0245 return PlayingGame.close(self)