def _get_player(self, player_id): """Build and execute DB API transaction to retrieve the player row. If player doesn't exist, build and execute DB API transaction to initialize the player row and then retrieve it. Args: player_id: Hashed player name. Returns: If successful: boolean True or a positive integer indicating the number of rows affected. If unsuccessful: boolean False or a zero-value integer. Note: Doesn't explicitly return latest player stats; if successful the updated results are available in the object's attributes. Raises: RuntimeError: There was an issue retrieving the player's row. """ logger.info("Getting Player!") # Var init self.player = None trans_id = str(uuid.uuid4()) transaction = player.get(player_id) # Since a query that returns no rows will return a 0, explicitly check for # the False keyword value if self._execute_db_transaction(trans_id, transaction) is not False: logger.debug("Printing player! %s", self.player) if self.player: return True else: # There was nothing to fetch from the db, need to make this player trans_id = str(uuid.uuid4()) # Generate a new transaction ID transaction = player.create(player_id, cfg) # Get queries to make the specified number of each kind of card, # defined in the config file. initial_cards = self.cfg['player']['initial_cards'] for loot_type in initial_cards: for i in range(initial_cards[loot_type]): # pylint: disable=unused-variable card_type = random.randint( self.cfg['loot_tables'][loot_type]['min'], self.cfg['loot_tables'][loot_type]['max']) transaction.extend(card.create(player_id, card_type)) logger.info("Creating initial cards for player '%d'", player_id) # Create player, create n cards. _get_cards is called immediately # after, so no need to get cards yet. transaction.extend(player.get(player_id)) return self._execute_db_transaction(trans_id, transaction) else: raise RuntimeError( "Unable to retrieve player %s from the database!" % player_id)
def play_stage(self): """Build and execute DB API transaction to simulate player playing a stage. Note: Stamina is not currently validated. Returns: If successful: boolean True or a positive integer indicating the number of rows affected. If unsuccessful: boolean False or a zero-value integer. Note: Doesn't explicitly return latest cardlist/player stats; if successful the updated results are available in the object's attributes. Raises: RuntimeError: There was an issue with the database transaction required to evolve the card. """ # Obviously this could be a call out to a key/value store to get a constantly # updating chance of drops loot_table = self.cfg['loot_tables']['std'] # Standard loot table num_rounds = 5 # rounds in this level transaction = [] # Test to see if the player failed the stage if random.random() <= self.cfg['stage']['failure_chance']: # Roll for card drops for i in range(num_rounds): if (len(self.cards) + len(transaction)) < self.player['slots']: #logger.debug(" Playing round %d" % i) card_type = None # Roll d100 roll = random.random() if roll <= loot_table['drop_chance']: # This can be replaced with a more advanced probabilistic function, just # random for now card_type = random.randint(loot_table['min'], loot_table['max']) transaction.extend(card.create(self.player['id'], card_type)) loot_msg = " Round %2d: Rolled %.2f/%.2f for player %d, dropped card %s" logger.info(loot_msg, i, roll, loot_table['drop_chance'], self.player['id'], str(card_type)) else: full_msg = "****Player (%d) doesn't have any more slots! Discarding remaining drops..." logger.warning(full_msg, self.player['id']) break logger.info(" Player completed stage - %2d loot cards acquired.", len(transaction)) # Assume player took a friend along, give them friend points updated_player = self.player.copy() updated_player['points'] = self.player['points'] + self.cfg[ 'stage']['points_per_run'] # Test that query generation is successful. Necessary as query generation # will fail if, for example, the player already has max friend points update_player_query = player.update(updated_player) if update_player_query: transaction.extend(update_player_query) else: logger.error( "Unable to update player! (continuing without update!)") # After updates, get the latest player/cardlist transaction.extend(player.get(self.player['id'])) transaction.extend(card.get_all(self.player['id'])) # Run transaction trans_id = str(uuid.uuid4()) results = self._execute_db_transaction(trans_id, transaction) # Since a query that returns no rows will return a 0, explicitly check for # the False keyword value if results is False: raise RuntimeError("Unable to Play Stage for player %s!" % self.player['id']) return results else: logger.info(" Player failed stage!") return False