def connect_teleporters(self): """ Creates area connections for teleporter line types. """ count = 0 rect = Rectangle() for teleporter in self.map_data.teleporters: target_area = None # Get the area that the teleporter target is in. if teleporter.kind == Teleporter.TELEPORTER_THING: floorz = self.map_data.get_floor_z(teleporter.dest.x, teleporter.dest.y) target_area = self.get_area_at(teleporter.dest, floorz) if teleporter.kind == Teleporter.TELEPORTER_LINE: dest = Vector2() dest.x, dest.y = self.map_data.get_line_center(teleporter.dest_line) floorz = self.map_data.get_floor_z(teleporter.dest.x, teleporter.dest.y) target_area = self.get_area_at(dest, floorz) # Ignore missing teleport targets. if target_area is None: print 'Teleporter linedef {} does not point to a place on the map with navigation areas.'.format(teleporter.source_line) continue # Create the teleport connection line from the linedef vertices. linedef = self.map_data.linedefs[teleporter.source_line] rect.set( linedef.vertex1.x, linedef.vertex1.y, linedef.vertex2.x, linedef.vertex2.y ) # Place a teleporter connection in all intersecting source areas. areas = self.get_areas_intersecting(rect) for area in areas: connection = Connection() connection.rect.copy_from(rect) connection.area_a = area connection.area_b = target_area connection.linedef = teleporter.source_line connection.flags = Connection.FLAG_AB | Connection.FLAG_TELEPORTER area.connections.append(connection) count += 1 print 'Connected {} teleporters.'.format(count)
def read(self, filename, map_data): """ Reads a mesh from a file. """ with open(filename, 'rb') as f: data = Mesh.FILE_HEADER.unpack(f.read(Mesh.FILE_HEADER.size)) file_id = data[0] file_version = data[1] data_hash = data[2] if data_hash != map_data.data_hash: self.outdated = True print 'Warning: the navigation mesh is out of date or the wrong map is loaded.' else: self.outdated = False # Validate header. if file_id != Mesh.FILE_ID: print 'Invalid mesh file.' return if file_version > Mesh.FILE_VERSION: print 'Unsupported mesh version {}.'.format(file_version) return area_hashes = {} plane_hashes = {} connection_hashes = {} self.areas = [] # Read planes. planes_count = Mesh.FILE_PLANES_HEADER.unpack(f.read(Mesh.FILE_PLANES_HEADER.size))[0] for _ in range(planes_count): plane = Plane() plane_hash, plane.a, plane.b, plane.c, plane.d, plane.invc = Mesh.FILE_PLANE.unpack(f.read(Mesh.FILE_PLANE.size)) plane_hashes[plane_hash] = plane # Read area connections. connections_count = Mesh.FILE_CONNECTIONS_HEADER.unpack(f.read(Mesh.FILE_CONNECTIONS_HEADER.size))[0] for _ in range(connections_count): connection = Connection() connection_hash, left, top, right, bottom, area_a_hash, area_b_hash, linedef, flags = Mesh.FILE_CONNECTION.unpack(f.read(Mesh.FILE_CONNECTION.size)) if linedef == -1: linedef = None connection.rect.set(left, top, right, bottom) connection.center = connection.rect.get_center() connection.area_a = area_a_hash connection.area_b = area_b_hash connection.linedef = linedef connection.flags = flags connection_hashes[connection_hash] = connection # Read mesh areas. area_count = Mesh.FILE_AREAS_HEADER.unpack(f.read(Mesh.FILE_AREAS_HEADER.size))[0] for index in range(area_count): area_hash, left, top, right, bottom, z, plane_hash, sector_index, flags, connection_count = Mesh.FILE_AREA.unpack(f.read(Mesh.FILE_AREA.size)) area = Area(left, top, right, bottom, z) if sector_index == -1: sector_index = None area.sector = sector_index area.flags = flags area.index = index if plane_hash != 0: area.plane = plane_hashes[plane_hash] for _ in range(connection_count): connection_hash = Mesh.FILE_AREA_CONNECTION.unpack(f.read(Mesh.FILE_AREA_CONNECTION.size))[0] area.connections.append(connection_hashes[connection_hash]) self.areas.append(area) area_hashes[area_hash] = area # Set connection objects. for connection in connection_hashes.itervalues(): if connection.area_a != 0: connection.area_a = area_hashes[connection.area_a] else: connection.area_a = None if connection.area_b != 0: connection.area_b = area_hashes[connection.area_b] else: connection.area_b = None self.map_data = map_data
def connect_areas(self): """ Connects navigation areas together. Area objects are expected to contain references to only their outermost elements. Using these elements and their connections, areas are connected to each other. """ count = 0 for area in self.areas: # Test each element in an area. for element in area.elements: for direction in Element.DIR_RANGE: if element.connection[direction] is not None: continue other_element = element.elements[direction] if other_element is None or other_element.area == area or other_element.area is None: continue # Find all elements that connect to the same area. connecting = [] other_area = other_element.area for c_element in area.elements: # Add elements that connect to the same area to a list of connection elements. if c_element.elements[direction] is not None and c_element.elements[direction].area == other_area: connecting.append(c_element) connecting.append(c_element.elements[direction]) # Calculate the bounding box of the connecting elements. # This forms the bounding box of the connection area. rect = self.get_elements_bounds(connecting) # See if a connection exists in the other area that is equal to the current one. connection = None for c_connection in other_area.connections: if c_connection.area_b == area and c_connection.rect == rect: connection = c_connection connection.flags |= Connection.FLAG_BA break # Create new connection object if needed. if connection is None: count += 1 connection = Connection() connection.flags = Connection.FLAG_AB connection.area_a = area connection.area_b = other_area connection.rect.copy_from(rect) connection.center = connection.rect.get_center() area.connections.append(connection) # Assign connection to elements. for c_element in connecting: if c_element.area == area: c_element.connection[direction] = connection return count