Пример #1
0
def call_display_hud_patch(
        patch_addresses: StringDisplayPatchAddresses) -> List[BaseInstruction]:
    # r31 = CStateManager
    return [
        # setup CHUDMemoParms
        lis(r5, 0x4100),  # 8.0f
        li(r6, 0x0),
        li(r7, 0x1),
        li(r9, 0x9),
        stw(r5, 0x10, r1),  # display time (seconds)
        stb(r7, 0x14, r1),  # clear memo window
        stb(r6, 0x15, r1),  # fade out only
        stb(r6, 0x16, r1),  # hint memo
        stb(r7, 0x17, r1),  # fade in text
        stw(r9, 0x18, r1),  # unk

        # setup wstring
        addi(r3, r1, 0x1C),
        custom_ppc.load_unsigned_32bit(
            r4, patch_addresses.message_receiver_string_ref),
        bl(patch_addresses.wstring_constructor),

        # r4 = CHUDMemoParms
        addi(r4, r1, 0x10),
        bl(patch_addresses.display_hud_memo),
    ]
Пример #2
0
def set_artifact_layer_active_patch(addresses: Prime1DolVersion, layer_id: int, active: bool,
                                    ) -> List[assembler.BaseInstruction]:
    # g_GameState->StateForWorld(0x39F2DE28)->GetLayerState()->SetLayerActive(templeAreaIndex, artifactLayer, true)
    result = []

    for_another_world = [
        # Get the LayerState via the CGameState
        lwz(r3, addresses.game_state_pointer - addresses.sda13_base, r13),  # get g_GameState
        # r4 already have the asset id
        bl(addresses.state_for_world),  # CGameState::StateForWorld
        lwz(r3, 0x14, r3),  # worldState->layerState
    ]

    result.extend([
        # Get the LayerState of current world. We'll overwrite if it's another world, it's just 1 instruction bigger
        lwz(r3, 0x8c8, r31),  # mgr->worldLayerState

        # Tallon Overworld asset id
        custom_ppc.load_unsigned_32bit(r4, 0x39f2de28),

        # Load current asset id in r5
        lwz(r5, 0x850, r31),  # mgr->world
        lwz(r5, 0x8, r5),  # world->mlvlId

        cmpw(0, r4, r5),  # compare asset ids
        beq(4 + assembler.byte_count(for_another_world), relative=True),
        *for_another_world,
        lwz(r3, 0x0, r3),

        # Set layer
        li(r4, 16),  # Artifact Layer
        stw(r4, 0x10, r1),

        # Set layer
        li(r5, layer_id),  # Artifact Layer
        stw(r5, 0x14, r1),

        # Make the layer change via SetLayerActive
        addi(r4, r1, 0x10),
        addi(r5, r1, 0x14),
        li(r6, int(active)),
        bl(addresses.set_layer_active),  # CWorldLayerState::SetLayerActive
    ])

    return result
Пример #3
0
def test_load_unsigned_32bit_invalid(value):
    with pytest.raises(AssertionError):
        custom_ppc.load_unsigned_32bit(ppc.r1, value)
Пример #4
0
def test_load_unsigned_32bit_valid(value, expected):
    codes = list(
        custom_ppc.load_unsigned_32bit(ppc.r1, value).bytes_for(0, symbols={}))
    assert bytes(codes) == expected
Пример #5
0
def _is_out_of_ammo_patch(symbols: Dict[str, int],
                          ammo_types: List[Tuple[int, int]]):
    def get_beam_ammo_amount(index: int):
        label = f"_after_get_ammo_type_{index}"

        body = [
            lwz(r5, 0x774, r30),  # r5 = get current beam
            addi(r5, r5, 0x1),  # current_beam += 1
            mtspr(CTR, r5),  # count_register = current_beam
        ]

        for beam_index, beam_ammo_types in enumerate(ammo_types):
            instructions = []
            if beam_index + 1 < len(ammo_types):
                instructions.append(
                    bdnz(f"_before_get_ammo_type_{beam_index + 1}_{index}"))

            if beam_ammo_types[index] == -1:
                instructions.extend([
                    li(r3, 0),  # No ammo type, so load result
                    b("_end"),  # and return
                ])
            else:
                instructions.extend([
                    li(r4, beam_ammo_types[index]),
                    b(label),
                ])

            instructions[0].with_label(
                f"_before_get_ammo_type_{beam_index}_{index}")
            body.extend(instructions)

        body.extend([
            or_(r3, r31, r31).with_label(
                label),  # arg1 = playerState, arg2 is already there
            li(r5, 1),  # arg3 = true, allow multiplayer ammo stuff
            bl("CPlayerState::GetItemAmount"),  # r3 = ammoCount
        ])

        return body

    get_uncharged_cost = [
        custom_ppc.load_unsigned_32bit(r4,
                                       symbols["BeamIdToChargedShotAmmoCost"]),
        lwz(r5, 0x774, r30),  # r5 = get current beam
        rlwinm(r5, r5, 0x2, 0x0, 0x1d),  # r5 *= 4
        lwzx(r4, r4, r5),  # ammoCost_r4 = UnchargedCosts_r4[currentBeam]
    ]
    compare_count_to_cost = [
        cmpw(0, r3, r4),
        bge(3 * 4, relative=True),  # if ammoCount_3 >= ammoCost_r4, goto
        li(r3, 1),  # Not enough ammo, load true
        b("_end"),  # and return
    ]

    return [
        # Save stack
        stwu(r1, -0x10, r1),
        mfspr(r0, LR),
        stw(r0, 0x14, r1),

        # Save r31 and r30
        stw(r31, 0xc, r1),
        stw(r30, 0x8, r1),

        # Save a pointer to CPlayerGun
        or_(r30, r3, r3),
        bl("CPlayerGun::GetPlayer"),

        # Get and save a pointer to CPlayerState
        lwz(r31, 0x1314, r3),

        # check ammo type 1
        *get_beam_ammo_amount(0),  # r3 = ammo amount
        *get_uncharged_cost,  # r4 = uncharged_cost
        *compare_count_to_cost,

        # check ammo type 2
        *get_beam_ammo_amount(1),  # r3 = ammo amount
        *get_uncharged_cost,  # r4 = uncharged_cost
        *compare_count_to_cost,

        # All ammo types for this beam are fine!
        li(r3, 0),
        b("_end"),  # and return

        # end
        lwz(r0, 0x14, r1).with_label("_end"),
        lwz(r31, 0xc, r1),
        lwz(r30, 0x8, r1),
        mtspr(LR, r0),
        addi(r1, r1, 0x10),
        blr(),
    ]