Пример #1
0
	def create_map_images(self, mode=0):
		if mode == 0:
			print 'Creating images....'
			t0 = libtcod.sys_elapsed_seconds()
		con = libtcod.console_new(game.WORLDMAP_WIDTH, game.WORLDMAP_HEIGHT)
		self.map_image_small = libtcod.image_new(game.WORLDMAP_WIDTH, game.WORLDMAP_HEIGHT)
		self.create_map_legend(con, mode)
		libtcod.image_scale(self.map_image_small, (game.SCREEN_WIDTH - 2) * 2, (game.SCREEN_HEIGHT - 2) * 2)

		if mode == 0:
			while self.player_positionx == 0:
				start = self.randomize('int', 0, (game.WORLDMAP_WIDTH * game.WORLDMAP_HEIGHT) - 1, 3)
				if int(self.hm_list[start] * 1000) in range(int(game.terrain['Forest']['elevation'] * 1000), int(game.terrain['Forest']['maxelev'] * 1000)):
					self.player_positionx = start % game.WORLDMAP_WIDTH
					self.player_positiony = start / game.WORLDMAP_WIDTH
					self.originx = self.player_positionx
					self.originy = self.player_positiony

					path = self.set_dijkstra_map()
					for y in range(game.WORLDMAP_HEIGHT):
						for x in range(game.WORLDMAP_WIDTH):
							dist = libtcod.dijkstra_get_distance(path, x, y)
							if dist > self.max_distance:
								self.max_distance = int(round(dist))
					#libtcod.image_put_pixel(self.map_image_small, self.player_positionx, self.player_positiony, libtcod.white)

		if mode == 2:
			self.map_image_big = libtcod.image_from_console(con)
			libtcod.image_save(self.map_image_big, 'maps/worldmap-' + game.player.name + '.png')
			self.map_image_big = None
		libtcod.console_delete(con)
		if mode == 0:
			t1 = libtcod.sys_elapsed_seconds()
			print '    done! (%.3f seconds)' % (t1 - t0)
Пример #2
0
	def smooth_edges(self):
		print 'Smoothing edges....'
		t0 = libtcod.sys_elapsed_seconds()
		hmcopy = libtcod.heightmap_new(game.WORLDMAP_WIDTH, game.WORLDMAP_HEIGHT)
		mask = libtcod.heightmap_new(game.WORLDMAP_WIDTH, game.WORLDMAP_HEIGHT)
		for x in range(game.WORLDMAP_WIDTH):
			for y in range(game.WORLDMAP_HEIGHT):
				ix = x * 0.04
				if x > game.WORLDMAP_WIDTH / 2:
					ix = (game.WORLDMAP_WIDTH - x - 1) * 0.04
				iy = y * 0.04
				if y > game.WORLDMAP_HEIGHT / 2:
					iy = (game.WORLDMAP_HEIGHT - y - 1) * 0.04
				if ix > 1.0:
					ix = 1.0
				if iy > 1.0:
					iy = 1.0
				h = min(ix, iy)
				libtcod.heightmap_set_value(mask, x, y, h)
		libtcod.heightmap_normalize(mask)
		libtcod.heightmap_copy(game.heightmap, hmcopy)
		libtcod.heightmap_multiply_hm(hmcopy, mask, game.heightmap)
		libtcod.heightmap_normalize(game.heightmap)
		t1 = libtcod.sys_elapsed_seconds()
		print '    done! (%.3f seconds)' % (t1 - t0)
Пример #3
0
	def generate(self):
		print 'Starting world map generation....'
		t0 = libtcod.sys_elapsed_seconds()
		accepted = False
		world = 1
		while not accepted:
			print 'World #' + str(world) + '....'
			self.noise = libtcod.noise_new(2, self.rnd)
			libtcod.noise_set_type(self.noise, libtcod.NOISE_PERLIN)
			game.heightmap = libtcod.heightmap_new(game.WORLDMAP_WIDTH, game.WORLDMAP_HEIGHT)
			#game.precipitation = libtcod.heightmap_new(game.WORLDMAP_WIDTH, game.WORLDMAP_HEIGHT)
			#game.temperature = libtcod.heightmap_new(game.WORLDMAP_WIDTH, game.WORLDMAP_HEIGHT)
			#game.biome = libtcod.heightmap_new(game.WORLDMAP_WIDTH, game.WORLDMAP_HEIGHT)

			self.add_landmass()
			self.smooth_edges()
			self.set_landmass(self.randomize('float', 0.30, 0.45, 3), self.sandheight)
			self.add_rivers()
			self.create_map_images()
			self.place_dungeons()
			accepted = self.analyse_world()
			world += 1
			print '-------------'
		t1 = libtcod.sys_elapsed_seconds()
		print 'World map generation finished.... (%.3f seconds)' % (t1 - t0)
Пример #4
0
	def set_landmass(self, landmass, waterlevel):
		print 'Reducing landmass....'
		t0 = libtcod.sys_elapsed_seconds()
		heightcount = [0] * 256
		for x in range(game.WORLDMAP_WIDTH):
			for y in range(game.WORLDMAP_HEIGHT):
				h = int(libtcod.heightmap_get_value(game.heightmap, x, y) * 255)
				heightcount[h] += 1

		i, totalcount = 0, 0
		while totalcount < game.WORLDMAP_WIDTH * game.WORLDMAP_HEIGHT * (1.0 - landmass):
			totalcount += heightcount[i]
			i += 1
		newwaterlevel = i / 255.0
		landcoef = (1.0 - waterlevel) / (1.0 - newwaterlevel)
		watercoef = waterlevel / newwaterlevel

		for x in range(game.WORLDMAP_WIDTH):
			for y in range(game.WORLDMAP_HEIGHT):
				h = libtcod.heightmap_get_value(game.heightmap, x, y)
				if h > newwaterlevel:
					h = waterlevel + (h - newwaterlevel) * landcoef
				else:
					h = h * watercoef
				libtcod.heightmap_set_value(game.heightmap, x, y, h)
		t1 = libtcod.sys_elapsed_seconds()
		print '    done! (%.3f seconds)' % (t1 - t0)
Пример #5
0
	def place_dungeons(self):
		print 'Placing dungeons....'
		t0 = libtcod.sys_elapsed_seconds()
		path = self.set_dijkstra_map()
		for i in range(game.MAX_THREAT_LEVEL):
			done = False
			attempt = 0
			while not done and attempt <= 1000:
				x = libtcod.random_get_int(self.rnd, 0, game.WORLDMAP_WIDTH - 1)
				y = libtcod.random_get_int(self.rnd, 0, game.WORLDMAP_HEIGHT - 1)
				cellheight = int(libtcod.heightmap_get_value(game.heightmap, x, y) * 1000)
				threat = self.set_threat_level(x, y, path)
				dice = libtcod.random_get_int(self.rnd, 1, 100)
				if dice <= 65:
					dtype = 'Dungeon'
				elif dice <= 95:
					dtype = 'Cave'
				else:
					dtype = 'Maze'
				if cellheight in range(int(game.terrain['Plains']['elevation'] * 1000), int(game.terrain['High Hills']['maxelev'] * 1000)) and threat == i + 1:
					self.dungeons.append((len(self.dungeons) + 1, 'Dungeon', 'Dng', x, y, threat + 1, dtype))
					done = True
				attempt += 1

		starter_dungeon = libtcod.random_get_int(self.rnd, 1, 4)
		if starter_dungeon == 1:
			self.dungeons.append((len(self.dungeons) + 1, 'Starter Dungeon', 'SD', self.player_positionx, self.player_positiony - 1, 1, 'Dungeon'))
		elif starter_dungeon == 2:
			self.dungeons.append((len(self.dungeons) + 1, 'Starter Dungeon', 'SD', self.player_positionx + 1, self.player_positiony, 1, 'Dungeon'))
		elif starter_dungeon == 3:
			self.dungeons.append((len(self.dungeons) + 1, 'Starter Dungeon', 'SD', self.player_positionx, self.player_positiony + 1, 1, 'Dungeon'))
		else:
			self.dungeons.append((len(self.dungeons) + 1, 'Starter Dungeon', 'SD', self.player_positionx - 1, self.player_positiony, 1, 'Dungeon'))
		t1 = libtcod.sys_elapsed_seconds()
		print '    done! (%.3f seconds)' % (t1 - t0)
Пример #6
0
def test_sys_time(console):
    libtcodpy.sys_set_fps(0)
    libtcodpy.sys_get_fps()
    libtcodpy.sys_get_last_frame_length()
    libtcodpy.sys_sleep_milli(0)
    libtcodpy.sys_elapsed_milli()
    libtcodpy.sys_elapsed_seconds()
Пример #7
0
	def analyse_world(self):
		print 'Analysing worldmap....'
		t0 = libtcod.sys_elapsed_seconds()
		mountain_peak = 0
		mountains = 0
		high_hills = 0
		low_hills = 0
		forest = 0
		plains = 0
		coast = 0
		shore = 0
		sea = 0
		ocean = 0
		accepted = True

		for x in range(game.WORLDMAP_WIDTH):
			for y in range(game.WORLDMAP_HEIGHT):
				cellheight = libtcod.heightmap_get_value(game.heightmap, x, y)
				if cellheight >= game.terrain['Mountain Peak']['elevation']:
					mountain_peak += 1
				elif cellheight >= game.terrain['Mountains']['elevation']:
					mountains += 1
				elif cellheight >= game.terrain['High Hills']['elevation']:
					high_hills += 1
				elif cellheight >= game.terrain['Low Hills']['elevation']:
					low_hills += 1
				elif cellheight >= game.terrain['Forest']['elevation']:
					forest += 1
				elif cellheight >= game.terrain['Plains']['elevation']:
					plains += 1
				elif cellheight >= game.terrain['Coast']['elevation']:
					coast += 1
				elif cellheight >= game.terrain['Shore']['elevation']:
					shore += 1
				elif cellheight >= game.terrain['Sea']['elevation']:
					sea += 1
				else:
					ocean += 1

		if mountain_peak < 15 or mountains < 150 or high_hills < 600 or low_hills < 1500 or coast < 2500:
			accepted = False
		if forest > 22000 or plains > 10000 or shore > 8000 or sea > 28000 or ocean > 30000:
			accepted = False
		t1 = libtcod.sys_elapsed_seconds()
		if accepted:
			print '    accepted! (%.3f seconds)' % (t1 - t0)
		else:
			self.player_positionx = 0
			self.max_distance = 0
			self.dungeons = []
			print '    rejected! (%.3f seconds)' % (t1 - t0)
		return accepted
Пример #8
0
	def add_landmass(self):
		print 'Creating landmass....'
		t0 = libtcod.sys_elapsed_seconds()
		for i in range(int(game.WORLDMAP_WIDTH * 0.55)):
			radius = self.randomize('float', 50 * (1.0 - 0.7), 50 * (1.0 + 0.7), 3)
			x = self.randomize('int', 0, game.WORLDMAP_WIDTH, 3)
			y = self.randomize('int', 0, game.WORLDMAP_HEIGHT, 3)
			libtcod.heightmap_add_hill(game.heightmap, x, y, radius, 0.3)
		libtcod.heightmap_normalize(game.heightmap)
		libtcod.heightmap_add_fbm(game.heightmap, self.noise, 6.5, 6.5, 0, 0, 8.0, 1.0, 4.0)
		libtcod.heightmap_normalize(game.heightmap)
		t1 = libtcod.sys_elapsed_seconds()
		print '    done! (%.3f seconds)' % (t1 - t0)
Пример #9
0
    def new_find_path(self, start, end, tiles=[]):
        t0 = libtcod.sys_elapsed_seconds()

        if len(tiles) == 0:
            self.tiles = R.tiles
        else:
            self.tiles = tiles
        if self.check_blocked(start) and self.check_blocked(end):
            return None
        if self.tiles[start[0]][start[1]].continent != self.tiles[end[0]][end[1]].continent:
            print "not on same continent"
            return None

        self.frontier = PriorityQueue()
        self.node_costs = {}
        self.node_status = {}
        self.came_from = {}
        self.largest_cost = 0

        self.end = end_node = PathNode(end, 0)
        self.start = start_node = PathNode(start, 0, endNode=end_node)

        self.heuristic_cost = heuristic_straightline(start,end)

        self.frontier.put(start_node, 0)
        self.node_costs[start_node] = 0

        while not self.frontier.empty():
            current = self.frontier.get()

            if current.is_equal_to_node(end_node) and current == end_node:
                t1 = libtcod.sys_elapsed_seconds()
                path = self.reconstruct_path(self.came_from, start_node, end_node)
                print "path of length: ", len(path), " succeeded in %s" % (t1 - t0), "explored ", len(self.node_costs.keys())

                print "heuristic_cost:", self.heuristic_cost, " Actual cost:", self.node_costs[end_node]
                # return current #TODO: reconstruct path.
                path.reverse()
                return path
            else:
                for neighbour in self.find_neighbours(current, end_node):
                    new_cost = neighbour.cost
                    # if self.node_costs.has_key(neighbour):
                    if new_cost < self.node_costs.get(neighbour, float("inf")):
                        if self.largest_cost < new_cost:
                            self.largest_cost = new_cost
                        self.node_costs[neighbour] = new_cost
                        self.frontier.put(neighbour, new_cost + heuristic_straightline(neighbour.grid, end_node.grid))
                        self.came_from[neighbour] = current
Пример #10
0
    def find_path(self, world, start, goal):

        if world.tiles[start[0]][start[1]].continent != world.tiles[goal[0]][goal[1]].continent:
            print "not on same continent"
            return None
        t0 = libtcod.sys_elapsed_seconds()
        graph = SquareGrid(R.MAP_WIDTH, R.MAP_HEIGHT)
        graph.walls = world.blocked
        graph.weights = world.weights
        came_from, costs = self.a_star(graph, start, goal)
        path = self.reconstruct_path(came_from, start, goal)
        path.reverse()
        t1 = libtcod.sys_elapsed_seconds()
        print "path of length: ", len(path), " succeeded in %s" % (t1 - t0), "explored ", len(self.node_costs.keys())
        return path
Пример #11
0
def play_game():
    global key, mouse, player_turn

    mouse = libtcod.Mouse()
    key = libtcod.Key()

    start_time = libtcod.sys_elapsed_seconds()
    while not libtcod.console_is_window_closed():

        libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse)

        delta_time = libtcod.sys_get_last_frame_length()
        #render the screen
        if not local:

            ##Clear the characters from screen.
            for object_ in R.world_obj:
                object_.clear(cam_x, cam_y)

            for city in cities:
                for merchant in city.trade_house.caravans_out:
                    merchant.clear(cam_x, cam_y)

            #handles the keys and exit if needed.
            player_action = handle_keys()
            if player_action == "exit":
                save_game()
                break
            if not pause:  #and not player_turn:
                advance_time()
                #player_turn = True

            handle_mouse()
            render_all()

        else:

            #            for object_ in R.locale_obj:
            #                object_.clear(cam_x,cam_y)
            #
            #            you.clear(cam_x, cam_y)

            #handles the keys and exit if needed.
            player_action = handle_keys()
            if player_action == "exit":
                save_game()
                break

            handle_mouse()
            render_local()

        if R.msg_redraw == True:
            update_msg_bar()
Пример #12
0
def stats():
	libtcod.console_set_default_foreground(None, libtcod.grey)
	
	libtcod.console_print_ex (
		None, 79, 46, libtcod.BKGND_NONE, libtcod.RIGHT,
		'last frame : %3d ms (%3d fps)' %
		(
			int(libtcod.sys_get_last_frame_length() * 1000.0),
			libtcod.sys_get_fps()
		)
	)
	
	libtcod.console_print_ex (
		None, 79, 47, libtcod.BKGND_NONE, libtcod.RIGHT,
		'elapsed : %8d ms %4.2fs' %
		(
			libtcod.sys_elapsed_milli(),
			libtcod.sys_elapsed_seconds()
		)
	)
Пример #13
0
    def find_path(self, start, end, tiles=[]):

        t0 = libtcod.sys_elapsed_seconds()
        if len(tiles) == 0:
            self.tiles = R.tiles
        else:
            self.tiles = tiles

        if len(tiles) <= 0 or start[0] < 0 or start[1] < 0 or end[0] < 0 or end[1] < 0:
            print "FALSE, no tiles, or start/end is out of bounds"
            return None

        if self.check_blocked(start) and self.check_blocked(end):
            print str(start[0]), "/", str(start[1]), "to" + str(end[0]), "/", str(end[1]) + " tile was not traversable."
            return None

        if self.tiles[start[0]][start[1]].continent != self.tiles[end[0]][end[1]].continent:
            print "not on same continent"
            return None

        self.open_list = []
        self.node_costs.clear()
        self.node_status.clear()
        self.largest_cost = 0

        self.end = end_node = PathNode(end, 0)
        self.start = start_node = PathNode(start, 0, endNode=end_node)
        # print "weeee let's go."
        self.add_node(start_node)

        while len(self.open_list) > 0:
            current_node = self.open_list[len(self.open_list) - 1]  #putting this to 0 is cool.
            #check to see if the end has been reached.
            if current_node.is_equal_to_node(end_node):# and current_node == self.open_list[0]: #why does this need to be 0?
                best_path = []
                while current_node != None:
                    best_path.insert(0, current_node.grid)
                    current_node = current_node.parent_node
                #return the path of grid points.
                t1 = libtcod.sys_elapsed_seconds()
                print "path of length: ", len(best_path), " succeeded in %s" % (t1 - t0), "explored ", \
                    len(self.node_costs.keys()), "and open nodes left: " + str(len(self.open_list))
                # print "open_list is " + str(len(self.open_list)) + " long"
                # print "path succeeded in %s" % (t1 - t0)
                t0 = t1
                return best_path
            else:
                if current_node.is_equal_to_node(end_node) and current_node != self.open_list[0]:
                    current_node = self.open_list[len(self.open_list) - 2]
                #do this
                if current_node.grid[0] < 0 or current_node.grid[1] < 0:
                    print "uh-oh somehow it's a minus!"
                    return None

                self.open_list.remove(current_node)
                self.node_status[current_node.grid] = self.CLOSED
                if self.node_costs[current_node.grid] != current_node.cost:
                    print "for some reason, the current grid costs don't match the dictionary.... fixing.."
                    self.node_costs[current_node.grid] = current_node.cost

                #                 if self.node_costs.has_key(current_node.grid):
                #                     #node_costs is used to track the nodes. so this NEEDS to be removed.
                #                     self.node_costs.pop(current_node.grid, 0)
                #                 else:
                #                     print "NODE WAS NOT IN NODE_COSTS"
                #                     continue

                for neighbour in self.find_adjacent_nodes_3(current_node, end_node):
                    if self.node_status.has_key(neighbour.grid):
                        if self.node_status[neighbour.grid] == self.CLOSED:
                            continue
                        if self.node_status[neighbour.grid] == self.OPEN or neighbour.cost < self.node_costs[
                            neighbour.grid]:
                            if neighbour.cost >= self.node_costs[neighbour.grid]:
                                continue
                            else:
                                self.replace_node(neighbour)
                    else:
                        self.add_node(neighbour)
                        if self.largest_cost < neighbour.cost:
                            self.largest_cost = neighbour.cost
                self.node_status[current_node.grid] = self.CLOSED
                # current_node = None

        print "failed", len(self.open_list), start[0], start[1], " --- > ", end[0], end[1]
        t1 = libtcod.sys_elapsed_seconds()
        print "path failed in %s" % (t1 - t0)
        t0 = t1
        return None
Пример #14
0
	def add_rivers(self):
		print 'Adding rivers....'
		t0 = libtcod.sys_elapsed_seconds()
		libtcod.heightmap_rain_erosion(game.heightmap, int((game.WORLDMAP_WIDTH * game.WORLDMAP_HEIGHT) * 1.00), 0.06, 0.01, self.rnd)
		t1 = libtcod.sys_elapsed_seconds()
		print '    done! (%.3f seconds)' % (t1 - t0)
Пример #15
0
def do_race(key, mouse):
  bottom_viewport_height = 7  
  main_viewport_height = g.screen_height - bottom_viewport_height
  main_viewport_width = g.MAIN_VIEWPORT_WIDTH
  side_viewport_width = g.screen_width - main_viewport_width
  main_viewport = tcod.console_new(main_viewport_width, main_viewport_height)

  bottom_viewport_y = g.screen_height - bottom_viewport_height
  bottom_viewport = tcod.console_new(main_viewport_width, bottom_viewport_height)
  tcod.console_set_alignment(bottom_viewport, tcod.LEFT)

  side_viewport_x = g.screen_width - side_viewport_width  
  side_viewport = tcod.console_new(side_viewport_width, g.screen_height)

  intro_w = int(g.screen_width * .35)
  intro_h = int(g.screen_height * .20)
  intro_x = int(g.screen_width * 0.5 - intro_w * 0.5)
  intro_y = int(g.screen_height * 0.5 - intro_h * 0.5)
  intro_window = tcod.console_new(intro_w, intro_h)
  tcod.console_set_alignment(intro_window, tcod.CENTER)
  tcod.console_set_default_foreground(intro_window, tcod.sea)

  lexicon = lex.genres_lexicons[g.lexicon_counter][0]
  title_and_song = build_song(lexicon)
  race = Race(g.season.teams, g.season.circuits[g.season.current_race], title_and_song[1], title_and_song[0])

  # Reset stuff
  for x in range(0, len(race.teams)):
    race.teams[x].reset()

  teams = race.teams
  player_team_index = 0
  lane_count = len(race.teams)
  track_width = ((race.lane_size + 1) * lane_count) + 1
  BASE_OFFSET_TO_CENTER = int((g.MAIN_VIEWPORT_WIDTH - track_width) / 2)
  for x in range(0, len(teams)):
    if (teams[x].isPlayer):
      player_team_index = x
    teams[x].vehicle.x = BASE_OFFSET_TO_CENTER + (x * (race.lane_size + 1)) + 2

  exit_game = False
  lyrics = race.lyrics
  vehicles_collided = set([])
  active_lyrics_character = 0
  keypress_timer = 99999
  race_finished = False
  race_started = False
  verse = 0
  song_completed = False
  barricade_locations = [] # holds tuples of x, y barricade locations
  intro_lines = get_race_intro(title_and_song[0], lexicon, race.circuit)
  current_intro_line = 0
  first_frame = True
  time_elapsed_last_frame = 0
  race_start_time = tcod.sys_elapsed_seconds()
  while not race_finished and not exit_game:
    tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS, key, mouse)
    keypress_timer += tcod.sys_get_last_frame_length()
    total_time_elapsed = tcod.sys_elapsed_seconds()
        
    if race_started:
      if not first_frame:
        time_elapsed_last_frame = tcod.sys_get_last_frame_length()
      for team in teams:
        team.ai_run_counters()
        # Apply collision physics if needed
        if team.vehicle in vehicles_collided:
          handle_post_collision(team)

        else:
          if team.vehicle.distance_traveled >= len(race.circuit.track_shape) and not team.finished_current_race:
            finish_race(race, team, total_time_elapsed - race_start_time)

          # Control player vehicle
          if team.isPlayer and not team.finished_current_race:
            action = handle_keys(key)
            pressed_key_char = action.get('key_char')
            steer = action.get('steer')
            exit = action.get('exit')
            if not song_completed:
              powerpct = g.get_powerpct_from_keyspeed(keypress_timer)
            else:
              powerpct = 1
            team.vehicle.apply_power(powerpct)

            if pressed_key_char and not song_completed:
              correct = check_key_char_input(pressed_key_char, race.lyrics[verse], active_lyrics_character)
              if correct:
                keypress_timer = 0.0
                active_lyrics_character += 1
                if (active_lyrics_character >= len(lyrics[verse])):
                  active_lyrics_character = 0
                  verse += 1
                  if verse >= len(lyrics):
                    song_completed = True

              else:
                # TODO: mis-steer
                pass

            if steer and team.vehicle.speed > 0: # Can only steer if moving
              teams[player_team_index].vehicle.x += steer
            
            if exit:
              exit_game = True

          # If team is not player
          elif not team.finished_current_race:
            direction = team.ai_determine_direction()
            if direction == td.LEFT:
              team.vehicle.x += -1
            elif direction == td.RIGHT:
              team.vehicle.x += 1
            team.ai_apply_power()

          # If team has reached the finish line
          else:
            team.vehicle.apply_power(0)
            # Don't have time to do proper checks to wait for all teams to
            # finsh race. For now, just wait until the player team's vehicle
            # has coasted to a stop, and then take everyone's place from that
            # moment.
            if team.isPlayer and team.vehicle.speed == 0:
              race_finished = True

        # Apply acceleration, determine speed
        speed_to_add = time_elapsed_last_frame * team.vehicle.acceleration
        team.vehicle.speed += speed_to_add
        if team.vehicle.speed > team.vehicle.current_max_speed_from_power:
          team.vehicle.speed -= 0.1
        if team.vehicle.speed > team.vehicle.max_speed:
          team.vehicle.speed = team.vehicle.max_speed
        elif team.vehicle.speed < 0:
          team.vehicle.speed = 0
        distance_traveled_this_frame = time_elapsed_last_frame * team.vehicle.speed

        team.ai_observe_curves(race.circuit.track_layout, int(team.vehicle.distance_traveled + distance_traveled_this_frame) - int(team.vehicle.distance_traveled)) # This HAS to come first
        team.vehicle.distance_traveled += distance_traveled_this_frame
        

      # Check for collisions
      vehicles_collided.clear()
      handle_collisions(race, vehicles_collided, barricade_locations)

      first_frame = False

    # Render
    tcod.console_clear(main_viewport)
    print_race(main_viewport, race, int(teams[player_team_index].vehicle.y), int(teams[player_team_index].vehicle.distance_traveled), barricade_locations)
    tcod.console_blit(main_viewport, 0, 0, g.screen_width, g.screen_height, 0, 0, 0,)

    tcod.console_clear(bottom_viewport)
    if not song_completed:
      print_lyrics(bottom_viewport, race.lyrics[verse], active_lyrics_character)
    tcod.console_blit(bottom_viewport, 0, 0, main_viewport_width, bottom_viewport_height, 0, 0, bottom_viewport_y)

    tcod.console_clear(side_viewport)
    print_panel_side(side_viewport, build_race_stats(race), side_viewport_width)
    tcod.console_blit(side_viewport, 0, 0, side_viewport_width, g.screen_height - bottom_viewport_height, 0, side_viewport_x, 0)

    if not race_started:
      # This structure is pretty ugly, but no time to clean it up
      if current_intro_line == len(intro_lines):
        time.sleep(intro_lines[current_intro_line - 1][1])
      elif current_intro_line >= len(intro_lines):
        race_started = True
      else:
        tcod.console_clear(intro_window)
        tcod.console_hline(intro_window, 0, 0, intro_w)
        tcod.console_hline(intro_window, 0, intro_h - 1, intro_w)
        tcod.console_vline(intro_window, 0, 0, intro_h)
        tcod.console_vline(intro_window, intro_w - 1, 0, intro_h)
        tcod.console_print_rect_ex(intro_window, int(intro_w/2), 1, intro_w - 3, intro_h - 2, tcod.BKGND_SET, tcod.CENTER, intro_lines[current_intro_line][0])
        tcod.console_blit(intro_window, 0, 0, intro_w, intro_h, 0, intro_x, intro_y)
        if current_intro_line > 0:
          time.sleep(intro_lines[current_intro_line - 1][1])
      current_intro_line += 1

    tcod.console_flush()

  # Race is finished
  if exit_game:
    tcod.console_clear(main_viewport)
    tcod.console_blit(main_viewport, 0, 0, g.screen_width, g.screen_height, 0, 0, 0,)
    tcod.console_clear(bottom_viewport)
    tcod.console_blit(bottom_viewport, 0, 0, main_viewport_width, bottom_viewport_height, 0, 0, bottom_viewport_y)
    tcod.console_flush()
    g.context = Context.MAIN_MENU
  else:
    final_stats = build_race_stats(race)
    place = 1
    for stat in final_stats:
      race.places[place] = stat.team
      place += 1
    g.season.races.append(race)
    g.lexicon_counter += 1
    if g.lexicon_counter >= len(lex.genres_lexicons):
      g.lexicon_counter = 0
    g.context = Context.POST_RACE