コード例 #1
0
ファイル: node_data_read.py プロジェクト: tobywf/mech3ax-py
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,
    )
コード例 #2
0
def _read_anim_info(reader: BinReader) -> Tuple[int, int, int]:
    LOG.debug("Reading anim info at %d", reader.offset)
    (
        zero00,
        ptr04,
        zero08,
        count,
        anim_ptr,
        loc_count,
        loc_ptr,
        world_ptr,
        gravity,
        zero32,
        zero36,
        zero40,
        zero44,
        zero48,
        zero52,
        zero56,
        one60,
        zero64,
    ) = reader.read(ANIM_INFO)

    assert_eq("field 00", 0, zero00, reader.prev + 0)
    assert_eq("field 04", 0, ptr04, reader.prev + 4)
    assert_eq("field 08", 0, zero08, reader.prev + 8)

    assert_gt("count", 0, count, reader.prev + 10)

    assert_ne("anim ptr", 0, anim_ptr, reader.prev + 12)
    # the localisation isn't used
    assert_eq("loc count", 0, loc_count, reader.prev + 16)
    assert_eq("loc ptr", 0, loc_ptr, reader.prev + 20)
    assert_ne("world ptr", 0, world_ptr, reader.prev + 24)

    # the gravity is always the same
    assert_eq("gravity", GRAVITY, gravity, reader.prev + 28)

    assert_eq("field 32", 0, zero32, reader.prev + 32)
    assert_eq("field 36", 0, zero36, reader.prev + 36)
    assert_eq("field 40", 0, zero40, reader.prev + 40)
    assert_eq("field 44", 0, zero44, reader.prev + 44)
    assert_eq("field 48", 0, zero48, reader.prev + 48)
    assert_eq("field 52", 0, zero52, reader.prev + 52)
    assert_eq("field 56", 0, zero56, reader.prev + 56)
    assert_eq("field 60", 1, one60, reader.prev + 60)
    # this is probably a float
    assert_eq("field 64", 0, zero64, reader.prev + 64)

    LOG.debug("Anim count is %d", count)

    return (count, anim_ptr, world_ptr)
コード例 #3
0
ファイル: node_info.py プロジェクト: tobywf/mech3ax-py
def _assert_node_info_lod(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_lod_base = node.flag & NODE_FLAG_LOD_BASE
    # assert_eq("flag lod base", NODE_FLAG_LOD_BASE, flag_lod_base, offset + 36)
    # # the only variable flag is Unk15
    # flag_lod_mask = node.flag & ~NODE_FLAG_LOD_BASE
    # assert_in("flag lod mask", (0, NodeFlag.Unk15), flag_lod_mask, offset + 36)

    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)
    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)
    # must have one parent
    assert_eq("parent count", 1, node.parent_count, offset + 84)
    assert_ne("parent array ptr", 0, node.parent_array_ptr, offset + 88)
    # always has at least one child
    assert_between("children count", 1, 32, node.children_count, offset + 92)
    assert_ne("children array ptr", 0, node.children_array_ptr, offset + 96)
    assert_ne("block 1", BLOCK_EMPTY, node.block1, offset + 116)
    assert_eq("block 2", BLOCK_EMPTY, node.block2, offset + 140)
    assert_eq("block 3", node.block1, node.block3, offset + 164)
    assert_eq("field 196", 160, node.unk196, offset + 196)
コード例 #4
0
ファイル: materials.py プロジェクト: tobywf/mech3ax-py
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
コード例 #5
0
def _read_nodes(reader: BinReader, count: int) -> List[NamePtrFlag]:
    # the first entry is always zero
    name_raw, zero, ptr = reader.read(NODE)
    assert_all_zero("name", name_raw, reader.prev + 0)
    assert_eq("field 32", 0, zero, reader.prev + 32)
    assert_eq("field 36", 0, ptr, reader.prev + 36)

    nodes = []
    for _ in range(1, count):
        name_raw, zero, ptr = reader.read(NODE)
        with assert_ascii("name", name_raw, reader.prev + 0):
            name = ascii_zterm_node_name(name_raw)
        assert_eq("field 32", 0, zero, reader.prev + 32)
        assert_ne("field 36", 0, ptr, reader.prev + 36)
        nodes.append(NamePtrFlag(name=name, ptr=ptr))

    return nodes
コード例 #6
0
ファイル: node_info.py プロジェクト: tobywf/mech3ax-py
def _assert_node_info_window(node: Node, offset: int,
                             _mesh_count: int) -> None:
    assert_eq("name", "window1", node.name, offset + 0)
    assert_eq("flag", NODE_FLAG_DEFAULT, node.flag, offset + 36)
    assert_eq("field 044", 0, node.unk044, offset + 44)
    assert_eq("zone id", ZONE_DEFAULT, node.zone_id, offset + 48)
    assert_ne("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)
    assert_eq("block 1", BLOCK_EMPTY, node.block1, offset + 116)
    assert_eq("block 2", BLOCK_EMPTY, node.block2, offset + 140)
    assert_eq("block 3", BLOCK_EMPTY, node.block3, offset + 164)
    assert_eq("field 196", 0, node.unk196, offset + 196)
コード例 #7
0
def _read_dynamic_sounds(reader: BinReader, count: int) -> List[NamePtrFlag]:
    # the first entry is always zero
    name_raw, flag, ptr, zero = reader.read(READER_LOOKUP)
    assert_all_zero("name", name_raw, reader.prev + 0)
    assert_eq("field 32", 0, flag, reader.prev + 32)
    assert_eq("field 36", 0, ptr, reader.prev + 36)
    assert_eq("field 40", 0, zero, reader.prev + 40)

    sounds = []
    for _ in range(1, count):
        name_raw, flag, ptr, zero = reader.read(READER_LOOKUP)
        with assert_ascii("name", name_raw, reader.prev + 0):
            name = ascii_zterm_node_name(name_raw)
        assert_eq("field 32", 0, flag, reader.prev + 32)
        assert_ne("field 36", 0, ptr, reader.prev + 36)
        assert_eq("field 40", 0, zero, reader.prev + 40)
        sounds.append(NamePtrFlag(name=name, ptr=ptr))

    return sounds
コード例 #8
0
def _read_lights(reader: BinReader, count: int) -> List[NamePtrFlag]:
    # the first entry is always zero
    name_raw, flag, ptr, zero = reader.read(READER_LOOKUP)
    assert_all_zero("name", name_raw, reader.prev + 0)
    assert_eq("field 32", 0, flag, reader.prev + 32)
    assert_eq("field 36", 0, ptr, reader.prev + 36)
    assert_eq("field 40", 0, zero, reader.prev + 40)

    lights = []
    for _ in range(1, count):
        name_raw, flag, ptr, zero = reader.read(READER_LOOKUP)
        with assert_ascii("name", name_raw, reader.prev + 0):
            name = ascii_zterm_node_name(name_raw)
        assert_eq("field 32", 0, flag, reader.prev + 32)
        assert_ne("field 36", 0, ptr, reader.prev + 36)
        # if this were non-zero, it would cause the light to be removed instead
        # of added (???)
        assert_eq("field 40", 0, zero, reader.prev + 40)
        lights.append(NamePtrFlag(name=name, ptr=ptr))

    return lights
コード例 #9
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
コード例 #10
0
def _read_reset_state(
    reader: BinReader,
    anim_def: AnimDef,
    length: int,
    ptr: int,
    offset: int,
) -> Optional[SeqDef]:
    reset_raw, reset_ptr, reset_len = reader.read(RESET_STATE)
    with assert_ascii("reset end", reset_raw, reader.prev + 0):
        reset_end = ascii_zterm_padded(reset_raw)

    # this is always "RESET_SEQUENCE"
    assert_eq("reset end", "RESET_SEQUENCE", reset_end, reader.prev + 0)
    assert_eq("reset ptr", ptr, reset_ptr, reader.prev + 56)
    assert_eq("reset len", length, reset_len, reader.prev + 60)

    if not length:
        assert_eq("reset ptr", 0, ptr, offset)
        return None

    assert_ne("reset ptr", 0, ptr, offset)
    script = _parse_script(reader, anim_def, length)
    return SeqDef(name="RESET_SEQUENCE", ptr=ptr, script=script)
コード例 #11
0
def _read_puffers(reader: BinReader, count: int) -> List[NamePtrFlag]:
    # the first entry is always zero
    name_raw, flag, ptr, zero = reader.read(READER_LOOKUP)
    assert_all_zero("name", name_raw, reader.prev + 0)
    assert_eq("field 32", 0, flag, reader.prev + 32)
    assert_eq("field 36", 0, ptr, reader.prev + 36)
    assert_eq("field 40", 0, zero, reader.prev + 40)

    puffers = []
    for _ in range(1, count):
        name_raw, flag, ptr, zero = reader.read(READER_LOOKUP)
        with assert_ascii("name", name_raw, reader.prev + 0):
            name = ascii_zterm_padded(name_raw)
        assert_eq("field 32", 0, (flag & 0x00FFFFFF), reader.prev + 32)
        # TODO: what does this flag mean?
        # this is something the code does, but i'm not sure why
        # some of these values make decent floating point numbers
        flag = flag >> 24
        assert_ne("field 36", 0, ptr, reader.prev + 36)
        assert_eq("field 40", 0, zero, reader.prev + 40)
        puffers.append(NamePtrFlag(name=name, ptr=ptr, flag=flag))

    return puffers
コード例 #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
ファイル: node_info.py プロジェクト: tobywf/mech3ax-py
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)
コード例 #14
0
    def read(  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
            cls, reader: BinReader, anim_def: AnimDef) -> ObjectMotion:
        (
            flag_raw,  # 000, 012
            node_index,  # 004, 016
            zero008,  # 008, 020
            gravity_value,  # 012, 024
            zero016,  # 016, 028
            trans_range_min_1,  # 020, 032
            trans_range_max_1,  # 024, 036
            trans_range_min_2,  # 028, 040
            trans_range_max_2,  # 032, 044
            trans_range_min_3,  # 036, 048
            trans_range_max_3,  # 040, 052
            trans_range_min_4,  # 044, 056
            trans_range_max_4,  # 048, 060
            translation_1,  # 052, 064
            translation_2,  # 056, 068
            translation_3,  # 060, 072
            translation_4,  # 064, 076
            translation_5,  # 068, 080
            translation_6,  # 072, 084
            # used for translation calculations
            zero076,  # 076, 088
            zero080,  # 080, 092
            zero084,  # 084, 096
            zero088,  # 088, 100
            zero092,  # 092, 104
            zero096,  # 096, 108
            # used for translation calculations
            unk100,  # 100, 112
            unk104,  # 104, 116
            unk108,  # 108, 120
            # FORWARD_ROTATION
            forward_rotation_1,  # 112, 124
            forward_rotation_2,  # 116, 128
            zero120,  # 120, 132
            # XYZ_ROTATION
            xyz_rotation_1,  # 124, 136
            xyz_rotation_2,  # 128, 140
            xyz_rotation_3,  # 132, 144
            xyz_rotation_4,  # 136, 148
            xyz_rotation_5,  # 140, 152
            xyz_rotation_6,  # 144, 156
            # used for xyz rotation calculations
            zero148,  # 148, 160
            zero152,  # 152, 164
            zero156,  # 156, 168
            scale_1,  # 160, 172
            scale_2,  # 164, 176
            scale_3,  # 168, 180
            scale_4,  # 172, 184
            scale_5,  # 176, 188
            scale_6,  # 180, 192
            # used for scale calculations
            zero184,  # 184, 196
            zero188,  # 188, 200
            zero192,  # 192, 204
            bounce_seq0_name_raw,  # 196, 208
            bounce_seq0_sentinel,  # 228, 240
            bounce_snd0_index,  # 230, 242
            bounce_snd0_volume,  # 232, 244
            bounce_seq1_name_raw,  # 236, 248
            bounce_seq1_sentinel,  # 268, 280
            bounce_snd1_index,  # 270, 282
            bounce_snd1_volume,  # 272, 284
            bounce_seq2_name_raw,  # 276, 288
            bounce_seq2_sentinel,  # 308, 320
            bounce_snd2_index,  # 310, 322
            bounce_snd2_volume,  # 312, 324
            run_time,  # 316, 328
        ) = reader.read(cls._STRUCT)

        assert_lt("flag", 0x7FFF, flag_raw, reader.prev + 0)
        with assert_flag("flag", flag_raw, reader.prev + 0):
            flag = MotionFlag.check(flag_raw)

        node = anim_def.get_node(node_index - 1, reader.prev + 4)
        assert_eq("field 008", 0.0, zero008, reader.prev + 8)
        assert_eq("field 016", 0.0, zero016, reader.prev + 16)

        gravity_no_alt = MotionFlag.GravityNoAltitude(flag)
        gravity_complex = MotionFlag.GravityComplex(flag)

        if not MotionFlag.Gravity(flag):
            assert_eq("gravity", 0.0, gravity_value, reader.prev + 12)
            assert_eq("gravity no alt", False, gravity_no_alt, reader.prev + 0)
            assert_eq("gravity complex", False, gravity_complex,
                      reader.prev + 0)
            gravity: Gravity = None
        elif gravity_no_alt:
            assert_eq("gravity complex", False, gravity_complex,
                      reader.prev + 0)
            gravity = ("NO_ALTITUDE", gravity_value)
        elif gravity_complex:
            gravity = ("COMPLEX", gravity_value)
        else:
            gravity = ("LOCAL", gravity_value)

        if MotionFlag.TranslationMin(flag):
            translation_range_min: Optional[Vec4] = (
                trans_range_min_1,
                trans_range_min_2,
                trans_range_min_3,
                trans_range_min_4,
            )
        else:
            assert_eq("trans range min 1", 0.0, trans_range_min_1,
                      reader.prev + 20)
            assert_eq("trans range min 2", 0.0, trans_range_min_2,
                      reader.prev + 28)
            assert_eq("trans range min 3", 0.0, trans_range_min_3,
                      reader.prev + 36)
            assert_eq("trans range min 4", 0.0, trans_range_min_4,
                      reader.prev + 44)
            translation_range_min = None

        if MotionFlag.TranslationMax(flag):
            translation_range_max: Optional[Vec4] = (
                trans_range_max_1,
                trans_range_max_2,
                trans_range_max_3,
                trans_range_max_4,
            )
        else:
            assert_eq("trans range max 1", 0.0, trans_range_max_1,
                      reader.prev + 24)
            assert_eq("trans range max 2", 0.0, trans_range_max_2,
                      reader.prev + 32)
            assert_eq("trans range max 3", 0.0, trans_range_max_3,
                      reader.prev + 40)
            assert_eq("trans range max 4", 0.0, trans_range_max_4,
                      reader.prev + 48)
            translation_range_max = None

        if MotionFlag.Translation(flag):
            translation: Optional[Vec9] = (
                translation_1,
                translation_2,
                translation_3,
                translation_4,
                translation_5,
                translation_6,
                unk100,
                unk104,
                unk108,
            )
        else:
            assert_eq("translation 1", 0.0, translation_1, reader.prev + 52)
            assert_eq("translation 2", 0.0, translation_2, reader.prev + 56)
            assert_eq("translation 3", 0.0, translation_3, reader.prev + 60)
            assert_eq("translation 4", 0.0, translation_4, reader.prev + 64)
            assert_eq("translation 5", 0.0, translation_5, reader.prev + 68)
            assert_eq("translation 6", 0.0, translation_6, reader.prev + 72)
            assert_eq("field 100", 0.0, unk100, reader.prev + 100)
            assert_eq("field 104", 0.0, unk104, reader.prev + 104)
            assert_eq("field 108", 0.0, unk108, reader.prev + 108)
            translation = None

        assert_eq("field 076", 0.0, zero076, reader.prev + 76)
        assert_eq("field 080", 0.0, zero080, reader.prev + 80)
        assert_eq("field 084", 0.0, zero084, reader.prev + 84)
        assert_eq("field 088", 0.0, zero088, reader.prev + 88)
        assert_eq("field 092", 0.0, zero092, reader.prev + 92)
        assert_eq("field 096", 0.0, zero096, reader.prev + 96)

        if MotionFlag.ForwardRotationTime(flag):
            forward_rotation: ForwardRotation = (
                "TIME",
                forward_rotation_1,
                forward_rotation_2,
            )
        elif MotionFlag.ForwardRotationDistance(flag):
            assert_eq("fwd rot 2", 0.0, forward_rotation_2, reader.prev + 116)
            forward_rotation = (
                "DISTANCE",
                forward_rotation_1,
                0.0,
            )
        else:
            assert_eq("fwd rot 1", 0.0, forward_rotation_1, reader.prev + 112)
            assert_eq("fwd rot 2", 0.0, forward_rotation_2, reader.prev + 116)
            forward_rotation = None

        assert_eq("field 120", 0.0, zero120, reader.prev + 120)

        if MotionFlag.XYZRotation(flag):
            xyz_rotation: Optional[Vec6] = (
                xyz_rotation_1,
                xyz_rotation_2,
                xyz_rotation_3,
                xyz_rotation_4,
                xyz_rotation_5,
                xyz_rotation_6,
            )
        else:
            assert_eq("xyz rot 1", 0.0, xyz_rotation_1, reader.prev + 124)
            assert_eq("xyz rot 2", 0.0, xyz_rotation_2, reader.prev + 128)
            assert_eq("xyz rot 3", 0.0, xyz_rotation_3, reader.prev + 132)
            assert_eq("xyz rot 4", 0.0, xyz_rotation_4, reader.prev + 136)
            assert_eq("xyz rot 5", 0.0, xyz_rotation_5, reader.prev + 140)
            assert_eq("xyz rot 6", 0.0, xyz_rotation_6, reader.prev + 144)
            xyz_rotation = None

        assert_eq("field 148", 0.0, zero148, reader.prev + 148)
        assert_eq("field 152", 0.0, zero152, reader.prev + 152)
        assert_eq("field 156", 0.0, zero156, reader.prev + 156)

        if MotionFlag.Scale(flag):
            scale: Optional[Vec6] = (
                scale_1,
                scale_2,
                scale_3,
                scale_4,
                scale_5,
                scale_6,
            )
        else:
            assert_eq("scale 1", 0.0, scale_1, reader.prev + 160)
            assert_eq("scale 2", 0.0, scale_2, reader.prev + 164)
            assert_eq("scale 3", 0.0, scale_3, reader.prev + 168)
            assert_eq("scale 4", 0.0, scale_4, reader.prev + 172)
            assert_eq("scale 5", 0.0, scale_5, reader.prev + 176)
            assert_eq("scale 6", 0.0, scale_6, reader.prev + 180)
            scale = None

        assert_eq("field 184", 0.0, zero184, reader.prev + 184)
        assert_eq("field 188", 0.0, zero188, reader.prev + 188)
        assert_eq("field 192", 0.0, zero192, reader.prev + 192)

        assert_eq("bounce seq 0 sentinel", -1, bounce_seq0_sentinel,
                  reader.prev + 228)
        assert_eq("bounce seq 1 sentinel", -1, bounce_seq1_sentinel,
                  reader.prev + 268)
        assert_eq("bounce seq 2 sentinel", -1, bounce_seq2_sentinel,
                  reader.prev + 308)

        bounce_sequence = []
        if MotionFlag.BounceSeq(flag):
            with assert_ascii("bounce seq 0 name", bounce_seq0_name_raw,
                              reader.prev + 196):
                bounce_seq0_name = ascii_zterm_padded(bounce_seq0_name_raw)

            # should have at least one value
            assert_ne("bounce seq 0 name", "", bounce_seq0_name,
                      reader.prev + 196)
            bounce_sequence.append(bounce_seq0_name)

            with assert_ascii("bounce seq 1 name", bounce_seq1_name_raw,
                              reader.prev + 236):
                bounce_seq1_name = ascii_zterm_padded(bounce_seq1_name_raw)
            if bounce_seq1_name:
                bounce_sequence.append(bounce_seq1_name)

            with assert_ascii("bounce seq 2 name", bounce_seq2_name_raw,
                              reader.prev + 276):
                bounce_seq2_name = ascii_zterm_padded(bounce_seq2_name_raw)
            if bounce_seq2_name:
                bounce_sequence.append(bounce_seq2_name)

        else:
            assert_all_zero("bounce seq 0 name", bounce_seq0_name_raw,
                            reader.prev + 196)
            assert_all_zero("bounce seq 1 name", bounce_seq1_name_raw,
                            reader.prev + 236)
            assert_all_zero("bounce seq 2 name", bounce_seq2_name_raw,
                            reader.prev + 276)

        bounce_sounds = []
        if MotionFlag.BounceSound(flag):

            # should have at least one value
            assert_gt("bounce snd 0 volume", 0.0, bounce_snd0_volume,
                      reader.prev + 232)
            sound = anim_def.get_sound(bounce_snd0_index - 1,
                                       reader.prev + 230)
            bounce_sounds.append((sound, bounce_snd0_volume))
        else:
            assert_eq("bounce snd 0 sound", 0, bounce_snd0_index,
                      reader.prev + 230)
            assert_eq("bounce snd 0 volume", 0.0, bounce_snd0_volume,
                      reader.prev + 232)

        # these are never set, regardless of the flag
        assert_eq("bounce snd 1 sound", 0, bounce_snd1_index,
                  reader.prev + 270)
        assert_eq("bounce snd 1 volume", 0.0, bounce_snd1_volume,
                  reader.prev + 272)

        assert_eq("bounce snd 2 sound", 0, bounce_snd2_index,
                  reader.prev + 310)
        assert_eq("bounce snd 2 volume", 0.0, bounce_snd2_volume,
                  reader.prev + 312)

        if MotionFlag.RunTime(flag):
            assert_gt("run time", 0.0, run_time, reader.prev + 316)
        else:
            assert_eq("run time", 0.0, run_time, reader.prev + 316)
            run_time = None

        return cls(
            node=node,
            gravity=gravity,
            impact_force=MotionFlag.ImpactForce(flag),
            translation_range_min=translation_range_min,
            translation_range_max=translation_range_max,
            translation=translation,
            forward_rotation=forward_rotation,
            xyz_rotation=xyz_rotation,
            scale=scale,
            bounce_sequence=bounce_sequence,
            bounce_sounds=bounce_sounds,
            run_time=run_time,
        )
コード例 #15
0
ファイル: node_data_read.py プロジェクト: tobywf/mech3ax-py
def _read_partitions(  # pylint: disable=too-many-locals
        reader: BinReader, area_x: Sequence[int],
        area_y: Sequence[int]) -> List[List[Partition]]:

    partitions = []
    for y in area_y:
        subpartitions = []
        for x in area_x:
            (
                flag_raw,
                mone04,
                part_x,
                part_y,
                unk16,
                unk20,
                unk24,
                unk28,
                unk32,
                unk36,
                unk40,
                unk44,
                unk48,
                unk52,
                zero56,
                count,  # 58
                ptr,  # 60
                zero64,
                zero68,
            ) = reader.read(PARTITION)

            assert_eq("partition field 00", 0x100, flag_raw, reader.prev + 0)
            assert_eq("partition field 04", -1, mone04, reader.prev + 4)

            assert_eq("partition field 56", 0, zero56, reader.prev + 56)
            assert_eq("partition field 64", 0, zero64, reader.prev + 64)
            assert_eq("partition field 68", 0, zero68, reader.prev + 68)

            assert_eq("partition x", x, part_x, reader.prev + 8)
            assert_eq("partition y", y, part_y, reader.prev + 12)

            assert_eq("partition field 16", x, unk16, reader.prev + 16)
            # unk20
            assert_eq("partition field 24", y - 256, unk24, reader.prev + 24)
            assert_eq("partition field 28", x + 256, unk28, reader.prev + 28)
            # unk32
            assert_eq("partition field 36", y, unk36, reader.prev + 36)

            # this is set through an extremely convoluted calculation starting with:
            #   unk40 = unk16 + (unk28 - unk16) * 0.5
            # which simplifies to:
            #   unk40 = x + 128.0
            assert_eq("partition field 40", x + 128, unk40, reader.prev + 40)

            # this is set through an extremely convoluted calculation starting with:
            #   unk44 = unk20 + (unk32 - unk20) * 0.5
            # ... at least initially, although unk20 and unk32 would be 0.0 because
            # calloc zeros memory. i can get this calculation to work with almost
            # all values, but some are ever so slightly off (lowest bits in the
            # single precision floating point numbers differ), so i suspect this
            # calculation is more complicated.
            # assert_eq("partition field 44", expected, unk44, reader.prev + 44)

            # this is set through an extremely convoluted calculation starting with:
            #   unk48 = unk24 + (unk36 - unk24) * 0.5
            # which simplifies to:
            #   unk48 = y - 128.0
            assert_eq("partition field 48", y - 128, unk48,
                      reader.prev + 48)  # two[2]

            # this is set through an extremely convoluted calculation starting with:
            #   temp1 = (unk28 - unk16) * 0.5
            #   temp2 = (unk32 - unk20) * 0.5
            #   temp3 = (unk36 - unk24) * 0.5
            # which simplifies to:
            #   temp1 = 128.0
            #   (does not simplify without knowing unk32 and unk20)
            #   temp3 = 128.0
            # approx_sqrt automatically converts to single precision
            temp = (unk32 - unk20) * 0.5
            expected = approx_sqrt(128 * 128 + temp * temp + 128 * 128)
            assert_eq("partition field 52", expected, unk52, reader.prev + 52)

            if count:
                assert_ne("partition ptr", 0, ptr, reader.prev + 60)
                nodes = [reader.read_u32() for _ in range(count)]
            else:
                assert_eq("partition ptr", 0, ptr, reader.prev + 60)
                nodes = []

            partition = Partition(
                x=x,
                y=y,
                nodes=nodes,
                unk=(unk20, unk32, unk44),
                ptr=ptr,
            )
            subpartitions.append(partition)
        partitions.append(subpartitions)

    return partitions
コード例 #16
0
ファイル: node_data_read.py プロジェクト: tobywf/mech3ax-py
def _read_node_data_world(  # pylint: disable=too-many-locals,too-many-statements
    reader: BinReader, ) -> World:
    (
        flag_raw,  # 000
        area_partition_used,  # 004
        area_partition_count,  # 008
        area_partition_ptr,  # 012
        fog_state_raw,  # 016
        fog_color_r,  # 020
        fog_color_g,  # 024
        fog_color_b,  # 028
        fog_range_near,  # 032
        fog_range_far,  # 036
        fog_alti_high,  # 040
        fog_alti_low,  # 044
        fog_density,  # 048
        area_left_f,  # 052
        area_bottom_f,  # 056
        area_width,  # 060
        area_height,  # 064
        area_right_f,  # 068
        area_top_f,  # 072
        partition_max_dec_feature_count,  # 076
        virtual_partition,  # 080
        virt_partition_x_min,  # 084
        virt_partition_y_min,  # 088
        virt_partition_x_max,  # 092
        virt_partition_y_max,  # 096
        virt_partition_x_size,  # 100
        virt_partition_y_size,  # 104
        virt_partition_x_half,  # 108
        virt_partition_y_half,  # 112
        virt_partition_x_inv,  # 116
        virt_partition_y_inv,  # 124
        virt_partition_diag,  # 128
        partition_inclusion_tol_low,  # 128
        partition_inclusion_tol_high,  # 132
        virt_partition_x_count,  # 136
        virt_partition_y_count,  # 140
        virt_partition_ptr,  # 144
        one148,
        one152,
        one156,
        children_count,  # 160
        children_ptr,  # 164
        lights_ptr,  # 168
        zero172,
        zero176,
        zero180,
        zero184,
    ) = reader.read(WORLD)

    assert_eq("flag", 0, flag_raw, reader.prev + 0)

    # LINEAR = 1, EXPONENTIAL = 2 (never set)
    assert_eq("fog state", 1, fog_state_raw, reader.prev + 16)
    # not set
    assert_eq("fog color r", 0.0, fog_color_r, reader.prev + 20)
    assert_eq("fog color g", 0.0, fog_color_g, reader.prev + 24)
    assert_eq("fog color b", 0.0, fog_color_b, reader.prev + 28)
    assert_eq("fog range near", 0.0, fog_range_near, reader.prev + 32)
    assert_eq("fog range far", 0.0, fog_range_far, reader.prev + 36)
    assert_eq("fog alti high", 0.0, fog_alti_high, reader.prev + 40)
    assert_eq("fog alti low", 0.0, fog_alti_low, reader.prev + 44)
    assert_eq("fog density", 0.0, fog_density, reader.prev + 48)

    # we need these values to be integers for the partition logic
    area_left = int(area_left_f)
    area_bottom = int(area_bottom_f)
    area_right = int(area_right_f)
    area_top = int(area_top_f)
    assert_eq("area left", area_left, area_left_f, reader.prev + 52)
    assert_eq("area bottom", area_bottom, area_bottom_f, reader.prev + 56)
    assert_eq("area right", area_right, area_right_f, reader.prev + 68)
    assert_eq("area top", area_top, area_top_f, reader.prev + 72)

    # validate rect
    assert_gt("area right", area_left, area_right, reader.prev + 68)
    assert_gt("area bottom", area_top, area_bottom, reader.prev + 72)
    width = area_right - area_left
    height = area_top - area_bottom
    assert_eq("area width", width, area_width, reader.prev + 60)
    assert_eq("area height", height, area_height, reader.prev + 64)

    assert_eq("partition max feat", 16, partition_max_dec_feature_count,
              reader.prev + 76)
    assert_eq("virtual partition", 1, virtual_partition, reader.prev + 80)

    assert_eq("vp x min", 1, virt_partition_x_min, reader.prev + 84)
    assert_eq("vp y min", 1, virt_partition_y_min, reader.prev + 88)

    assert_eq("vp x size", 256.0, virt_partition_x_size, reader.prev + 100)
    assert_eq("vp y size", -256.0, virt_partition_y_size, reader.prev + 104)
    assert_eq("vp x half", 128.0, virt_partition_x_half, reader.prev + 108)
    assert_eq("vp y half", -128.0, virt_partition_y_half, reader.prev + 112)
    assert_eq("vp x inv", 1.0 / 256.0, virt_partition_x_inv, reader.prev + 116)
    assert_eq("vp y inv", 1.0 / -256.0, virt_partition_y_inv,
              reader.prev + 120)
    # this is sqrt(x_size * x_size + y_size * y_size) * -0.5, but because of the
    # (poor) sqrt approximation used, it comes out as -192.0 instead of -181.0
    assert_eq("vp diagonal", -192.0, virt_partition_diag, reader.prev + 124)

    assert_eq("vp inc tol low", 3, partition_inclusion_tol_low,
              reader.prev + 128)
    assert_eq("vp inc tol high", 3, partition_inclusion_tol_high,
              reader.prev + 132)

    area_x = range(area_left, area_right, 256)
    # because the virtual partition y size is negative, this is inverted!
    area_y = range(area_bottom, area_top, -256)

    assert_eq("vp x count", len(area_x), virt_partition_x_count,
              reader.prev + 136)
    assert_eq("vp y count", len(area_y), virt_partition_y_count,
              reader.prev + 140)
    assert_eq("ap used", 0, area_partition_used, reader.prev + 4)
    assert_eq(
        "vp x max",
        virt_partition_x_count - 1,
        virt_partition_x_max,
        reader.prev + 92,
    )
    assert_eq(
        "vp y max",
        virt_partition_y_count - 1,
        virt_partition_y_max,
        reader.prev + 96,
    )

    # TODO: why isn't this a perfect fit for T1?
    virt_partition_count = virt_partition_x_count * virt_partition_y_count
    assert_between(
        "ap count",
        virt_partition_count - 1,
        virt_partition_count,
        area_partition_count,
        reader.prev + 8,
    )
    fudge_count = area_partition_count != virt_partition_count
    assert_ne("ap ptr", 0, area_partition_ptr, reader.prev + 12)
    assert_ne("vp ptr", 0, virt_partition_ptr, reader.prev + 144)

    assert_eq("field 148", 1, one148, reader.prev + 148)
    assert_eq("field 152", 1, one152, reader.prev + 152)
    assert_eq("field 156", 1, one156, reader.prev + 156)
    assert_eq("children count", 1, children_count, reader.prev + 160)
    assert_ne("children ptr", 0, children_ptr, reader.prev + 164)
    assert_ne("lights ptr", 0, lights_ptr, reader.prev + 168)
    assert_eq("field 172", 0, zero172, reader.prev + 172)
    assert_eq("field 176", 0, zero176, reader.prev + 176)
    assert_eq("field 180", 0, zero180, reader.prev + 180)
    assert_eq("field 184", 0, zero184, reader.prev + 184)

    # read as a result of children_count
    child = reader.read_u32()
    # read as a result of zero172 (i.e. nothing to do)

    partitions = _read_partitions(reader, area_x, area_y)

    # world nodes always have an action priority of 13

    return World(
        type="World",
        area=(area_left, area_top, area_right, area_bottom),
        partitions=partitions,
        children=[child],
        area_partition_x_count=virt_partition_x_count,
        area_partition_y_count=virt_partition_y_count,
        fudge_count=fudge_count,
        area_partition_ptr=area_partition_ptr,
        virt_partition_ptr=virt_partition_ptr,
        children_ptr=children_ptr,
        lights_ptr=lights_ptr,
    )
コード例 #17
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
コード例 #18
0
ファイル: node_data_read.py プロジェクト: tobywf/mech3ax-py
def _read_node_data_light(  # pylint: disable=too-many-locals
        reader: BinReader, ) -> Light:
    (
        direction_x,  # 000
        direction_y,  # 004
        direction_z,  # 008
        trans_x,  # 012
        trans_y,  # 016
        trans_z,  # 020
        zero024,  # 112 zero bytes
        one136,
        zero140,
        zero144,
        zero148,
        zero152,
        diffuse,  # 156
        ambient,  # 160
        color_r,  # 164
        color_g,  # 168
        color_b,  # 172
        flag_raw,  # 176
        range_min,  # 180
        range_max,  # 184
        range_min_sq,  # 188
        range_max_sq,  # 192
        range_inv,  # 196
        parent_count,  # 200
        parent_ptr,  # 204
        zero208,
    ) = reader.read(LIGHT)

    # translation is never set
    assert_eq("trans x", 0.0, trans_x, reader.prev + 12)
    assert_eq("trans y", 0.0, trans_y, reader.prev + 16)
    assert_eq("trans z", 0.0, trans_z, reader.prev + 20)

    assert_all_zero("field 024", zero024, reader.prev + 24)

    assert_eq("field 136", 1.0, one136, reader.prev + 136)
    assert_eq("field 140", 0.0, zero140, reader.prev + 140)
    assert_eq("field 144", 0.0, zero144, reader.prev + 144)
    assert_eq("field 148", 0.0, zero148, reader.prev + 148)
    assert_eq("field 152", 0.0, zero152, reader.prev + 152)

    assert_between("diffuse", 0.0, 1.0, diffuse, reader.prev + 156)
    assert_between("ambient", 0.0, 1.0, ambient, reader.prev + 160)

    assert_eq("color r", 1.0, color_r, reader.prev + 164)
    assert_eq("color g", 1.0, color_g, reader.prev + 168)
    assert_eq("color b", 1.0, color_b, reader.prev + 172)

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

    assert_eq("flag", LIGHT_FLAG, flag, reader.prev + 176)

    assert_gt("range min", 0.0, range_min, reader.prev + 180)
    assert_gt("range max", range_min, range_max, reader.prev + 184)
    expected = range_min * range_min
    assert_eq("range min sq", expected, range_min_sq, reader.prev + 188)
    expected = range_max * range_max
    assert_eq("range max sq", expected, range_max_sq, reader.prev + 192)
    expected = force_single_prec(1.0 / (range_max - range_min))
    assert_eq("range inv", expected, range_inv, reader.prev + 196)

    # if this was ever zero, field 208 wouldn't be read
    assert_eq("parent count", 1, parent_count, reader.prev + 200)
    assert_ne("parent ptr", 0, parent_ptr, reader.prev + 204)
    assert_eq("field 208", 0, zero208, reader.prev + 208)

    # light nodes always have an action priority of 9

    return Light(
        type="Light",
        direction=(direction_x, direction_y, direction_z),
        diffuse=diffuse,
        ambient=ambient,
        color=(color_r, color_g, color_b),
        range=(range_min, range_max),
        parent_ptr=parent_ptr,
    )
コード例 #19
0
ファイル: materials.py プロジェクト: tobywf/mech3ax-py
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