예제 #1
0
def read_activation_prereq(
    reader: BinReader,
    count: int,
    min_to_satisfy: int,
) -> Optional[ActivationPrereq]:
    LOG.debug("Reading activation prerequisites at %d", reader.offset)

    anim_list = []
    obj_list = []
    prev: OptPrereqObj = None
    for _ in range(count):
        optional, prereq_type = reader.read(ACTIV_PREREQ_HEADER)
        # this is actually a byte in the code, but this way we also validate the padding
        assert_in("activ prereq type", (1, 2, 3), prereq_type, reader.prev + 4)
        if prereq_type == 1:
            # ANIMATION_LIST (these are always required)
            assert_eq("activ prereq optional", 0, optional, reader.prev + 0)
            anim_list.append(read_activation_prereq_anim(reader))
        else:
            # OBJECT_INACTIVE_LIST / OBJECT_ACTIVE_LIST
            assert_in("activ prereq optional", (0, 1), optional,
                      reader.prev + 0)
            prev, obj = read_activation_prereq_obj(reader, optional == 0,
                                                   prereq_type, prev)
            if obj:
                obj_list.append(obj)

    LOG.debug("Read activation prerequisites")
    return ActivationPrereq(min_to_satisfy=min_to_satisfy,
                            anim_list=anim_list,
                            obj_list=obj_list)
예제 #2
0
def get_comparison(
    condition: int, value: bytes, offset: int
) -> Tuple[str, Discriminator, RightHandSide]:
    assert_in("condition", IF_COND.keys(), condition, offset)
    lhs, function = IF_COND[condition]
    discriminator, rhs = function(value)
    return lhs, discriminator, rhs
예제 #3
0
    def read(cls, reader: BinReader, anim_def: AnimDef) -> ObjectOpacityFromTo:
        (
            node_index,
            from_state,
            to_state,
            from_value,
            to_value,
            delta,
            run_time,
        ) = reader.read(cls._STRUCT)

        node = anim_def.get_node(node_index - 1, reader.prev + 0)
        assert_in("from state", (-1, 0, 1), from_state, reader.prev + 4)
        assert_in("to state", (-1, 0, 1), to_state, reader.prev + 6)
        assert_between("from opacity", 0.0, 1.0, from_value, reader.prev + 8)
        assert_between("to opacity", 0.0, 1.0, to_value, reader.prev + 12)
        # delta is roughly: (to_value - from_value) / run_time
        assert_gt("run time", 0.0, run_time, reader.prev + 20)

        return cls(
            node=node,
            opacity_from=(from_value, from_state),
            opacity_to=(to_value, to_state),
            run_time=run_time,
            delta=delta,
        )
예제 #4
0
    def read(cls, reader: BinReader, anim_def: AnimDef) -> ObjectRotateState:
        flag, rx, ry, rz, node_index, at_index = reader.read(cls._STRUCT)

        # FLAG (mutually exclusive)
        # if this is a camera:
        # 0 -> absolute rotation
        # 1 -> relative rotation
        # if this is a 3d object:
        # 0 -> absolute rotation
        # 1 -> relative rotation
        # 2 -> AT_NODE_XYZ
        # 4 -> AT_NODE_MATRIX
        assert_in("flag", (0, 2, 4), flag, reader.prev + 0)
        node = anim_def.get_node(node_index - 1, reader.prev + 16)

        if flag == 0:
            assert_between("rot x", -PI2, PI2, rx, reader.prev + 4)
            assert_between("rot y", -PI2, PI2, ry, reader.prev + 8)
            assert_between("rot z", -PI2, PI2, rz, reader.prev + 12)
            state = (degrees(rx), degrees(ry), degrees(rz))
            assert_eq("at node", 0, at_index, reader.prev + 18)
            mode: RotationMode = "ABSOLUTE"
        else:
            assert_eq("rot x", 0.0, rx, reader.prev + 4)
            assert_eq("rot y", 0.0, ry, reader.prev + 8)
            assert_eq("rot z", 0.0, rz, reader.prev + 12)
            state = (0.0, 0.0, 0.0)
            assert_eq("at node", -200, at_index, reader.prev + 18)
            if flag == 2:
                mode = "AT_NODE_XYZ"
            else:
                mode = "AT_NODE_MATRIX"

        return cls(node=node, mode=mode, state=state)
예제 #5
0
파일: script.py 프로젝트: tobywf/mech3ax-py
def _parse_script(reader: BinReader, anim_def: AnimDef,
                  rel_end: int) -> List[ScriptItem]:
    LOG.debug("Reading script with length %d at %d", rel_end, reader.offset)

    abs_end = rel_end + reader.offset
    script = []

    while reader.offset < abs_end:
        stype, start_offset, pad, size, start_time = reader.read(SCRIPT_HEADER)
        assert_in("type", OBJECT_REGISTRY_NUM.keys(), stype, reader.prev + 0)
        assert_in("start offset", (1, 2, 3), start_offset, reader.prev + 1)
        assert_eq("field 02", 0, pad, reader.prev + 2)

        start_offset = StartOffset(start_offset)
        if start_time == 0.0:
            assert_eq("start offset", StartOffset.Animation, start_offset,
                      reader.prev + 1)
            start_offset = StartOffset.Unset

        actual_length = size - SCRIPT_HEADER.size
        base_model = OBJECT_REGISTRY_NUM[stype]

        obj = base_model.validate_and_read(reader, anim_def, actual_length)
        item = ScriptItem(
            name=base_model._NAME,  # pylint: disable=protected-access
            item=obj,
            start_offset=start_offset,
            start_time=start_time,
        )
        script.append(item)

    assert_eq("script end", abs_end, reader.offset, reader.offset)
    LOG.debug("Read script")
    return script
예제 #6
0
def _read_node_data_lod(reader: BinReader) -> LevelOfDetail:
    (
        level,  # 00
        range_near_sq,  # 04
        range_far,  # 08
        range_far_sq,  # 12
        zero16,  # 44 zero bytes
        unk60,  # 60
        unk64,  # 64
        one68,  # 68
        zero72,  # 72
        unk76,  # 76
    ) = reader.read(LEVEL_OF_DETAIL)

    assert_in("level", (0, 1), level, reader.prev + 0)

    assert_between(
        "range near sq",
        0.0,
        1000.0 * 1000.0,
        range_near_sq,
        reader.prev + 4,
    )
    range_near = sqrt(range_near_sq)

    assert_ge("range far", 0.0, range_far, reader.prev + 8)
    expected = force_single_prec(range_far * range_far)
    assert_eq("range far sq", expected, range_far_sq, reader.prev + 12)

    assert_all_zero("field 16", zero16, reader.prev + 16)

    # TODO:
    assert_ge("field 60", 0.0, unk60, reader.prev + 60)
    expected = force_single_prec(unk60 * unk60)
    assert_eq("field 64", expected, unk64, reader.prev + 64)

    assert_eq("field 68", 1, one68, reader.prev + 68)
    # TODO:
    assert_in("field 72", (0, 1), zero72, reader.prev + 72)
    if zero72 == 0:
        assert_eq("field 76", 0, unk76, reader.prev + 76)
    else:
        assert_ne("field 76", 0, unk76, reader.prev + 76)

    # object 3d nodes always have an action priority of 6

    return LevelOfDetail(
        type="LOD",
        level=level == 1,
        range=(range_near, range_far),
        unk60=unk60,
        unk76=unk76,
    )
예제 #7
0
 def read(cls, reader: BinReader, anim_def: AnimDef) -> ObjectOpacityState:
     is_set_raw, state_raw, opacity, node_index = reader.read(cls._STRUCT)
     # this could be another value (e.g. -1), in which case is set is not changed
     assert_in("is set", (0, 1), is_set_raw, reader.prev + 0)
     # the state does not seem to depend on is_set?
     assert_in("state", (0, 1), state_raw, reader.prev + 2)
     state = state_raw == 1
     if state:
         assert_between("opacity", 0.0, 1.0, opacity, reader.prev + 4)
     else:
         assert_eq("opacity", 0.0, opacity, reader.prev + 4)
     node = anim_def.get_node(node_index - 1, reader.prev + 8)
     return cls(node=node,
                is_set=is_set_raw == 1,
                state=state,
                opacity=opacity)
예제 #8
0
def read_materials(reader: BinReader, texture_count: int) -> Tuple[int, List[Material]]:
    (array_size, mat_count, index_max, mat_unknown) = reader.read(MATERIAL_HEADER)
    assert_eq("index max", mat_count, index_max, reader.prev + 8)
    assert_eq("field 12", mat_count - 1, mat_unknown, reader.prev + 12)

    materials_and_cycle = _read_materials(reader, mat_count, texture_count)
    _read_materials_zero(reader, mat_count, array_size)

    materials = []
    for material, cycle_info_ptr in materials_and_cycle:
        if cycle_info_ptr:
            (
                unk00,
                unk04,
                zero08,
                unk12,
                cycle_count1,
                cycle_count2,
                data_ptr,
            ) = reader.read(CYCLE_HEADER)

            assert_in("field 00", (0, 1), unk00, reader.prev + 0)
            # field 04
            assert_eq("field 08", 0, zero08, reader.prev + 8)
            assert_between("field 12", 2.0, 16.0, unk12, reader.prev + 12)
            assert_eq("cycle count", cycle_count1, cycle_count2, reader.prev + 20)
            assert_ne("field 24", 0, data_ptr, reader.prev + 24)

            cycle_textures = reader.read(Struct(f"<{cycle_count1}I"))

            for i, cycle_texture in enumerate(cycle_textures):
                # the texture should be in range
                assert_between(
                    "texture", 0, texture_count - 1, cycle_texture, reader.prev + i * 4
                )

            material.cycle = Cycle(
                textures=list(cycle_textures),
                unk00=unk00 == 1,
                unk04=unk04,
                unk12=unk12,
                info_ptr=cycle_info_ptr,
                data_ptr=data_ptr,
            )
        materials.append(material)

    return array_size, materials
예제 #9
0
def _assert_node_info_object3d(node: Node, offset: int,
                               mesh_count: int) -> None:
    # cannot assert name
    # these values are always set
    flag_base = node.flag & NODE_FLAG_BASE
    assert_eq("flag base", NODE_FLAG_BASE, flag_base, offset + 36)
    # TODO: flag?

    assert_eq("field 044", 1, node.unk044, offset + 44)
    if node.zone_id != ZONE_DEFAULT:
        assert_between("zone id", 1, 80, node.zone_id, offset + 48)
    assert_ne("data ptr", 0, node.data_ptr, offset + 56)

    if node.flag & NodeFlag.HasMesh != 0:
        assert_between("mesh index", 0, mesh_count, node.mesh_index,
                       offset + 60)
    else:
        assert_eq("mesh index", -1, node.mesh_index, offset + 60)

    # assert area partition properly once we have read the world data
    assert_between("area partition x", -1, 64, node.area_partition_x,
                   offset + 76)
    assert_between("area partition y", -1, 64, node.area_partition_y,
                   offset + 80)

    # can only have one parent
    assert_in("parent count", (0, 1), node.parent_count, offset + 84)
    if node.parent_count:
        assert_ne("parent array ptr", 0, node.parent_array_ptr, offset + 88)
    else:
        assert_eq("parent array ptr", 0, node.parent_array_ptr, offset + 88)

    assert_between("children count", 0, 64, node.children_count, offset + 92)
    if node.children_count:
        assert_ne("children array ptr", 0, node.children_array_ptr,
                  offset + 96)
    else:
        assert_eq("children array ptr", 0, node.children_array_ptr,
                  offset + 96)

    # unknowns are not 0.0

    assert_eq("field 196", 160, node.unk196, offset + 196)
예제 #10
0
def _assert_node_info_empty(node: Node, offset: int, _mesh_count: int) -> None:
    # cannot assert name
    # these values are always set
    flag_base = node.flag & NODE_FLAG_BASE
    assert_eq("flag base", NODE_FLAG_BASE, flag_base, offset + 36)
    # flag?

    assert_in("field 044", (1, 3, 5, 7), node.unk044, offset + 44)
    assert_in("zone id", (1, ZONE_DEFAULT), node.zone_id, offset + 48)
    assert_eq("data ptr", 0, node.data_ptr, offset + 56)
    assert_eq("mesh index", -1, node.mesh_index, offset + 60)
    assert_eq("area partition x", -1, node.area_partition_x, offset + 76)
    assert_eq("area partition y", -1, node.area_partition_y, offset + 80)
    assert_eq("parent count", 0, node.parent_count, offset + 84)
    assert_eq("parent array ptr", 0, node.parent_array_ptr, offset + 88)
    assert_eq("children count", 0, node.children_count, offset + 92)
    assert_eq("children array ptr", 0, node.children_array_ptr, offset + 96)

    # unknowns are not 0.0

    assert_eq("field 196", 160, node.unk196, offset + 196)
예제 #11
0
def _read_sequence_definitions(reader: BinReader, anim_def: AnimDef,
                               count: int) -> List[SeqDef]:
    sequences = []
    for _ in range(count):
        name_raw, flag, zero, seqdef_ptr, seqdef_len = reader.read(SEQDEF_INFO)
        with assert_ascii("name", name_raw, reader.prev + 0):
            name = ascii_zterm_padded(name_raw)

        assert_in("activation", (0x0, 0x303), flag, reader.prev + 32)
        activation: SeqActivation = "ON_CALL" if flag == 0x303 else "NONE"
        assert_all_zero("field 36", zero, reader.prev + 36)
        assert_gt("seqdef length", 0, seqdef_len, reader.prev + 56)
        assert_ne("seqdef ptr", 0, seqdef_ptr, reader.prev + 60)

        script = _parse_script(reader, anim_def, seqdef_len)
        sequences.append(
            SeqDef(name=name,
                   ptr=seqdef_ptr,
                   activation=activation,
                   script=script))

    return sequences
예제 #12
0
def read_activation_prereq_obj(
        reader: BinReader, required: bool, prereq_type: int,
        prev: OptPrereqObj) -> Tuple[OptPrereqObj, OptPrereqObj]:
    active, name_raw, ptr = reader.read(ACTIV_PREREQ_OBJ)
    with assert_ascii("activ prereq name", name_raw, reader.prev + 4):
        name = ascii_zterm_padded(name_raw)
    assert_ne("activ prereq ptr", 0, ptr, reader.prev + 36)

    if prereq_type == 3:
        assert_eq("activ prereq active", 0, active, reader.prev + 0)
        # remember the current node as the previous one
        prev = PrereqObject(required=required,
                            active=False,
                            name=name,
                            ptr=ptr)
        return prev, None

    assert_in("activ prereq active", (0, 1), active, reader.prev + 0)
    if prev:
        assert_eq("activ prereq required", prev.required, required,
                  reader.prev + 0)
        parent_name = prev.name
        parent_ptr = prev.ptr
    else:
        parent_name = ""
        parent_ptr = 0

    obj = PrereqObject(
        required=required,
        active=active == 1,
        name=name,
        ptr=ptr,
        parent_name=parent_name,
        parent_ptr=parent_ptr,
    )
    # set the previous node to NULL
    return None, obj
예제 #13
0
    def read(cls, reader: BinReader, anim_def: AnimDef) -> SoundNode:
        (
            name_raw,
            one32,
            inherit_trans,
            active_state,
            node_index,
            tx,
            ty,
            tz,
        ) = reader.read(cls._STRUCT)

        with assert_ascii("name", name_raw, reader.prev + 0):
            name = ascii_zterm_padded(name_raw)

        # this would cause the sound node to be dynamically allocated
        assert_eq("field 32", 1, one32, reader.prev + 32)  # 44
        assert_in("active state", (0, 1), active_state, reader.prev + 40)  # 52

        # this is actually a bit field.
        # if it's 1, then the translation would be applied directly to the node
        # if it's 2 and AT_NODE is given, then the translation is applied relative
        # to the node
        assert_in("field 36", (0, 2), inherit_trans, reader.prev + 36)  # 48

        if inherit_trans == 0:
            at_node = None
            assert_eq("at node", 0, node_index, reader.prev + 44)
            assert_eq("at tx", 0.0, tx, reader.prev + 48)
            assert_eq("at ty", 0.0, ty, reader.prev + 52)
            assert_eq("at tz", 0.0, tz, reader.prev + 56)
        else:
            node = anim_def.get_node(node_index - 1, reader.prev + 44)
            at_node = AtNodeShort(node=node, tx=tx, ty=ty, tz=tz)

        return cls(name=name, active_state=active_state == 1, at_node=at_node)
예제 #14
0
def read_node_data_object3d(  # pylint: disable=too-many-locals
        reader: BinReader, ) -> Object3d:
    (
        flag_raw,  # 000
        opacity,  # 004
        zero008,
        zero012,
        zero016,
        zero020,
        rot_x,  # 024
        rot_y,  # 028
        rot_z,  # 032
        scale_x,  # 036
        scale_y,  # 040
        scale_z,  # 044
        matrix00,  # 048
        matrix01,  # 052
        matrix02,  # 056
        matrix10,  # 060
        matrix11,  # 064
        matrix12,  # 068
        matrix20,  # 072
        matrix21,  # 076
        matrix22,  # 080
        trans_x,  # 084
        trans_y,  # 088
        trans_z,  # 092
        zero096,  # 42 zero bytes
    ) = reader.read(OBJECT3D)

    assert_in("flag", (32, 40), flag_raw, reader.prev + 0)
    assert_eq("opacity", 0.0, opacity, reader.prev + 4)

    assert_eq("field 008", 0.0, zero008, reader.prev + 8)
    assert_eq("field 012", 0.0, zero012, reader.prev + 12)
    assert_eq("field 016", 0.0, zero016, reader.prev + 16)
    assert_eq("field 020", 0.0, zero020, reader.prev + 20)

    assert_eq("scale x", 1.0, scale_x, reader.prev + 36)
    assert_eq("scale y", 1.0, scale_y, reader.prev + 40)
    assert_eq("scale z", 1.0, scale_z, reader.prev + 44)

    assert_all_zero("field 096", zero096, reader.prev + 96)

    def _assert_matrix(expected: Matrix) -> None:
        assert_eq("matrix 00", expected[0], matrix00, reader.prev + 48)
        assert_eq("matrix 01", expected[1], matrix01, reader.prev + 52)
        assert_eq("matrix 02", expected[2], matrix02, reader.prev + 56)
        assert_eq("matrix 10", expected[3], matrix10, reader.prev + 60)
        assert_eq("matrix 11", expected[4], matrix11, reader.prev + 64)
        assert_eq("matrix 12", expected[5], matrix12, reader.prev + 68)
        assert_eq("matrix 20", expected[6], matrix20, reader.prev + 72)
        assert_eq("matrix 21", expected[7], matrix21, reader.prev + 76)
        assert_eq("matrix 22", expected[8], matrix22, reader.prev + 80)

    matrix_sign = extract_zero_signs(
        matrix00,
        matrix01,
        matrix02,
        matrix10,
        matrix11,
        matrix12,
        matrix20,
        matrix21,
        matrix22,
    )

    if flag_raw == 40:
        assert_eq("rot x", 0.0, rot_x, reader.prev + 24)
        assert_eq("rot y", 0.0, rot_y, reader.prev + 28)
        assert_eq("rot z", 0.0, rot_z, reader.prev + 32)

        assert_eq("trans x", 0.0, trans_x, reader.prev + 84)
        assert_eq("trans y", 0.0, trans_y, reader.prev + 88)
        assert_eq("trans z", 0.0, trans_z, reader.prev + 92)

        _assert_matrix(IDENTITY_MATRIX)

        rotation = None
        translation = None
        matrix = None
    else:
        # all values between PI
        assert_between("rot x", -PI, PI, rot_x, reader.prev + 24)
        assert_between("rot y", -PI, PI, rot_y, reader.prev + 28)
        assert_between("rot z", -PI, PI, rot_z, reader.prev + 32)

        rotation = (rot_x, rot_y, rot_z)
        translation = (trans_x, trans_y, trans_z)

        expected = euler_to_matrix(rot_x, rot_y, rot_z)

        # in most cases, the calculated matrix is correct :/
        # for 58 out of 2729 Object3D nodes, this fails though
        try:
            _assert_matrix(expected)
        except Mech3ParseError:
            matrix = (
                matrix00,
                matrix01,
                matrix02,
                matrix10,
                matrix11,
                matrix12,
                matrix20,
                matrix21,
                matrix22,
            )
            matrix_sign = 0
        else:
            matrix = None

    # object 3d nodes always have an action priority of 6

    return Object3d(
        type="Object3D",
        rotation=rotation,
        translation=translation,
        matrix=matrix,
        matrix_sign=matrix_sign,
    )
예제 #15
0
    def read(  # pylint: disable=too-many-locals,too-many-statements
            cls, reader: BinReader, anim_def: AnimDef) -> ObjectMotionFromTo:
        (
            flag_raw,  # 000
            node_index,  # 004
            morph_from,  # 008
            morph_to,  # 012
            morph_delta,  # 016
            translate_from_x,  # 020
            translate_from_y,  # 024
            translate_from_z,  # 028
            translate_to_x,  # 032
            translate_to_y,  # 036
            translate_to_z,  # 040
            translate_delta_x,  # 044
            translate_delta_y,  # 048
            translate_delta_z,  # 052
            rotate_from_x,  # 056
            rotate_from_y,  # 060
            rotate_from_z,  # 064
            rotate_to_x,  # 068
            rotate_to_y,  # 072
            rotate_to_z,  # 076
            rotate_delta_x,  # 080
            rotate_delta_y,  # 084
            rotate_delta_z,  # 088
            scale_from_x,  # 092
            scale_from_y,  # 096
            scale_from_z,  # 100
            scale_to_x,  # 104
            scale_to_y,  # 108
            scale_to_z,  # 112
            scale_delta_x,  # 116
            scale_delta_y,  # 120
            scale_delta_z,  # 124
            run_time,  # 128
        ) = reader.read(cls._STRUCT)

        # these only appear in mutually exclusive combinations, but it really is
        # a flag in the game code
        assert_in("flag", (1, 2, 4, 8), flag_raw, reader.prev + 0)
        node = anim_def.get_node(node_index - 1, reader.prev + 4)

        if flag_raw == 8:
            morph: Optional[Vec3] = (morph_from, morph_to, morph_delta)
        else:
            assert_eq("morph from", 0.0, morph_from, reader.prev + 8)
            assert_eq("morph to", 0.0, morph_to, reader.prev + 12)
            assert_eq("morph delta", 0.0, morph_delta, reader.prev + 16)
            morph = None

        if flag_raw == 1:
            translate: Optional[Vec3FromTo] = Vec3FromTo(
                from_=(translate_from_x, translate_from_y, translate_from_z),
                to_=(translate_to_x, translate_to_y, translate_to_z),
                delta=(translate_delta_x, translate_delta_y,
                       translate_delta_z),
            )
        else:
            assert_eq("translate from x", 0.0, translate_from_x,
                      reader.prev + 20)
            assert_eq("translate from y", 0.0, translate_from_y,
                      reader.prev + 24)
            assert_eq("translate from z", 0.0, translate_from_z,
                      reader.prev + 28)
            assert_eq("translate to x", 0.0, translate_to_x, reader.prev + 32)
            assert_eq("translate to y", 0.0, translate_to_y, reader.prev + 36)
            assert_eq("translate to z", 0.0, translate_to_z, reader.prev + 40)
            assert_eq("translate delta x", 0.0, translate_delta_x,
                      reader.prev + 44)
            assert_eq("translate delta y", 0.0, translate_delta_y,
                      reader.prev + 48)
            assert_eq("translate delta z", 0.0, translate_delta_z,
                      reader.prev + 52)
            translate = None

        if flag_raw == 2:
            rotate: Optional[Vec3FromTo] = Vec3FromTo(
                from_=(
                    degrees(rotate_from_x),
                    degrees(rotate_from_y),
                    degrees(rotate_from_z),
                ),
                to_=(degrees(rotate_to_x), degrees(rotate_to_y),
                     degrees(rotate_to_z)),
                delta=(
                    degrees(rotate_delta_x),
                    degrees(rotate_delta_y),
                    degrees(rotate_delta_z),
                ),
            )
        else:
            assert_eq("rotate from x", 0.0, rotate_from_x, reader.prev + 56)
            assert_eq("rotate from y", 0.0, rotate_from_y, reader.prev + 60)
            assert_eq("rotate from z", 0.0, rotate_from_z, reader.prev + 64)
            assert_eq("rotate to x", 0.0, rotate_to_x, reader.prev + 68)
            assert_eq("rotate to y", 0.0, rotate_to_y, reader.prev + 72)
            assert_eq("rotate to z", 0.0, rotate_to_z, reader.prev + 76)
            assert_eq("rotate delta x", 0.0, rotate_delta_x, reader.prev + 80)
            assert_eq("rotate delta y", 0.0, rotate_delta_y, reader.prev + 84)
            assert_eq("rotate delta z", 0.0, rotate_delta_z, reader.prev + 88)
            rotate = None

        if flag_raw == 4:
            scale: Optional[Vec3FromTo] = Vec3FromTo(
                from_=(scale_from_x, scale_from_y, scale_from_z),
                to_=(scale_to_x, scale_to_y, scale_to_z),
                delta=(scale_delta_x, scale_delta_y, scale_delta_z),
            )
        else:
            assert_eq("scale from x", 0.0, scale_from_x, reader.prev + 92)
            assert_eq("scale from y", 0.0, scale_from_y, reader.prev + 96)
            assert_eq("scale from z", 0.0, scale_from_z, reader.prev + 100)
            assert_eq("scale to x", 0.0, scale_to_x, reader.prev + 104)
            assert_eq("scale to y", 0.0, scale_to_y, reader.prev + 108)
            assert_eq("scale to z", 0.0, scale_to_z, reader.prev + 112)
            assert_eq("scale delta x", 0.0, scale_delta_x, reader.prev + 116)
            assert_eq("scale delta y", 0.0, scale_delta_y, reader.prev + 120)
            assert_eq("scale delta z", 0.0, scale_delta_z, reader.prev + 124)
            scale = None

        assert_gt("run time", 0.0, run_time, reader.prev + 128)

        return cls(
            node=node,
            morph=morph,
            translate=translate,
            rotate=rotate,
            scale=scale,
            run_time=run_time,
        )
예제 #16
0
def _read_materials(  # pylint: disable=too-many-locals
    reader: BinReader, mat_count: int, texture_count: int
) -> List[Tuple[Material, int]]:
    materials = []
    for i in range(0, mat_count):
        # very similar to materials in the mechlib
        (
            unk00,
            flag_raw,
            rgb,
            red,
            green,
            blue,
            texture,
            unk20,
            unk24,
            unk28,
            unk32,
            cycle_ptr,
            index1,
            index2,
        ) = reader.read(MATERIAL_INFO)

        with assert_flag("flag", flag_raw, reader.prev + 1):
            flag = MaterialFlag.check(flag_raw)

        assert_eq("flag always", True, MaterialFlag.Always(flag), reader.prev + 1)
        assert_eq("flag free", False, MaterialFlag.Free(flag), reader.prev + 1)

        cycled = MaterialFlag.Cycled(flag)

        if MaterialFlag.Textured(flag):
            assert_eq("field 00", 255, unk00, reader.prev + 0)

            # if the material is textured, it should not have an RGB value
            assert_eq("rgb", 0x7FFF, rgb, reader.prev + 2)
            assert_eq("red", 255.0, red, reader.prev + 4)
            assert_eq("green", 255.0, green, reader.prev + 8)
            assert_eq("blue", 255.0, blue, reader.prev + 12)
            color: Optional[Vec3] = None
            # the texture should be in range
            assert_between("texture", 0, texture_count - 1, texture, reader.prev + 16)
        else:
            # value distribution:
            #   24 0
            #    2 51
            #    2 76
            #    2 89
            #    3 102
            #    1 127
            #    1 153
            # 2629 255 (includes textured)
            values_00 = (0, 51, 76, 89, 102, 127, 153, 255)
            assert_in("field 00", values_00, unk00, reader.prev + 0)
            # this is  never true for untextured materials
            assert_eq("flag unk", False, MaterialFlag.Unknown(flag), reader.prev + 1)

            # if the material is not textured, it can't be cycled
            assert_eq("texture cycled", False, cycled, reader.prev + 1)
            # this is calculated from the floating point values, since this short
            # representation depends on the hardware RGB565 or RGB555 support
            assert_eq("rgb", 0x0, rgb, reader.prev + 2)
            color = (red, green, blue)
            assert_eq("texture", 0, texture, reader.prev + 16)
            texture = None

        # not sure what these are?
        assert_eq("field 20", 0.0, unk20, reader.prev + 20)
        assert_eq("field 24", 0.5, unk24, reader.prev + 24)
        assert_eq("field 28", 0.5, unk28, reader.prev + 28)

        # value distribution:
        # 2480 0
        #   12 1
        #    1 4
        #   61 6
        #   17 7
        #    3 8
        #   72 9
        #    4 10
        #   11 12
        #    3 13
        # bit field?
        #  0 0b0000
        #  1 0b0001
        #  4 0b0100
        #  6 0b0110
        #  7 0b0111
        #  8 0b1000
        #  9 0b1001
        # 10 0b1010
        # 12 0b1100
        # 13 0b1101
        assert_in(
            "field 32", (0, 1, 4, 6, 7, 8, 9, 10, 12, 13), unk32, reader.prev + 32
        )

        if cycled:
            assert_ne("cycle pointer", 0, cycle_ptr, reader.prev + 36)
        else:
            assert_eq("cycle pointer", 0, cycle_ptr, reader.prev + 36)

        expected1 = i + 1
        if expected1 >= mat_count:
            expected1 = -1
        assert_eq("index 1", expected1, index1, reader.prev + 40)

        expected2 = i - 1
        if expected2 < 0:
            expected2 = -1
        assert_eq("index 2", expected2, index2, reader.prev + 42)

        material = Material(
            texture=texture,
            color=color,
            unk00=unk00,
            unk32=unk32,
            unknown=MaterialFlag.Unknown(flag),
        )
        materials.append((material, cycle_ptr))
    return materials
예제 #17
0
 def read(cls, reader: BinReader, anim_def: AnimDef) -> ObjectActiveState:
     state, node_index = reader.read(cls._STRUCT)
     assert_in("state", (0, 1), state, reader.prev + 0)
     node = anim_def.get_node(node_index - 1, reader.prev + 4)
     return cls(node=node, state=state == 1)
예제 #18
0
    def read(  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
            cls, reader: BinReader, anim_def: AnimDef) -> LightState:
        (
            name_raw,
            light_index,
            flag_raw,
            active_state_raw,
            point_source_raw,
            directional_raw,
            saturated_raw,
            subdivide_raw,
            static_raw,
            node_index,
            tx,
            ty,
            tz,
            rx,
            ry,
            rz,
            range_min,
            range_max,
            color_r,
            color_g,
            color_b,
            ambient_value,
            diffuse_value,
        ) = reader.read(cls._STRUCT)

        with assert_ascii("name", name_raw, reader.prev + 0):
            name = ascii_zterm_padded(name_raw)

        expected_name = anim_def.get_light(light_index - 1, reader.prev + 32)
        assert_eq("index name", expected_name, name, reader.prev + 32)  # 44

        with assert_flag("flag", flag_raw, reader.prev + 36):
            flag = LightFlag.check(flag_raw)

        # 0 = directed (never set), 1 = point source
        assert_eq("point source", 1, point_source_raw, reader.prev + 44)  # 56

        active_state = flag != LightFlag.Inactive
        if anim_def.anim_name in ("impact_ppc_mech", "exp_flash",
                                  "exp_flash_small"):
            # unfortunately, in these few cases, the active state doesn't line up
            assert_in("active state", (0, 1), active_state_raw,
                      reader.prev + 40)  # 52
        else:
            expected = 1 if active_state else 0
            assert_eq("active state", expected, active_state_raw,
                      reader.prev + 40)

        # WARNING: the values are the state, and the flag indicates whether this
        # state should be set or not

        if LightFlag.Directional(flag):
            assert_in("directional", (0, 1), directional_raw,
                      reader.prev + 48)  # 60
            directional = directional_raw == 1
        else:
            assert_eq("directional", 0, directional_raw, reader.prev + 48)
            directional = None

        if LightFlag.Saturated(flag):
            assert_in("saturated", (0, 1), saturated_raw,
                      reader.prev + 52)  # 64
            saturated = saturated_raw == 1
        else:
            assert_eq("saturated", 0, saturated_raw, reader.prev + 52)
            saturated = None

        if LightFlag.Subdivide(flag):
            assert_in("subdivide", (0, 1), subdivide_raw,
                      reader.prev + 56)  # 68
            subdivide = subdivide_raw == 1
        else:
            assert_eq("subdivide", 0, subdivide_raw, reader.prev + 56)
            subdivide = None

        if LightFlag.Static(flag):
            assert_in("static", (0, 1), static_raw, reader.prev + 60)  # 72
            static = static_raw == 1
        else:
            assert_eq("static", 0, static_raw, reader.prev + 60)
            static = None

        if not LightFlag.Translation(flag):
            assert_eq("at node", 0, node_index, reader.prev + 64)
            assert_eq("trans x", 0.0, tx, reader.prev + 68)
            assert_eq("trans y", 0.0, ty, reader.prev + 72)
            assert_eq("trans z", 0.0, tz, reader.prev + 76)
            assert_eq("rotation", False, LightFlag.Rotation(flag),
                      reader.prev + 36)
            assert_eq("rot x", 0.0, rx, reader.prev + 80)
            assert_eq("rot y", 0.0, ry, reader.prev + 84)
            assert_eq("rot z", 0.0, rz, reader.prev + 88)

            at_node = None
        else:
            if node_index == -200:
                node = INPUT_NODE
            else:
                node = anim_def.get_node(node_index - 1, reader.prev + 64)

            # this is never set
            assert_eq("rotation", False, LightFlag.Rotation(flag),
                      reader.prev + 36)
            assert_eq("rot x", 0.0, rx, reader.prev + 80)
            assert_eq("rot y", 0.0, ry, reader.prev + 84)
            assert_eq("rot z", 0.0, rz, reader.prev + 88)
            at_node = AtNodeShort(node=node, tx=tx, ty=ty, tz=tz)

        if LightFlag.Range(flag):
            assert_ge("range min", 0.0, range_min, reader.prev + 92)
            assert_ge("range max", range_min, range_max, reader.prev + 96)
            range_: Range = (range_min, range_max)
        else:
            assert_eq("range min", 0.0, range_min, reader.prev + 92)
            assert_eq("range max", 0.0, range_max, reader.prev + 96)
            range_ = None

        if LightFlag.Color(flag):
            assert_between("red", 0.0, 1.0, color_r, reader.prev + 100)
            assert_between("green", 0.0, 1.0, color_g, reader.prev + 104)
            assert_between("blue", 0.0, 1.0, color_b, reader.prev + 108)
            color: Color = (color_r, color_g, color_b)
        else:
            assert_eq("red", 0.0, color_r, reader.prev + 100)
            assert_eq("green", 0.0, color_g, reader.prev + 104)
            assert_eq("blue", 0.0, color_b, reader.prev + 108)
            color = None

        if LightFlag.Ambient(flag):
            assert_between("ambient", 0.0, 1.0, ambient_value,
                           reader.prev + 112)
            ambient = ambient_value
        else:
            assert_eq("ambient", 0.0, ambient_value, reader.prev + 112)
            ambient = None

        if LightFlag.Diffuse(flag):
            assert_between("diffuse", 0.0, 1.0, diffuse_value,
                           reader.prev + 116)
            diffuse = diffuse_value
        else:
            assert_eq("diffuse", 0.0, diffuse_value, reader.prev + 116)
            diffuse = None

        return cls(
            name=name,
            active_state=active_state,
            directional=directional,
            saturated=saturated,
            subdivide=subdivide,
            static=static,
            at_node=at_node,
            range=range_,
            color=color,
            ambient=ambient,
            diffuse=diffuse,
        )
예제 #19
0
    def read(  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
            cls, reader: BinReader, anim_def: AnimDef) -> CallAnimation:
        (
            name_raw,
            operand_index,
            flag_raw,
            anim_index,
            wait_for_completion,
            node_index,
            tx,
            ty,
            tz,
            rx,
            ry,
            rz,
        ) = reader.read(cls._STRUCT)

        with assert_ascii("name", name_raw, reader.prev + 0):
            name = ascii_zterm_padded(name_raw)

        # not all combinations are present
        assert_in("flag", (0, 1, 3, 7, 8, 10, 16), flag_raw,
                  reader.prev + 34)  # 46

        with assert_flag("flag", flag_raw, reader.prev + 34):
            flag = CallAnimationFlag.check(flag_raw)

        # this is used to store the index of the animation to call once loaded
        assert_eq("anim index", 0, anim_index, reader.prev + 36)  # 48

        if CallAnimationFlag.WaitFor(flag):
            # since multiple animation with the same name may be called, translating
            # this to a name would lose information
            max_prev_ref = len(anim_def.anim_refs) - 1
            assert_between("wait for", 0, max_prev_ref, wait_for_completion,
                           reader.prev + 38)
        else:
            assert_eq("wait for", -1, wait_for_completion,
                      reader.prev + 38)  # 50

        has_at_node = CallAnimationFlag.AtNode(flag)
        has_with_node = CallAnimationFlag.WithNode(flag)
        has_translation = CallAnimationFlag.Translation(flag)
        has_rotation = CallAnimationFlag.Rotation(flag)

        if not has_translation:
            assert_eq("tx", 0.0, tx, reader.prev + 44)
            assert_eq("ty", 0.0, ty, reader.prev + 48)
            assert_eq("tz", 0.0, tz, reader.prev + 52)

        if not has_rotation:
            assert_eq("rx", 0.0, rx, reader.prev + 56)
            assert_eq("ry", 0.0, ry, reader.prev + 60)
            assert_eq("rz", 0.0, rz, reader.prev + 64)

        at_node: AtNodeFlex = None
        with_node = None
        if has_at_node:
            # when using AT_NODE, OPERAND_NODE can't be used
            assert_eq("operand node", 0, operand_index, reader.prev + 32)
            operand_node = None
            assert_eq("with node", False, has_with_node, reader.prev + 34)

            if node_index == 65336:
                node = INPUT_NODE
            else:
                node = anim_def.get_node(node_index - 1, reader.prev + 40)

            if has_rotation:
                at_node = AtNodeLong(node=node,
                                     tx=tx,
                                     ty=ty,
                                     tz=tz,
                                     rx=rx,
                                     ry=ry,
                                     rz=rz)
            else:
                at_node = AtNodeShort(node=node, tx=tx, ty=ty, tz=tz)

        elif has_with_node:
            # when using WITH_NODE, OPERAND_NODE can't be used
            assert_eq("operand node", 0, operand_index, reader.prev + 32)
            operand_node = None
            assert_eq("has rotation", False, has_rotation, reader.prev + 34)

            # WITH_NODE doesn't seem to use INPUT_NODE
            node = anim_def.get_node(node_index - 1, reader.prev + 40)
            with_node = AtNodeShort(node=node, tx=tx, ty=ty, tz=tz)
        else:
            # otherwise, OPERAND_NODE may be used but doesn't need to be
            if operand_index < 1:
                assert_eq("operand node", 0, operand_index, reader.prev + 32)
                operand_node = None
            else:
                operand_node = anim_def.get_node(operand_index - 1,
                                                 reader.prev + 32)
            assert_eq("node index", 0, node_index, reader.prev + 40)
            assert_eq("has translation", False, has_translation,
                      reader.prev + 34)
            assert_eq("has rotation", False, has_rotation, reader.prev + 34)

        return cls(
            name=name,
            at_node=at_node,
            with_node=with_node,
            operand_node=operand_node,
            wait_for_completion=wait_for_completion,
        )
예제 #20
0
def read_anim_def(  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
    reader: BinReader, ) -> Tuple[AnimDef, AnimDefPointers]:
    (
        anim_name_raw,
        name_raw,
        base_node_ptr,  # 064
        anim_root_raw,
        anim_root_ptr,
        zero104,  # 44 zero bytes
        flag_raw,  # 148
        zero152,
        activation_value,
        action_prio,
        byte155,
        exec_by_range_min,
        exec_by_range_max,
        reset_time,
        zero168,
        max_health,
        cur_health,
        zero180,
        zero184,
        zero188,
        zero192,
        seq_defs_ptr,  # 196
        reset_state_ptr,  # 200
        int204,
        int208,
        int212,
        zero216,  # 40 zero bytes
        reset_state_events_ptr,  # 256
        reset_state_events_len,  # 260
        seq_def_count,  # 264
        object_count,  # 265
        node_count,  # 266
        light_count,  # 267
        puffer_count,  # 268
        dynamic_sound_count,  # 269
        static_sound_count,  # 270
        unknown_count,  # 271
        activ_prereq_count,  # 272
        activ_prereq_min_to_satisfy,  # 273
        anim_ref_count,  # 274
        zero275,
        objects_ptr,  # 276
        nodes_ptr,  # 280
        lights_ptr,  # 284
        puffers_ptr,  # 288
        dynamic_sounds_ptr,  # 292
        static_sounds_ptr,  # 296
        unknown_ptr,  # 300
        activ_prereqs_ptr,  # 304
        anim_refs_ptr,  # 308
        zero312,
    ) = reader.read(ANIM_DEF)

    # save this so we can output accurate offsets after doing further reads
    data_offset = reader.prev

    with assert_ascii("anim name", anim_name_raw, reader.prev + 0):
        anim_name, _anim_name_pad = ascii_zterm_partition(anim_name_raw)

    with assert_ascii("name", name_raw, reader.prev + 32):
        name = ascii_zterm_padded(name_raw)

    assert_ne("base node ptr", 0, base_node_ptr, data_offset + 64)

    with assert_ascii("anim root", anim_root_raw, reader.prev + 68):
        anim_root, _anim_root_pad = ascii_zterm_partition(anim_root_raw)

    if name != anim_root:
        assert_ne("anim root ptr", base_node_ptr, anim_root_ptr,
                  data_offset + 100)
    else:
        assert_eq("anim root ptr", base_node_ptr, anim_root_ptr,
                  data_offset + 100)

    assert_all_zero("field 104", zero104, data_offset + 104)

    with assert_flag("flag", flag_raw, data_offset + 148):
        flag = AnimDefFlag.check(flag_raw)

    network_log: Optional[bool] = None
    if AnimDefFlag.NetworkLogSet(flag):
        network_log = AnimDefFlag.NetworkLogOn(flag)

    save_log: Optional[bool] = None
    if AnimDefFlag.SaveLogSet(flag):
        save_log = AnimDefFlag.SaveLogOn(flag)

    assert_eq("field 152", 0, zero152, data_offset + 152)
    assert_in("field 153", (0, 1, 2, 3, 4), activation_value,
              data_offset + 153)
    assert_eq("field 154", 4, action_prio, data_offset + 154)
    assert_eq("field 155", 2, byte155, data_offset + 155)

    exec_by_zone = AnimDefFlag.ExecutionByZone(flag)
    if not AnimDefFlag.ExecutionByRange(flag):
        assert_eq("exec by range min", 0.0, exec_by_range_min,
                  data_offset + 156)
        assert_eq("exec by range max", 0.0, exec_by_range_max,
                  data_offset + 156)
        exec_by_range = None
    else:
        assert_eq("exec by zone", False, exec_by_zone, data_offset + 148)
        assert_ge("exec by range min", 0.0, exec_by_range_min,
                  data_offset + 156)
        assert_ge("exec by range max", exec_by_range_max, exec_by_range_max,
                  data_offset + 156)
        exec_by_range = (exec_by_range_min, exec_by_range_max)

    if not AnimDefFlag.ResetUnk(flag):
        assert_eq("reset time", -1.0, reset_time, data_offset + 164)
        reset_time = None

    assert_eq("field 168", 0.0, zero168, data_offset + 168)
    assert_ge("health", 0.0, max_health, data_offset + 172)
    assert_eq("health", max_health, cur_health, data_offset + 176)
    assert_eq("field 180", 0, zero180, data_offset + 180)
    assert_eq("field 184", 0, zero184, data_offset + 184)
    assert_eq("field 188", 0, zero188, data_offset + 188)
    assert_eq("field 192", 0, zero192, data_offset + 192)

    # WTF???
    assert_eq("field 200", 0x45534552, int200, data_offset + 200)
    assert_eq("field 204", 0x45535F54, int204, data_offset + 204)
    assert_eq("field 208", 0x4E455551, int208, data_offset + 208)
    assert_eq("field 212", 0x00004543, int212, data_offset + 212)

    assert_all_zero("field 216", zero216, data_offset + 216)

    assert_eq("field 275", 0, zero275, data_offset + 275)
    assert_eq("field 312", 0, zero312, data_offset + 312)

    activation = ANIM_ACTIVATION[activation_value]

    if object_count:
        assert_ne("object ptr", 0, objects_ptr, data_offset + 276)
        objects = _read_objects(reader, object_count)
    else:
        assert_eq("object ptr", 0, objects_ptr, data_offset + 276)
        objects = []

    if node_count:
        assert_ne("node ptr", 0, nodes_ptr, data_offset + 280)
        nodes = _read_nodes(reader, node_count)
    else:
        assert_eq("node ptr", 0, nodes_ptr, data_offset + 280)
        nodes = []

    if light_count:
        assert_ne("light ptr", 0, lights_ptr, data_offset + 284)
        lights = _read_lights(reader, light_count)
    else:
        assert_eq("light ptr", 0, lights_ptr, data_offset + 284)
        lights = []

    if puffer_count:
        assert_ne("puffer ptr", 0, puffers_ptr, data_offset + 288)
        puffers = _read_puffers(reader, puffer_count)
    else:
        assert_eq("puffer ptr", 0, puffers_ptr, data_offset + 288)
        puffers = []

    if dynamic_sound_count:
        assert_ne("dynamic sound ptr", 0, dynamic_sounds_ptr,
                  data_offset + 292)
        dynamic_sounds = _read_dynamic_sounds(reader, dynamic_sound_count)
    else:
        assert_eq("dynamic sound ptr", 0, dynamic_sounds_ptr,
                  data_offset + 292)
        dynamic_sounds = []

    if static_sound_count:
        assert_ne("static sound ptr", 0, static_sounds_ptr, data_offset + 296)
        static_sounds = _read_static_sounds(reader, static_sound_count)
    else:
        assert_eq("static sound ptr", 0, static_sounds_ptr, data_offset + 296)
        static_sounds = []

    # this isn't set in any file i have (it is read like the static sound data)
    assert_eq("unknown count", 0, unknown_count, data_offset + 271)
    assert_eq("unknown ptr", 0, unknown_ptr, data_offset + 300)

    if activ_prereq_count:
        assert_ne("activ prereq ptr", 0, activ_prereqs_ptr, data_offset + 304)
        assert_in(
            "activ prereq min",
            (0, 1, 2),
            activ_prereq_min_to_satisfy,
            data_offset + 273,
        )
        activ_prereq = read_activation_prereq(
            reader,
            activ_prereq_count,
            activ_prereq_min_to_satisfy,
        )
    else:
        assert_eq("activ prereq ptr", 0, activ_prereqs_ptr, data_offset + 304)
        assert_eq("activ prereq min", 0, activ_prereq_min_to_satisfy,
                  data_offset + 273)
        activ_prereq = None

    if anim_ref_count:
        assert_ne("anim ref ptr", 0, anim_refs_ptr, data_offset + 308)
        anim_refs = _read_anim_refs(reader, anim_ref_count)
    else:
        assert_eq("anim ref ptr", 0, anim_refs_ptr, data_offset + 308)
        anim_refs = []

    base_name = name.replace(".flt", "")
    if name == anim_root:
        file_name = f"{base_name}-{anim_name}.json"
    else:
        file_name = f"{base_name}-{anim_name}-{anim_root}.json"

    anim_def = AnimDef(
        name=name,
        anim_name=anim_name,
        anim_root=anim_root,
        file_name=file_name,
        # ---
        auto_reset_node_states=AnimDefFlag.AutoResetNodeStates(flag),
        activation=activation,
        execution_by_range=exec_by_range,
        execution_by_zone=exec_by_zone,
        network_log=network_log,
        save_log=save_log,
        has_callback=AnimDefFlag.HasCallback(flag),
        callback_count=0,
        reset_time=reset_time,
        health=max_health,
        proximity_damage=AnimDefFlag.ProximityDamage(flag),
        # ---
        objects=objects,
        nodes=nodes,
        lights=lights,
        puffers=puffers,
        dynamic_sounds=dynamic_sounds,
        static_sounds=static_sounds,
        activation_prereq=activ_prereq,
        anim_refs=anim_refs,
        # skip reset_sequence and sequences, as they need to look up other items
    )

    # unconditional read
    anim_def.reset_sequence = _read_reset_state(
        reader,
        anim_def,
        reset_state_events_len,
        reset_state_events_ptr,
        data_offset + 256,
    )

    # this could be zero, in which case the pointer would also be NULL (but never is)
    assert_gt("seq count", 0, seq_def_count, data_offset + 264)
    assert_ne("seq ptr", 0, seq_defs_ptr, data_offset + 196)
    anim_def.sequences = _read_sequence_definitions(reader, anim_def,
                                                    seq_def_count)

    # the Callback script object checks if callbacks are allowed, but i also
    # want to catch the case where the flag might've been set, but no callbacks
    # were in the scripts
    if anim_def.has_callback:
        assert_gt("callbacks", 0, anim_def.callback_count, data_offset + 148)

    # don't need this value any more
    anim_def.callback_count = 0

    pointers = AnimDefPointers(
        file_name=file_name,
        objects_ptr=objects_ptr,
        nodes_ptr=nodes_ptr,
        lights_ptr=lights_ptr,
        puffers_ptr=puffers_ptr,
        dynamic_sounds_ptr=dynamic_sounds_ptr,
        static_sounds_ptr=static_sounds_ptr,
        activ_prereqs_ptr=activ_prereqs_ptr,
        anim_refs_ptr=anim_refs_ptr,
        reset_state_ptr=reset_state_ptr,
        reset_state_events_ptr=reset_state_events_ptr,
        seq_defs_ptr=seq_defs_ptr,
    )

    return anim_def, pointers