예제 #1
0
def res_conveyor_belt(vmf: VMF, inst: Entity, res: Property) -> None:
    """Create a conveyor belt.

    * Options:
        * `SegmentInst`: Generated at each square. (`track` is the name of the
          path to attach to.)
        * `TrackTeleport`: Set the track points so they teleport trains to the start.
        * `Speed`: The fixup or number for the train speed.
        * `MotionTrig`: If set, a trigger_multiple will be spawned that
          `EnableMotion`s weighted cubes. The value is the name of the relevant filter.
        * `EndOutput`: Adds an output to the last track. The value is the same as
          outputs in VMFs.
        `RotateSegments`: If true (default), force segments to face in the
          direction of movement.
        * `BeamKeys`: If set, a list of keyvalues to use to generate an env_beam 
          travelling from start to end. The origin is treated specially - X is
          the distance from walls, y is the distance to the side, and z is the
          height.
        `RailTemplate`: A template for the track sections. This is made into a
          non-solid func_brush, combining all sections.
        * `NoPortalFloor`: If set, add a `func_noportal_volume` on the floor
          under the track.
        * `PaintFizzler`: If set, add a paint fizzler underneath the belt.
    """
    move_dist = inst.fixup.int('$travel_distance')

    if move_dist <= 2:
        # There isn't room for a conveyor, so don't bother.
        inst.remove()
        return

    move_dir = Vec(1, 0, 0).rotate_by_str(inst.fixup['$travel_direction'])
    move_dir = move_dir.rotate_by_str(inst['angles'])
    start_offset = inst.fixup.float('$starting_position')
    teleport_to_start = res.bool('TrackTeleport', True)
    segment_inst_file = instanceLocs.resolve_one(res['SegmentInst', ''])
    rail_template = res['RailTemplate', None]

    track_speed = res['speed', None]

    start_pos = Vec.from_str(inst['origin'])
    end_pos = start_pos + move_dist * move_dir

    if start_offset > 0:
        # If an oscillating platform, move to the closest side..
        offset = start_offset * move_dir
        # The instance is placed this far along, so move back to the end.
        start_pos -= offset
        end_pos -= offset
        if start_offset > 0.5:
            # Swap the direction of movement..
            start_pos, end_pos = end_pos, start_pos
        inst['origin'] = start_pos

    norm = Vec(z=1).rotate_by_str(inst['angles'])

    if res.bool('rotateSegments', True):
        inst['angles'] = angles = move_dir.to_angle_roll(norm)
    else:
        angles = Vec.from_str(inst['angles'])

    # Add the EnableMotion trigger_multiple seen in platform items.
    # This wakes up cubes when it starts moving.
    motion_filter = res['motionTrig', None]

    # Disable on walls, or if the conveyor can't be turned on.
    if norm != (0, 0, 1) or inst.fixup['$connectioncount'] == '0':
        motion_filter = None

    track_name = conditions.local_name(inst, 'segment_{}')
    rail_temp_solids = []
    last_track = None
    # Place tracks at the top, so they don't appear inside wall sections.
    track_start: Vec = start_pos + 48 * norm
    track_end: Vec = end_pos + 48 * norm
    for index, pos in enumerate(track_start.iter_line(track_end, stride=128),
                                start=1):
        track = vmf.create_ent(
            classname='path_track',
            targetname=track_name.format(index) + '-track',
            origin=pos,
            spawnflags=0,
            orientationtype=0,  # Don't rotate
        )
        if track_speed is not None:
            track['speed'] = track_speed
        if last_track:
            last_track['target'] = track['targetname']

        if index == 1 and teleport_to_start:
            track['spawnflags'] = 16  # Teleport here..

        last_track = track

        # Don't place at the last point - it doesn't teleport correctly,
        # and would be one too many.
        if segment_inst_file and pos != track_end:
            seg_inst = vmf.create_ent(
                classname='func_instance',
                targetname=track_name.format(index),
                file=segment_inst_file,
                origin=pos,
                angles=angles,
            )
            seg_inst.fixup.update(inst.fixup)

        if rail_template:
            temp = template_brush.import_template(
                vmf,
                rail_template,
                pos,
                angles,
                force_type=template_brush.TEMP_TYPES.world,
                add_to_map=False,
            )
            rail_temp_solids.extend(temp.world)

    if rail_temp_solids:
        vmf.create_ent(
            classname='func_brush',
            origin=track_start,
            spawnflags=1,  # Ignore +USE
            solidity=1,  # Not solid
            vrad_brush_cast_shadows=1,
            drawinfastreflection=1,
        ).solids = rail_temp_solids

    if teleport_to_start:
        # Link back to the first track..
        last_track['target'] = track_name.format(1) + '-track'

    # Generate an env_beam pointing from the start to the end of the track.
    try:
        beam_keys = res.find_key('BeamKeys')
    except LookupError:
        pass
    else:
        beam = vmf.create_ent(classname='env_beam')

        beam_off = beam_keys.vec('origin', 0, 63, 56)

        for prop in beam_keys:
            beam[prop.real_name] = prop.value

        # Localise the targetname so it can be triggered..
        beam['LightningStart'] = beam['targetname'] = conditions.local_name(
            inst, beam['targetname', 'beam'])
        del beam['LightningEnd']
        beam['origin'] = start_pos + Vec(
            -beam_off.x,
            beam_off.y,
            beam_off.z,
        ).rotate(*angles)
        beam['TargetPoint'] = end_pos + Vec(
            +beam_off.x,
            beam_off.y,
            beam_off.z,
        ).rotate(*angles)

    # Allow adding outputs to the last path_track.
    for prop in res.find_all('EndOutput'):
        output = Output.parse(prop)
        output.output = 'OnPass'
        output.inst_out = None
        output.comma_sep = False
        output.target = conditions.local_name(inst, output.target)
        last_track.add_out(output)

    if motion_filter is not None:
        motion_trig = vmf.create_ent(
            classname='trigger_multiple',
            targetname=conditions.local_name(inst, 'enable_motion_trig'),
            origin=start_pos,
            filtername=motion_filter,
            startDisabled=1,
            wait=0.1,
        )
        motion_trig.add_out(
            Output('OnStartTouch', '!activator', 'ExitDisabledState'))
        # Match the size of the original...
        motion_trig.solids.append(
            vmf.make_prism(
                start_pos + Vec(72, -56, 58).rotate(*angles),
                end_pos + Vec(-72, 56, 144).rotate(*angles),
                mat=consts.Tools.TRIGGER,
            ).solid)

    if res.bool('NoPortalFloor'):
        # Block portals on the floor..
        floor_noportal = vmf.create_ent(
            classname='func_noportal_volume',
            origin=track_start,
        )
        floor_noportal.solids.append(
            vmf.make_prism(
                start_pos + Vec(-60, -60, -66).rotate(*angles),
                end_pos + Vec(60, 60, -60).rotate(*angles),
                mat=consts.Tools.INVISIBLE,
            ).solid)

    # A brush covering under the platform.
    base_trig = vmf.make_prism(
        start_pos + Vec(-64, -64, 48).rotate(*angles),
        end_pos + Vec(64, 64, 56).rotate(*angles),
        mat=consts.Tools.INVISIBLE,
    ).solid

    vmf.add_brush(base_trig)

    # Make a paint_cleanser under the belt..
    if res.bool('PaintFizzler'):
        pfizz = vmf.create_ent(
            classname='trigger_paint_cleanser',
            origin=start_pos,
        )
        pfizz.solids.append(base_trig.copy())
        for face in pfizz.sides():
            face.mat = consts.Tools.TRIGGER
예제 #2
0
def make_frames(vmf: VMF, targ: str, conf: dict, bbox_min: Vec, bbox_max: Vec,
                norm: Vec):
    """Generate frames for a rectangular glass item."""
    def make_frame(frame_type, loc, angles):
        """Make a frame instance."""
        vmf.create_ent(
            classname='func_instance',
            targetname=targ,
            file=conf['frame_' + frame_type],
            # Position at the center of the block, instead of at the glass.
            origin=loc - norm * 64,
            angles=angles,
        )

    if bbox_min == bbox_max:
        # 1x1 glass..
        make_frame('single', bbox_min, norm.to_angle())
        return

    norm_axis = norm.axis()
    u_axis, v_axis = Vec.INV_AXIS[norm_axis]

    u_norm = Vec()
    v_norm = Vec()
    u_norm[u_axis] = 1
    v_norm[v_axis] = 1

    single_u = bbox_min[u_axis] == bbox_max[u_axis]
    single_v = bbox_min[v_axis] == bbox_max[v_axis]

    # If single in either direction, it needs a u-bend.
    if single_u:
        ubend_axis = v_axis
    elif single_v:
        ubend_axis = u_axis
    else:
        ubend_axis = None

    if ubend_axis is not None:
        for bend_mag, bbox in [(1, bbox_min), (-1, bbox_max)]:
            make_frame(
                'ubend',
                bbox,
                norm.to_angle_roll(Vec.with_axes(ubend_axis, bend_mag)),
            )
    else:
        # Make 4 corners - one in each roll direction.

        for roll in range(0, 360, 90):
            angles = norm.to_angle(roll)
            # The two directions with a border in the corner instance.
            # We want to put it on those sides.
            corner_a = Vec(y=-1).rotate(*angles)
            corner_b = Vec(z=-1).rotate(*angles)

            # If the normal is positive, we want to be bbox_max in that axis,
            # otherwise bbox_min.

            pos = Vec.with_axes(
                norm_axis,
                bbox_min,
                corner_a.axis(),
                (bbox_max if corner_a >= (0, 0, 0) else bbox_min),
                corner_b.axis(),
                (bbox_max if corner_b >= (0, 0, 0) else bbox_min),
            )

            make_frame(
                'corner',
                pos,
                angles,
            )

    # Make straight sections.
    straight_u_pos = norm.to_angle_roll(v_norm)
    straight_u_neg = norm.to_angle_roll(-v_norm)
    straight_v_pos = norm.to_angle_roll(u_norm)
    straight_v_neg = norm.to_angle_roll(-u_norm)
    for u_pos in range(int(bbox_min[u_axis] + 128), int(bbox_max[u_axis]),
                       128):
        make_frame(
            'edge',
            Vec.with_axes(u_axis, u_pos, v_axis, bbox_min, norm_axis,
                          bbox_min),
            straight_u_pos,
        )
        make_frame(
            'edge',
            Vec.with_axes(u_axis, u_pos, v_axis, bbox_max, norm_axis,
                          bbox_min),
            straight_u_neg,
        )
    for v_pos in range(int(bbox_min[v_axis] + 128), int(bbox_max[v_axis]),
                       128):
        make_frame(
            'edge',
            Vec.with_axes(v_axis, v_pos, u_axis, bbox_min, norm_axis,
                          bbox_min),
            straight_v_pos,
        )
        make_frame(
            'edge',
            Vec.with_axes(v_axis, v_pos, u_axis, bbox_max, norm_axis,
                          bbox_min),
            straight_v_neg,
        )
예제 #3
0
파일: glass.py 프로젝트: BenVlodgi/BEE2.4
def make_frames(vmf: VMF, targ: str, conf: dict, bbox_min: Vec, bbox_max: Vec, norm: Vec):
    """Generate frames for a rectangular glass item."""
    def make_frame(frame_type, loc, angles):
        """Make a frame instance."""
        vmf.create_ent(
            classname='func_instance',
            targetname=targ,
            file=conf['frame_' + frame_type],
            # Position at the center of the block, instead of at the glass.
            origin=loc - norm * 64,
            angles=angles,
        )

    if bbox_min == bbox_max:
        # 1x1 glass..
        make_frame('single', bbox_min, norm.to_angle())
        return

    norm_axis = norm.axis()
    u_axis, v_axis = Vec.INV_AXIS[norm_axis]

    u_norm = Vec()
    v_norm = Vec()
    u_norm[u_axis] = 1
    v_norm[v_axis] = 1

    single_u = bbox_min[u_axis] == bbox_max[u_axis]
    single_v = bbox_min[v_axis] == bbox_max[v_axis]

    # If single in either direction, it needs a u-bend.
    if single_u:
        ubend_axis = v_axis
    elif single_v:
        ubend_axis = u_axis
    else:
        ubend_axis = None

    if ubend_axis is not None:
        for bend_mag, bbox in [(1, bbox_min), (-1, bbox_max)]:
            make_frame(
                'ubend',
                bbox,
                norm.to_angle_roll(Vec.with_axes(ubend_axis, bend_mag)),
            )
    else:
        # Make 4 corners - one in each roll direction.

        for roll in range(0, 360, 90):
            angles = norm.to_angle(roll)
            # The two directions with a border in the corner instance.
            # We want to put it on those sides.
            corner_a = Vec(y=-1).rotate(*angles)
            corner_b = Vec(z=-1).rotate(*angles)

            # If the normal is positive, we want to be bbox_max in that axis,
            # otherwise bbox_min.

            pos = Vec.with_axes(
                norm_axis, bbox_min,

                corner_a.axis(),
                (bbox_max if corner_a >= (0, 0, 0) else bbox_min),

                corner_b.axis(),
                (bbox_max if corner_b >= (0, 0, 0) else bbox_min),
            )

            make_frame(
                'corner',
                pos,
                angles,
            )

    # Make straight sections.
    straight_u_pos = norm.to_angle_roll(v_norm)
    straight_u_neg = norm.to_angle_roll(-v_norm)
    straight_v_pos = norm.to_angle_roll(u_norm)
    straight_v_neg = norm.to_angle_roll(-u_norm)
    for u_pos in range(int(bbox_min[u_axis] + 128), int(bbox_max[u_axis]), 128):
        make_frame(
            'edge',
            Vec.with_axes(u_axis, u_pos, v_axis, bbox_min, norm_axis, bbox_min),
            straight_u_pos,
        )
        make_frame(
            'edge',
            Vec.with_axes(u_axis, u_pos, v_axis, bbox_max, norm_axis, bbox_min),
            straight_u_neg,
        )
    for v_pos in range(int(bbox_min[v_axis] + 128), int(bbox_max[v_axis]), 128):
        make_frame(
            'edge',
            Vec.with_axes(v_axis, v_pos, u_axis, bbox_min, norm_axis, bbox_min),
            straight_v_pos,
        )
        make_frame(
            'edge',
            Vec.with_axes(v_axis, v_pos, u_axis, bbox_max, norm_axis, bbox_min),
            straight_v_neg,
        )