def from_json_dict(cls, json_dict: dict) -> "CosmeticPatches": return cls( disable_hud_popup=json_dict["disable_hud_popup"], speed_up_credits=json_dict["speed_up_credits"], open_map=json_dict["open_map"], pickup_markers=json_dict["pickup_markers"], user_preferences=(EchoesUserPreferences.from_json_dict(json_dict["user_preferences"]) if "user_preferences" in json_dict else EchoesUserPreferences()) )
def test_change_hud_lag(skip_qtbot): preferences = CosmeticPatches(user_preferences=EchoesUserPreferences( hud_lag=False)) dialog = EchoesUserPreferencesDialog(None, preferences) skip_qtbot.addWidget(dialog) dialog.hud_lag_check.setChecked(True) assert dialog.preferences == EchoesUserPreferences(hud_lag=True)
def test_change_sfx_volume(skip_qtbot): preferences = CosmeticPatches(user_preferences=EchoesUserPreferences( sfx_volume=15)) dialog = EchoesUserPreferencesDialog(None, preferences) skip_qtbot.addWidget(dialog) dialog.sfx_volume_slider.setValue(50) assert dialog.preferences == EchoesUserPreferences(sfx_volume=50)
def test_change_sound_mode(skip_qtbot): preferences = CosmeticPatches(user_preferences=EchoesUserPreferences( sound_mode=SoundMode.MONO)) dialog = EchoesUserPreferencesDialog(None, preferences) skip_qtbot.addWidget(dialog) dialog.sound_mode_combo.setCurrentIndex(2) assert dialog.preferences == EchoesUserPreferences( sound_mode=SoundMode.SURROUND)
def test_apply_patcher_file( mock_ensure_no_menu_mod: MagicMock, mock_create_pak_backups: MagicMock, mock_add_menu_mod_to_files: MagicMock, mock_run_with_args: MagicMock, mock_apply_patches: MagicMock, mock_create_progress_update_from_successive_messages: MagicMock, include_menu_mod: bool, has_backup_path: bool, ): # Setup game_root = MagicMock(spec=Path()) backup_files_path = MagicMock() if has_backup_path else None game_specific = MagicMock() progress_update = MagicMock() status_update = mock_create_progress_update_from_successive_messages.return_value patcher_data = { "menu_mod": include_menu_mod, "user_preferences": EchoesUserPreferences().as_json, "default_items": { "foo": "bar" }, } # Run claris_randomizer.apply_patcher_file(game_root, backup_files_path, patcher_data, game_specific, progress_update) # Assert mock_create_progress_update_from_successive_messages.assert_called_once_with( progress_update, 400 if include_menu_mod else 100) mock_ensure_no_menu_mod.assert_called_once_with(game_root, backup_files_path, status_update) if has_backup_path: mock_create_pak_backups.assert_called_once_with( game_root, backup_files_path, status_update) else: mock_create_pak_backups.assert_not_called() mock_run_with_args.assert_called_once_with( claris_randomizer._base_args(game_root), json.dumps(patcher_data), "Randomized!", status_update) mock_apply_patches.assert_called_once_with(game_root, game_specific, EchoesUserPreferences(), {"foo": "bar"}) if include_menu_mod: mock_add_menu_mod_to_files.assert_called_once_with( game_root, status_update) else: mock_add_menu_mod_to_files.assert_not_called()
def apply_patcher_file(game_root: Path, backup_files_path: Optional[Path], patcher_data: dict, game_specific: EchoesGameSpecific, progress_update: ProgressUpdateCallable, ): """ Applies the modifications listed in the given patcher_data to the game in game_root. :param game_root: :param backup_files_path: :param patcher_data: :param game_specific: :param progress_update: :return: """ menu_mod = patcher_data["menu_mod"] user_preferences = EchoesUserPreferences.from_json_dict(patcher_data["user_preferences"]) status_update = status_update_lib.create_progress_update_from_successive_messages( progress_update, 400 if menu_mod else 100) _ensure_no_menu_mod(game_root, backup_files_path, status_update) if backup_files_path is not None: _create_pak_backups(game_root, backup_files_path, status_update) _run_with_args(_base_args(game_root), json.dumps(patcher_data), "Randomized!", status_update) dol_patcher.apply_patches(game_root, game_specific, user_preferences) if menu_mod: _add_menu_mod_to_files(game_root, status_update)
def test_apply_game_options_patch(dol_file): user_preferences = EchoesUserPreferences() offset = 0x2000 # Run dol_file.set_editable(True) with dol_file: echoes_dol_patches.apply_game_options_patch(offset, user_preferences, dol_file) # Assert results = dol_file.dol_path.read_bytes()[0x100:] assert results == (b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\xe1\x00\x1c\x7c\x7f\x1b\x78' b'\x38\x61\x00\x08\x38\x00\x00\x01\x90\x1f\x00\x00\x38\x00\x00\x04\x90\x1f\x00\x04' b'\x38\x00\x00\x00\x90\x1f\x00\x08\x38\x00\x00\x00\x90\x1f\x00\x0c\x38\x00\x00\x00' b'\x90\x1f\x00\x10\x38\x00\x00\x69\x90\x1f\x00\x14\x38\x00\x00\x4f\x90\x1f\x00\x18' b'\x38\x00\x00\xff\x90\x1f\x00\x1c\x38\x00\x00\xff\x90\x1f\x00\x20\x38\x00\x00\xa0' b'\x98\x1f\x00\x24\x38\x00\x00\x00\x90\x1f\x00\x2c\x90\x1f\x00\x30\x90\x1f\x00\x34' b'\x60\x00\x00\x00\x60\x00\x00\x00\x60\x00\x00\x00\x60\x00\x00\x00\x60\x00\x00\x00' b'\x60\x00\x00\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' )
def test_apply_game_options_patch(): offset = 0x15 dol_file = MagicMock() user_preferences = EchoesUserPreferences() # Run dol_patcher._apply_game_options_patch(offset, user_preferences, dol_file) # Assert dol_file.write.assert_called_once_with(53, ANY)
def apply_patcher_file(game_root: Path, backup_files_path: Optional[Path], patcher_data: dict, game_specific: EchoesGameSpecific, progress_update: ProgressUpdateCallable, ): """ Applies the modifications listed in the given patcher_data to the game in game_root. :param game_root: :param backup_files_path: :param patcher_data: :param game_specific: :param progress_update: :return: """ menu_mod = patcher_data["menu_mod"] user_preferences = EchoesUserPreferences.from_json_dict(patcher_data["user_preferences"]) default_items = patcher_data["default_items"] status_update = status_update_lib.create_progress_update_from_successive_messages( progress_update, 400 if menu_mod else 100) last_version = get_patch_version(game_root) if last_version > CURRENT_PATCH_VERSION: raise RuntimeError(f"Game at {game_root} was last patched with version {last_version}, " f"which is above supported version {CURRENT_PATCH_VERSION}. " f"\nPlease press 'Delete internal copy'.") _ensure_no_menu_mod(game_root, backup_files_path, status_update) if backup_files_path is not None: _create_pak_backups(game_root, backup_files_path, status_update) _run_with_args(_base_args(game_root), json.dumps(patcher_data), "Randomized!", status_update) dol_patcher.apply_patches(game_root, game_specific, user_preferences, default_items) write_patch_version(game_root, CURRENT_PATCH_VERSION) if menu_mod: _add_menu_mod_to_files(game_root, status_update)