using UnityEngine; using UnityEngine.UI; using TMPro; using UnityEngine.SceneManagement; using System.Collections; using System.Collections.Generic; public class ParagraphOrder27Mod : MonoBehaviour { [Header("DATA")] public TextAsset wordFile; public string wordsResourcePath = "Mod27Words"; [Header("MAIN TEXTS")] public TMP_Text instructionText; [Header("TEXTS")] public TMP_Text titleText; public TMP_Text languageText; public TMP_Text feedbackText; public TMP_Text scoreText; public TMP_Text comboText; public TMP_Text timerText; [Header("SENTENCE BUTTONS")] public Button[] sentenceButtons; public TMP_Text[] sentenceTexts; [Header("MAIN BUTTONS")] public Button submitButton; public Button resetButton; public Button backButton; [Header("EXTRA BUTTONS")] public Button extraTimeButton; public Button extraHintButton; public Button extraSkipButton; public TMP_Text extraTimeCooldownText; public TMP_Text extraHintCooldownText; public TMP_Text extraSkipCooldownText; [Header("SCENES")] public string backSceneName = "modsec 27"; public string resultSceneName = "modres 27"; [Header("LANGUAGE TEST")] [Tooltip("-1 otomatik. 0 TR, 1 EN, 2 ES, 3 DE, 4 FR, 5 PT")] public int forcedQuestionLanguageIndex = -1; [Header("GAME SETTINGS")] public float startTime = 60f; public int basePoints = 60; public int wrongPenalty = 50; public float correctTimeBonus = 3f; public float nextQuestionDelay = 1.5f; [Header("EXTRA SETTINGS")] public float extraTimeAmount = 5f; public float cooldownDuration = 5f; [Header("COMBO MULTIPLIERS")] public float mult_1to2 = 1f; public float mult_3to4 = 1.15f; public float mult_5to7 = 1.3f; public float mult_8plus = 1.5f; [Header("COLORS")] public Color normalButtonColor = new Color32(120, 70, 220, 255); public Color selectedButtonColor = new Color32(155, 105, 255, 255); public Color correctButtonColor = new Color32(70, 240, 130, 255); public Color wrongButtonColor = new Color32(255, 80, 95, 255); public Color disabledButtonColor = new Color32(90, 75, 120, 255); readonly string[] langNames = { "Türkçe", "English", "Español", "Deutsch", "Français", "Português" }; const string modKey = "Mod27"; class ParagraphOrderEntry { public string[] sentences = new string[24]; } class SentenceOption { public string text; public int correctOrder; } readonly List allQuestions = new List(); readonly List questionPool = new List(); readonly List currentOptions = new List(); ParagraphOrderEntry currentQuestion; ParagraphOrderEntry lastQuestion; int sentenceLangIndex = 1; int[] selectedOrderByButton; int selectedCount = 0; int score = 0; int combo = 0; int correctCount = 0; int wrongCount = 0; int bestComboThisRun = 0; float timeLeft; bool gameOver = false; bool waitingNextQuestion = false; bool extraTimeReady = true; bool extraHintReady = true; bool extraSkipReady = true; Vector3[] originalButtonScales; Vector3[] originalButtonPositions; string[] baseButtonTexts; void Awake() { LoadQuestions(); } void Start() { ResolveLanguage(); timeLeft = PlayerPrefs.GetFloat("SelectedGameTime", startTime); if (timeLeft <= 0f) timeLeft = startTime; if (allQuestions.Count < 1) { Debug.LogError("Mod27: En az 1 geçerli TXT satırı gerekli. Yüklenen soru sayısı: " + allQuestions.Count); enabled = false; return; } if (allQuestions.Count == 1) { Debug.LogWarning("Mod27: Sadece 1 geçerli TXT satırı var. Bu yüzden aynı soru tekrar gelir. Random için TXT satır sayısını artır."); } if (sentenceButtons == null || sentenceButtons.Length < 4) { Debug.LogError("Mod27: 4 sentenceButtons atanmalı."); enabled = false; return; } if (sentenceTexts == null || sentenceTexts.Length < 4) { Debug.LogError("Mod27: 4 sentenceTexts atanmalı."); enabled = false; return; } PrepareUI(); BindButtons(); ResetQuestionPool(); UpdateLanguageUI(); UpdateScoreUI(); UpdateComboUI(); UpdateTimerUI(); NextQuestion(); Debug.Log("Mod27 aktif dil: " + sentenceLangIndex + " / " + langNames[sentenceLangIndex]); } void Update() { if (gameOver) return; timeLeft -= Time.deltaTime; if (timeLeft <= 0f) { timeLeft = 0f; UpdateTimerUI(); GameOver(); return; } UpdateTimerUI(); } /* TXT FORMAT: Her satır 24 alan olmalı. tr1|tr2|tr3|tr4| en1|en2|en3|en4| es1|es2|es3|es4| de1|de2|de3|de4| fr1|fr2|fr3|fr4| pt1|pt2|pt3|pt4 TXT içindeki cümleler doğru sırayla yazılır. Script ekranda otomatik karıştırır. */ void LoadQuestions() { allQuestions.Clear(); TextAsset txt = wordFile; if (txt == null) txt = Resources.Load(wordsResourcePath); if (txt == null) { Debug.LogError("Mod27: TXT bulunamadı. Dosya yolu: Assets/Resources/" + wordsResourcePath + ".txt"); return; } string[] lines = txt.text.Split( new[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries ); for (int i = 0; i < lines.Length; i++) { string line = lines[i].Trim(); if (string.IsNullOrWhiteSpace(line)) continue; if (line.StartsWith("#")) continue; string[] parts = SplitLineSmart(line); if (parts.Length < 24) { Debug.LogWarning("Mod27 TXT eksik satır atlandı. Satır: " + (i + 1) + " / Alan sayısı: " + parts.Length); continue; } ParagraphOrderEntry entry = new ParagraphOrderEntry(); bool valid = true; for (int s = 0; s < 24; s++) { entry.sentences[s] = CleanField(parts[s]); if (string.IsNullOrWhiteSpace(entry.sentences[s])) valid = false; } if (valid) allQuestions.Add(entry); } Debug.Log("Mod27 yüklenen soru sayısı: " + allQuestions.Count); if (allQuestions.Count <= 1) { Debug.LogWarning("Mod27 UYARI: TXT içinden sadece " + allQuestions.Count + " soru yüklendi. Random düzgün görünmesi için Mod27Words.txt içine daha fazla geçerli satır ekle."); } } string[] SplitLineSmart(string line) { if (line.Contains("|")) return line.Split('|'); if (line.Contains("\t")) return line.Split('\t'); return line.Split(','); } string CleanField(string value) { if (string.IsNullOrEmpty(value)) return ""; return value.Trim().Trim('"').Trim().Replace("\\n", "\n"); } void ResolveLanguage() { if (forcedQuestionLanguageIndex >= 0 && forcedQuestionLanguageIndex <= 5) sentenceLangIndex = forcedQuestionLanguageIndex; else sentenceLangIndex = PlayerPrefs.GetInt("QuestionLangID", 1); sentenceLangIndex = ClampLanguage(sentenceLangIndex, 1); } int ClampLanguage(int value, int fallback) { if (value < 0 || value > 5) return fallback; return value; } public void RefreshLanguagesFromPrefs() { ResolveLanguage(); UpdateLanguageUI(); if (currentQuestion != null && !gameOver) RefreshCurrentQuestion(); } public void SetQuestionLanguage(int id) { if (id < 0 || id > 5) return; sentenceLangIndex = id; PlayerPrefs.SetInt("QuestionLangID", id); PlayerPrefs.SetString("QuestionLangCode", ToCode(id)); PlayerPrefs.Save(); UpdateLanguageUI(); RefreshCurrentQuestion(); } string ToCode(int id) { switch (id) { case 0: return "tr"; case 1: return "en"; case 2: return "es"; case 3: return "de"; case 4: return "fr"; case 5: return "pt"; default: return "en"; } } void UpdateLanguageUI() { if (languageText != null) languageText.text = GetText("language") + ": " + langNames[sentenceLangIndex]; if (titleText != null) titleText.text = GetTitleText(); if (instructionText != null) instructionText.text = GetText("instruction"); } string GetTitleText() { switch (sentenceLangIndex) { case 0: return "Paragrafı Sırala"; case 1: return "Order the Paragraph"; case 2: return "Ordena el párrafo"; case 3: return "Ordne den Absatz"; case 4: return "Remets le paragraphe dans l'ordre"; case 5: return "Ordene o parágrafo"; default: return "Order the Paragraph"; } } string GetText(string key) { int lang = sentenceLangIndex; if (key == "language") { if (lang == 0) return "DİL"; if (lang == 1) return "LANGUAGE"; if (lang == 2) return "IDIOMA"; if (lang == 3) return "SPRACHE"; if (lang == 4) return "LANGUE"; if (lang == 5) return "IDIOMA"; } if (key == "instruction") { if (lang == 0) return "Cümlelere doğru sırayla dokun. Sonra SUBMIT'e bas."; if (lang == 1) return "Tap the sentences in the correct order. Then press SUBMIT."; if (lang == 2) return "Toca las oraciones en el orden correcto. Luego pulsa SUBMIT."; if (lang == 3) return "Tippe die Sätze in der richtigen Reihenfolge an. Dann drücke SUBMIT."; if (lang == 4) return "Touche les phrases dans le bon ordre. Puis appuie sur SUBMIT."; if (lang == 5) return "Toque nas frases na ordem correta. Depois aperte SUBMIT."; } if (key == "chooseAll") { if (lang == 0) return "4 CÜMLENİN HEPSİNİ SIRALA"; if (lang == 1) return "ORDER ALL 4 SENTENCES"; if (lang == 2) return "ORDENA LAS 4 ORACIONES"; if (lang == 3) return "ORDNE ALLE 4 SÄTZE"; if (lang == 4) return "ORDONNE LES 4 PHRASES"; if (lang == 5) return "ORDENE AS 4 FRASES"; } if (key == "correct") { if (lang == 0) return "DOĞRU SIRALAMA"; if (lang == 1) return "CORRECT ORDER"; if (lang == 2) return "ORDEN CORRECTO"; if (lang == 3) return "RICHTIGE REIHENFOLGE"; if (lang == 4) return "BON ORDRE"; if (lang == 5) return "ORDEM CORRETA"; } if (key == "wrong") { if (lang == 0) return "SIRALAMA YANLIŞ"; if (lang == 1) return "WRONG ORDER"; if (lang == 2) return "ORDEN INCORRECTO"; if (lang == 3) return "FALSCHE REIHENFOLGE"; if (lang == 4) return "MAUVAIS ORDRE"; if (lang == 5) return "ORDEM ERRADA"; } if (key == "hint") { if (lang == 0) return "İPUCU: SIRADAKİ DOĞRU CÜMLE SEÇİLDİ"; if (lang == 1) return "HINT: THE NEXT CORRECT SENTENCE WAS SELECTED"; if (lang == 2) return "PISTA: SE SELECCIONÓ LA SIGUIENTE ORACIÓN CORRECTA"; if (lang == 3) return "HINWEIS: DER NÄCHSTE RICHTIGE SATZ WURDE GEWÄHLT"; if (lang == 4) return "INDICE : LA PROCHAINE PHRASE CORRECTE A ÉTÉ CHOISIE"; if (lang == 5) return "DICA: A PRÓXIMA FRASE CORRETA FOI SELECIONADA"; } if (key == "hintReset") { if (lang == 0) return "İPUCU İÇİN ÖNCE SEÇİMİ RESETLE"; if (lang == 1) return "RESET YOUR ORDER BEFORE USING HINT"; if (lang == 2) return "REINICIA TU ORDEN ANTES DE USAR LA PISTA"; if (lang == 3) return "SETZE DEINE REIHENFOLGE ZURÜCK, BEVOR DU DEN HINWEIS NUTZT"; if (lang == 4) return "RÉINITIALISE TON ORDRE AVANT L'INDICE"; if (lang == 5) return "REDEFINA SUA ORDEM ANTES DE USAR A DICA"; } if (key == "skipped") { if (lang == 0) return "GEÇİLDİ"; if (lang == 1) return "SKIPPED"; if (lang == 2) return "SALTADO"; if (lang == 3) return "ÜBERSPRUNGEN"; if (lang == 4) return "PASSÉ"; if (lang == 5) return "PULADO"; } return key; } void PrepareUI() { if (instructionText != null) { instructionText.alignment = TextAlignmentOptions.Center; instructionText.textWrappingMode = TextWrappingModes.Normal; } if (feedbackText != null) { feedbackText.text = ""; feedbackText.alignment = TextAlignmentOptions.Center; feedbackText.textWrappingMode = TextWrappingModes.Normal; } originalButtonScales = new Vector3[sentenceButtons.Length]; originalButtonPositions = new Vector3[sentenceButtons.Length]; selectedOrderByButton = new int[sentenceButtons.Length]; baseButtonTexts = new string[sentenceButtons.Length]; for (int i = 0; i < sentenceButtons.Length; i++) { if (sentenceButtons[i] == null) continue; originalButtonScales[i] = sentenceButtons[i].transform.localScale; originalButtonPositions[i] = sentenceButtons[i].transform.localPosition; sentenceButtons[i].transition = Selectable.Transition.None; if (sentenceButtons[i].image != null) sentenceButtons[i].image.color = FullAlpha(normalButtonColor); } HideCooldownTexts(); } void HideCooldownTexts() { if (extraTimeCooldownText != null) extraTimeCooldownText.gameObject.SetActive(false); if (extraHintCooldownText != null) extraHintCooldownText.gameObject.SetActive(false); if (extraSkipCooldownText != null) extraSkipCooldownText.gameObject.SetActive(false); } void BindButtons() { if (submitButton != null) { submitButton.onClick.RemoveAllListeners(); submitButton.onClick.AddListener(OnSubmit); } if (resetButton != null) { resetButton.onClick.RemoveAllListeners(); resetButton.onClick.AddListener(ResetCurrentSelection); } if (backButton != null) { backButton.onClick.RemoveAllListeners(); backButton.onClick.AddListener(() => { SaveProgressOnly(); SceneManager.LoadScene(backSceneName); }); } if (extraTimeButton != null) { extraTimeButton.onClick.RemoveAllListeners(); extraTimeButton.onClick.AddListener(OnExtraTime); } if (extraHintButton != null) { extraHintButton.onClick.RemoveAllListeners(); extraHintButton.onClick.AddListener(OnExtraHint); } if (extraSkipButton != null) { extraSkipButton.onClick.RemoveAllListeners(); extraSkipButton.onClick.AddListener(OnExtraSkip); } for (int i = 0; i < sentenceButtons.Length; i++) { int index = i; if (sentenceButtons[i] == null) continue; sentenceButtons[i].onClick.RemoveAllListeners(); sentenceButtons[i].onClick.AddListener(() => SelectSentence(index)); } } void ResetQuestionPool() { questionPool.Clear(); questionPool.AddRange(allQuestions); Shuffle(questionPool); if (questionPool.Count > 1 && lastQuestion != null && questionPool[0] == lastQuestion) { int swapIndex = Random.Range(1, questionPool.Count); ParagraphOrderEntry temp = questionPool[0]; questionPool[0] = questionPool[swapIndex]; questionPool[swapIndex] = temp; } } void NextQuestion() { if (gameOver) return; if (allQuestions.Count <= 0) return; if (questionPool.Count <= 0) ResetQuestionPool(); if (questionPool.Count <= 0) return; currentQuestion = questionPool[0]; questionPool.RemoveAt(0); lastQuestion = currentQuestion; RefreshCurrentQuestion(); } void RefreshCurrentQuestion() { if (currentQuestion == null) return; waitingNextQuestion = false; selectedCount = 0; currentOptions.Clear(); for (int i = 0; i < 4; i++) { SentenceOption option = new SentenceOption(); option.text = GetSentence(currentQuestion, sentenceLangIndex, i); option.correctOrder = i; currentOptions.Add(option); } ShuffleSentenceOptions(); ResetButtonsForNewQuestion(); for (int i = 0; i < 4; i++) { baseButtonTexts[i] = currentOptions[i].text; if (sentenceTexts[i] != null) sentenceTexts[i].text = baseButtonTexts[i]; } if (feedbackText != null) feedbackText.text = ""; if (submitButton != null) submitButton.interactable = true; if (resetButton != null) resetButton.interactable = true; StartCoroutine(SentencesPopAnim()); } void ShuffleSentenceOptions() { if (currentOptions.Count <= 1) return; int safety = 0; do { Shuffle(currentOptions); safety++; } while (IsOptionsInCorrectOrder() && safety < 20); } bool IsOptionsInCorrectOrder() { for (int i = 0; i < currentOptions.Count; i++) { if (currentOptions[i].correctOrder != i) return false; } return true; } string GetSentence(ParagraphOrderEntry entry, int langIndex, int sentenceIndex) { int index = langIndex * 4 + sentenceIndex; if (index < 0 || index >= entry.sentences.Length) return ""; return entry.sentences[index]; } void ResetButtonsForNewQuestion() { selectedCount = 0; for (int i = 0; i < sentenceButtons.Length; i++) { selectedOrderByButton[i] = 0; if (sentenceButtons[i] == null) continue; bool active = i < 4; sentenceButtons[i].gameObject.SetActive(active); sentenceButtons[i].interactable = active; sentenceButtons[i].transform.localScale = originalButtonScales[i]; sentenceButtons[i].transform.localPosition = originalButtonPositions[i]; if (sentenceButtons[i].image != null) sentenceButtons[i].image.color = FullAlpha(normalButtonColor); } } void ResetCurrentSelection() { if (gameOver || waitingNextQuestion) return; selectedCount = 0; for (int i = 0; i < 4; i++) { selectedOrderByButton[i] = 0; if (sentenceButtons[i] != null) { sentenceButtons[i].interactable = true; sentenceButtons[i].transform.localScale = originalButtonScales[i]; if (sentenceButtons[i].image != null) sentenceButtons[i].image.color = FullAlpha(normalButtonColor); } if (sentenceTexts[i] != null) sentenceTexts[i].text = baseButtonTexts[i]; } if (feedbackText != null) feedbackText.text = ""; } void SelectSentence(int index) { if (gameOver || waitingNextQuestion) return; if (index < 0 || index >= 4) return; if (selectedOrderByButton[index] > 0) { RemoveSelection(index); return; } if (selectedCount >= 4) return; selectedCount++; selectedOrderByButton[index] = selectedCount; ApplySelectedVisual(index); } void ForceSelectSentence(int index) { if (index < 0 || index >= 4) return; if (selectedOrderByButton[index] > 0) return; if (selectedCount >= 4) return; selectedCount++; selectedOrderByButton[index] = selectedCount; ApplySelectedVisual(index); } void RemoveSelection(int index) { int removedOrder = selectedOrderByButton[index]; if (removedOrder <= 0) return; selectedOrderByButton[index] = 0; selectedCount--; for (int i = 0; i < 4; i++) { if (selectedOrderByButton[i] > removedOrder) selectedOrderByButton[i]--; } RefreshSelectionVisuals(); } void RefreshSelectionVisuals() { for (int i = 0; i < 4; i++) { if (sentenceButtons[i] == null) continue; sentenceButtons[i].transform.localScale = originalButtonScales[i]; if (sentenceButtons[i].image != null) sentenceButtons[i].image.color = FullAlpha(normalButtonColor); if (sentenceTexts[i] != null) sentenceTexts[i].text = baseButtonTexts[i]; if (selectedOrderByButton[i] > 0) ApplySelectedVisual(i); } } void ApplySelectedVisual(int index) { if (sentenceButtons[index] != null) { if (sentenceButtons[index].image != null) sentenceButtons[index].image.color = FullAlpha(selectedButtonColor); sentenceButtons[index].transform.localScale = originalButtonScales[index] * 0.94f; } if (sentenceTexts[index] != null) sentenceTexts[index].text = selectedOrderByButton[index] + ". " + baseButtonTexts[index]; } void OnSubmit() { if (gameOver || waitingNextQuestion) return; if (selectedCount < 4) { ShowFeedback(GetText("chooseAll"), wrongButtonColor); return; } waitingNextQuestion = true; if (submitButton != null) submitButton.interactable = false; if (resetButton != null) resetButton.interactable = false; for (int i = 0; i < 4; i++) { if (sentenceButtons[i] != null) sentenceButtons[i].interactable = false; } if (IsCorrectOrder()) CorrectAnswer(); else WrongAnswer(); UpdateScoreUI(); UpdateComboUI(); SaveProgressOnly(); StartCoroutine(NextQuestionDelay()); } bool IsCorrectOrder() { for (int i = 0; i < 4; i++) { int correctOrderNumber = currentOptions[i].correctOrder + 1; if (selectedOrderByButton[i] != correctOrderNumber) return false; } return true; } void CorrectAnswer() { for (int i = 0; i < 4; i++) { if (sentenceButtons[i] != null && sentenceButtons[i].image != null) sentenceButtons[i].image.color = FullAlpha(correctButtonColor); } combo++; correctCount++; if (combo > bestComboThisRun) bestComboThisRun = combo; int earned = Mathf.RoundToInt(basePoints * GetComboMultiplier(combo)); score += earned; timeLeft += correctTimeBonus; ShowFeedback(GetText("correct") + " +" + earned, correctButtonColor); for (int i = 0; i < 4; i++) StartCoroutine(ButtonPop(sentenceButtons[i])); } void WrongAnswer() { for (int i = 0; i < 4; i++) { int correctOrderNumber = currentOptions[i].correctOrder + 1; bool thisButtonCorrect = selectedOrderByButton[i] == correctOrderNumber; if (sentenceButtons[i] != null && sentenceButtons[i].image != null) sentenceButtons[i].image.color = FullAlpha(thisButtonCorrect ? correctButtonColor : wrongButtonColor); if (sentenceTexts[i] != null) sentenceTexts[i].text = correctOrderNumber + ". " + baseButtonTexts[i]; } wrongCount++; combo = 0; score -= wrongPenalty; if (score < 0) score = 0; ShowFeedback(GetText("wrong"), wrongButtonColor); } IEnumerator NextQuestionDelay() { yield return new WaitForSeconds(nextQuestionDelay); if (!gameOver) NextQuestion(); } void OnExtraTime() { if (!extraTimeReady || gameOver) return; timeLeft += extraTimeAmount; extraTimeReady = false; if (extraTimeButton != null) extraTimeButton.interactable = false; StartCoroutine(Cooldown(extraTimeCooldownText, extraTimeButton, () => extraTimeReady = true)); } void OnExtraHint() { if (!extraHintReady || gameOver || waitingNextQuestion) return; for (int i = 0; i < 4; i++) { if (selectedOrderByButton[i] <= 0) continue; int correctOrderNumber = currentOptions[i].correctOrder + 1; if (selectedOrderByButton[i] != correctOrderNumber) { ShowFeedback(GetText("hintReset"), wrongButtonColor); return; } } if (selectedCount < 4) { int neededCorrectOrder = selectedCount; for (int i = 0; i < 4; i++) { if (currentOptions[i].correctOrder == neededCorrectOrder && selectedOrderByButton[i] == 0) { ForceSelectSentence(i); ShowFeedback(GetText("hint"), Color.white); break; } } } extraHintReady = false; if (extraHintButton != null) extraHintButton.interactable = false; StartCoroutine(Cooldown(extraHintCooldownText, extraHintButton, () => extraHintReady = true)); } void OnExtraSkip() { if (!extraSkipReady || gameOver || waitingNextQuestion) return; combo = 0; UpdateComboUI(); ShowFeedback(GetText("skipped"), Color.white); NextQuestion(); extraSkipReady = false; if (extraSkipButton != null) extraSkipButton.interactable = false; StartCoroutine(Cooldown(extraSkipCooldownText, extraSkipButton, () => extraSkipReady = true)); } IEnumerator Cooldown(TMP_Text label, Button button, System.Action done) { float t = cooldownDuration; if (label != null) label.gameObject.SetActive(true); while (t > 0) { if (label != null) label.text = Mathf.CeilToInt(t).ToString(); t -= Time.deltaTime; yield return null; } if (label != null) { label.text = ""; label.gameObject.SetActive(false); } if (button != null) button.interactable = true; done?.Invoke(); } void SaveProgressOnly() { PlayerPrefs.SetInt("Mod27Skor", score); PlayerPrefs.SetInt("Mod27Score", score); PlayerPrefs.SetInt("Mod27Correct", correctCount); PlayerPrefs.SetInt("Mod27Wrong", wrongCount); PlayerPrefs.SetInt(modKey + "_LastScore", score); PlayerPrefs.SetInt(modKey + "_Correct", correctCount); PlayerPrefs.SetInt(modKey + "_Wrong", wrongCount); PlayerPrefs.SetInt(modKey + "_LastCombo", combo); PlayerPrefs.SetInt(modKey + "_BestComboRun", bestComboThisRun); PlayerPrefs.SetInt(modKey + "_LastTimeLeft", Mathf.CeilToInt(timeLeft)); int total = correctCount + wrongCount; int accuracy = total > 0 ? Mathf.RoundToInt((correctCount / (float)total) * 100f) : 0; PlayerPrefs.SetInt(modKey + "_LastAccuracy", accuracy); if (score > PlayerPrefs.GetInt(modKey + "_MaxScore", 0)) PlayerPrefs.SetInt(modKey + "_MaxScore", score); if (score > PlayerPrefs.GetInt("Mod27LeaderScore", 0)) PlayerPrefs.SetInt("Mod27LeaderScore", score); if (score > PlayerPrefs.GetInt("Mod27BestScore", 0)) PlayerPrefs.SetInt("Mod27BestScore", score); if (bestComboThisRun > PlayerPrefs.GetInt(modKey + "_BestCombo", 0)) PlayerPrefs.SetInt(modKey + "_BestCombo", bestComboThisRun); PlayerPrefs.Save(); } void GameOver() { if (gameOver) return; gameOver = true; SaveProgressOnly(); PlayerPrefs.SetString("LastPlayedMod", modKey); PlayerPrefs.SetInt(modKey + "_TotalCorrect", PlayerPrefs.GetInt(modKey + "_TotalCorrect", 0) + correctCount); PlayerPrefs.SetInt(modKey + "_TotalWrong", PlayerPrefs.GetInt(modKey + "_TotalWrong", 0) + wrongCount); PlayerPrefs.SetInt(modKey + "_PlayCount", PlayerPrefs.GetInt(modKey + "_PlayCount", 0) + 1); PlayerPrefs.SetInt("TotalScore", PlayerPrefs.GetInt("TotalScore", 0) + score); PlayerPrefs.Save(); SceneManager.LoadScene(resultSceneName); } void UpdateScoreUI() { if (scoreText != null) scoreText.text = score.ToString(); } void UpdateComboUI() { if (comboText != null) comboText.text = combo + "x"; } void UpdateTimerUI() { if (timerText == null) return; timerText.text = Mathf.CeilToInt(timeLeft).ToString(); if (timeLeft <= 10f) timerText.color = Color.red; else timerText.color = Color.white; } void ShowFeedback(string msg, Color color) { if (feedbackText == null) return; feedbackText.text = msg; feedbackText.color = FullAlpha(color); StopCoroutine(nameof(FeedbackAnim)); StartCoroutine(nameof(FeedbackAnim)); } float GetComboMultiplier(int c) { if (c >= 8) return mult_8plus; if (c >= 5) return mult_5to7; if (c >= 3) return mult_3to4; return mult_1to2; } IEnumerator FeedbackAnim() { if (feedbackText == null) yield break; Vector3 normal = Vector3.one; Vector3 big = Vector3.one * 1.15f; feedbackText.transform.localScale = normal; float t = 0f; while (t < 1f) { t += Time.deltaTime / 0.15f; feedbackText.transform.localScale = Vector3.Lerp(normal, big, t); yield return null; } t = 0f; while (t < 1f) { t += Time.deltaTime / 0.15f; feedbackText.transform.localScale = Vector3.Lerp(big, normal, t); yield return null; } feedbackText.transform.localScale = normal; } IEnumerator ButtonPop(Button button) { if (button == null) yield break; Vector3 normal = button.transform.localScale; Vector3 big = normal * 1.12f; float t = 0f; while (t < 1f) { t += Time.deltaTime / 0.12f; button.transform.localScale = Vector3.Lerp(normal, big, t); yield return null; } t = 0f; while (t < 1f) { t += Time.deltaTime / 0.12f; button.transform.localScale = Vector3.Lerp(big, normal, t); yield return null; } button.transform.localScale = normal; } IEnumerator SentencesPopAnim() { for (int i = 0; i < 4; i++) { if (sentenceButtons[i] == null) continue; sentenceButtons[i].transform.localScale = originalButtonScales[i] * 0.92f; } float t = 0f; while (t < 1f) { t += Time.deltaTime / 0.18f; for (int i = 0; i < 4; i++) { if (sentenceButtons[i] == null) continue; sentenceButtons[i].transform.localScale = Vector3.Lerp(originalButtonScales[i] * 0.92f, originalButtonScales[i], t); } yield return null; } for (int i = 0; i < 4; i++) { if (sentenceButtons[i] != null) sentenceButtons[i].transform.localScale = originalButtonScales[i]; } } Color FullAlpha(Color color) { color.a = 1f; return color; } void Shuffle(List list) { for (int i = 0; i < list.Count; i++) { int randomIndex = Random.Range(i, list.Count); T temp = list[i]; list[i] = list[randomIndex]; list[randomIndex] = temp; } } }