package com.projectsacrifice.game; /** All player-facing copy behind one typed, Android-independent interface. */ public final class GameStrings { private final GameLanguage language; private GameStrings(GameLanguage language) { this.language = language == null ? GameLanguage.EN : language; } public static GameStrings forLanguage(GameLanguage language) { return new GameStrings(language); } public GameLanguage language() { return language; } private boolean russian() { return language == GameLanguage.RU; } public String appContentDescription() { return russian() ? "Project Sacrifice. Платформенная головоломка из десяти уровней." : "Project Sacrifice. Ten-level puzzle platform game."; } public String projectTitle() { return "PROJECT SACRIFICE"; } public String tagline() { return russian() ? "Каждый конец оставляет путь вперёд" : "Every ending leaves a way forward"; } public String locked() { return russian() ? "ЗАКРЫТО" : "LOCKED"; } public String tapToEnter() { return russian() ? "Нажмите, чтобы войти" : "Tap to enter"; } public String levelSelectFooter() { return russian() ? "Альбомная ориентация · мультитач · прогресс сохраняется автоматически" : "Landscape · multitouch · progress saves automatically"; } public String settingsButton() { return russian() ? "Настройки" : "Settings"; } public String settingsTitle() { return russian() ? "НАСТРОЙКИ" : "SETTINGS"; } public String settingsInstruction() { return russian() ? "Нажмите на строку, чтобы изменить. Всё сохраняется автоматически." : "Tap a row to change it. Changes save automatically."; } public String controlSizeSetting() { return russian() ? "Размер управления" : "Control size"; } public String controlOpacitySetting() { return russian() ? "Прозрачность управления" : "Control opacity"; } public String vibrationSetting() { return russian() ? "Вибрация" : "Vibration"; } public String languageSetting() { return russian() ? "Язык" : "Language"; } public String languageName() { return russian() ? "Русский" : "English"; } public String controlSizeValue(int index) { String[] values = russian() ? new String[]{"Маленький", "Средний", "Большой"} : new String[]{"Small", "Medium", "Large"}; return values[validPreset(index)]; } public String controlOpacityValue(int index) { String[] values = russian() ? new String[]{"Низкая", "Средняя", "Высокая"} : new String[]{"Low", "Medium", "High"}; return values[validPreset(index)]; } public String hapticsValue(boolean enabled) { if (russian()) return enabled ? "Вкл." : "Выкл."; return enabled ? "On" : "Off"; } public String accessibilityTitle() { return russian() ? "ДОСТУПНОСТЬ" : "ACCESSIBILITY"; } public String textSizeSetting() { return russian() ? "Размер текста" : "Text size"; } public String textSizeValue(float scale) { return scale > 1f ? (russian() ? "Крупный" : "Large") : (russian() ? "Обычный" : "Standard"); } public String highContrastSetting() { return russian() ? "Контраст" : "High contrast"; } public String highContrastValue(boolean enabled) { return hapticsValue(enabled); } public String reducedMotionSetting() { return russian() ? "Меньше движения" : "Reduced motion"; } public String reducedMotionValue(boolean enabled) { return hapticsValue(enabled); } public String audioTitle() { return russian() ? "ЗВУК" : "Audio"; } public String musicSetting() { return russian() ? "Музыка" : "Music"; } public String effectsSetting() { return russian() ? "Эффекты" : "Effects"; } public String voiceSetting() { return russian() ? "Голоса" : "Voice"; } public String volumeValue(AudioSettings settings, int preset) { return settings.volumeLabel(preset); } public String back() { return russian() ? "Назад" : "Back"; } public String hudStats(int deaths, long elapsedMilliseconds) { if (russian()) { return "Добровольцы " + deaths + " Время " + GameMath.formatTime(elapsedMilliseconds); } return "Volunteers " + deaths + " Time " + GameMath.formatTime(elapsedMilliseconds); } public String restart() { return russian() ? "Заново" : "Restart"; } public String respawning() { return russian() ? "Следующий доброволец уже в пути…" : "Another volunteer is on the way…"; } public String levelBestStats(int deaths, long elapsedMilliseconds) { return "✓ " + deaths + " " + volunteerWord(deaths) + " · " + GameMath.formatTime(elapsedMilliseconds); } public String relicClaimed() { return russian() ? "РЕЛИКВИЯ ПОЛУЧЕНА" : "RELIC CLAIMED"; } public String completion() { return russian() ? "Завершение ★" : "Completion ★"; } public String completionDeaths(boolean earned, int deaths, int targetDeaths) { return (earned ? "★" : "☆") + " " + deaths + " / " + targetDeaths + " " + volunteerWord(deaths); } public String completionTime(boolean earned, long elapsedMilliseconds, long targetMilliseconds) { return (earned ? "★" : "☆") + " " + GameMath.formatTime(elapsedMilliseconds) + " / " + GameMath.formatTime(targetMilliseconds); } public String levelSelect() { return russian() ? "Выбор уровня" : "Level select"; } public String replay() { return russian() ? "Повторить" : "Replay"; } public String nextLevel() { return russian() ? "Следующий уровень" : "Next level"; } public String paused() { return russian() ? "ПАУЗА" : "PAUSED"; } public String resume() { return russian() ? "Продолжить" : "Resume"; } // Result-flow hooks used by the Stage 3 result screen. public String currentResult() { return russian() ? "Текущий результат" : "Current result"; } public String bestResult() { return russian() ? "Лучший результат" : "Best result"; } public String deathsStat() { return russian() ? "Добровольцы" : "Volunteers"; } public String timeStat() { return russian() ? "Время" : "Time"; } public String newBest() { return russian() ? "НОВЫЙ РЕКОРД" : "NEW BEST"; } public String currentResultLine(int deaths, long timeMs) { return currentResult() + " · " + deaths + " " + volunteerWord(deaths) + " · " + GameMath.formatTime(timeMs); } public String bestResultLine(int deaths, long timeMs) { return bestResult() + " · " + deaths + " " + volunteerWord(deaths) + " · " + GameMath.formatTime(timeMs); } public String targetsResultLine(int deaths, long timeMs) { String label = russian() ? "Цели" : "Targets"; return label + " · " + deaths + " " + volunteerWord(deaths) + " · " + GameMath.formatTime(timeMs); } public String nextGoalDeaths(long deaths) { return russian() ? "Следующая цель · пройти с " + deaths + " добровольцами" : "Next goal · finish with " + deaths + " volunteers"; } public String nextGoalTime(long timeMs) { return (russian() ? "Следующая цель · пройти за " : "Next goal · finish in ") + GameMath.formatTime(timeMs); } public String nextGoalLevel(long level) { return (russian() ? "Следующая цель · перейти на уровень " : "Next goal · enter level ") + level; } public String nextGoalPersonalBest() { return russian() ? "Следующая цель · улучшить личный рекорд" : "Next goal · improve your personal best"; } // Onboarding hooks keep new tutorial Canvas copy out of GameView conditionals. public String tutorialWelcomeTitle() { return russian() ? "Смерть — это инструмент" : "Death is a tool"; } public String tutorialWelcomeBody() { return russian() ? "Двигайтесь стрелками и прыгайте кнопкой с крылом. Доберитесь до реликвии." : "Move with the arrows and jump with the winged button. Reach the relic."; } public String tutorialSacrificeTitle() { return russian() ? "Оставьте путь вперёд" : "Leave a way forward"; } public String tutorialSacrificeBody() { return russian() ? "После смерти тело остаётся в мире: закрывает шипы, держит плиты и становится ступенью." : "A body stays in the world after death: cover spikes, hold plates, and make a step."; } public String tutorialSkip() { return russian() ? "Пропустить" : "Skip"; } public String tutorialNext() { return russian() ? "Далее" : "Next"; } public String tutorialStart() { return russian() ? "Начать" : "Start"; } public String tutorialDone() { return russian() ? "Готово" : "Done"; } public String tutorialMovementTitle() { return russian() ? "ДВИЖЕНИЕ" : "MOVE"; } public String tutorialMovementBody() { return russian() ? "Удерживайте левую или правую стрелку, чтобы двигаться." : "Hold the left or right arrow to explore."; } public String tutorialJumpTitle() { return russian() ? "ДВИЖЕНИЕ + ПРЫЖОК" : "MOVE + JUMP"; } public String tutorialJumpBody() { return russian() ? "Используйте два пальца: держите направление и нажмите Прыжок." : "Use two fingers: hold a direction and tap Jump."; } public String tutorialCorpseTitle() { return russian() ? "СМЕРТЬ ОСТАВЛЯЕТ ИНСТРУМЕНТ" : "DEATH LEAVES A TOOL"; } public String tutorialCorpseBody() { return russian() ? "Павший доброволец остаётся. Используйте тело, чтобы открыть путь." : "A fallen volunteer remains. Use the body to open a path."; } public String tutorialProgress(int step, int total) { return step + " / " + total; } public String accessibilityStatus(int activeSignals, int totalSignals, int openDoors, int totalDoors, boolean playerAlive) { if (russian()) { return "Сигналы " + activeSignals + "/" + totalSignals + " · Двери " + openDoors + "/" + totalDoors + " · Доброволец " + (playerAlive ? "активен" : "возрождается"); } return "Signals " + activeSignals + "/" + totalSignals + " · Doors " + openDoors + "/" + totalDoors + " · Volunteer " + (playerAlive ? "active" : "respawning"); } public String levelSelectDescription(int unlocked, int total) { if (russian()) { return "Выбор уровня. Открыто " + unlocked + " из " + total + ". Выберите открытый уровень или Настройки."; } return "Level select. " + unlocked + " of " + total + " unlocked. Choose an unlocked level or open Settings."; } public String settingsDescription(ControlSettings controls, AccessibilitySettings accessibility) { return settingsDescription(controls, accessibility, AudioSettings.defaults()); } public String settingsDescription(ControlSettings controls, AccessibilitySettings accessibility, AudioSettings audio) { if (russian()) { return "Настройки. Размер управления " + controlSizeValue(controls.controlSizeIndex()) + ". Прозрачность управления " + controlOpacityValue(controls.controlOpacityIndex()) + ". Вибрация " + hapticsValue(controls.hapticsEnabled()) + ". Размер текста " + textSizeValue(accessibility.textScale()) + ". Контраст " + highContrastValue(accessibility.highContrastEnabled()) + ". Меньше движения " + reducedMotionValue(accessibility.reducedMotionEnabled()) + ". Музыка " + volumeValue(audio, audio.musicPreset()) + ". Эффекты " + volumeValue(audio, audio.effectsPreset()) + ". Голоса " + volumeValue(audio, audio.voicePreset()) + ". Назад."; } return "Settings. Control size " + controls.controlSizeLabel() + ". Control opacity " + controls.controlOpacityLabel() + ". Vibration " + controls.hapticsLabel() + ". Text size " + accessibility.textSizeLabel() + ". High contrast " + accessibility.highContrastLabel() + ". Reduced motion " + accessibility.reducedMotionLabel() + ". Music " + volumeValue(audio, audio.musicPreset()) + ". Effects " + volumeValue(audio, audio.effectsPreset()) + ". Voice " + volumeValue(audio, audio.voicePreset()) + ". Back."; } public String playingDescription(int levelNumber, int deaths, String elapsed, String criticalState, boolean paused) { if (paused) { return russian() ? "Пауза на уровне " + levelNumber + ", " + levelTitle(levelNumber) + ". Продолжить или вернуться к выбору уровня." : "Paused on level " + levelNumber + ", " + levelTitle(levelNumber) + ". Resume or return to level select."; } if (russian()) { return "Идёт уровень " + levelNumber + ", " + levelTitle(levelNumber) + ". Добровольцы " + deaths + ". Время " + elapsed + ". " + criticalState + ". Движение влево и вправо, прыжок, заново, пауза."; } return "Playing level " + levelNumber + ", " + levelTitle(levelNumber) + ". " + deaths + " volunteers. Time " + elapsed + ". " + criticalState + ". Move left, move right, jump, restart, pause."; } public String completeDescription(int levelNumber, int deaths, String elapsed, boolean hasNextLevel) { if (russian()) { return "Уровень завершён. " + levelTitle(levelNumber) + ". Добровольцы " + deaths + ". Время " + elapsed + ". Выбор уровня. Повторить." + (hasNextLevel ? " Следующий уровень." : ""); } return "Level complete. " + levelTitle(levelNumber) + ". " + deaths + " volunteers. Time " + elapsed + ". Level select. Replay." + (hasNextLevel ? " Next level." : ""); } public String levelTitle(int oneBasedLevelNumber) { LevelDefinition level = level(oneBasedLevelNumber); return russian() ? level.titleRu : level.title; } public String levelHint(int oneBasedLevelNumber) { LevelDefinition level = level(oneBasedLevelNumber); return russian() ? level.hintRu : level.hint; } private String volunteerWord(int count) { if (!russian()) return count == 1 ? "volunteer" : "volunteers"; int mod100 = Math.abs(count) % 100; int mod10 = Math.abs(count) % 10; if (mod100 >= 11 && mod100 <= 14) return "добровольцев"; if (mod10 == 1) return "доброволец"; if (mod10 >= 2 && mod10 <= 4) return "добровольца"; return "добровольцев"; } private static int validPreset(int index) { return index >= 0 && index <= 2 ? index : 1; } private static LevelDefinition level(int oneBasedLevelNumber) { int index = oneBasedLevelNumber - 1; if (index < 0 || index >= LevelCatalog.all().size()) index = 0; return LevelCatalog.get(index); } }