def on_login(self, data: dict): if self.game is not None or self.player is not None: raise errors.BadCommand('You are already logged in') self.check_keys(data, ['name']) player_name = data['name'] password = data.get('password', None) player = Player.get(player_name, password=password) if not player.check_password(password): raise errors.AccessDenied('Password mismatch') game_name = data.get('game', 'Game of {}'.format(player_name)) num_players = data.get('num_players', CONFIG.DEFAULT_NUM_PLAYERS) num_turns = data.get('num_turns', CONFIG.DEFAULT_NUM_TURNS) game = Game.get(game_name, num_players=num_players, num_turns=num_turns) game.check_state(GameState.INIT, GameState.RUN) player = game.add_player(player) self.game = game self.game_idx = game.game_idx self.player = player log.info('Player successfully logged in: {}'.format(player), game=self.game) message = self.player.to_json_str() return Result.OKEY, message
def add_player(self, player: Player): """ Adds player to the game. """ # If player is returning to the game: if player.idx in self.players: player = self.players[player.idx] player.in_game = True return player # Add new player to the game: with self._lock: # Check players count: if len(self.players) == self.num_players: raise errors.AccessDenied( 'The maximum number of players reached') else: self.players[player.idx] = player player.in_game = True # Pick first available Town on the map as player's Town: player_town = [t for t in self.map.towns if t.player_idx is None][0] player_home_point = self.map.points[player_town.point_idx] player.set_home(player_home_point, player_town) # Create trains for the player: start_train_idx = len(self.trains) + 1 for i in range(CONFIG.TRAINS_COUNT): # Create Train: train = Train(idx=start_train_idx + i) # Add Train: player.add_train(train) self.map.add_train(train) self.trains[train.idx] = train # Put the Train into Town: self.put_train_into_town(train, with_cooldown=False) # Start thread with game loop: if self.num_players == len( self.players) and self.state == GameState.INIT: self.start() # Set player's rating: self.map.ratings[player.idx] = { 'rating': player.rating, 'name': player.name, 'town': player_town.name, 'idx': player.idx, } log.info( 'New player has been connected to the game, player: {}'.format( player), game=self) return player
def make_upgrade(self, player: Player, posts_idx=(), trains_idx=()): """ Upgrades given Posts and Trains to next level. """ # Get posts from request: posts = [] for post_idx in posts_idx: if post_idx not in self.map.posts: raise errors.ResourceNotFound( 'Post index not found, index: {}'.format(post_idx)) post = self.map.posts[post_idx] if post.type != PostType.TOWN: raise errors.BadCommand( 'The post is not a Town, post: {}'.format(post)) if post.player_idx != player.idx: raise errors.AccessDenied('Town\'s owner mismatch') posts.append(post) # Get trains from request: trains = [] for train_idx in trains_idx: if train_idx not in self.trains: raise errors.ResourceNotFound( 'Train index not found, index: {}'.format(train_idx)) train = self.trains[train_idx] if train.player_idx != player.idx: raise errors.AccessDenied('Train\'s owner mismatch') trains.append(train) # Check existence of next level for each entity: posts_has_next_lvl = all( [p.level + 1 in CONFIG.TOWN_LEVELS for p in posts]) trains_has_next_lvl = all( [t.level + 1 in CONFIG.TRAIN_LEVELS for t in trains]) if not all([posts_has_next_lvl, trains_has_next_lvl]): raise errors.BadCommand( 'Not all entities requested for upgrade have next levels') # Check armor quantity for upgrade: armor_to_up_posts = sum([p.next_level_price for p in posts]) armor_to_up_trains = sum([t.next_level_price for t in trains]) armor_to_up = sum([armor_to_up_posts, armor_to_up_trains]) if player.town.armor < armor_to_up: raise errors.BadCommand( 'Not enough armor resource for upgrade, player\'s armor: {}, ' 'armor needed to upgrade: {}'.format(player.town.armor, armor_to_up)) # Check that trains are in town now: for train in trains: if not self.is_train_at_post(train, post_to_check=player.town): raise errors.BadCommand( 'The train is not in Town now, train: {}'.format(train)) # Upgrade entities: for post in posts: player.town.armor -= post.next_level_price post.set_level(post.level + 1) log.info('Post has been upgraded, post: {}'.format(post), game=self) for train in trains: player.town.armor -= train.next_level_price train.set_level(train.level + 1) log.info('Train has been upgraded, post: {}'.format(train), game=self)
def move_train(self, player, train_idx, speed, line_idx): """ Process action MOVE. Changes path or speed of the Train. """ if train_idx not in self.trains: raise errors.ResourceNotFound( 'Train index not found, index: {}'.format(train_idx)) if line_idx not in self.map.lines: raise errors.ResourceNotFound( 'Line index not found, index: {}'.format(line_idx)) train = self.trains[train_idx] if train.player_idx != player.idx: raise errors.AccessDenied('Train\'s owner mismatch') if train_idx in self.next_train_moves: self.next_train_moves.pop(train_idx) # Check cooldown for the train: if train.cooldown > 0: raise errors.BadCommand( 'The train is under cooldown, cooldown: {}'.format( train.cooldown)) # Stop the train; reverse direction on move; continue run the train: if speed == 0 or train.line_idx == line_idx: train.speed = speed # The train is standing: elif train.speed == 0: # The train is standing at the end of the line: if self.map.lines[train.line_idx].length == train.position: line_from = self.map.lines[train.line_idx] line_to = self.map.lines[line_idx] if line_from.points[1] in line_to.points: train.line_idx = line_idx train.speed = speed if line_from.points[1] == line_to.points[0]: train.position = 0 else: train.position = line_to.length else: raise errors.BadCommand( 'The end of the train\'s line is not connected to the next line, ' 'train\'s line: {}, next line: {}'.format( line_from, line_to)) # The train is standing at the beginning of the line: elif train.position == 0: line_from = self.map.lines[train.line_idx] line_to = self.map.lines[line_idx] if line_from.points[0] in line_to.points: train.line_idx = line_idx train.speed = speed if line_from.points[0] == line_to.points[0]: train.position = 0 else: train.position = line_to.length else: raise errors.BadCommand( 'The beginning of the train\'s line is not connected to the next line, ' 'train\'s line: {}, next line: {}'.format( line_from, line_to)) # The train is standing on the line (between line's points), player have to continue run the train. else: raise errors.BadCommand( 'The train is standing on the line (between line\'s points), ' 'player have to continue run the train') # The train is moving on the line (between line's points): elif train.speed != 0 and train.line_idx != line_idx: switch_line_possible = False line_from = self.map.lines[train.line_idx] line_to = self.map.lines[line_idx] if train.speed > 0 and speed > 0: switch_line_possible = ( line_from.points[1] == line_to.points[0]) elif train.speed > 0 and speed < 0: switch_line_possible = ( line_from.points[1] == line_to.points[1]) elif train.speed < 0 and speed > 0: switch_line_possible = ( line_from.points[0] == line_to.points[0]) elif train.speed < 0 and speed < 0: switch_line_possible = ( line_from.points[0] == line_to.points[1]) # This train move request is valid and will be applied later: if switch_line_possible: self.next_train_moves[train_idx] = { 'speed': speed, 'line_idx': line_idx } # This train move request is invalid: else: raise errors.BadCommand( 'The train is not able to switch the current line to the next line, ' 'or new speed is incorrect, train\'s line: {}, next line: {}, ' 'train\'s speed: {}, new speed: {}'.format( line_from, line_to, train.speed, speed))
def wrapped(self, *args, **kwargs): if self.game is None or self.player is None: raise errors.AccessDenied('Login required') else: return func(self, *args, **kwargs)