def build_solid_dict(): """Build a dictionary mapping origins to brush faces. This allows easily finding brushes that are at certain locations. """ import vbsp mat_types = {} for mat in vbsp.BLACK_PAN: mat_types[mat] = template_brush.MAT_TYPES.black for mat in vbsp.WHITE_PAN: mat_types[mat] = template_brush.MAT_TYPES.white for solid in VMF.brushes: for face in solid: if face.mat.casefold in consts.Goo: # Record all locations containing goo. bbox_min, bbox_max = solid.get_bbox() x = bbox_min.x + 64 y = bbox_min.y + 64 # If goo is multi-level, we want to record all pos! for z in range(int(bbox_min.z) + 64, int(bbox_max.z), 128): GOO_LOCS[Vec_tuple(x, y, z)] = face # Add the location of the top face GOO_FACE_LOC[Vec_tuple(x, y, bbox_max.z)] = face # Indicate that this map contains goo... vbsp.settings['has_attr']['goo'] = True continue try: mat_type = mat_types[face.mat] except KeyError: continue else: origin = face.get_origin().as_tuple() if origin in SOLIDS: # The only time two textures will be in the same # place is if they are covering each other - # nodraw them both and ignore them SOLIDS.pop(origin).face.mat = consts.Tools.NODRAW face.mat = consts.Tools.NODRAW continue SOLIDS[origin] = solidGroup( color=mat_type, face=face, solid=solid, normal=face.normal(), )
def test(x1, y1, z1, x2, y2, z2): """Check a Vec pair for incorrect comparisons.""" vec1 = Vec(x1, y1, z1) vec2 = Vec(x2, y2, z2) for op_func in comp_ops: if op_func is op.ne: # special-case - != uses or, not and corr_result = x1 != x2 or y1 != y2 or z1 != z2 else: corr_result = op_func(x1, x2) and op_func(y1, y2) and op_func( z1, z2) comp = ('Incorrect {{}} comparison for ' '({} {} {}) {} ({} {} {})'.format(x1, y1, z1, op_func.__name__, x2, y2, z2)) assert op_func(vec1, vec2) == corr_result, comp.format('Vec') assert op_func(vec1, Vec_tuple( x2, y2, z2)) == corr_result, comp.format('Vec_tuple') assert op_func(vec1, (x2, y2, z2)) == corr_result, comp.format('tuple') # Bare numbers compare magnitude.. assert op_func(vec1, x2) == op_func(vec1.mag(), x2), comp.format('x') assert op_func(vec1, y2) == op_func(vec1.mag(), y2), comp.format('y') assert op_func(vec1, z2) == op_func(vec1.mag(), z2), comp.format('z')
def res_cutout_tile(vmf: srctools.VMF, res: Property): """Generate random quarter tiles, like in Destroyed or Retro maps. - `MarkerItem` is the instance file to look for (`<ITEM_BEE2_CUTOUT_TILE>`) - `floor_chance`: The percentage change for a segment in the middle of the floor to be a normal tile. - `floor_glue_chance`: The chance for any tile to be glue - this should be higher than the regular chance, as that overrides this. - `rotateMax` is the maximum angle to rotate squarebeam models. - `squarebeamsSkin` sets the skin to use for the squarebeams floor frame. - `dispBase`, if true makes the floor a displacement with random alpha. - `Materials` blocks specify the possible materials to use: - `squarebeams` is the squarebeams variant to use. - `ceilingwalls` are the sides of the ceiling section. - `floorbase` is the texture under floor sections. If `dispBase` is True this is a displacement material. - `tile_glue` is used on top of a thinner tile segment. - `clip` is the player_clip texture used over floor segments. (This allows customising the surfaceprop.) """ marker_filenames = instanceLocs.resolve(res['markeritem']) # TODO: Reimplement cutout tiles. for inst in vmf.by_class['func_instance']: if inst['file'].casefold() in marker_filenames: inst.remove() return x: float y: float max_x: float max_y: float INST_LOCS = {} # Map targetnames -> surface loc CEIL_IO = [] # Pairs of ceil inst corners to cut out. FLOOR_IO = [] # Pairs of floor inst corners to cut out. overlay_ids = {} # When we replace brushes, we need to fix any overlays # on that surface. MATS.clear() floor_edges = [] # Values to pass to add_floor_sides() at the end sign_locs = set() # If any signage is present in the map, we need to force tiles to # appear at that location! for over in vmf.by_class['info_overlay']: if (over['material'].casefold() in FORCE_TILE_MATS and # Only check floor/ceiling overlays over['basisnormal'] in ('0 0 1', '0 0 -1')): add_signage_loc(sign_locs, Vec.from_str(over['origin'])) for item in connections.ITEMS.values(): for ind_pan in item.ind_panels: loc = Vec(0, 0, -64) loc.localise( Vec.from_str(ind_pan['origin']), Vec.from_str(ind_pan['angles']), ) add_signage_loc(sign_locs, loc) SETTINGS = { 'floor_chance': srctools.conv_int(res['floorChance', '100'], 100), 'ceil_chance': srctools.conv_int(res['ceilingChance', '100'], 100), 'floor_glue_chance': srctools.conv_int(res['floorGlueChance', '0']), 'ceil_glue_chance': srctools.conv_int(res['ceilingGlueChance', '0']), 'rotate_beams': int(srctools.conv_float(res['rotateMax', '0']) * BEAM_ROT_PRECISION), 'beam_skin': res['squarebeamsSkin', '0'], 'base_is_disp': srctools.conv_bool(res['dispBase', '0']), 'quad_floor': res['FloorSize', '4x4'].casefold() == '2x2', 'quad_ceil': res['CeilingSize', '4x4'].casefold() == '2x2', } random.seed(vbsp.MAP_RAND_SEED + '_CUTOUT_TILE_NOISE') noise = SimplexNoise(period=4 * 40) # 4 tiles/block, 50 blocks max # We want to know the number of neighbouring tile cutouts before # placing tiles - blocks away from the sides generate fewer tiles. # all_floors[z][x,y] = count floor_neighbours = defaultdict( dict) # type: Dict[float, Dict[Tuple[float, float], int]] for mat_prop in res.find_key('Materials', []): MATS[mat_prop.name].append(mat_prop.value) if SETTINGS['base_is_disp']: # We want the normal brushes to become nodraw. MATS['floorbase_disp'] = MATS['floorbase'] MATS['floorbase'] = ['tools/toolsnodraw'] # Since this uses random data for initialisation, the alpha and # regular will use slightly different patterns. alpha_noise = SimplexNoise(period=4 * 50) else: alpha_noise = None for key, default in TEX_DEFAULT: if key not in MATS: MATS[key] = [default] # Find our marker ents for inst in vmf.by_class['func_instance']: if inst['file'].casefold() not in marker_filenames: continue targ = inst['targetname'] normal = Vec(0, 0, 1).rotate_by_str(inst['angles', '0 0 0']) # Check the orientation of the marker to figure out what to generate if normal == (0, 0, 1): io_list = FLOOR_IO else: io_list = CEIL_IO # Reuse orient to calculate where the solid face will be. loc = Vec.from_str(inst['origin']) - 64 * normal INST_LOCS[targ] = loc item = connections.ITEMS[targ] item.delete_antlines() if item.outputs: for conn in list(item.outputs): if conn.to_item.inst['file'].casefold() in marker_filenames: io_list.append((targ, conn.to_item.name)) else: LOGGER.warning('Cutout tile connected to non-cutout!') conn.remove() # Delete the connection. else: # If the item doesn't have any connections, 'connect' # it to itself so we'll generate a 128x128 tile segment. io_list.append((targ, targ)) # Remove all traces of this item (other than in connections lists). inst.remove() del connections.ITEMS[targ] for start_floor, end_floor in FLOOR_IO: box_min = Vec(INST_LOCS[start_floor]) box_min.min(INST_LOCS[end_floor]) box_max = Vec(INST_LOCS[start_floor]) box_max.max(INST_LOCS[end_floor]) if box_min.z != box_max.z: continue # They're not in the same level! z = box_min.z if SETTINGS['rotate_beams']: # We have to generate 1 model per 64x64 block to do rotation... gen_rotated_squarebeams( vmf, box_min - (64, 64, 0), box_max + (64, 64, -8), skin=SETTINGS['beam_skin'], max_rot=SETTINGS['rotate_beams'], ) else: # Make the squarebeams props, using big models if possible gen_squarebeams(vmf, box_min + (-64, -64, 0), box_max + (64, 64, -8), skin=SETTINGS['beam_skin']) # Add a player_clip brush across the whole area vmf.add_brush( vmf.make_prism( p1=box_min - (64, 64, FLOOR_DEPTH), p2=box_max + (64, 64, 0), mat=MATS['clip'][0], ).solid) # Add a noportal_volume covering the surface, in case there's # room for a portal. noportal_solid = vmf.make_prism( # Don't go all the way to the sides, so it doesn't affect wall # brushes. p1=box_min - (63, 63, 9), p2=box_max + (63, 63, 0), mat='tools/toolsinvisible', ).solid noportal_ent = vmf.create_ent( classname='func_noportal_volume', origin=box_min.join(' '), ) noportal_ent.solids.append(noportal_solid) if SETTINGS['base_is_disp']: # Use displacements for the base instead. make_alpha_base( vmf, box_min + (-64, -64, 0), box_max + (64, 64, 0), noise=alpha_noise, ) for x, y in utils.iter_grid( min_x=int(box_min.x), max_x=int(box_max.x) + 1, min_y=int(box_min.y), max_y=int(box_max.y) + 1, stride=128, ): # Build the set of all positions.. floor_neighbours[z][x, y] = -1 # Mark borders we need to fill in, and the angle (for func_instance) # The wall is the face pointing inwards towards the bottom brush, # and the ceil is the ceiling of the block above the bordering grid # points. for x in range(int(box_min.x), int(box_max.x) + 1, 128): # North floor_edges.append( BorderPoints( wall=Vec(x, box_max.y + 64, z - 64), ceil=Vec_tuple(x, box_max.y + 128, z), rot=270, )) # South floor_edges.append( BorderPoints( wall=Vec(x, box_min.y - 64, z - 64), ceil=Vec_tuple(x, box_min.y - 128, z), rot=90, )) for y in range(int(box_min.y), int(box_max.y) + 1, 128): # East floor_edges.append( BorderPoints( wall=Vec(box_max.x + 64, y, z - 64), ceil=Vec_tuple(box_max.x + 128, y, z), rot=180, )) # West floor_edges.append( BorderPoints( wall=Vec(box_min.x - 64, y, z - 64), ceil=Vec_tuple(box_min.x - 128, y, z), rot=0, )) # Now count boundaries near tiles, then generate them. # Do it separately for each z-level: for z, xy_dict in floor_neighbours.items(): for x, y in xy_dict: # We want to count where there aren't any tiles xy_dict[x, y] = (((x - 128, y - 128) not in xy_dict) + ((x - 128, y + 128) not in xy_dict) + ((x + 128, y - 128) not in xy_dict) + ((x + 128, y + 128) not in xy_dict) + ((x - 128, y) not in xy_dict) + ((x + 128, y) not in xy_dict) + ((x, y - 128) not in xy_dict) + ((x, y + 128) not in xy_dict)) max_x = max_y = 0 weights = {} # Now the counts are all correct, compute the weight to apply # for tiles. # Adding the neighbouring counts will make a 5x5 area needed to set # the center to 0. for (x, y), cur_count in xy_dict.items(): max_x = max(x, max_x) max_y = max(y, max_y) # Orthrogonal is worth 0.2, diagonal is worth 0.1. # Not-present tiles would be 8 - the maximum tile_count = (0.8 * cur_count + 0.1 * xy_dict.get( (x - 128, y - 128), 8) + 0.1 * xy_dict.get( (x - 128, y + 128), 8) + 0.1 * xy_dict.get( (x + 128, y - 128), 8) + 0.1 * xy_dict.get( (x + 128, y + 128), 8) + 0.2 * xy_dict.get( (x - 128, y), 8) + 0.2 * xy_dict.get( (x, y - 128), 8) + 0.2 * xy_dict.get( (x, y + 128), 8) + 0.2 * xy_dict.get( (x + 128, y), 8)) # The number ranges from 0 (all tiles) to 12.8 (no tiles). # All tiles should still have a small chance to generate tiles. weights[x, y] = min((tile_count + 0.5) / 8, 1) # Share the detail entity among same-height tiles.. detail_ent = vmf.create_ent(classname='func_detail', ) for x, y in xy_dict: convert_floor( vmf, Vec(x, y, z), overlay_ids, MATS, SETTINGS, sign_locs, detail_ent, noise_weight=weights[x, y], noise_func=noise, ) add_floor_sides(vmf, floor_edges) return conditions.RES_EXHAUSTED
Entity, ) COND_MOD_NAME = None LOGGER = utils.getLogger(__name__, alias='cond.vactubes') PUSH_SPEED = 700 # The speed of the push triggers. UP_PUSH_SPEED = 900 # Make it slightly faster when up to counteract gravity DN_PUSH_SPEED = 400 # Slow down when going down since gravity also applies.. PUSH_TRIGS = {} CornerAng = namedtuple('CornerAng', 'ang, axis') xp = Vec_tuple(1, 0, 0) xn = Vec_tuple(-1, 0, 0) yp = Vec_tuple(0, 1, 0) yn = Vec_tuple(0, -1, 0) zp = Vec_tuple(0, 0, 1) zn = Vec_tuple(0, 0, -1) # start, end normals -> angle of corner instance and the unchanged axis CORNER_ANG = { (zp, xp): CornerAng('0 0 0', 'y'), (zp, xn): CornerAng('0 180 0', 'y'), (zp, yp): CornerAng('0 90 0', 'x'), (zp, yn): CornerAng('0 270 0', 'x'), (zn, xp): CornerAng('0 0 180', 'y'), (zn, xn): CornerAng('0 180 180', 'y'), (zn, yp): CornerAng('0 90 180', 'x'),
def test(x1, y1, z1, x2, y2, z2): """Check a Vec pair for addition and subtraction.""" vec1 = Vec(x1, y1, z1) vec2 = Vec(x2, y2, z2) # These are direct methods, so no inheritence and iop to deal with. # Commutative assert vec1.dot(vec2) == (x1 * x2 + y1 * y2 + z1 * z2) assert vec2.dot(vec1) == (x1 * x2 + y1 * y2 + z1 * z2) assert_vec( vec1.cross(vec2), y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2, ) # Ensure they haven't modified the originals assert_vec(vec1, x1, y1, z1) assert_vec(vec2, x2, y2, z2) # Addition and subtraction for op_name, op_func, op_ifunc in operators: result = ( op_func(x1, x2), op_func(y1, y2), op_func(z1, z2), ) assert_vec(op_func(vec1, vec2), *result, msg='Vec({} {} {}) {} Vec({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) # Ensure they haven't modified the originals assert_vec(vec1, x1, y1, z1) assert_vec(vec2, x2, y2, z2) assert_vec(op_func(vec1, Vec_tuple(x2, y2, z2)), *result, msg='Vec({} {} {}) {} Vec_tuple({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) assert_vec(vec1, x1, y1, z1) assert_vec(op_func(Vec_tuple(x1, y1, z1), vec2), *result, msg='Vec_tuple({} {} {}) {} Vec({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) assert_vec(vec2, x2, y2, z2) new_vec1 = Vec(x1, y1, z1) assert_vec(op_ifunc(new_vec1, vec2), *result, msg='Return val: ({} {} {}) {}= ({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) # Check it modifies the original object too. assert_vec(new_vec1, *result, msg='Original: ({} {} {}) {}= ({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) new_vec1 = Vec(x1, y1, z1) assert_vec(op_ifunc(new_vec1, tuple(vec2)), *result, msg='Return val: ({} {} {}) {}= tuple({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) # Check it modifies the original object too. assert_vec(new_vec1, *result, msg='Original: ({} {} {}) {}= tuple({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, ))
def res_cutout_tile(res: Property): """Generate random quarter tiles, like in Destroyed or Retro maps. - "MarkerItem" is the instance to look for. - "TileSize" can be "2x2" or "4x4". - rotateMax is the amount of degrees to rotate squarebeam models. Materials: - "squarebeams" is the squarebeams variant to use. - "ceilingwalls" are the sides of the ceiling section. - "floorbase" is the texture under floor sections. - "tile_glue" is used on top of a thinner tile segment. - "clip" is the player_clip texture used over floor segments. (This allows customising the surfaceprop.) - "Floor4x4Black", "Ceil2x2White" and other combinations can be used to override the textures used. """ item = instanceLocs.resolve(res['markeritem']) INST_LOCS = {} # Map targetnames -> surface loc CEIL_IO = [] # Pairs of ceil inst corners to cut out. FLOOR_IO = [] # Pairs of floor inst corners to cut out. overlay_ids = {} # When we replace brushes, we need to fix any overlays # on that surface. MATS.clear() floor_edges = [] # Values to pass to add_floor_sides() at the end sign_loc = set(FORCE_LOCATIONS) # If any signage is present in the map, we need to force tiles to # appear at that location! for over in conditions.VMF.by_class['info_overlay']: if (over['material'].casefold() in FORCE_TILE_MATS and # Only check floor/ceiling overlays over['basisnormal'] in ('0 0 1', '0 0 -1')): loc = Vec.from_str(over['origin']) # Sometimes (light bridges etc) a sign will be halfway between # tiles, so in that case we need to force 2 tiles. loc_min = (loc - (15, 15, 0)) // 32 * 32 # type: Vec loc_max = (loc + (15, 15, 0)) // 32 * 32 # type: Vec loc_min += (16, 16, 0) loc_max += (16, 16, 0) FORCE_LOCATIONS.add(loc_min.as_tuple()) FORCE_LOCATIONS.add(loc_max.as_tuple()) SETTINGS = { 'floor_chance': srctools.conv_int(res['floorChance', '100'], 100), 'ceil_chance': srctools.conv_int(res['ceilingChance', '100'], 100), 'floor_glue_chance': srctools.conv_int(res['floorGlueChance', '0']), 'ceil_glue_chance': srctools.conv_int(res['ceilingGlueChance', '0']), 'rotate_beams': int(srctools.conv_float(res['rotateMax', '0']) * BEAM_ROT_PRECISION), 'beam_skin': res['squarebeamsSkin', '0'], 'base_is_disp': srctools.conv_bool(res['dispBase', '0']), 'quad_floor': res['FloorSize', '4x4'].casefold() == '2x2', 'quad_ceil': res['CeilingSize', '4x4'].casefold() == '2x2', } random.seed(vbsp.MAP_RAND_SEED + '_CUTOUT_TILE_NOISE') noise = SimplexNoise(period=4 * 40) # 4 tiles/block, 50 blocks max # We want to know the number of neighbouring tile cutouts before # placing tiles - blocks away from the sides generate fewer tiles. floor_neighbours = defaultdict(dict) # all_floors[z][x,y] = count for mat_prop in res['Materials', []]: MATS[mat_prop.name].append(mat_prop.value) if SETTINGS['base_is_disp']: # We want the normal brushes to become nodraw. MATS['floorbase_disp'] = MATS['floorbase'] MATS['floorbase'] = ['tools/toolsnodraw'] # Since this uses random data for initialisation, the alpha and # regular will use slightly different patterns. alpha_noise = SimplexNoise(period=4 * 50) else: alpha_noise = None for key, default in TEX_DEFAULT: if key not in MATS: MATS[key] = [default] # Find our marker ents for inst in conditions.VMF.by_class['func_instance']: # type: VLib.Entity if inst['file'].casefold() not in item: continue targ = inst['targetname'] orient = Vec(0, 0, 1).rotate_by_str(inst['angles', '0 0 0']) # Check the orientation of the marker to figure out what to generate if orient == (0, 0, 1): io_list = FLOOR_IO else: io_list = CEIL_IO # Reuse orient to calculate where the solid face will be. loc = (orient * -64) + Vec.from_str(inst['origin']) INST_LOCS[targ] = loc for out in inst.output_targets(): io_list.append((targ, out)) if not inst.outputs and inst.fixup['$connectioncount'] == '0': # If the item doesn't have any connections, 'connect' # it to itself so we'll generate a 128x128 tile segment. io_list.append((targ, targ)) inst.remove() # Remove the instance itself from the map. for start_floor, end_floor in FLOOR_IO: if end_floor not in INST_LOCS: # Not a marker - remove this and the antline. for toggle in conditions.VMF.by_target[end_floor]: conditions.remove_ant_toggle(toggle) continue box_min = Vec(INST_LOCS[start_floor]) box_min.min(INST_LOCS[end_floor]) box_max = Vec(INST_LOCS[start_floor]) box_max.max(INST_LOCS[end_floor]) if box_min.z != box_max.z: continue # They're not in the same level! z = box_min.z if SETTINGS['rotate_beams']: # We have to generate 1 model per 64x64 block to do rotation... gen_rotated_squarebeams( box_min - (64, 64, 0), box_max + (64, 64, -8), skin=SETTINGS['beam_skin'], max_rot=SETTINGS['rotate_beams'], ) else: # Make the squarebeams props, using big models if possible gen_squarebeams(box_min + (-64, -64, 0), box_max + (64, 64, -8), skin=SETTINGS['beam_skin']) # Add a player_clip brush across the whole area conditions.VMF.add_brush( conditions.VMF.make_prism( p1=box_min - (64, 64, FLOOR_DEPTH), p2=box_max + (64, 64, 0), mat=MATS['clip'][0], ).solid) # Add a noportal_volume covering the surface, in case there's # room for a portal. noportal_solid = conditions.VMF.make_prism( # Don't go all the way to the sides, so it doesn't affect wall # brushes. p1=box_min - (63, 63, 9), p2=box_max + (63, 63, 0), mat='tools/toolsinvisible', ).solid noportal_ent = conditions.VMF.create_ent( classname='func_noportal_volume', origin=box_min.join(' '), ) noportal_ent.solids.append(noportal_solid) if SETTINGS['base_is_disp']: # Use displacements for the base instead. make_alpha_base( box_min + (-64, -64, 0), box_max + (64, 64, 0), noise=alpha_noise, ) for x, y in utils.iter_grid( min_x=int(box_min.x), max_x=int(box_max.x) + 1, min_y=int(box_min.y), max_y=int(box_max.y) + 1, stride=128, ): # Build the set of all positions.. floor_neighbours[z][x, y] = -1 # Mark borders we need to fill in, and the angle (for func_instance) # The wall is the face pointing inwards towards the bottom brush, # and the ceil is the ceiling of the block above the bordering grid # points. for x in range(int(box_min.x), int(box_max.x) + 1, 128): # North floor_edges.append( BorderPoints( wall=Vec(x, box_max.y + 64, z - 64), ceil=Vec_tuple(x, box_max.y + 128, z), rot=270, )) # South floor_edges.append( BorderPoints( wall=Vec(x, box_min.y - 64, z - 64), ceil=Vec_tuple(x, box_min.y - 128, z), rot=90, )) for y in range(int(box_min.y), int(box_max.y) + 1, 128): # East floor_edges.append( BorderPoints( wall=Vec(box_max.x + 64, y, z - 64), ceil=Vec_tuple(box_max.x + 128, y, z), rot=180, )) # West floor_edges.append( BorderPoints( wall=Vec(box_min.x - 64, y, z - 64), ceil=Vec_tuple(box_min.x - 128, y, z), rot=0, )) # Now count boundries near tiles, then generate them. # Do it seperately for each z-level: for z, xy_dict in floor_neighbours.items(): # type: float, dict for x, y in xy_dict: # type: float, float # We want to count where there aren't any tiles xy_dict[x, y] = (((x - 128, y - 128) not in xy_dict) + ((x - 128, y + 128) not in xy_dict) + ((x + 128, y - 128) not in xy_dict) + ((x + 128, y + 128) not in xy_dict) + ((x - 128, y) not in xy_dict) + ((x + 128, y) not in xy_dict) + ((x, y - 128) not in xy_dict) + ((x, y + 128) not in xy_dict)) max_x = max_y = 0 weights = {} # Now the counts are all correct, compute the weight to apply # for tiles. # Adding the neighbouring counts will make a 5x5 area needed to set # the center to 0. for (x, y), cur_count in xy_dict.items(): max_x = max(x, max_x) max_y = max(y, max_y) # Orthrogonal is worth 0.2, diagonal is worth 0.1. # Not-present tiles would be 8 - the maximum tile_count = (0.8 * cur_count + 0.1 * xy_dict.get( (x - 128, y - 128), 8) + 0.1 * xy_dict.get( (x - 128, y + 128), 8) + 0.1 * xy_dict.get( (x + 128, y - 128), 8) + 0.1 * xy_dict.get( (x + 128, y + 128), 8) + 0.2 * xy_dict.get( (x - 128, y), 8) + 0.2 * xy_dict.get( (x, y - 128), 8) + 0.2 * xy_dict.get( (x, y + 128), 8) + 0.2 * xy_dict.get( (x + 128, y), 8)) # The number ranges from 0 (all tiles) to 12.8 (no tiles). # All tiles should still have a small chance to generate tiles. weights[x, y] = min((tile_count + 0.5) / 8, 1) # Share the detail entity among same-height tiles.. detail_ent = conditions.VMF.create_ent(classname='func_detail', ) for x, y in xy_dict: convert_floor( Vec(x, y, z), overlay_ids, MATS, SETTINGS, sign_loc, detail_ent, noise_weight=weights[x, y], noise_func=noise, ) add_floor_sides(floor_edges) conditions.reallocate_overlays(overlay_ids) return conditions.RES_EXHAUSTED
def test(x1, y1, z1, x2, y2, z2): """Check a Vec pair for addition and subtraction.""" vec1 = Vec(x1, y1, z1) vec2 = Vec(x2, y2, z2) for op_name, op_func, op_ifunc in operators: result = ( op_func(x1, x2), op_func(y1, y2), op_func(z1, z2), ) assert_vec(op_func(vec1, vec2), *result, msg='Vec({} {} {}) {} Vec({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) # Ensure they haven't modified the originals assert_vec(vec1, x1, y1, z1) assert_vec(vec2, x2, y2, z2) assert_vec(op_func(vec1, Vec_tuple(x2, y2, z2)), *result, msg='Vec({} {} {}) {} Vec_tuple({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) assert_vec(vec1, x1, y1, z1) assert_vec(op_func(Vec_tuple(x1, y1, z1), vec2), *result, msg='Vec_tuple({} {} {}) {} Vec({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) assert_vec(vec2, x2, y2, z2) new_vec1 = Vec(x1, y1, z1) assert_vec(op_ifunc(new_vec1, vec2), *result, msg='Return val: ({} {} {}) {}= ({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) # Check it modifies the original object too. assert_vec(new_vec1, *result, msg='Original: ({} {} {}) {}= ({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) new_vec1 = Vec(x1, y1, z1) assert_vec(op_ifunc(new_vec1, tuple(vec2)), *result, msg='Return val: ({} {} {}) {}= tuple({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, )) # Check it modifies the original object too. assert_vec(new_vec1, *result, msg='Original: ({} {} {}) {}= tuple({} {} {})'.format( x1, y1, z1, op_name, x2, y2, z2, ))