Beispiel #1
0
def parse_map(vmf: VMF, has_attr: Dict[str, bool]) -> None:
    """Find all glass/grating in the map.

    This removes the per-tile instances, and all original brushwork.
    The frames are updated with a fixup var, as appropriate.
    """
    frame_inst = resolve('[glass_frames]', silent=True)
    glass_inst = resolve_one('[glass_128]')

    pos = None
    for brush_ent in vmf.by_class['func_detail']:
        is_glass = False
        for face in brush_ent.sides():
            if face.mat == consts.Special.GLASS:
                has_attr['glass'] = True
                pos = face.get_origin()
                is_glass = True
                break
        if is_glass:
            brush_ent.remove()
            BARRIERS[get_pos_norm(pos)] = BarrierType.GLASS

    for brush_ent in vmf.by_class['func_brush']:
        is_grating = False
        for face in brush_ent.sides():
            if face.mat == consts.Special.GRATING:
                has_attr['grating'] = True
                pos = face.get_origin()
                is_grating = True
                break
        if is_grating:
            brush_ent.remove()
            BARRIERS[get_pos_norm(pos)] = BarrierType.GRATING

    for inst in vmf.by_class['func_instance']:
        filename = inst['file'].casefold()
        if filename == glass_inst:
            inst.remove()
        elif filename in frame_inst:
            # Add a fixup to allow distinguishing the type.
            pos = Vec.from_str(inst['origin']) // 128 * 128 + (64, 64, 64)
            norm = Vec(z=-1) @ Angle.from_str(inst['angles'])
            try:
                inst.fixup[consts.FixupVars.BEE_GLS_TYPE] = BARRIERS[
                    pos.as_tuple(), norm.as_tuple()].value
            except KeyError:
                LOGGER.warning('No glass/grating for frame at {}, {}?', pos,
                               norm)

    if options.get(str, 'glass_pack') and has_attr['glass']:
        packing.pack_list(vmf, options.get(str, 'glass_pack'))
Beispiel #2
0
def parse_map(vmf: VMF, has_attr: Dict[str, bool]) -> None:
    """Remove instances from the map, and store off the positions."""
    glass_inst = resolve_one('[glass_128]')

    pos = None
    for brush_ent in vmf.by_class['func_detail']:
        is_glass = False
        for face in brush_ent.sides():
            if face.mat == consts.Special.GLASS:
                has_attr['glass'] = True
                pos = face.get_origin()
                is_glass = True
                break
        if is_glass:
            brush_ent.remove()
            BARRIERS[get_pos_norm(pos)] = BarrierType.GLASS

    for brush_ent in vmf.by_class['func_brush']:
        is_grating = False
        for face in brush_ent.sides():
            if face.mat == consts.Special.GRATING:
                has_attr['grating'] = True
                pos = face.get_origin()
                is_grating = True
                break
        if is_grating:
            brush_ent.remove()
            BARRIERS[get_pos_norm(pos)] = BarrierType.GRATING

    for inst in vmf.by_class['func_instance']:
        filename = inst['file'].casefold()
        if filename == glass_inst:
            inst.remove()

    if options.get(str, 'glass_pack') and has_attr['glass']:
        packing.pack_list(vmf, options.get(str, 'glass_pack'))
Beispiel #3
0
def add_quote(
    vmf: VMF,
    quote: Property,
    targetname: str,
    quote_loc: Vec,
    style_vars: dict,
    use_dings: bool,
) -> None:
    """Add a quote to the map."""
    LOGGER.info('Adding quote: {}', quote)

    only_once = atomic = False
    cc_emit_name = None
    start_ents = []  # type: List[Entity]
    end_commands = []
    start_names = []

    # The OnUser1 outputs always play the quote (PlaySound/Start), so you can
    # mix ent types in the same pack.

    for prop in quote:
        name = prop.name.casefold()

        if name == 'file':
            vmf.create_ent(
                classname='func_instance',
                targetname='',
                file=INST_PREFIX + prop.value,
                origin=quote_loc,
                fixup_style='2',  # No fixup
            )
        elif name == 'choreo':
            # If the property has children, the children are a set of sequential
            # voice lines.
            # If the name is set to '@glados_line', the ents will be named
            # ('@glados_line', 'glados_line_2', 'glados_line_3', ...)
            start_names.append(targetname)
            if prop.has_children():
                secondary_name = targetname.lstrip('@') + '_'
                # Evenly distribute the choreo ents across the width of the
                # voice-line room.
                off = Vec(y=120 / (len(prop) + 1))
                start = quote_loc - (0, 60, 0) + off
                for ind, choreo_line in enumerate(
                        prop, start=1):  # type: int, Property
                    is_first = (ind == 1)
                    is_last = (ind == len(prop))
                    name = (targetname if is_first else secondary_name +
                            str(ind))
                    choreo = add_choreo(
                        vmf,
                        choreo_line.value,
                        targetname=name,
                        loc=start + off * (ind - 1),
                        use_dings=use_dings,
                        is_first=is_first,
                        is_last=is_last,
                        only_once=only_once,
                    )
                    # Add a IO command to start the next one.
                    if not is_last:
                        choreo.add_out(
                            Output(
                                'OnCompletion',
                                secondary_name + str(ind + 1),
                                'Start',
                                delay=0.1,
                            ))
                    if is_first:  # Ensure this works with cc_emit
                        start_ents.append(choreo)
                    if is_last:
                        for out in end_commands:
                            choreo.add_out(out.copy())
                        end_commands.clear()
            else:
                # Add a single choreo command.
                choreo = add_choreo(
                    vmf,
                    prop.value,
                    targetname,
                    quote_loc,
                    use_dings=use_dings,
                    only_once=only_once,
                )
                start_ents.append(choreo)
                for out in end_commands:
                    choreo.add_out(out.copy())
                end_commands.clear()
        elif name == 'snd':
            start_names.append(targetname)

            snd = vmf.create_ent(
                classname='ambient_generic',
                spawnflags='49',  # Infinite Range, Starts Silent
                targetname=targetname,
                origin=quote_loc,
                message=prop.value,
                health='10',  # Volume
            )
            snd.add_out(
                Output(
                    'OnUser1',
                    targetname,
                    'PlaySound',
                    only_once=only_once,
                ))
            start_ents.append(snd)
        elif name == 'bullseye':
            add_bullseye(vmf, quote_loc, prop.value)
        elif name == 'cc_emit':
            # In Aperture Tag, this additional console command is used
            # to add the closed captions.
            # Store in a variable, so we can be sure to add the output
            # regardless of the property order.
            cc_emit_name = prop.value
        elif name == 'setstylevar':
            # Set this stylevar to True
            # This is useful so some styles can react to which line was
            # chosen.
            style_vars[prop.value.casefold()] = True
        elif name == 'packlist':
            packing.pack_list(vmf, prop.value)
        elif name == 'pack':
            if prop.has_children():
                packing.pack_files(vmf, *[subprop.value for subprop in prop])
            else:
                packing.pack_files(vmf, prop.value)
        elif name == 'choreo_name':
            # Change the targetname used for subsequent entities
            targetname = prop.value
        elif name == 'onlyonce':
            only_once = srctools.conv_bool(prop.value)
        elif name == 'atomic':
            atomic = srctools.conv_bool(prop.value)
        elif name == 'endcommand':
            end_commands.append(
                Output(
                    'OnCompletion',
                    prop['target'],
                    prop['input'],
                    prop['parm', ''],
                    prop.float('delay'),
                    only_once=prop.bool('only_once'),
                    times=prop.int('times', -1),
                ))

    if cc_emit_name:
        for ent in start_ents:
            ent.add_out(
                Output(
                    'OnUser1',
                    '@command',
                    'Command',
                    param='cc_emit ' + cc_emit_name,
                ))

    # If Atomic is true, after a line is started all variants
    # are blocked from playing.
    if atomic:
        for ent in start_ents:
            for name in start_names:
                if ent['targetname'] == name:
                    # Don't block yourself.
                    continue
                ent.add_out(Output(
                    'OnUser1',
                    name,
                    'Kill',
                    only_once=True,
                ))