Пример #1
0
    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)
Пример #2
0
 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
Пример #3
0
    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