# Xenoblade Chronicles 3 2.1.1
# BID: 0AE74B263D8AC3CF

unsafeCheck: true

MASTER_WRITE:
  # Redirect DR frametime target reading to .bss code cave [MAIN, 0x236AB00]
  -
    type: bytes
    main_offset: 0x124E9A8
    value_type: uint32
    value:
      - 0x900088E8
      - 0xBD4B0100
  # Original DR frametime target
  -
    type: bytes
    main_offset: 0x236AB00
    value_type: float
    value:
      - 0.0166666666
  # Fix crash when gathering big amount of ether for > 30 FPS
  - # Code cave at 0x1295300
    type: bytes
    main_offset: 0x67370
    value_type: uint32
    value: 0x9448B7E4
  - # Push fixed 1/30 float to game speed pointer late enough to not affect it 
    type: bytes
    main_offset: 0x1295300
    value_type: uint32
    value:
      - 0xF9400015
      - 0x1E2E1001
      - 0x1E27D002
      - 0x1E221821
      - 0xBD0216A1
      - 0xD65F03C0
# For 15-20 FPS use internal FPS lock, for 25-30 set default value
15FPS:
  # vsync
  -
    type: write
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [4, 4]
  -
    type: write
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.0166666666
  # UI speed
  -
    type: write
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0666666666
  -
    type: block
    what: timing
20FPS:
  -
    type: write
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [3, 3]
  -
    type: write
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.0166666666
  -
    type: write
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.05
  -
    type: block
    what: timing
25FPS:
  -
    type: write
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [2, 2]
  -
    type: write
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.02
  -
    type: write
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.04
30FPS:
  -
    type: write
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [2, 2]
  -
    type: write
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.0166666666
  -
    type: write
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0333333333

# For 35-60 FPS check if cutscene is played. If it is, set 30 FPS lock. If not, disable it.
35FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.024
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [2, 2]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.0166666666
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.028571
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0333333333
40FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.021
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [2, 2]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.0166666666
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.025
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0333333333
45FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.018
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [2, 2]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.0166666666
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0222222222
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0333333333
50FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.016
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [2, 2]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.0166666666
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.02
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0333333333
55FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.014
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [2, 2]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.0166666666
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.01818181818
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0333333333
60FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1B42DB0]
    value_type: int32
    value: [2, 2]
  # Set lowest possible resolution since DR is glitching framebuffer on 60 FPS if we allow even small changes in res
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.000001
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x236AB00]
    value_type: float
    value: 0.0166666666
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0166666666
  -
    type: compare
    compare_address: [MAIN, 0x1BA1A98]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1BA1A90, 128]
    value_type: float
    value: 0.0333333333