Esempio n. 1
0
    def read(  # pylint: disable=too-many-locals
            cls, reader: BinReader, anim_def: AnimDef) -> LightAnimation:
        (
            name_raw,
            light_index,
            range_min,
            range_max,
            zero44,
            zero48,
            zero52,
            zero56,
            color_r,
            color_g,
            color_b,
            zero72,
            zero76,
            zero80,
            zero84,
            zero88,
            zero92,
            run_time,
        ) = 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)

        if range_min >= 0.0:
            assert_ge("range max", range_min, range_max, reader.prev + 40)
        else:
            assert_lt("range max", range_min, range_max, 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_between("red", -5.0, 5.0, color_r, reader.prev + 60)
        assert_between("green", -5.0, 5.0, color_g, reader.prev + 64)
        assert_between("blue", -5.0, 5.0, color_b, reader.prev + 68)

        assert_eq("field 72", 0, zero72, reader.prev + 72)
        assert_eq("field 76", 0, zero76, reader.prev + 76)
        assert_eq("field 80", 0, zero80, reader.prev + 80)
        assert_eq("field 84", 0, zero84, reader.prev + 84)
        assert_eq("field 88", 0, zero88, reader.prev + 88)
        assert_eq("field 92", 0, zero92, reader.prev + 92)

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

        return cls(
            name=name,
            range=(range_min, range_max),
            color=(color_r, color_g, color_b),
            run_time=run_time,
        )
Esempio n. 2
0
    def validate_and_read(cls, reader: BinReader, _anim_def: AnimDef,
                          actual_length: int) -> ObjectMotionSIScript:
        abs_end = reader.offset + actual_length
        (
            index,
            count,
            zero08,
            zero12,
            zero16,
            zero20,
        ) = reader.read(cls._STRUCT)

        assert_between("index", 0, 20, index, reader.prev + 0)  # 12
        assert_eq("field 08", 0.0, zero08, reader.prev + 8)  # 20
        assert_eq("field 12", 0.0, zero12, reader.prev + 12)  # 24
        assert_eq("field 16", 0, zero16, reader.prev + 16)  # 28
        assert_eq("field 20", 0, zero20, reader.prev + 20)  # 32

        frames = []
        for i in range(count):
            flag, start_time, end_time = reader.read(SI_SCRIPT_FRAME)
            assert_between(f"motion {i} flag", 1, 7, flag, reader.prev + 0)
            assert_ge(f"motion {i} start", 0.0, start_time, reader.prev + 4)
            if end_time != 0.0:
                assert_ge(f"motion {i} end", start_time, end_time,
                          reader.prev + 8)

            if (flag & 1) == 0:
                translate: Optional[Vector] = None
            else:
                values = cast(Values, reader.read(SI_SCRIPT_DATA))
                translate = parse_vec_data(values, start_time)

            if (flag & 2) == 0:
                rotate: Optional[Quaternion] = None
            else:
                values = cast(Values, reader.read(SI_SCRIPT_DATA))
                rotate = parse_quat_data(values, start_time)

            if (flag & 4) == 0:
                scale: Optional[Vector] = None
            else:
                values = cast(Values, reader.read(SI_SCRIPT_DATA))
                scale = parse_vec_data(values, start_time)

            frame = MotionFrame(
                start=start_time,
                end=end_time,
                translate=translate,
                rotate=rotate,
                scale=scale,
            )
            frames.append(frame)

        assert_eq("motion script end", abs_end, reader.offset, reader.offset)
        return cls(index=index, frames=frames)
Esempio n. 3
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,
    )
Esempio n. 4
0
    def read(cls, reader: BinReader, _anim_def: AnimDef) -> FogState:
        (
            name_raw,
            flag_raw,
            fog_type,
            color_r,
            color_g,
            color_b,
            altitude_min,
            altitude_max,
            range_min,
            range_max,
        ) = reader.read(cls._STRUCT)
        assert_eq("name", DEFAULT_FOG_NAME, name_raw, reader.prev + 0)
        # see LIGHT_STATE - in this case, all FOG_STATEs use the same flags
        # 1 << 0 set fog state
        # 1 << 1 set fog color
        # 1 << 2 set fog altitude
        # 1 << 3 set fog range
        assert_eq("flag", 14, flag_raw, reader.prev + 32)
        # OFF = 0, LINEAR = 1, EXPONENTIAL = 2
        assert_eq("fog type", 1, fog_type, reader.prev + 36)

        assert_between("red", 0.0, 1.0, color_r, reader.prev + 40)
        assert_between("green", 0.0, 1.0, color_g, reader.prev + 44)
        assert_between("blue", 0.0, 1.0, color_b, reader.prev + 48)

        # altitude is always ordered this way even negative (unlike range)
        assert_ge("altitude max", altitude_min, altitude_max, reader.prev + 56)

        assert_ge("range min", 0.0, range_min, reader.prev + 60)
        assert_ge("range max", range_min, range_max, reader.prev + 64)

        return cls(
            fog_type="LINEAR",
            color=(color_r, color_g, color_b),
            altitude=(altitude_min, altitude_max),
            range=(range_min, range_max),
        )
Esempio n. 5
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
Esempio n. 6
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,
        )