def from_ent(cls, ent: Entity) -> Iterator[BBox]: """Parse keyvalues on a VMF entity. One bounding box is produced for each brush.""" coll = CollideType.NOTHING for key, value in ent.keys.items(): if key.casefold().startswith('coll_') and conv_bool(value): coll_name = key[5:].upper() try: coll |= CollideType[coll_name] except KeyError: LOGGER.warning('Invalid collide type: "{}"!', key) tags = frozenset(ent['tags'].split()) for solid in ent.solids: mins, maxes = solid.get_bbox() non_skip_faces = [ face for face in solid if face.mat != consts.Tools.SKIP ] try: # Only one non-skip face, "flatten" along its plane. face: Side [face] = non_skip_faces except ValueError: pass # Regular bbox. else: plane_norm = face.normal() plane_point = face.planes[0] for point in [mins, maxes]: # Get the offset from the plane, then subtract to force it onto the plane. point -= plane_norm * Vec.dot(point - plane_point, plane_norm) yield cls(mins, maxes, contents=coll, tags=tags)
def res_transfer_bullseye(inst: Entity, props: Property): """Transfer catapult targets and placement helpers from one tile to another.""" start_pos = conditions.resolve_offset(inst, props['start_pos', '']) end_pos = conditions.resolve_offset(inst, props['end_pos', '']) angles = Angle.from_str(inst['angles']) start_norm = props.vec('start_norm', 0, 0, 1) @ angles end_norm = props.vec('end_norm', 0, 0, 1) @ angles try: start_tile = tiling.TILES[(start_pos - 64 * start_norm).as_tuple(), start_norm.as_tuple()] except KeyError: LOGGER.warning( '"{}": Cannot find tile to transfer from at {}, {}!'.format( inst['targetname'], start_pos, start_norm)) return end_tile = tiling.TileDef.ensure( end_pos - 64 * end_norm, end_norm, ) # Now transfer the stuff. if start_tile.has_oriented_portal_helper: # We need to rotate this. orient = start_tile.portal_helper_orient.copy() # If it's directly opposite, just mirror - we have no clue what the # intent is. if Vec.dot(start_norm, end_norm) != -1.0: # Use the dict to compute the rotation to apply. orient @= NORM_ROTATIONS[start_norm.as_tuple(), end_norm.as_tuple()] end_tile.add_portal_helper(orient) elif start_tile.has_portal_helper: # Non-oriented, don't orient. end_tile.add_portal_helper() start_tile.remove_portal_helper(all=True) if start_tile.bullseye_count: end_tile.bullseye_count = start_tile.bullseye_count start_tile.bullseye_count = 0 # Then transfer the targets across. for plate in faithplate.PLATES.values(): if getattr(plate, 'target', None) is start_tile: plate.target = end_tile