async def pay(self, ctx, target_location, amount): amount = int(amount) # dumb. member = ctx.message.author p = models.Player() try: p.custom_load("discord_id = ?", (member.id, )) except Exception: await ctx.send("I don't have you listed as a player, {}\n\ If you believe this is an error, please talk to a Lord or the Monarch" .format(member.mention)) return # Make sure player has enough coins!!! if amount < 1: await ctx.send("You can't pay 0 or negative coins, {}".format( member.mention)) return elif amount > p.coins: await ctx.send("{}, you don't have enough coins!".format( member.mention)) return # Get team, current location id, available locations t = models.Team() t.load(p.team_id) current_loc = t.current_location_id avail_locs = graphanalyzer.get_next_location_list(t.team_id) # Make sure it's a valid target location. if target_location.lower() not in (name.lower() for name in avail_locs.keys()): await ctx.send( "I don't think {} is a valid location. Maybe you mistyped it?". format(target_location)) return # Get the ID for the target location... target_loc = models.Location() target_loc.custom_load("name = ? COLLATE NOCASE", (target_location, )) # target_loc.load((current_loc + 1) % 51) # Hax for Paris edge = models.LocationEdge() edge.custom_load("start_location_id = ? AND end_location_id = ?", ( current_loc, target_loc.location_id, )) # Store the payment in the db payment = models.Payment() payment.player_id = p.player_id payment.team_id = p.team_id payment.amount = amount payment.location_edge = edge.edge_id payment.time = helpers.get_game_day() payment.insert() # Remove coins from player's account. p.coins -= amount p.last_active_day = helpers.get_game_day() p.update() models.save() # Send confirmation message. await ctx.send("{} has paid **{}** coins toward **{}**".format( member.mention, amount, target_loc.name))
async def check_for_new_logs(): # Also triggers end of game. Sue me. HACK while True: if helpers.get_game_day( ) > config['game_length'] and config['game_ongoing']: await end_game() t = models.Team_list() t.custom_load("team_id > ?", (0, )) for team in t.items: if team.current_location_id == 0 and config['game_ongoing']: await end_game() logs = models.Log_list() logs.custom_load("sent = ?", (0, )) if len(logs.items) > 0: logging.info("Found {} new logs, attempting to send...".format( len(logs.items))) # Try to send them and die inside. try: for log in logs.items: ch = get(client.get_all_channels(), id=log.target_channel_id) await ch.send(log.msg) log.sent = 1 log.update() models.save() except AttributeError: logging.error( "We can't see the channel yet. We'll get 'em next time.") await asyncio.sleep(5)
async def team(self, ctx): # Prints the player's team's current funding for the day, # As well as current location, # And total distance remaining. member = ctx.message.author try: p = models.Player() p.custom_load("discord_id = ?", (member.id, )) if p.last_active_day != helpers.get_game_day(): p.last_active_day = helpers.get_game_day() p.update() models.save() except Exception: await ctx.send("I don't think you're playing, {}\n\ (If you think this is a mistake, please talk to a Lord or the Monarch)" .format(member.mention)) return t = models.Team() t.load(p.team_id) l = models.Location() l.load(t.current_location_id) funding_table = paymentreducer.get_funding_table( p.team_id, helpers.get_game_day()) await ctx.send( "Your team is in **{}**, with at least **{}km** to go!\nHere is how today's funding is going:\n{}" .format( l.name, graphanalyzer.dijkstra(graphanalyzer.graph, t.current_location_id, 0), "```" + funding_table + "```"))
async def scramble(self, ctx): # TODO fix rate limiting issue becuase I think it's breaking more things. guild = ctx.message.guild logging.info(guild) players = models.Player_list() players.load_all() for p in players.items: old_team_id = p.team_id # Pick a number & update player team_id = randint(1, 3) if old_team_id != team_id: p.team_id = team_id p.update() old_team = models.Team() old_team.load(old_team_id) team = models.Team() team.load(team_id) # Clear/Assign role old_team_role = get(guild.roles, name=old_team.name) team_role = get(guild.roles, name=team.name) member = guild.get_member(int(p.discord_id)) if member is None: logging.info( "Player w/ id {} not found. Maybe they left the server.".format(p.discord_id)) continue await member.remove_roles(old_team_role, reason="Automated Team Scramble") await member.add_roles(team_role, reason="Automated Team Scramble") logging.info("{} (ID:{}) moved from {} to {}".format( member.nick if member.nick is not None else member.name, p.discord_id, old_team.name, team.name)) await asyncio.sleep(1) models.save() logging.info("Scramble complete")
async def spectate(self, ctx): member = ctx.message.author if helpers.get_game_day( ) > config['latest_spectate_day'] and config['game_ongoing']: await ctx.send( "Sorry, {}, it's too late to switch to spectator mode".format( member.mention)) return player = models.Player() team = models.Team() try: player.custom_load("discord_id = ?", (str(member.id), )) team.load(player.team_id) except Exception as e: await ctx.send( "I think you're already out of the game, {}. If you think this was a mistake, please talk to a Lord or the Monarch" .format(member.mention)) logging.error(e) return # Remove flair from user role = get(member.guild.roles, name=team.name) await member.remove_roles(role, reason='Player left game') # Add spectator role role = get(member.guild.roles, name='Spectator') await member.add_roles(role, reason='Player left game') player.delete() models.save() logging.info("{} has switched to spectating".format(member.id)) await ctx.send("{}, you're now a spectator. Enjoy the show!".format( member.mention))
async def on_member_join(member): pa_chan = get(member.guild.text_channels, name="player-assignments") ins_chan = get(member.guild.text_channels, name="instructions") # Assign the new member to one of the three teams randomly # FIXME Get number of teams through the DB and not hardcode a 3 team_id = randint(1, 3) t = models.Team() t.load(team_id) # Add flair to user role = get(member.guild.roles, name=t.name) await member.add_roles(role) # Create new Player record. p = models.Player() # First check if they already exist try: p.custom_load("discord_id = ?", (member.id, )) t.load(p.team_id) await pa_chan.send("Welcome back, {}! the **{}** missed you!".format( member.mention, t.name)) return except Exception: pass p.discord_id = member.id p.team_id = team_id p.coins = config['starting_coins'] p.last_active_day = helpers.get_game_day() p.shares = 100 p.insert() models.save() # Post message to player-assignments channel await pa_chan.send("Welcome, {}! You have been assigned to the **{}**!\n\ Make sure to check out the {} and good luck!".format( member.mention, t.name, ins_chan.mention))
def pay_players(): teams = models.Team_list() teams.custom_load("team_id > ?", (0, )) for t in teams.items: # load all the players players = models.Player_list() # Still the dumb Loadall HACK players.custom_load("team_id = ?", (t.team_id, )) total_team_shares = sum([p.shares for p in players.items]) share_value = config['daily_team_coins'] / total_team_shares # pay 'em for player in players.items: # add daily salary player.coins += int(share_value * player.shares) # get THIS PLAYER's payments from TODAY for THIS PLAYER's TEAM that # WEREN'T put toward the current location (for refunds) models.c.execute( "SELECT SUM(amount) FROM Payment p LEFT JOIN LocationEdge le ON(p.location_edge = le.edge_id) WHERE player_id = ? AND team_id = ? AND time = ? AND end_location_id != ?", (player.player_id, player.team_id, helpers.get_game_day() - 1, t.current_location_id)) refund = models.c.fetchone()[0] if refund is None: refund = 0 player.coins += int(refund * (config['refund_percentage'] / 100)) player.update() models.save()
def ten_minute_warning(): if not config['game_ongoing']: return l = models.Log() l.date = str(datetime.now()) l.game_day = helpers.get_game_day() l.msg = "10 minutes remaining in the day! Get those payments in!!!" l.target_channel_id = config['channels']['progress-announcements'] l.insert() models.save()
def update_shares(): players = models.Player_list() players.load_all() for player in players.items: days_since_active = helpers.get_game_day() - player.last_active_day if days_since_active < len(config['afk_falloff']): player.shares = config['afk_falloff'][days_since_active] else: player.shares = 1 player.update() models.save()
async def end_game(): logging.info("Time to end the game!") ch = get(client.get_all_channels(), id=config["channels"]["progress-announcements"]) config['game_ongoing'] = 0 with open(Path(__file__).parent / 'config.json', 'w') as f: json.dump(config, f, indent=4) scheduledjobs.config = config helpers.config = config # Invalidate All Oustanding Logs logs = models.Log_list() logs.custom_load("sent = ?", (0, )) if len(logs.items) > 0: try: for log in logs.items: log.sent = 1 log.update() except Exception as e: logging.error("Failed to invalidate old logs - {}".format(e)) models.save() # Load winners winners = [] teams = models.Team_list() teams.custom_load("team_id > ?", (0, )) for t in teams.items: start_loc = t.current_location_id if start_loc == 1: start_loc = 0 winners.append( (t.name, graphanalyzer.dijkstra(graphanalyzer.graph, start_loc, 0))) winners.sort(key=lambda x: x[1], reverse=True) # Make a big deal of everything, really. try: await ch.send( "All right, adventurers! The game has ended! Drumroll please!!!") await (asyncio.sleep(5)) await ch.send("In third place, with {}km remaining, the {}!".format( winners[0][1], winners[0][0])) await (asyncio.sleep(3)) await ch.send("In second place, with {}km remaining, the {}!!".format( winners[1][1], winners[1][0])) await (asyncio.sleep(3)) await ch.send( "Finally, in first place, the {}!!!!!!!!! Congratulations!".format( winners[2][0])) await (asyncio.sleep(3)) await ch.send( "Thank you all for playing! I hope you had fun! Now, I'm going to take a nap. Maybe we can do this again some time :sweat_smile:" ) except AttributeError: logging.info("Can't see the channel. We'll get 'em next time.") return
async def me(self, ctx): # Print's players current coin count member = ctx.message.author try: p = models.Player() p.custom_load("discord_id = ?", (member.id, )) await ctx.send("{}, you have **{}** coins".format( member.mention, p.coins)) if p.last_active_day != helpers.get_game_day(): p.last_active_day = helpers.get_game_day() p.update() models.save() except Exception: # Show error if user isn't actually playing await ctx.send("I... don't believe you're playing, {}\n\ (If you think this is a mistake, please talk to a Lord or the Monarch)" .format(member.mention))
async def join(self, ctx): member = ctx.message.author if config['game_ongoing']: await ctx.send( "Sorry, {}, you can't join the game while it's ongoing!". format(member.mention)) return p = models.Player() # Make sure player doesn't already exist try: p.custom_load('discord_id = ?', (member.id, )) await ctx.send( "I think you're already playing, {}. If you think this is an error, please talk to a Lord or the Monarch" .format(member.mention)) return except Exception: pass # Pick a team team_id = randint(1, 3) team = models.Team() team.load(team_id) # Add flair to user role = get(member.guild.roles, name=team.name) await member.add_roles(role, reason='Player joined game') # Remove spectator role role = get(member.guild.roles, name='Spectator') if role in member.roles: await member.remove_roles(role, reason='Player joined game') # Create new player p.discord_id = member.id p.team_id = team_id p.coins = config['starting_coins'] p.last_active_day = 0 p.shares = 100 p.insert() models.save() logging.info("{} has joined the {}".format(member.id, team.name)) await ctx.send( "{}, you've been added to the **{}**! Good Luck!".format( member.mention, team.name))
def team_attempt_move(team_id): process_log = "" # Load team. t = models.Team() t.load(team_id) flns = paymentreducer.get_funding_list(team_id, helpers.get_game_day() - 1, False) fl = paymentreducer.get_funding_list(team_id, helpers.get_game_day() - 1, True) # Check for best-funded succesful path new_loc = t.current_location_id biggest_funding = -1 was_sabotaged = False for k, v in flns.items(): le = models.LocationEdge() le.load(k) if v >= le.weight and v > biggest_funding: new_loc = le.end_location_id biggest_funding = v if fl[k] < le.weight: was_sabotaged = True else: was_sabotaged = False if biggest_funding == -1: process_log = "The {} didn't raise enough to book passage anywhere...".format( t.name) else: l = models.Location() l.load(new_loc) if was_sabotaged: process_log = "The {} tried to travel to {}, but someone sabotaged them and they were stopped by the Black Cats!".format( t.name, l.name) else: t.current_location_id = new_loc t.update() process_log = "The {} have successfully reached {}!".format( t.name, l.name) models.save() return process_log + "\n"
async def startgame(self, ctx): logging.info("The Monarch has signalled to begin the game!") # Reset every player's coins logging.info("Resetting player coins and last_active_day...") ps = models.Player_list() ps.custom_load("player_id > ?", (0,)) # HACK to select all for p in ps.items: p.coins = config["starting_coins"] p.last_active_day = 0 p.update() # Reset every team's starting location logging.info("Resetting team locations...") ts = models.Team_list() ts.custom_load("team_id > ?", (0,)) # SAME HACK to select all for t in ts.items: t.current_location_id = 1 t.update() # Set time to -1 for all payments (i'm sorry reality) logging.info("Invalidating previous payments...") pmts = models.Payment_list() pmts.custom_load("time >= ?", (0,)) for p in pmts.items: p.time = -1 p.update() models.save() # Update config config['game_ongoing'] = 1 d = datetime.now() d = d.replace(minute=0, second=0, microsecond=0) config['start_date'] = str(d) with open(Path(__file__).parent / 'config.json', 'w') as f: json.dump(config, f, indent=4) scheduledjobs.config = config helpers.config = config scheduledjobs.on_new_day()
async def sabotage(self, ctx, target_team, target_location, amount): # just pay() but with negative coins and another team amount = int(amount) # still dumb member = ctx.message.author p = models.Player() try: p.custom_load("discord_id = ?", (member.id, )) except Exception: await ctx.send( "Gonna be hard to sabotage when I don't have you listed as a player, {}\n\ If you believe this is a mistake, please talk to a Lord or the Monarch" .format(member.mention)) return # Mke sure player has enough coins if amount < 1: await ctx.send("You can't pay 0 or negative coins, {}".format( member.mention)) return elif amount > p.coins: await ctx.send("{}, you don't have enough coins!".format( member.mention)) return t = models.Team() try: # TODO make this more user-friendly t.custom_load("name = ? COLLATE NOCASE", (target_team, )) except Exception: await ctx.send( "I don't think {} is a real team, {}. Make sure you type the full name!" .format(target_team, member.mention)) return if t.team_id == p.team_id: await ctx.send( "You can't sabotage your own team, {}!!! They won't like you for that!" .format(member.mention)) return current_loc = t.current_location_id avail_locs = graphanalyzer.get_next_location_list(t.team_id) # Validate target location... if target_location.lower() not in (name.lower() for name in avail_locs.keys()): await ctx.send( "I don't think {} is a valid location. Maybe a typo?".format( target_location)) return # Get id for the target location... location = models.Location() location.custom_load("name = ? COLLATE NOCASE", (target_location, )) # location.load((current_loc + 1) % 51) # Hax for Paris edge = models.LocationEdge() edge.custom_load("start_location_id = ? AND end_location_id = ?", (current_loc, location.location_id)) # Store the payment! payment = models.Payment() payment.player_id = p.player_id payment.team_id = t.team_id payment.amount = -amount # VERY IMPORTANT DIFFERENCE payment.location_edge = edge.edge_id payment.time = helpers.get_game_day() payment.insert() # Remove coins from the player's account p.coins -= amount p.last_active_day = helpers.get_game_day() p.update() models.save() # Send confirmation message. await ctx.send( "{} has paid **{}** coins to sabotage the **{}'** trip to **{}**". format(member.mention, amount, t.name, location.name))