Example #1
0
async def on_ready():
    ewutils.logMsg('Logged in as {} ({}).'.format(client.user.name,
                                                  client.user.id))

    ewutils.logMsg("Loaded NLACakaNM world map. ({}x{})".format(
        ewmap.map_width, ewmap.map_height))
    ewmap.map_draw()

    # Flatten role names to all lowercase, no spaces.
    for poi in ewcfg.poi_list:
        if poi.role != None:
            poi.role = ewutils.mapRoleName(poi.role)

    await client.change_presence(game=discord.Game(name=("dev. by @krak " +
                                                         ewcfg.version)))

    # Look for a Twitch client_id on disk.
    # FIXME debug - temporarily disable Twitch integration
    if False:
        twitch_client_id = ewutils.getTwitchClientId()

    # If no twitch client ID is available, twitch integration will be disabled.
    # FIXME debug - temporarily disable Twitch integration.
    if True:
        twich_client_id = None
        ewutils.logMsg('Twitch integration disabled.')
    elif twitch_client_id == None or len(twitch_client_id) == 0:
        ewutils.logMsg(
            'No twitch_client_id file found. Twitch integration disabled.')
    else:
        ewutils.logMsg("Enabled Twitch integration.")

    # Channels in the connected discord servers to announce to.
    channels_announcement = []

    # Channels in the connected discord servers to send stock market updates to. Map of server ID to channel.
    channels_stockmarket = {}

    for server in client.servers:
        # Update server data in the database
        ewserver.server_update(server=server)

        # store the list of channels in an ewutils field
        ewcfg.update_server_list(server=server)

        # Grep around for channels
        ewutils.logMsg("connected to server: {}".format(server.name))
        for channel in server.channels:
            if (channel.type == discord.ChannelType.text):
                if (channel.name == ewcfg.channel_twitch_announcement):
                    channels_announcement.append(channel)
                    ewutils.logMsg(
                        "• found channel for announcements: {}".format(
                            channel.name))

                elif (channel.name == ewcfg.channel_stockexchange):
                    channels_stockmarket[server.id] = channel
                    ewutils.logMsg(
                        "• found channel for stock exchange: {}".format(
                            channel.name))

        # create all the districts in the database
        for poi in ewcfg.capturable_districts:
            # call the constructor to create an entry if it doesnt exist yet
            dist = EwDistrict(id_server=server.id, district=poi)
            # change the ownership to the faction that's already in control to initialize topic names
            try:
                await dist.change_ownership(new_owner=dist.controlling_faction,
                                            actor="init",
                                            client=client)
            except:
                ewutils.logMsg(
                    'Could not change ownership for {} to "{}".'.format(
                        poi, dist.controlling_faction))

        asyncio.ensure_future(
            ewdistrict.capture_tick_loop(id_server=server.id))

    try:
        ewutils.logMsg('Creating message queue directory.')
        os.mkdir(ewcfg.dir_msgqueue)
    except FileExistsError:
        ewutils.logMsg('Message queue directory already exists.')

    ewutils.logMsg('Ready.')

    ewcfg.set_client(client)
    """
		Set up for infinite loop to perform periodic tasks.
	"""
    time_now = int(time.time())

    time_last_twitch = time_now
    time_twitch_downed = 0

    # Every three hours we log a message saying the periodic task hook is still active. On startup, we want this to happen within about 60 seconds, and then on the normal 3 hour interval.
    time_last_logged = time_now - ewcfg.update_hookstillactive + 60

    stream_live = None

    ewutils.logMsg('Beginning periodic hook loop.')
    while True:
        time_now = int(time.time())

        # Periodic message to log that this stuff is still running.
        if (time_now - time_last_logged) >= ewcfg.update_hookstillactive:
            time_last_logged = time_now

            ewutils.logMsg("Periodic hook still active.")

        # Check to see if a stream is live via the Twitch API.
        # FIXME disabled
        if False:
            #if twitch_client_id != None and (time_now - time_last_twitch) >= ewcfg.update_twitch:
            time_last_twitch = time_now

            try:
                # Twitch API call to see if there are any active streams.
                json_string = ""
                p = subprocess.Popen(
                    "curl -H 'Client-ID: {}' -X GET 'https://api.twitch.tv/helix/streams?user_login = rowdyfrickerscopkillers' 2>/dev/null"
                    .format(twitch_client_id),
                    shell=True,
                    stdout=subprocess.PIPE)

                for line in p.stdout.readlines():
                    json_string += line.decode('utf-8')

                json_parsed = json.loads(json_string)

                # When a stream is up, data is an array of stream information objects.
                data = json_parsed.get('data')
                if data != None:
                    data_count = len(data)
                    stream_was_live = stream_live
                    stream_live = True if data_count > 0 else False

                    if stream_was_live == True and stream_live == False:
                        time_twitch_downed = time_now

                    if stream_was_live == False and stream_live == True and (
                            time_now - time_twitch_downed) > 600:
                        ewutils.logMsg("The stream is now live.")

                        # The stream has transitioned from offline to online. Make an announcement!
                        for channel in channels_announcement:
                            await client.send_message(
                                channel,
                                "ATTENTION CITIZENS. THE **ROWDY F****R** AND THE **COP KILLER** ARE **STREAMING**. BEWARE OF INCREASED KILLER AND ROWDY ACTIVITY.\n\n@everyone\n{}"
                                .format(
                                    "https://www.twitch.tv/rowdyfrickerscopkillers"
                                ))
            except:
                ewutils.logMsg(
                    'Twitch handler hit an exception (continuing): {}'.format(
                        json_string))
                traceback.print_exc(file=sys.stdout)

        # Adjust the exchange rate of slime for the market.
        try:
            for server in client.servers:
                # Load market data from the database.
                market_data = EwMarket(id_server=server.id)

                if market_data.time_lasttick + ewcfg.update_market <= time_now:
                    market_data.time_lasttick = time_now

                    # Advance the time and potentially change weather.
                    market_data.clock += 1

                    if market_data.clock >= 24 or market_data.clock < 0:
                        market_data.clock = 0
                        market_data.day += 1

                    if random.randrange(30) == 0:
                        pattern_count = len(ewcfg.weather_list)

                        if pattern_count > 1:
                            weather_old = market_data.weather

                            # Randomly select a new weather pattern. Try again if we get the same one we currently have.
                            while market_data.weather == weather_old:
                                pick = random.randrange(len(
                                    ewcfg.weather_list))
                                market_data.weather = ewcfg.weather_list[
                                    pick].name

                        # Log message for statistics tracking.
                        ewutils.logMsg(
                            "The weather changed. It's now {}.".format(
                                market_data.weather))

                    # Persist new data.
                    market_data.persist()

                    # Decay slime totals
                    ewutils.decaySlimes(id_server=server.id)

                    # Increase hunger for all players below the max.
                    ewutils.pushupServerHunger(id_server=server.id)

                    # Decrease inebriation for all players above min (0).
                    ewutils.pushdownServerInebriation(id_server=server.id)

                    await ewdistrict.give_kingpins_slime_and_decay_capture_points(
                        id_server=server.id)

                    # Post leaderboards at 6am NLACakaNM time.
                    if market_data.clock == 6:
                        await ewleaderboard.post_leaderboards(client=client,
                                                              server=server)

        except:
            ewutils.logMsg(
                'An error occurred in the scheduled slime market update task:')
            traceback.print_exc(file=sys.stdout)

        # Parse files dumped into the msgqueue directory and send messages as needed.
        try:
            for msg_file in os.listdir(ewcfg.dir_msgqueue):
                fname = "{}/{}".format(ewcfg.dir_msgqueue, msg_file)

                msg = ewutils.readMessage(fname)
                os.remove(fname)

                msg_channel_names = []
                msg_channel_names_reverb = []

                if msg.channel != None:
                    msg_channel_names.append(msg.channel)

                if msg.poi != None:
                    poi = ewcfg.id_to_poi.get(msg.poi)
                    if poi != None:
                        if poi.channel != None and len(poi.channel) > 0:
                            msg_channel_names.append(poi.channel)

                        if msg.reverb == True:
                            pois_adjacent = ewmap.path_to(poi_start=msg.poi)

                            for poi_adjacent in pois_adjacent:
                                if poi_adjacent.channel != None and len(
                                        poi_adjacent.channel) > 0:
                                    msg_channel_names_reverb.append(
                                        poi_adjacent.channel)

                if len(msg_channel_names) == 0:
                    ewutils.logMsg(
                        'in file {} message for channel {} (reverb {})\n{}'.
                        format(msg_file, msg.channel, msg.reverb, msg.message))
                else:
                    # Send messages to every connected server.
                    for server in client.servers:
                        for channel in server.channels:
                            if channel.name in msg_channel_names:
                                await client.send_message(
                                    channel, "**{}**".format(msg.message))
                            elif channel.name in msg_channel_names_reverb:
                                await client.send_message(
                                    channel,
                                    "**Something is happening nearby...\n\n{}**"
                                    .format(msg.message))
        except:
            ewutils.logMsg(
                'An error occurred while trying to process the message queue:')
            traceback.print_exc(file=sys.stdout)

        # Wait a while before running periodic tasks.
        await asyncio.sleep(15)
Example #2
0
async def on_ready():
    ewutils.logMsg('Logged in as {} ({}).'.format(client.user.name,
                                                  client.user.id))
    ewutils.logMsg('Ready.')

    await client.change_presence(game=discord.Game(name=("dev. by @krak " +
                                                         ewcfg.version)))

    # Look for a Twitch client_id on disk.
    twitch_client_id = ewutils.getTwitchClientId()

    # If no twitch client ID is available, twitch integration will be disabled.
    if twitch_client_id == None or len(twitch_client_id) == 0:
        ewutils.logMsg(
            'No twitch_client_id file found. Twitch integration disabled.')
    else:
        ewutils.logMsg("Enabled Twitch integration.")

    # Channels in the connected discord servers to announce to.
    channels_announcement = []

    # Channels in the connected discord servers to send stock market updates to. Map of server ID to channel.
    channels_stockmarket = {}

    for server in client.servers:
        # Update server data in the database
        ewserver.server_update(server=server)

        # Grep around for channels
        ewutils.logMsg("connected to: {}".format(server.name))
        for channel in server.channels:
            if (channel.type == discord.ChannelType.text):
                if (channel.name == ewcfg.channel_twitch_announcement):
                    channels_announcement.append(channel)
                    ewutils.logMsg("• found for announcements: {}".format(
                        channel.name))

                elif (channel.name == ewcfg.channel_stockexchange):
                    channels_stockmarket[server.id] = channel
                    ewutils.logMsg("• found for stock exchange: {}".format(
                        channel.name))

    time_now = int(time.time())
    time_last_twitch = time_now
    time_twitch_downed = 0
    time_last_pvp = time_now
    time_last_market = time_now

    # Every three hours we log a message saying the periodic task hook is still active. On startup, we want this to happen within about 60 seconds, and then on the normal 3 hour interval.
    time_last_logged = time_now - ewcfg.update_hookstillactive + 60

    stream_live = None
    while True:
        time_now = int(time.time())

        # Periodic message to log that this stuff is still running.
        if (time_now - time_last_logged) >= ewcfg.update_hookstillactive:
            time_last_logged = time_now

            ewutils.logMsg("Periodic hook still active.")

        # Check to see if a stream is live via the Twitch API.
        if twitch_client_id != None and (
                time_now - time_last_twitch) >= ewcfg.update_twitch:
            time_last_twitch = time_now

            try:
                # Twitch API call to see if there are any active streams.
                json_string = ""
                p = subprocess.Popen(
                    "curl -H 'Client-ID: {}' -X GET 'https://api.twitch.tv/helix/streams?user_login=rowdyfrickerscopkillers' 2>/dev/null"
                    .format(twitch_client_id),
                    shell=True,
                    stdout=subprocess.PIPE)
                for line in p.stdout.readlines():
                    json_string += line.decode('utf-8')
                json_parsed = json.loads(json_string)

                # When a stream is up, data is an array of stream information objects.
                data = json_parsed.get('data')
                if data != None:
                    data_count = len(data)
                    stream_was_live = stream_live
                    stream_live = True if data_count > 0 else False

                    if stream_was_live == True and stream_live == False:
                        time_twitch_downed = time_now

                    if stream_was_live == False and stream_live == True and (
                            time_now - time_twitch_downed) > 600:
                        ewutils.logMsg("The stream is now live.")

                        # The stream has transitioned from offline to online. Make an announcement!
                        for channel in channels_announcement:
                            await client.send_message(
                                channel,
                                "ATTENTION CITIZENS. THE **ROWDY F****R** AND THE **COP KILLER** ARE **STREAMING**. BEWARE OF INCREASED KILLER AND ROWDY ACTIVITY.\n\n@everyone\n{}"
                                .format(
                                    "https://www.twitch.tv/rowdyfrickerscopkillers"
                                ))
            except:
                ewutils.logMsg('Twitch handler hit an exception (continuing):')
                traceback.print_exc(file=sys.stdout)

        # Clear PvP roles from players who are no longer flagged.
        if (time_now - time_last_pvp) >= ewcfg.update_pvp:
            time_last_pvp = time_now

            try:
                for server in client.servers:
                    roles_map = ewutils.getRoleMap(server.roles)

                    role_juvenile_pvp = roles_map[ewcfg.role_juvenile_pvp]
                    role_rowdyfuckers_pvp = roles_map[
                        ewcfg.role_rowdyfuckers_pvp]
                    role_copkillers_pvp = roles_map[ewcfg.role_copkillers_pvp]

                    # Monitor all user roles and update if a user is no longer flagged for PvP.
                    for member in server.members:
                        pvp_role = None

                        if role_juvenile_pvp in member.roles:
                            pvp_role = role_juvenile_pvp
                        elif role_copkillers_pvp in member.roles:
                            pvp_role = role_copkillers_pvp
                        elif role_rowdyfuckers_pvp in member.roles:
                            pvp_role = role_rowdyfuckers_pvp

                        if pvp_role != None:
                            # Retrieve user data from the database.
                            user_data = EwUser(member=member)

                            # If the user's PvP expire time is historical, remove the PvP role.
                            if user_data.time_expirpvp < int(time.time()):
                                await client.remove_roles(member, pvp_role)

            except:
                ewutils.logMsg(
                    'An error occurred in the scheduled role update task:')
                traceback.print_exc(file=sys.stdout)

        # Adjust the exchange rate of slime for the market.
        try:
            for server in client.servers:
                # Load market data from the database.
                try:
                    conn = ewutils.databaseConnect()
                    cursor = conn.cursor()

                    market_data = EwMarket(id_server=server.id,
                                           conn=conn,
                                           cursor=cursor)
                    credit_totals = ewutils.getRecentTotalSlimeCoins(
                        id_server=server.id, conn=conn, cursor=cursor)
                finally:
                    cursor.close()
                    conn.close()

                if market_data.time_lasttick + ewcfg.update_market < time_now:
                    market_data.time_lasttick = time_now

                    # Nudge the value back to stability.
                    rate_market = market_data.rate_market
                    if rate_market >= 1030:
                        rate_market -= 10
                    elif rate_market <= 970:
                        rate_market += 10

                    # Add participation bonus.
                    active_bonus = 0
                    active_map = active_users_map.get(server.id)
                    if active_map != None:
                        active_bonus = len(active_map)

                        if active_bonus > 20:
                            active_bonus = 20

                    active_users_map[server.id] = {}
                    rate_market += (active_bonus / 4)

                    # Invest/Withdraw effects
                    credit_rate = 0
                    if credit_totals[0] != credit_totals[1]:
                        # Positive if net investment, negative if net withdrawal.
                        credit_change = (credit_totals[0] - credit_totals[1])
                        credit_rate = ((credit_change * 1.0) /
                                       credit_totals[1])

                        if credit_rate > 1.0:
                            credit_rate = 1.0
                        elif credit_rate < -0.5:
                            credit_rate = -0.5

                        credit_rate = int((
                            credit_rate *
                            ewcfg.max_iw_swing) if credit_rate > 0 else (
                                credit_rate * 2 * ewcfg.max_iw_swing))

                    rate_market += credit_rate

                    # Tick down the boombust cooldown.
                    if market_data.boombust < 0:
                        market_data.boombust += 1
                    elif market_data.boombust > 0:
                        market_data.boombust -= 1

                    # Adjust the market rate.
                    fluctuation = 0  #(random.randrange(5) - 2) * 100
                    noise = (random.randrange(19) - 9) * 2
                    subnoise = (random.randrange(13) - 6)

                    # Some extra excitement!
                    if noise == 0 and subnoise == 0:
                        boombust = (random.randrange(3) - 1) * 200

                        # If a boombust occurs shortly after a previous boombust, make sure it's the opposite effect. (Boom follows bust, bust follows boom.)
                        if (market_data.boombust > 0
                                and boombust > 0) or (market_data.boombust < 0
                                                      and boombust < 0):
                            boombust *= -1

                        if boombust != 0:
                            market_data.boombust = ewcfg.cd_boombust

                            if boombust < 0:
                                market_data.boombust *= -1
                    else:
                        boombust = 0

                    rate_market += fluctuation + noise + subnoise + boombust
                    if rate_market < 300:
                        rate_market = (300 + noise + subnoise)

                    percentage = ((rate_market / 10) - 100)
                    percentage_abs = percentage * -1

                    # If the value hits 0, we're stuck there forever.
                    if market_data.rate_exchange <= 100:
                        market_data.rate_exchange = 100

                    # Apply the market change to the casino balance and exchange rate.
                    market_data.slimes_casino = int(market_data.slimes_casino *
                                                    (rate_market / 1000.0))
                    market_data.rate_exchange = int(market_data.rate_exchange *
                                                    (rate_market / 1000.0))

                    # Advance the time and potentially change weather.
                    market_data.clock += 1
                    if market_data.clock >= 24 or market_data.clock < 0:
                        market_data.clock = 0
                    weatherchange = random.randrange(30)
                    if weatherchange >= 29:
                        pattern_count = len(ewcfg.weather_list)
                        if pattern_count > 1:
                            weather_old = market_data.weather

                            # Randomly select a new weather pattern. Try again if we get the same one we currently have.
                            while market_data.weather == weather_old:
                                pick = random.randrange(len(
                                    ewcfg.weather_list))
                                market_data.weather = ewcfg.weather_list[
                                    pick].name

                        # Log message for statistics tracking.
                        ewutils.logMsg(
                            "The weather changed. It's now {}.".format(
                                market_data.weather))

                    try:
                        conn = ewutils.databaseConnect()
                        cursor = conn.cursor()

                        # Persist new data.
                        market_data.rate_market = rate_market
                        market_data.persist(conn=conn, cursor=cursor)

                        # Create a historical snapshot.
                        ewutils.persistMarketHistory(market_data=market_data,
                                                     conn=conn,
                                                     cursor=cursor)

                        # Increase stamina for all players below the max.
                        ewutils.pushupServerStamina(id_server=server.id,
                                                    conn=conn,
                                                    cursor=cursor)

                        # Decrease inebriation for all players above min (0).
                        ewutils.pushdownServerInebriation(id_server=server.id,
                                                          conn=conn,
                                                          cursor=cursor)

                        conn.commit()
                    finally:
                        cursor.close()
                        conn.close()

                    # Give some indication of how the market is doing to the users.
                    response = "..."

                    # Market is up ...
                    if rate_market > 1200:
                        response = 'The slimeconomy is skyrocketing!!! Slime stock is up {p:.3g}%!!!'.format(
                            p=percentage)
                    elif rate_market > 1100:
                        response = 'The slimeconomy is booming! Slime stock is up {p:.3g}%!'.format(
                            p=percentage)
                    elif rate_market > 1000:
                        response = 'The slimeconomy is doing well. Slime stock is up {p:.3g}%.'.format(
                            p=percentage)
                    # Market is down ...
                    elif rate_market < 800:
                        response = 'The slimeconomy is plummetting!!! Slime stock is down {p:.3g}%!!!'.format(
                            p=percentage_abs)
                    elif rate_market < 900:
                        response = 'The slimeconomy is stagnating! Slime stock is down {p:.3g}%!'.format(
                            p=percentage_abs)
                    elif rate_market < 1000:
                        response = 'The slimeconomy is a bit sluggish. Slime stock is down {p:.3g}%.'.format(
                            p=percentage_abs)
                    # Perfectly balanced
                    else:
                        response = 'The slimeconomy is holding steady. No change in slime stock value.'

                    if market_data.clock == 6:
                        response += ' The Slime Stock Exchange is now open for business.'
                    elif market_data.clock == 18:
                        response += ' The Slime Stock Exchange has closed for the night.'

                    # Send the announcement.
                    channel = channels_stockmarket.get(server.id)
                    if channel != None:
                        await client.send_message(channel,
                                                  ('**' + response + '**'))
                    else:
                        ewutils.logMsg(
                            'No stock market channel for server {}'.format(
                                server.name))
        except:
            ewutils.logMsg(
                'An error occurred in the scheduled slime market update task:')
            traceback.print_exc(file=sys.stdout)

        # Wait a while before running periodic tasks.
        await asyncio.sleep(15)
Example #3
0
async def on_ready():
	global init_complete
	if init_complete:
		return
	init_complete = True
	ewcfg.set_client(client)
	ewutils.logMsg('Logged in as {} ({}).'.format(client.user.name, client.user.id))

	ewutils.logMsg("Loaded NLACakaNM world map. ({}x{})".format(ewmap.map_width, ewmap.map_height))
	ewmap.map_draw()

	# Flatten role names to all lowercase, no spaces.
	fake_observer = EwUser()
	fake_observer.life_state = ewcfg.life_state_observer
	for poi in ewcfg.poi_list:
		if poi.role != None:
			poi.role = ewutils.mapRoleName(poi.role)

		neighbors = []
		neighbor_ids = []
		if poi.coord != None:
			neighbors = ewmap.path_to(coord_start = poi.coord, user_data = fake_observer)
		#elif poi.id_poi == ewcfg.poi_id_thesewers:
		#	neighbors = ewcfg.poi_list

		if neighbors != None:
			for neighbor in neighbors:
				neighbor_ids.append(neighbor.id_poi)

		ewcfg.poi_neighbors[poi.id_poi] = set(neighbor_ids)
		ewutils.logMsg("Found neighbors for poi {}: {}".format(poi.id_poi, ewcfg.poi_neighbors[poi.id_poi]))


	for id_poi in ewcfg.landmark_pois:
		ewutils.logMsg("beginning landmark precomputation for " + id_poi)
		poi = ewcfg.id_to_poi.get(id_poi)
		ewmap.landmarks[id_poi] = ewmap.score_map_from(
			coord_start = poi.coord,
			user_data = fake_observer,
			landmark_mode = True
		)

	ewutils.logMsg("finished landmark precomputation")

	try:
		await client.change_presence(game = discord.Game(name = "EW " + ewcfg.version))
	except:
		ewutils.logMsg("Failed to change_presence!")

	# Look for a Twitch client_id on disk.
	# FIXME debug - temporarily disable Twitch integration
	if False:
		twitch_client_id = ewutils.getTwitchClientId()

	# If no twitch client ID is available, twitch integration will be disabled.
	# FIXME debug - temporarily disable Twitch integration.
	if True:
		twitch_client_id = None
		ewutils.logMsg('Twitch integration disabled.')
	elif twitch_client_id == None or len(twitch_client_id) == 0:
		ewutils.logMsg('No twitch_client_id file found. Twitch integration disabled.')
	else:
		ewutils.logMsg("Enabled Twitch integration.")

	# Channels in the connected discord servers to announce to.
	channels_announcement = []

	# Channels in the connected discord servers to send stock market updates to. Map of server ID to channel.
	channels_stockmarket = {}

	for server in client.servers:
		# Update server data in the database
		ewserver.server_update(server = server)

		# store the list of channels in an ewutils field
		ewcfg.update_server_list(server = server)

		# find roles and add them to the database
		ewrolemgr.setupRoles(client = client, id_server = server.id)

		# hides the names of poi roles
		await ewrolemgr.hideRoleNames(client = client, id_server = server.id)

		# Grep around for channels
		ewutils.logMsg("connected to server: {}".format(server.name))
		for channel in server.channels:
			if(channel.type == discord.ChannelType.text):
				if(channel.name == ewcfg.channel_twitch_announcement):
					channels_announcement.append(channel)
					ewutils.logMsg("• found channel for announcements: {}".format(channel.name))

				elif(channel.name == ewcfg.channel_stockexchange):
					channels_stockmarket[server.id] = channel
					ewutils.logMsg("• found channel for stock exchange: {}".format(channel.name))

		# create all the districts in the database
		for poi_object in ewcfg.poi_list:
			poi = poi_object.id_poi
			# call the constructor to create an entry if it doesnt exist yet
			dist = EwDistrict(id_server = server.id, district = poi)
			# change the ownership to the faction that's already in control to initialize topic names
			try:
				# initialize gang bases
				if poi == ewcfg.poi_id_rowdyroughhouse:
					dist.controlling_faction = ewcfg.faction_rowdys
				elif poi == ewcfg.poi_id_copkilltown:
					dist.controlling_faction = ewcfg.faction_killers

				resp_cont = dist.change_ownership(new_owner = dist.controlling_faction, actor = "init", client = client)
				dist.persist()
				await resp_cont.post()

			except:
				ewutils.logMsg('Could not change ownership for {} to "{}".'.format(poi, dist.controlling_faction))

		asyncio.ensure_future(ewdistrict.capture_tick_loop(id_server = server.id))
		asyncio.ensure_future(ewutils.bleed_tick_loop(id_server = server.id))
		asyncio.ensure_future(ewutils.enemy_action_tick_loop(id_server=server.id))
		asyncio.ensure_future(ewutils.spawn_enemies_tick_loop(id_server = server.id))
		asyncio.ensure_future(ewutils.burn_tick_loop(id_server = server.id))
		asyncio.ensure_future(ewutils.remove_status_loop(id_server = server.id))
		asyncio.ensure_future(ewworldevent.event_tick_loop(id_server = server.id))
		asyncio.ensure_future(ewutils.sap_tick_loop(id_server = server.id))
		
		if not debug:
			await ewtransport.init_transports(id_server = server.id)
			asyncio.ensure_future(ewweather.weather_tick_loop(id_server = server.id))
		asyncio.ensure_future(ewslimeoid.slimeoid_tick_loop(id_server = server.id))
		asyncio.ensure_future(ewfarm.farm_tick_loop(id_server = server.id))

	try:
		ewutils.logMsg('Creating message queue directory.')
		os.mkdir(ewcfg.dir_msgqueue)
	except FileExistsError:
		ewutils.logMsg('Message queue directory already exists.')

	ewutils.logMsg('Ready.')

	"""
		Set up for infinite loop to perform periodic tasks.
	"""
	time_now = int(time.time())
	time_last_pvp = time_now

	time_last_twitch = time_now
	time_twitch_downed = 0

	# Every three hours we log a message saying the periodic task hook is still active. On startup, we want this to happen within about 60 seconds, and then on the normal 3 hour interval.
	time_last_logged = time_now - ewcfg.update_hookstillactive + 60

	stream_live = None

	ewutils.logMsg('Beginning periodic hook loop.')
	while not ewutils.TERMINATE:
		time_now = int(time.time())

		# Periodic message to log that this stuff is still running.
		if (time_now - time_last_logged) >= ewcfg.update_hookstillactive:
			time_last_logged = time_now

			ewutils.logMsg("Periodic hook still active.")

		# Check to see if a stream is live via the Twitch API.
		# FIXME disabled
		if False:
		#if twitch_client_id != None and (time_now - time_last_twitch) >= ewcfg.update_twitch:
			time_last_twitch = time_now

			try:
				# Twitch API call to see if there are any active streams.
				json_string = ""
				p = subprocess.Popen(
					"curl -H 'Client-ID: {}' -X GET 'https://api.twitch.tv/helix/streams?user_login = rowdyfrickerscopkillers' 2>/dev/null".format(twitch_client_id),
					shell = True,
					stdout = subprocess.PIPE
				)

				for line in p.stdout.readlines():
					json_string += line.decode('utf-8')

				json_parsed = json.loads(json_string)

				# When a stream is up, data is an array of stream information objects.
				data = json_parsed.get('data')
				if data != None:
					data_count = len(data)
					stream_was_live = stream_live
					stream_live = True if data_count > 0 else False

					if stream_was_live == True and stream_live == False:
						time_twitch_downed = time_now

					if stream_was_live == False and stream_live == True and (time_now - time_twitch_downed) > 600:
						ewutils.logMsg("The stream is now live.")

						# The stream has transitioned from offline to online. Make an announcement!
						for channel in channels_announcement:
							await ewutils.send_message(
								client,
								channel,
								"ATTENTION CITIZENS. THE **ROWDY F****R** AND THE **COP KILLER** ARE **STREAMING**. BEWARE OF INCREASED KILLER AND ROWDY ACTIVITY.\n\n@everyone\n{}".format(
									"https://www.twitch.tv/rowdyfrickerscopkillers"
								)
							)
			except:
				ewutils.logMsg('Twitch handler hit an exception (continuing): {}'.format(json_string))
				traceback.print_exc(file = sys.stdout)

		# Clear PvP roles from players who are no longer flagged.
		if (time_now - time_last_pvp) >= ewcfg.update_pvp:
			time_last_pvp = time_now

			try:
				for server in client.servers:
					role_ids = []
					for pvp_role in ewcfg.role_to_pvp_role.values():
						role = ewrolemgr.EwRole(id_server = server.id, name = pvp_role)
						role_ids.append(role.id_role)

					# Monitor all user roles and update if a user is no longer flagged for PvP.
					for member in server.members:
						for role in member.roles:
							if role.id in role_ids:
								await ewrolemgr.updateRoles(client = client, member = member)
								break

			except:
				ewutils.logMsg('An error occurred in the scheduled role update task:')
				traceback.print_exc(file=sys.stdout)

		# Adjust the exchange rate of slime for the market.
		try:
			for server in client.servers:

				# Load market data from the database.
				market_data = EwMarket(id_server = server.id)

				if market_data.time_lasttick + ewcfg.update_market <= time_now:

					market_response = ""

					for stock in ewcfg.stocks:
						s = EwStock(server.id, stock)
						# we don't update stocks when they were just added
						if s.timestamp != 0:
							s.timestamp = time_now
							market_response = ewmarket.market_tick(s, server.id)
							await ewutils.send_message(client, channels_stockmarket.get(server.id), market_response)

					market_data = EwMarket(id_server = server.id)
					market_data.time_lasttick = time_now

					# Advance the time and potentially change weather.
					market_data.clock += 1

					if market_data.clock >= 24 or market_data.clock < 0:
						market_data.clock = 0
						market_data.day += 1

					if market_data.clock == 6:
						# Update the list of available bazaar items by clearing the current list and adding the new items
						market_data.bazaar_wares.clear()

						bazaar_foods = []
						bazaar_cosmetics = []
						bazaar_general_items = []
						bazaar_furniture = []

						for item in ewcfg.vendor_inv.get(ewcfg.vendor_bazaar):
							if item in ewcfg.item_names:
								bazaar_general_items.append(item)

							elif item in ewcfg.food_names:
								bazaar_foods.append(item)

							elif item in ewcfg.cosmetic_names:
								bazaar_cosmetics.append(item)

							elif item in ewcfg.furniture_names:
								bazaar_furniture.append(item)

						market_data.bazaar_wares['slimecorp1'] = ewcfg.weapon_id_umbrella
						market_data.bazaar_wares['slimecorp2'] = ewcfg.cosmetic_id_raincoat

						market_data.bazaar_wares['generalitem'] = random.choice(bazaar_general_items)

						market_data.bazaar_wares['food1'] = random.choice(bazaar_foods)
						# Don't add repeated foods
						bw_food2 = None
						while bw_food2 is None or bw_food2 in market_data.bazaar_wares.values():
							bw_food2 = random.choice(bazaar_foods)

						market_data.bazaar_wares['food2'] = bw_food2

						market_data.bazaar_wares['cosmetic1'] = random.choice(bazaar_cosmetics)
						# Don't add repeated cosmetics
						bw_cosmetic2 = None
						while bw_cosmetic2 is None or bw_cosmetic2 in market_data.bazaar_wares.values():
							bw_cosmetic2 = random.choice(bazaar_cosmetics)

						market_data.bazaar_wares['cosmetic2'] = bw_cosmetic2

						bw_cosmetic3 = None
						while bw_cosmetic3 is None or bw_cosmetic3 in market_data.bazaar_wares.values():
							bw_cosmetic3 = random.choice(bazaar_cosmetics)

						market_data.bazaar_wares['cosmetic3'] = bw_cosmetic3

						bw_furniture2 = None
						while bw_furniture2 is None or bw_furniture2 in market_data.bazaar_wares.values():
							bw_furniture2 = random.choice(bazaar_furniture)

						market_data.bazaar_wares['furniture2'] = bw_furniture2

						bw_furniture3 = None
						while bw_furniture3 is None or bw_furniture3 in market_data.bazaar_wares.values():
							bw_furniture3 = random.choice(bazaar_furniture)

						market_data.bazaar_wares['furniture3'] = bw_furniture3


						if random.random() == 0.1:
							market_data.bazaar_wares['minigun'] = ewcfg.weapon_id_minigun


					market_data.persist()

					if not ewutils.check_fursuit_active(market_data.id_server):
						ewcosmeticitem.dedorn_all_costumes()

					if market_data.clock == 6 and market_data.day % 8 == 0:
						await ewapt.rent_time(id_server=server.id)

					market_data = EwMarket(id_server=server.id)

					market_data.persist()
					if market_data.clock == 6:
						response = ' The SlimeCorp Stock Exchange is now open for business.'
						await ewutils.send_message(client, channels_stockmarket.get(server.id), response)
					elif market_data.clock == 20:
						response = ' The SlimeCorp Stock Exchange has closed for the night.'
						await ewutils.send_message(client, channels_stockmarket.get(server.id), response)

					market_data = EwMarket(id_server = server.id)

					if random.randrange(3) == 0:
						pattern_count = len(ewcfg.weather_list)

						if pattern_count > 1:
							weather_old = market_data.weather

							if random.random() < 0.4:
								market_data.weather = ewcfg.weather_bicarbonaterain

							# Randomly select a new weather pattern. Try again if we get the same one we currently have.
							while market_data.weather == weather_old:
								pick = random.randrange(len(ewcfg.weather_list))
								market_data.weather = ewcfg.weather_list[pick].name

						# Log message for statistics tracking.
						ewutils.logMsg("The weather changed. It's now {}.".format(market_data.weather))

					# Persist new data.
					market_data.persist()

					# Decay slime totals
					ewutils.decaySlimes(id_server = server.id)

					# Increase hunger for all players below the max.
					#ewutils.pushupServerHunger(id_server = server.id)

					# Decrease inebriation for all players above min (0).
					ewutils.pushdownServerInebriation(id_server = server.id)

					# Remove fish offers which have timed out
					ewfish.kill_dead_offers(id_server = server.id)

					# kill advertisements that have timed out
					ewads.delete_expired_ads(id_server = server.id)

					await ewdistrict.give_kingpins_slime_and_decay_capture_points(id_server = server.id)

					await ewmap.kick(server.id)

					# Post leaderboards at 6am NLACakaNM time.
					if market_data.clock == 6:
						await ewleaderboard.post_leaderboards(client = client, server = server)

		except:
			ewutils.logMsg('An error occurred in the scheduled slime market update task:')
			traceback.print_exc(file = sys.stdout)

		# Parse files dumped into the msgqueue directory and send messages as needed.
		try:
			for msg_file in os.listdir(ewcfg.dir_msgqueue):
				fname = "{}/{}".format(ewcfg.dir_msgqueue, msg_file)

				msg = ewutils.readMessage(fname)
				os.remove(fname)

				msg_channel_names = []
				msg_channel_names_reverb = []

				if msg.channel != None:
					msg_channel_names.append(msg.channel)

				if msg.poi != None:
					poi = ewcfg.id_to_poi.get(msg.poi)
					if poi != None:
						if poi.channel != None and len(poi.channel) > 0:
							msg_channel_names.append(poi.channel)

						if msg.reverb == True:
							pois_adjacent = ewmap.path_to(poi_start = msg.poi)

							for poi_adjacent in pois_adjacent:
								if poi_adjacent.channel != None and len(poi_adjacent.channel) > 0:
									msg_channel_names_reverb.append(poi_adjacent.channel)

				if len(msg_channel_names) == 0:
					ewutils.logMsg('in file {} message for channel {} (reverb {})\n{}'.format(msg_file, msg.channel, msg.reverb, msg.message))
				else:
					# Send messages to every connected server.
					for server in client.servers:
						for channel in server.channels:
							if channel.name in msg_channel_names:
								await ewutils.send_message(client, channel, "**{}**".format(msg.message))
							elif channel.name in msg_channel_names_reverb:
								await ewutils.send_message(client, channel, "**Something is happening nearby...\n\n{}**".format(msg.message))
		except:
			ewutils.logMsg('An error occurred while trying to process the message queue:')
			traceback.print_exc(file = sys.stdout)

		# Wait a while before running periodic tasks.
		await asyncio.sleep(15)