Compare commits

1 Commits

Author SHA1 Message Date
1c1110a6e7 feat(dialogs): change buttons accept/reject to AutoSizeButton
Some checks failed
Code and build check / Check code (pull_request) Failing after 1m38s
Code and build check / Build with uv (pull_request) Successful in 56s
2025-06-28 04:54:58 +00:00
198 changed files with 1420 additions and 6353 deletions

View File

@ -8,7 +8,7 @@ on:
env:
# Common version, will be used for tagging the release
VERSION: 0.1.3
VERSION: 0.1.2
PKGDEST: "/tmp/portprotonqt"
PACKAGE: "portprotonqt"
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}

View File

@ -3,16 +3,13 @@
Все заметные изменения в этом проекте фиксируются в этом файле.
Формат основан на [Keep a Changelog](https://keepachangelog.com/) и придерживается принципов [Semantic Versioning](https://semver.org/).
## [0.1.3] - 2025-07-05
## [Unreleased]
### Added
- Аргумент `--session` для запуска приложения в gamescope (Исключительно в целях тестирования)
- Аргумент `--session` для запуска приложения в gamescope с GAMESCOPE_CMD
- Начальная поддержка EGS (Без EOS, скачивания игр и запуска игр из сторонних магазинов)
- Автодополнение bash для комманды portprotonqt
- Поддержка геймпадов в диалоге выбора игры
- Быстрый запуск и остановка игры через контекстное меню
- Иконки в контекстом меню
- Обложки для части автоинсталлов
### Changed
- Удалены сборки для Fedora 40
@ -20,8 +17,6 @@
- Статус выделения и наведения на карточки теперь взаимоисключают друг друга
- Все desktop файлы создаются с коментарием "Запустить игру {название} через PortProton"
- Заполнители в переводах теперь стали более осмысленными
- Изменена компоновка диалога добавления игры для лучшего отображения в Gamescope
- Текст бейджей теперь обрезается через ... если не помещается
### Fixed
- Дублирование обводки выделения карточек при быстром перемешении мыши
@ -30,8 +25,6 @@
- Ошибки темы в нативном пакете
- Ошибки темы в Gamescope
- Размер иконок для desktop файлов теперь 128x128
- Пустая область при обновлении сетки игр
- Запуск игры при открытом оверлее
### Contributors
- @Dervart

View File

@ -34,8 +34,6 @@
- [ ] Достигнуть паритета функциональности с PortProton
- [X] Добавить возможность изменения названия, описания и обложки через файлы `.local/share/PortProtonQT/custom_data/exe_name/{desc,name,cover}`
- [X] Добавить встроенное переопределение названия, описания и обложки, например, по пути `portprotonqt/custom_data` [Документация](documentation/metadata_override/)
- [ ] Добавить переводы в переопределения
- [ ] Придумать как переопределять launcher.exe
- [X] Добавить в карточку игры сведения о поддержке геймпада
- [X] Добавить в карточки данные с ProtonDB
- [X] Добавить в карточки данные с AreWeAntiCheatYet

View File

@ -25,7 +25,7 @@ AppDir:
id: ru.linux_gaming.PortProtonQt
name: PortProtonQt
icon: ru.linux_gaming.PortProtonQt
version: 0.1.3
version: 0.1.2
exec: usr/bin/python3
exec_args: "-m portprotonqt.app $@"

View File

@ -1,5 +1,5 @@
pkgname=portprotonqt
pkgver=0.1.3
pkgver=0.1.2
pkgrel=1
pkgdesc="Modern GUI for managing and launching games from PortProton, Steam, and Epic Games Store"
arch=('any')

View File

@ -2,7 +2,6 @@
%global pypi_version 0.1.1
%global oname PortProtonQt
%global build_timestamp %(date +"%Y%m%d")
%global _python_no_extras_requires 1
%global rel_build 1.git.%{build_timestamp}%{?dist}
@ -48,8 +47,6 @@ Requires: xdg-utils
%description -n python3-%{pypi_name}-git
This application provides a sleek, intuitive graphical interface for managing and launching games from PortProton, Steam, and Epic Games Store. It consolidates your game libraries into a single, user-friendly hub for seamless navigation and organization. Its lightweight structure and cross-platform support deliver a cohesive gaming experience, eliminating the need for multiple launchers. Unique PortProton integration enhances Linux gaming, enabling effortless play of Windows-based titles with minimal setup.
%{?python_disable_dependency_generator}
%prep
git clone https://git.linux-gaming.ru/Boria138/PortProtonQt.git

View File

@ -1,7 +1,6 @@
%global pypi_name portprotonqt
%global pypi_version 0.1.3
%global pypi_version 0.1.2
%global oname PortProtonQt
%global _python_no_extras_requires 1
Name: python-%{pypi_name}
Version: %{pypi_version}
@ -45,8 +44,6 @@ Requires: xdg-utils
%description -n python3-%{pypi_name}
This application provides a sleek, intuitive graphical interface for managing and launching games from PortProton, Steam, and Epic Games Store. It consolidates your game libraries into a single, user-friendly hub for seamless navigation and organization. Its lightweight structure and cross-platform support deliver a cohesive gaming experience, eliminating the need for multiple launchers. Unique PortProton integration enhances Linux gaming, enabling effortless play of Windows-based titles with minimal setup.
%{?python_disable_dependency_generator}
%prep
git clone https://git.linux-gaming.ru/Boria138/PortProtonQt
cd %{oname}

View File

@ -197,7 +197,7 @@
},
{
"normalized_name": "rec room",
"status": "Running"
"status": "Broken"
},
{
"normalized_name": "world war 3",
@ -221,7 +221,7 @@
},
{
"normalized_name": "zero hour",
"status": "Running"
"status": "Broken"
},
{
"normalized_name": "ironsight",
@ -309,7 +309,7 @@
},
{
"normalized_name": "dirty bomb",
"status": "Running"
"status": "Broken"
},
{
"normalized_name": "empyrion galactic survival",
@ -989,7 +989,7 @@
},
{
"normalized_name": "marauders",
"status": "Running"
"status": "Broken"
},
{
"normalized_name": "predecessor",
@ -1101,7 +1101,7 @@
},
{
"normalized_name": "deceit 2",
"status": "Running"
"status": "Broken"
},
{
"normalized_name": "block n load 2",
@ -1781,7 +1781,7 @@
},
{
"normalized_name": "splitgate 2",
"status": "Running"
"status": "Planned"
},
{
"normalized_name": "xera survival",
@ -1897,7 +1897,7 @@
},
{
"normalized_name": "test drive unlimited solar crown",
"status": "Running"
"status": "Planned"
},
{
"normalized_name": "resident evil resistance",
@ -3461,7 +3461,7 @@
},
{
"normalized_name": "crsed cuisine royale",
"status": "Denied"
"status": "Supported"
},
{
"normalized_name": "project nebula",
@ -4329,7 +4329,7 @@
},
{
"normalized_name": "blindfire",
"status": "Supported"
"status": "Broken"
},
{
"normalized_name": "h hour world's elite",
@ -4414,17 +4414,5 @@
{
"normalized_name": "ragnarok origin roo",
"status": "Running"
},
{
"normalized_name": "fantasy life i the girl who steals time",
"status": "Running"
},
{
"normalized_name": "la tale evolved",
"status": "Running"
},
{
"normalized_name": "carx street",
"status": "Broken"
}
]

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,20 +1,4 @@
[
{
"normalized_title": "settlement survival",
"slug": "settlement-survival"
},
{
"normalized_title": "the elder scrolls iv oblivion",
"slug": "the-elder-scrolls-iv-oblivion-remastered"
},
{
"normalized_title": "dead space 3",
"slug": "dead-space-3"
},
{
"normalized_title": "dead space 2",
"slug": "dead-space-2"
},
{
"normalized_title": "hades",
"slug": "hades"
@ -115,6 +99,10 @@
"normalized_title": "hotshot racing",
"slug": "hotshot-racing"
},
{
"normalized_title": "s.t.a.l.k.e.r. anomaly g.a.m.m.a",
"slug": "s-t-a-l-k-e-r-anomaly-g-a-m-m-a"
},
{
"normalized_title": "golazo! 2",
"slug": "golazo-2"
@ -1810,45 +1798,5 @@
{
"normalized_title": "atomic heart",
"slug": "atomic-heart"
},
{
"normalized_title": "genshin impact",
"slug": "genshin-impact"
},
{
"normalized_title": "battle.net",
"slug": "battle-net"
},
{
"normalized_title": "valorant",
"slug": "valorant"
},
{
"normalized_title": "русы против ящеров",
"slug": "rusy-protiv-yashherov"
},
{
"normalized_title": "last floor",
"slug": "last-floor"
},
{
"normalized_title": "fpv kamikaze drone",
"slug": "fpv-kamikaze-drone"
},
{
"normalized_title": "wild terra 2 new lands",
"slug": "wild-terra-2-new-lands"
},
{
"normalized_title": "armored warfare",
"slug": "armored-warfare"
},
{
"normalized_title": "warhammer 40 000 dawn of war",
"slug": "warhammer-40-000-dawn-of-war"
},
{
"normalized_title": "warhammer 40 000 space marine",
"slug": "warhammer-40-000-space-marine"
}
]

Binary file not shown.

View File

@ -16,5 +16,3 @@ Content-Transfer-Encoding:
Generated-By:
start.sh
EGS
Stop Game
\t

View File

@ -20,9 +20,9 @@ Current translation status:
| Locale | Progress | Translated |
| :----- | -------: | ---------: |
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 of 192 |
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 of 192 |
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 192 of 192 |
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 of 182 |
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 of 182 |
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 182 of 182 |
---

View File

@ -20,9 +20,9 @@
| Локаль | Прогресс | Переведено |
| :----- | -------: | ---------: |
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 из 192 |
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 из 192 |
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 192 из 192 |
| [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 из 182 |
| [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 из 182 |
| [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 182 из 182 |
---

View File

@ -14,7 +14,7 @@ logger = get_logger(__name__)
__app_id__ = "ru.linux_gaming.PortProtonQt"
__app_name__ = "PortProtonQt"
__app_version__ = "0.1.3"
__app_version__ = "0.1.2"
def main():
app = QApplication(sys.argv)

View File

@ -6,17 +6,14 @@ import subprocess
import threading
import logging
import orjson
import psutil
import signal
from PySide6.QtWidgets import QMessageBox, QDialog, QMenu, QLineEdit, QApplication
from PySide6.QtWidgets import QMessageBox, QDialog, QMenu, QFileDialog
from PySide6.QtCore import QUrl, QPoint, QObject, Signal, Qt
from PySide6.QtGui import QDesktopServices, QIcon, QKeySequence
from PySide6.QtGui import QDesktopServices
from portprotonqt.localization import _
from portprotonqt.config_utils import parse_desktop_entry, read_favorites, save_favorites
from portprotonqt.steam_api import is_game_in_steam, add_to_steam, remove_from_steam
from portprotonqt.egs_api import add_egs_to_steam, get_egs_executable, remove_egs_from_steam
from portprotonqt.dialogs import AddGameDialog, FileExplorer, generate_thumbnail
from portprotonqt.theme_manager import ThemeManager
from portprotonqt.dialogs import AddGameDialog, generate_thumbnail
logger = logging.getLogger(__name__)
@ -43,7 +40,6 @@ class ContextMenuManager:
self.parent = parent
self.portproton_location = portproton_location
self.theme = theme
self.theme_manager = ThemeManager()
self.load_games = load_games_callback
self.update_game_grid = update_game_grid_callback
self.legendary_path = os.path.join(
@ -122,37 +118,6 @@ class ContextMenuManager:
logger.error("Failed to read installed.json: %s", e)
return False
def _is_game_running(self, game_card) -> bool:
"""
Check if the game associated with the game_card is currently running.
Args:
game_card: The GameCard instance containing game data.
Returns:
bool: True if the game is running, False otherwise.
"""
if game_card.game_source == "epic":
exe_path = get_egs_executable(game_card.appid, self.legendary_config_path)
if not exe_path or not os.path.exists(exe_path):
return False
current_exe = os.path.basename(exe_path)
elif game_card.game_source == "steam":
return False
else:
exec_line = self._get_exec_line(game_card.name, game_card.exec_line)
if not exec_line:
return False
exe_path = self._parse_exe_path(exec_line, game_card.name)
if not exe_path:
return False
current_exe = os.path.basename(exe_path)
# Check if the current_exe matches the target_exe in MainWindow
if hasattr(self.parent, 'target_exe') and self.parent.target_exe == current_exe:
return True
return False
def show_context_menu(self, game_card, pos: QPoint):
"""
Show the context menu for a game card at the specified position.
@ -161,58 +126,40 @@ class ContextMenuManager:
game_card: The GameCard instance requesting the context menu.
pos: The position (in widget coordinates) where the menu should appear.
"""
def get_safe_icon(icon_name: str) -> QIcon:
icon = self.theme_manager.get_icon(icon_name)
if isinstance(icon, QIcon):
return icon
elif isinstance(icon, str) and os.path.exists(icon):
return QIcon(icon)
return QIcon()
menu = QMenu(self.parent)
menu.setStyleSheet(self.theme.CONTEXT_MENU_STYLE)
# Check if the game is running
is_running = self._is_game_running(game_card)
action_text = _("Stop Game") if is_running else _("Launch Game")
action_icon = "stop" if is_running else "play"
launch_action = menu.addAction(get_safe_icon(action_icon), action_text)
launch_action.triggered.connect(
lambda: self._launch_game(game_card)
)
favorites = read_favorites()
is_favorite = game_card.name in favorites
icon_name = "star_full" if is_favorite else "star"
text = _("Remove from Favorites") if is_favorite else _("Add to Favorites")
favorite_action = menu.addAction(get_safe_icon(icon_name), text)
favorite_action = menu.addAction(
_("Remove from Favorites") if is_favorite else _("Add to Favorites")
)
favorite_action.triggered.connect(lambda: self.toggle_favorite(game_card, not is_favorite))
if game_card.game_source == "epic":
import_action = menu.addAction(get_safe_icon("epic_games"), _("Import to Legendary"))
import_action = menu.addAction(_("Import to Legendary"))
import_action.triggered.connect(
lambda: self.import_to_legendary(game_card.name, game_card.appid)
)
if self._is_egs_game_installed(game_card.appid):
is_in_steam = is_game_in_steam(game_card.name)
icon_name = "delete" if is_in_steam else "steam"
text = _("Remove from Steam") if is_in_steam else _("Add to Steam")
steam_action = menu.addAction(get_safe_icon(icon_name), text)
steam_action = menu.addAction(
_("Remove from Steam") if is_in_steam else _("Add to Steam")
)
steam_action.triggered.connect(
lambda: self.remove_from_steam(game_card.name, game_card.exec_line, game_card.game_source)
if is_in_steam
else self.add_egs_to_steam(game_card.name, game_card.appid)
)
open_folder_action = menu.addAction(get_safe_icon("search"), _("Open Game Folder"))
open_folder_action = menu.addAction(_("Open Game Folder"))
open_folder_action.triggered.connect(
lambda: self.open_egs_game_folder(game_card.appid)
)
desktop_dir = subprocess.check_output(['xdg-user-dir', 'DESKTOP']).decode('utf-8').strip()
desktop_path = os.path.join(desktop_dir, f"{game_card.name}.desktop")
icon_name = "delete" if os.path.exists(desktop_path) else "desktop"
text = _("Remove from Desktop") if os.path.exists(desktop_path) else _("Add to Desktop")
desktop_action = menu.addAction(get_safe_icon(icon_name), text)
desktop_action = menu.addAction(
_("Remove from Desktop") if os.path.exists(desktop_path) else _("Add to Desktop")
)
desktop_action.triggered.connect(
lambda: self.remove_egs_from_desktop(game_card.name)
if os.path.exists(desktop_path)
@ -221,7 +168,6 @@ class ContextMenuManager:
applications_dir = os.path.join(os.path.expanduser("~"), ".local", "share", "applications")
menu_path = os.path.join(applications_dir, f"{game_card.name}.desktop")
menu_action = menu.addAction(
get_safe_icon("delete" if os.path.exists(menu_path) else "menu"),
_("Remove from Menu") if os.path.exists(menu_path) else _("Add to Menu")
)
menu_action.triggered.connect(
@ -233,113 +179,46 @@ class ContextMenuManager:
if game_card.game_source not in ("steam", "epic"):
desktop_dir = subprocess.check_output(['xdg-user-dir', 'DESKTOP']).decode('utf-8').strip()
desktop_path = os.path.join(desktop_dir, f"{game_card.name}.desktop")
icon_name = "delete" if os.path.exists(desktop_path) else "desktop"
text = _("Remove from Desktop") if os.path.exists(desktop_path) else _("Add to Desktop")
desktop_action = menu.addAction(get_safe_icon(icon_name), text)
desktop_action = menu.addAction(
_("Remove from Desktop") if os.path.exists(desktop_path) else _("Add to Desktop")
)
desktop_action.triggered.connect(
lambda: self.remove_from_desktop(game_card.name)
if os.path.exists(desktop_path)
else self.add_to_desktop(game_card.name, game_card.exec_line)
)
edit_action = menu.addAction(get_safe_icon("edit"), _("Edit Shortcut"))
edit_action = menu.addAction(_("Edit Shortcut"))
edit_action.triggered.connect(
lambda: self.edit_game_shortcut(game_card.name, game_card.exec_line, game_card.cover_path)
)
delete_action = menu.addAction(get_safe_icon("delete"), _("Delete from PortProton"))
delete_action = menu.addAction(_("Delete from PortProton"))
delete_action.triggered.connect(lambda: self.delete_game(game_card.name, game_card.exec_line))
open_folder_action = menu.addAction(get_safe_icon("search"), _("Open Game Folder"))
open_folder_action = menu.addAction(_("Open Game Folder"))
open_folder_action.triggered.connect(
lambda: self.open_game_folder(game_card.name, game_card.exec_line)
)
applications_dir = os.path.join(os.path.expanduser("~"), ".local", "share", "applications")
menu_path = os.path.join(applications_dir, f"{game_card.name}.desktop")
icon_name = "delete" if os.path.exists(menu_path) else "menu"
text = _("Remove from Menu") if os.path.exists(menu_path) else _("Add to Menu")
menu_action = menu.addAction(get_safe_icon(icon_name), text)
menu_action = menu.addAction(
_("Remove from Menu") if os.path.exists(menu_path) else _("Add to Menu")
)
menu_action.triggered.connect(
lambda: self.remove_from_menu(game_card.name)
if os.path.exists(menu_path)
else self.add_to_menu(game_card.name, game_card.exec_line)
)
is_in_steam = is_game_in_steam(game_card.name)
icon_name = "delete" if is_in_steam else "steam"
text = _("Remove from Steam") if is_in_steam else _("Add to Steam")
steam_action = menu.addAction(get_safe_icon(icon_name), text)
steam_action = menu.addAction(
_("Remove from Steam") if is_in_steam else _("Add to Steam")
)
steam_action.triggered.connect(
lambda: (
self.remove_from_steam(game_card.name, game_card.exec_line, game_card.game_source)
if is_in_steam
else self.add_to_steam(game_card.name, game_card.exec_line, game_card.cover_path)
)
lambda: self.remove_from_steam(game_card.name, game_card.exec_line, game_card.game_source)
if is_in_steam
else self.add_to_steam(game_card.name, game_card.exec_line, game_card.cover_path)
)
menu.exec(game_card.mapToGlobal(pos))
def _launch_game(self, game_card):
"""
Launch or stop a game based on its current state.
Args:
game_card: The GameCard instance containing game data.
"""
if not self._check_portproton():
return
# Check if the game is running
if self._is_game_running(game_card):
# Stop the game
if hasattr(self.parent, 'game_processes') and self.parent.game_processes:
for proc in self.parent.game_processes:
try:
parent = psutil.Process(proc.pid)
children = parent.children(recursive=True)
for child in children:
try:
child.terminate()
except psutil.NoSuchProcess:
pass
psutil.wait_procs(children, timeout=5)
for child in children:
if child.is_running():
child.kill()
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
except psutil.NoSuchProcess:
pass
self.parent.game_processes = []
self.parent.resetPlayButton()
if hasattr(self.parent, 'checkProcessTimer') and self.parent.checkProcessTimer is not None:
self.parent.checkProcessTimer.stop()
self.parent.checkProcessTimer.deleteLater()
self.parent.checkProcessTimer = None
self._show_status_message(_("Stopped '{game_name}'").format(game_name=game_card.name))
return
# Launch the game
if game_card.game_source == "epic":
if not os.path.exists(self.legendary_path):
self.signals.show_warning_dialog.emit(
_("Error"),
_("Legendary executable not found at {path}").format(path=self.legendary_path)
)
return
# Construct EGS launch command
wrapper = "flatpak run ru.linux_gaming.PortProton"
start_sh_path = os.path.join(self.portproton_location, "data", "scripts", "start.sh")
if self.portproton_location and ".var" not in self.portproton_location:
wrapper = start_sh_path
if not os.path.exists(start_sh_path):
self.signals.show_warning_dialog.emit(
_("Error"),
_("start.sh not found at {path}").format(path=start_sh_path)
)
return
exec_line = f'"{self.legendary_path}" launch {game_card.appid} --no-wine --wrapper "env START_FROM_STEAM=1 {wrapper}"'
else:
exec_line = self._get_exec_line(game_card.name, game_card.exec_line)
if not exec_line:
return
self.parent.toggleGame(exec_line)
def add_egs_to_steam(self, game_name: str, app_name: str):
"""
Adds an EGS game to Steam using the egs_api.
@ -403,56 +282,35 @@ class ContextMenuManager:
"""
if not self._check_portproton():
return
folder_path = QFileDialog.getExistingDirectory(
self.parent, _("Select Game Installation Folder"), os.path.expanduser("~")
)
if not folder_path:
self._show_status_message(_("No folder selected"))
return
if not os.path.exists(self.legendary_path):
self.signals.show_warning_dialog.emit(
_("Error"),
_("Legendary executable not found at {path}").format(path=self.legendary_path)
)
return
# Используем FileExplorer с directory_only=True
file_explorer = FileExplorer(
parent=self.parent,
theme=self.theme,
initial_path=os.path.expanduser("~"),
directory_only=True
)
def on_folder_selected(folder_path):
if not folder_path:
self._show_status_message(_("No folder selected"))
return
def run_import():
cmd = [self.legendary_path, "import", app_name, folder_path]
try:
subprocess.run(cmd, capture_output=True, text=True, check=True)
self.signals.show_info_dialog.emit(
_("Success"),
_("Imported '{game_name}' to Legendary").format(game_name=game_name)
def run_import():
cmd = [self.legendary_path, "import", app_name, folder_path]
try:
subprocess.run(cmd, capture_output=True, text=True, check=True)
self.signals.show_info_dialog.emit(
_("Success"),
_("Imported '{game_name}' to Legendary").format(game_name=game_name)
)
except subprocess.CalledProcessError as e:
self.signals.show_warning_dialog.emit(
_("Error"),
_("Failed to import '{game_name}' to Legendary: {error}").format(
game_name=game_name, error=e.stderr
)
except subprocess.CalledProcessError as e:
self.signals.show_warning_dialog.emit(
_("Error"),
_("Failed to import '{game_name}' to Legendary: {error}").format(
game_name=game_name, error=e.stderr
)
)
self._show_status_message(_("Importing '{game_name}' to Legendary...").format(game_name=game_name))
threading.Thread(target=run_import, daemon=True).start()
# Подключаем сигнал выбора файла/папки
file_explorer.file_signal.file_selected.connect(on_folder_selected)
# Центрируем FileExplorer относительно родительского виджета
parent_widget = self.parent
if parent_widget:
parent_geometry = parent_widget.geometry()
center_point = parent_geometry.center()
file_explorer_geometry = file_explorer.geometry()
file_explorer_geometry.moveCenter(center_point)
file_explorer.setGeometry(file_explorer_geometry)
file_explorer.show()
)
self._show_status_message(_("Importing '{game_name}' to Legendary...").format(game_name=game_name))
threading.Thread(target=run_import, daemon=True).start()
def toggle_favorite(self, game_card, add: bool):
"""
@ -1082,55 +940,3 @@ Icon={icon_path}
_("Error"),
_("Failed to open folder: {error}").format(error=str(e))
)
class CustomLineEdit(QLineEdit):
def __init__(self, *args, theme=None, **kwargs):
super().__init__(*args, **kwargs)
self.theme = theme
self.theme_manager = ThemeManager()
def contextMenuEvent(self, event):
def get_safe_icon(icon_name: str) -> QIcon:
icon = self.theme_manager.get_icon(icon_name)
if isinstance(icon, QIcon):
return icon
elif isinstance(icon, str) and os.path.exists(icon):
return QIcon(icon)
return QIcon()
def add_action(text: str, shortcut: QKeySequence.StandardKey, icon_name: str, slot, enabled=True):
icon = get_safe_icon(icon_name)
shortcut_str = QKeySequence(shortcut).toString(QKeySequence.SequenceFormat.NativeText)
action_text = f"{text}\t{shortcut_str}"
action = menu.addAction(icon, action_text)
action.triggered.connect(slot)
action.setEnabled(enabled)
menu = QMenu(self)
if self.theme and hasattr(self.theme, "CONTEXT_MENU_STYLE"):
menu.setStyleSheet(self.theme.CONTEXT_MENU_STYLE)
add_action(_("Undo"), QKeySequence.StandardKey.Undo, "undo", self.undo, self.isUndoAvailable())
add_action(_("Redo"), QKeySequence.StandardKey.Redo, "redo", self.redo, self.isRedoAvailable())
menu.addSeparator()
add_action(_("Cut"), QKeySequence.StandardKey.Cut, "cut", self.cut, self.hasSelectedText())
add_action(_("Copy"), QKeySequence.StandardKey.Copy, "copy", self.copy, self.hasSelectedText())
add_action(_("Paste"), QKeySequence.StandardKey.Paste, "paste", self.paste,
QApplication.clipboard().mimeData().hasText())
add_action(_("Delete"), QKeySequence.StandardKey.Delete, "delete", self._delete_selected_text,
self.hasSelectedText())
menu.addSeparator()
add_action(_("Select All"), QKeySequence.StandardKey.SelectAll, "select_all", self.selectAll, bool(self.text()))
menu.exec(event.globalPos())
def _delete_selected_text(self):
cursor_pos = self.cursorPosition()
self.backspace()
self.setCursorPosition(cursor_pos)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 KiB

View File

@ -1,3 +0,0 @@
name=Albion Online
description_ru=Многопользовательская песочница в жанре MMORPG, где игроки могут исследовать открытый мир, заниматься ремеслом, добычей ресурсов и сражаться с другими игроками. Игра предлагает уникальную систему классов, позволяющую игрокам изменять свои роли в зависимости от выбранного снаряжения.
description_en=A multiplayer sandbox MMORPG where players can explore an open world, engage in crafting, gather resources, and battle against other players. The game features a unique class system that allows players to change their roles based on the gear they equip.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

View File

@ -1,3 +0,0 @@
name=Ankama Launcher
description_ru=Лаунчер для игр Ankama.
description_en=Launcher for Ankama studio games.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 KiB

View File

@ -1,3 +0,0 @@
name=Arizona Games Launcher
description_ru=Лаунчер для игры Arizona Role Play.
description_en=Launcher for the Arizona Role Play game.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

View File

@ -1,3 +0,0 @@
name=Battle.net Launcher
description_ru=Лаунчер для игр Activision и Blizzard.
description_en=Launcher for Activision and Blizzard studio games.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 KiB

View File

@ -1,3 +0,0 @@
name=Black Desert Online (RU)
description_ru=Многопользовательская ролевая игра с открытым миром, известная своей потрясающей графикой и глубокой системой кастомизации персонажей. Игроки могут исследовать обширные земли, выполнять задания, участвовать в PvP-сражениях и заниматься различными ремеслами.
description_en=A massively multiplayer online role-playing game set in an open world, renowned for its stunning graphics and deep character customization system. Players can explore vast lands, complete quests, engage in PvP battles, and participate in various crafting activities.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 827 KiB

View File

@ -1,3 +0,0 @@
name=Chicken Invaders Universe
description_ru=Захватывающая аркадная игра, в которой игроки сражаются с агрессивными курицами из космоса, защищая свою планету. Игра предлагает множество уровней, кооперативный режим и возможность улучшения космического корабля.
description_en=An exciting arcade game where players battle aggressive space chickens to defend their planet. The game features multiple levels, a cooperative mode, and the ability to upgrade their spaceship.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 KiB

View File

@ -1,3 +0,0 @@
name=CONTRACT WARS
description_ru=Многопользовательский шутер от первого лица, где игроки участвуют в противостоянии между двумя командами на разнообразных картах. Игра предлагает широкий выбор оружия и возможностей для настройки персонажей, что делает каждый матч уникальным.
description_en=A multiplayer first-person shooter where players engage in battles between two teams on various maps. The game offers a wide selection of weapons and character customization options, making each match unique.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1,3 +0,0 @@
name=Age of Empires Online
description_ru=Многопользовательская стратегия в реальном времени, где игроки строят свои цивилизации, собирают ресурсы и сражаются с противниками. Игра предлагает уникальную экономическую систему и возможность развивать свои города с помощью различных миссий и задач.
description_en=A multiplayer real-time strategy game where players build their civilizations, gather resources, and battle against opponents. The game features a unique economic system and the ability to develop cities through various missions and quests.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

View File

@ -1,3 +0,0 @@
name=Cemu
description_ru=Эмулятор Wii U, который позволяет пользователям запускать и играть в игры, выпущенные на этой консоли, с высокой производительностью и улучшенной графикой.
description_en=A Wii U emulator that allows users to launch and play games released on this console with high performance and enhanced graphics.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 KiB

View File

@ -1,3 +0,0 @@
name=Secret World Legends (ENG)
description_ru=MMORPG с уникальной историей и сеттингом, основанная на мифах, легендах и тайных обществах, позволяющая игрокам исследовать современный мир, полный сверхъестественных существ и загадок. Игра предлагает свободу в выборе навыков и построении персонажей, а также захватывающие квесты и глубокий сюжет.
description_en=An MMORPG with a unique story and setting based on myths, legends, and secret societies, allowing players to explore a modern world filled with supernatural beings and mysteries. The game offers freedom in skill selection and character building, along with engaging quests and a rich narrative.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 KiB

View File

@ -1,3 +0,0 @@
name=Broken Ranks (ENG)
description_ru=MMORPG игра, предлагающая глубокий сон и уникальную боевую систему, которая ориентирует внимание на стратегию и деятельность персоны. Игроки исследуют мрачный мир, полный интриг и опасностей, развивая своих героев и принимая ключевые решения, влияющие на ход истории.
description_en=An MMORPG game offering deep sleep and a unique combat system that focuses on the strategy and activities of the person. Players explore a dark world full of intrigue and danger, developing their characters and making key decisions that affect the course of history.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@ -1,3 +0,0 @@
name=Dolphin 5.0
description_ru=Мощный эмулятор для игровых консолей Nintendo GameCube и Wii, который позволяет запускать игры на ПК с улучшенной графикой и производительностью. Он поддерживает широкий спектр функций, включая HD-разрешение, множество настройек управления и возможность использования модификаций.
description_en=A powerful emulator for Nintendo GameCube and Wii consoles that allows users to play games on their PCs with enhanced graphics and performance. It supports a wide range of features, including HD resolution, numerous control configurations, and the ability to use modifications.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 936 KiB

View File

@ -1,3 +0,0 @@
name=Doomsday
description_ru=Стратегическая игра в реальном времени, где игроки управляют отрядом выживших в постапокалиптическом мире, стремясь восстановить цивилизацию и защититься от различных угроз. Игра предлагает элементы строительства базы, тактические сражения и глубокую проработку сюжета.
description_en=A real-time strategy game where players manage a group of survivors in a post-apocalyptic world, aiming to rebuild civilization and defend against various threats. The game features base-building elements, tactical combat, and a deep narrative experience.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 674 KiB

View File

@ -1,3 +0,0 @@
name=Eldevin (ENG)
description_ru=MMORPG с красочной графикой, где игроки исследуют обширный фэнтезийный мир, выполняют квесты и сражаются с врагами, чтобы развивать свои персонажи. Игра предлагает разнообразные классы и навыки, а также системы крафта и группового взаимодействия.
description_en=An MMORPG with vibrant graphics where players explore a vast fantasy world, complete quests, and battle enemies to develop their characters. The game features diverse classes and skills, as well as crafting and group interaction systems.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 351 KiB

View File

@ -1,3 +0,0 @@
name=Epic Games Launcher
description_ru=Лаунчер для библиотеки игр Epic Games.
description_en=Launcher for the Epic Games game library.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 963 KiB

View File

@ -1,3 +0,0 @@
name=STALCRAFT
description_ru=Многопользовательская игра с открытым миром, вдохновленная вселенной S.T.A.L.K.E.R., где игроки исследуют заброшенные зоны, сражаются с мутантами и другими сталкерами, а также выполняют различные квесты. Игра сочетает элементы выживания, RPG и шутера от первого лица, предлагая уникальный опыт в постапокалиптическом мире.
description_en=A multiplayer open-world game inspired by the S.T.A.L.K.E.R. universe, where players explore abandoned zones, battle mutants and other stalkers, and complete various quests. The game combines elements of survival, RPG, and first-person shooter, offering a unique experience in a post-apocalyptic world.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 KiB

View File

@ -1,3 +0,0 @@
name=ExoTanks
description_ru=Многопользовательская боевая игра, в которой игроки управляют экзоскелетами и сражаются в различных аренах, используя мощное вооружение и стратегический подход. Игра предлагает как командные, так и одиночные режимы, а также возможность кастомизации своего экзоскелета для уникального стиля игры.
description_en=A multiplayer battle game where players control exoskeletons and fight in various arenas using powerful weapons and strategic gameplay. The game offers both team and solo modes, along with the ability to customize their exoskeleton for a unique playing style.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 KiB

View File

@ -1,3 +0,0 @@
name=Farlight 84
description_ru=Многопользовательская игра в жанре королевская битва, которая проходит в красочном и футуристическом мире, где игроки сражаются друг с другом с использованием уникальных навыков и оружия. Игра предлагает захватывающий геймплей с элементами строительства, а также возможность использовать различные транспортные средства для перемещения по карте.
description_en=A multiplayer battle royale game set in a colorful and futuristic world where players fight against each other using unique skills and weapons. The game features exciting gameplay with building elements, as well as the ability to utilize various vehicles to navigate the map.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -1,3 +0,0 @@
name=Fractured Online (ENG)
description_ru=Fractured Online — это первая массовая многопользовательская ролевая онлайн-игра с открытым миром, сочетающая динамичные сражения с полностью интерактивным окружением. Она одинаково понравится любителям соревновательного и кооперативного игрового процесса. С самого первого дня погрузитесь в бой. Побеждайте врагов благодаря собственным навыкам и смекалке, а не снаряжению или уровню. Собирайте ресурсы, создавайте предметы, торгуйте и отправляйтесь в легендарные путешествия в одиночку или создайте поселение со своей гильдией и превратите его в следующую империю.
description_en=Fractured Online is the first open-world sandbox MMORPG mixing action combat with fully interactable environments, appealing equally to lovers of competitive and cooperative gameplay. Jump right into the fray from day one. Defeat your enemies through your own skill and cleverness, not equipment or level. Gather resources, craft, trade and venture into legendary travels as a solitary hero, or start a settlement with your guild and grow it into the next empire.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 552 KiB

View File

@ -1,3 +0,0 @@
name=Goose Goose Duck
description_ru=Многопользовательская игра в жанре социальной дедукции, где игроки выступают в роли уток или гусей, пытаясь выполнить задания и выявить среди них "уток" — предателей. Игра сочетает в себе элементы стратегии и общения, требуя от игроков координации и способности распознавать обман.
description_en=A multiplayer social deduction game where players take on the roles of ducks or geese, trying to complete tasks and identify the "ducks" — the impostors among them. The game combines elements of strategy and communication, requiring players to coordinate and recognize deception.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 KiB

View File

@ -1,3 +0,0 @@
name=GOG Galaxy Launcher
description_ru=Лаунчер для библиотеки игр GOG.
description_en=Launcher for the GOG game library.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 360 KiB

View File

@ -1,3 +0,0 @@
name=Guild Wars 2
description_ru=MMORPG с ярким миром и уникальной системой динамических событий, где игроки могут свободно исследовать просторы Тираи и участвовать в масштабных сражениях. Игра предлагает разнообразие рас и классов, а также акцент на совместной игре и взаимодействии между игроками.
description_en=An MMORPG with a vibrant world and a unique system of dynamic events, where players can freely explore the realms of Tyria and engage in large-scale battles. The game offers a variety of races and classes, with an emphasis on cooperative play and player interaction.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB

View File

@ -1,3 +0,0 @@
name=Indiegala Client
description_ru=Лаунчер для библиотеки игр Indiegala.
description_en=Launcher for the Indiegala game library.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -1,3 +0,0 @@
name=Last Chaos
description_ru=Last Chaos классическая MMORPG с шестью классами, осадами замков, корейским гриндом и километрами подземелий. Противостояние Апполона и Эреса набирает обороты, так что спешите принять одну из сторон.
description_en=Last Chaos is a classic MMORPG with six classes, castle sieges, a Korean grind and kilometers of dungeons. The confrontation between Apollo and Eres is gaining momentum, so hurry up to take one of the sides.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 901 KiB

View File

@ -1,3 +0,0 @@
name=DC Universe Online (ENG)
description_ru=MMORPG, в которой игроки создают собственных супергероев или суперзлодеев во вселенной DC Comics и участвуют в эпических битвах с известными персонажами, такими как Супермен и Бэтмен. Игра предлагает обширные квесты, захватывающие PvP-режимы и возможность совместной игры с другими игроками.
description_en=An MMORPG where players create their own superheroes or supervillains in the DC Comics universe and engage in epic battles alongside iconic characters like Superman and Batman. The game features extensive quests, exciting PvP modes, and the ability to team up with other players.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 864 KiB

View File

@ -1,3 +0,0 @@
name=Anomaly Zone
description_ru=Экшен-игра про сталкеров, где игроки исследуют таинственные миры и сражаются с разнообразными противниками. Игра предлагает захватывающий сюжет и возможность улучшать персонажа, открывая новые способности и снаряжение.
description_en=An action game about stalkers, where players explore mysterious worlds and fight against a variety of opponents. The game offers an exciting storyline and the opportunity to improve the character by unlocking new abilities and equipment.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 KiB

View File

@ -1,3 +0,0 @@
name=CALIBER
description_ru=Тактический шутер от третьего лица, где игроки могут выбирать из различных персонажей с уникальными способностями и сражаться в командных режимах. Игра предлагает реалистичную графику и динамичные бои, обеспечивая увлекательный игровой процесс.
description_en=A tactical third-person shooter where players can choose from various characters with unique abilities and engage in team-based modes. The game features realistic graphics and dynamic combat, providing an engaging gameplay experience.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

View File

@ -1,3 +0,0 @@
name=Rockstar Games Launcher
description_ru=Лаунчер для игр Rockstar.
description_en=Launcher for Rockstar studio games.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -1,3 +0,0 @@
name=Toontown Rewritten (ENG)
description_ru=Многопользовательская онлайн-игра, где игроки берут на себя роли мультяшных персонажей, сражаясь с противниками в локациях, наполненных юмором и приключениями. Игра предлагает кооперативный геймплей, квесты, мини-игры и возможность взаимодействия с другими игроками в красочном мире.
description_en=A multiplayer online game, where players take on the roles of cartoon characters battling foes in humorous and adventurous locations. The game offers cooperative gameplay, quests, mini-games, and opportunities for interaction with other players in a colorful world.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 769 KiB

View File

@ -1,3 +0,0 @@
name=Warframe
description_ru=Бесплатная многопользовательская онлайн-игра в жанре экшен-RPG, в которой игроки управляют древними воинами, известными как Тенно, и сражаются против различных фракций в разнообразных миссиях по всей галактике. Игра предлагает множество возможностей для кастомизации персонажей, кооперативный геймплей и постоянно обновляющийся контент.
description_en=A free-to-play multiplayer online action RPG where players control ancient warriors known as Tenno and battle against various factions in diverse missions across the galaxy. The game offers extensive character customization options, cooperative gameplay, and continuously updated content.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 KiB

View File

@ -1,3 +0,0 @@
name=The Lord of the Rings Online (ENG)
description_ru=MMORPG, основанная на произведениях Дж. Р. Р. Толкиена, позволяющая игрокам исследовать Средиземье, принимать участие в эпических квестах и сражениях с известными персонажами и созданиями из вселенной Властелина колец. Игра предлагает глубокую кастомизацию персонажей, богатый сюжет и множество возможностей для игры в одиночку или в группе.
description_en=An MMORPG based on the works of J. R. R. Tolkien, allowing players to explore Middle-earth, take part in epic quests and battles with famous characters and creatures from the Lord of the Rings universe. The game offers deep customization of characters, a rich plot and many opportunities to play alone or in a group.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 KiB

View File

@ -1,3 +0,0 @@
name=Metal War Online
description_ru=Многопользовательская онлайн-игра в жанре экшен с элементами стратегии, где игроки управляют боевыми роботами и сражаются на различных аренах. Игра предлагает богатую кастомизацию техники и разнообразные игровые режимы, позволяя каждому игроку создавать уникальный стиль боя.
description_en=A multiplayer online action game with strategic elements, where players control combat robots and battle on various arenas. The game offers extensive customization options for the machines and a variety of game modes, allowing each player to create a unique fighting style.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 KiB

View File

@ -1,3 +0,0 @@
name=Mini World
description_ru=Песочница, в которой игроки могут исследовать, строить и создавать свои уникальные миры в 3D-окружении. Игра предлагает разнообразные режимы, включая выживание и творчество, а также возможность взаимодействовать с другими игроками в многопользовательском формате.
description_en=A sandbox game where players can explore, build, and create their unique worlds in a 3D environment. The game offers various modes, including survival and creative, as well as the ability to interact with other players in a multiplayer format.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

View File

@ -1,3 +0,0 @@
name=PPSSPP
description_ru=Эмулятор портативной игровой консоли PlayStation Portable (PSP), позволяющий запускать игры PSP на компьютерах и мобильных устройствах. Он поддерживает улучшенную графику и различные настройки, что позволяет наслаждаться классическими играми с высоким качеством.
description_en=An emulator for the PlayStation Portable (PSP) handheld gaming console, enabling users to play PSP games on computers and mobile devices. It supports enhanced graphics and various settings, allowing players to enjoy classic games at high quality.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 963 KiB

View File

@ -1,3 +0,0 @@
name=Panzar
description_ru=Многопользовательская онлайн-игра в жанре экшен, где игроки сражаются в командах, используя различные классы персонажей и уникальные способности. Игра предлагает тактические сражения на больших картах с разрушительным взаимодействием окружения.
description_en=A multiplayer online action game where players battle in teams using various character classes and unique abilities. The game features tactical battles on large maps with destructible environments.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 961 KiB

View File

@ -1,3 +0,0 @@
name=Path of Exile
description_ru=Бесплатная онлайн-игра в жанре action RPG, в которой игроки исследуют мрачный мир, сражаются с монстрами и развивают свои персонажи через глубокую систему навыков и предметов. Игра известна своим сложным геймплеем и постоянно обновляемым контентом, включая сезонные лиги и уникальные механики.
description_en=A free online action RPG where players explore a dark world, fight monsters, and develop their characters through a deep skill and item system. The game is known for its challenging gameplay and constantly updated content, including seasonal leagues and unique mechanics.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 701 KiB

View File

@ -1,3 +0,0 @@
name=Plarium Play
description_ru=Лаунчер для игр Plarium.
description_en=Launcher for Plarium studio games.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 KiB

View File

@ -1,3 +0,0 @@
name=Project64
description_ru=Эмулятор Nintendo 64, который позволяет играть в игры этой консоли на современных устройствах. Поддерживает различные настройки графики и управления, обеспечивая высококачественный игровой опыт.
description_en=The Nintendo 64 emulator, which allows you to play games of this console on modern devices. Supports various graphics and control settings, providing a high-quality gaming experience.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 KiB

View File

@ -1,3 +0,0 @@
name=Pulse Online
description_ru=Многопользовательская онлайн-игра в жанре MMORPG, действие которой происходит в научно-фантастическом мире с уникальной боевой системой и глубоким крафтом. Игроки могут исследовать обширные локации, выполнять квесты, сражаться с противниками и взаимодействовать с другими участниками игры.
description_en=A multiplayer online game in the MMORPG genre set in a sci-fi world with a unique combat system and deep crafting mechanics. Players can explore vast locations, complete quests, battle enemies, and interact with other participants in the game.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 724 KiB

View File

@ -1,3 +0,0 @@
name=Russian Fishing 4
description_ru=Реалистичный симулятор рыбалки, который предлагает игрокам погрузиться в увлекательный процесс ловли рыбы в различных красивых водоемах России. Игра включает в себя широкий выбор снастей, видов рыб и возможностей для соревнований с другими рыбаками.
description_en=A realistic fishing simulator that immerses players in the enjoyable process of catching fish in various beautiful bodies of water across Russia. The game features a wide selection of tackle, fish species, and opportunities for competition with other anglers.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 623 KiB

View File

@ -1,4 +0,0 @@
name=Saturn
description_ru=Сатурн — это тактическая RPG, действие которой происходит на Земле и на спутниках Сатурна.
Таинственный сигнал из космоса заставляет искусственный интеллект машин восстать против своих создателей по всей Солнечной системе. Защищайтесь от угрозы на Земле и подключайтесь к роботам на спутниках Сатурна, чтобы остановить конец света. На спасение мира дается всего 3 дня.
description_en=Saturn is a tactical RPG set on the moons of Saturn and on Earth. The protagonist controls robots on the moons of Saturn and explores an underground city where one can find keys to the secrets of deep space.

Some files were not shown because too many files have changed in this diff Show More