using UnityEngine; using UnityEngine.UI; using TMPro; using UnityEngine.SceneManagement; using System.Collections; using System.Collections.Generic; public class DialogueComplete22Mod : MonoBehaviour { [Header("DATA")] public TextAsset wordFile; public string wordsResourcePath = "Mod22Words"; [Header("MAIN DIALOGUE TEXT")] [Tooltip("Ekranda kısa diyalog burada gösterilecek.")] public TMP_Text dialogueText; [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("OPTIONAL TEXTS")] public TMP_Text questionCounterText; public TMP_Text accuracyText; public TMP_Text streakText; [Header("ANSWER BUTTONS")] public Button[] answerButtons; public TMP_Text[] answerTexts; [Header("MAIN BUTTONS")] public Button submitButton; 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 22"; public string resultSceneName = "modres 22"; [Header("LANGUAGE TEST")] [Tooltip("-1 otomatik. 0 TR, 1 EN, 2 ES, 3 DE, 4 FR, 5 PT | QuestionLangID = ekrandaki diyalog dili")] public int forcedQuestionLanguageIndex = -1; [Tooltip("-1 otomatik. 0 TR, 1 EN, 2 ES, 3 DE, 4 FR, 5 PT | AnswerLangID = şıklardaki cevap dili")] public int forcedAnswerLanguageIndex = -1; [Header("GAME SETTINGS")] public float startTime = 60f; public bool useSelectedGameTime = true; public int basePoints = 50; public int wrongPenalty = 50; public float correctTimeBonus = 2f; public float wrongTimePenalty = 0f; public float nextQuestionDelay = 1.05f; [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, 245); public Color selectedButtonColor = new Color32(165, 115, 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, 170); readonly string[] langNames = { "Türkçe", "English", "Español", "Deutsch", "Français", "Português" }; const string modKey = "Mod22"; class DialogueEntry { public string[] dialogues = new string[6]; // Her dil için 4 cevap şıkkı: // 0 doğru // 1 yanlış // 2 yanlış // 3 yanlış public string[] options = new string[24]; public int sourceLine; } readonly List allQuestions = new List(); readonly List questionPool = new List(); DialogueEntry currentQuestion; int screenLangIndex = 1; int optionLangIndex = 0; int selectedAnswer = -1; int correctAnswerIndex = -1; int questionNumber = 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; void Awake() { LoadQuestions(); } void Start() { ResolveLanguages(); timeLeft = startTime; if (useSelectedGameTime) { float selectedTime = PlayerPrefs.GetFloat("SelectedGameTime", startTime); if (selectedTime > 0f) timeLeft = selectedTime; } if (timeLeft <= 0f) timeLeft = 60f; if (!ValidateRequiredReferences()) return; if (allQuestions.Count < 1) { Debug.LogError("Mod22: Geçerli soru yok. TXT dosyası 30 alanlı satırlardan oluşmalı."); enabled = false; return; } PrepareUI(); BindButtons(); ResetQuestionPool(); UpdateLanguageUI(); UpdateScoreUI(); UpdateComboUI(); UpdateTimerUI(); UpdateExtraStatsUI(); NextQuestion(); Debug.Log("Mod22 Diyalog Dili: " + screenLangIndex + " / " + langNames[screenLangIndex]); Debug.Log("Mod22 Şık Dili: " + optionLangIndex + " / " + langNames[optionLangIndex]); Debug.Log("Mod22 Toplam Soru: " + allQuestions.Count); } void Update() { if (gameOver) return; timeLeft -= Time.deltaTime; if (timeLeft <= 0f) { timeLeft = 0f; UpdateTimerUI(); GameOver(); return; } UpdateTimerUI(); } bool ValidateRequiredReferences() { if (dialogueText == null) { Debug.LogError("Mod22: dialogueText atanmadı."); enabled = false; return false; } if (answerButtons == null || answerButtons.Length < 4) { Debug.LogError("Mod22: En az 4 answerButtons atanmalı."); enabled = false; return false; } if (answerTexts == null || answerTexts.Length < 4) { Debug.LogError("Mod22: En az 4 answerTexts atanmalı."); enabled = false; return false; } for (int i = 0; i < 4; i++) { if (answerButtons[i] == null) { Debug.LogError("Mod22: answerButtons[" + i + "] boş."); enabled = false; return false; } if (answerTexts[i] == null) { Debug.LogError("Mod22: answerTexts[" + i + "] boş."); enabled = false; return false; } } return true; } // TXT FORMAT: // 0-5 diyalog: // trDialogue|enDialogue|esDialogue|deDialogue|frDialogue|ptDialogue // // 6-29 cevap şıkları: // trCorrect|trWrong1|trWrong2|trWrong3 // enCorrect|enWrong1|enWrong2|enWrong3 // esCorrect|esWrong1|esWrong2|esWrong3 // deCorrect|deWrong1|deWrong2|deWrong3 // frCorrect|frWrong1|frWrong2|frWrong3 // ptCorrect|ptWrong1|ptWrong2|ptWrong3 void LoadQuestions() { allQuestions.Clear(); TextAsset txt = wordFile; if (txt == null) txt = Resources.Load(wordsResourcePath); if (txt == null) { Debug.LogError("Mod22: TXT bulunamadı. Şuraya koy: Assets/Resources/" + wordsResourcePath + ".txt"); return; } string[] lines = txt.text.Split( new[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries ); int skipped = 0; for (int i = 0; i < lines.Length; i++) { string line = lines[i].Trim(); if (string.IsNullOrWhiteSpace(line)) continue; if (line.StartsWith("#")) continue; string[] p = SplitLineSmart(line); if (p.Length < 30) { skipped++; Debug.LogWarning("Mod22 TXT eksik satır atlandı. Satır: " + (i + 1) + " Alan sayısı: " + p.Length + " / Gerekli: 30"); continue; } DialogueEntry entry = new DialogueEntry(); entry.sourceLine = i + 1; bool valid = true; for (int l = 0; l < 6; l++) { entry.dialogues[l] = CleanField(p[l]); if (string.IsNullOrWhiteSpace(entry.dialogues[l])) valid = false; } for (int q = 0; q < 24; q++) { entry.options[q] = CleanField(p[6 + q]); if (string.IsNullOrWhiteSpace(entry.options[q])) valid = false; } if (!valid) { skipped++; Debug.LogWarning("Mod22 TXT boş alan içerdiği için satır atlandı. Satır: " + (i + 1)); continue; } allQuestions.Add(entry); } Debug.Log("Mod22 yüklenen soru sayısı: " + allQuestions.Count + " | Atlanan satır: " + skipped); } string[] SplitLineSmart(string line) { if (line.Contains("|")) return line.Split('|'); if (line.Contains("\t")) return line.Split('\t'); return line.Split(','); } string CleanField(string s) { if (string.IsNullOrEmpty(s)) return ""; return s.Trim() .Trim('"') .Trim() .Replace("\\n", "\n") .Replace("[blank]", "____") .Replace(" ", " "); } void ResolveLanguages() { if (forcedQuestionLanguageIndex >= 0 && forcedQuestionLanguageIndex <= 5) screenLangIndex = forcedQuestionLanguageIndex; else screenLangIndex = PlayerPrefs.GetInt("QuestionLangID", 1); if (forcedAnswerLanguageIndex >= 0 && forcedAnswerLanguageIndex <= 5) optionLangIndex = forcedAnswerLanguageIndex; else optionLangIndex = PlayerPrefs.GetInt("AnswerLangID", 0); screenLangIndex = ClampLanguage(screenLangIndex, 1); optionLangIndex = ClampLanguage(optionLangIndex, 0); } int ClampLanguage(int value, int fallback) { if (value < 0 || value > 5) return fallback; return value; } public void RefreshLanguagesFromPrefs() { ResolveLanguages(); UpdateLanguageUI(); if (currentQuestion != null && !gameOver) RefreshCurrentQuestion(); } public void SetQuestionLanguage(int id) { if (id < 0 || id > 5) return; screenLangIndex = id; PlayerPrefs.SetInt("QuestionLangID", id); PlayerPrefs.SetString("QuestionLangCode", ToCode(id)); PlayerPrefs.Save(); UpdateLanguageUI(); RefreshCurrentQuestion(); } public void SetAnswerLanguage(int id) { if (id < 0 || id > 5) return; optionLangIndex = id; PlayerPrefs.SetInt("AnswerLangID", id); PlayerPrefs.SetString("AnswerLangCode", 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("dialogueLabel").ToUpper() + ": " + langNames[screenLangIndex] + " | " + GetText("answerLabel").ToUpper() + ": " + langNames[optionLangIndex]; } if (titleText != null) titleText.text = GetTitleText(); } string GetTitleText() { switch (optionLangIndex) { case 0: return "Eksik Cevabı Tamamla"; case 1: return "Complete the Missing Reply"; case 2: return "Completa la respuesta faltante"; case 3: return "Ergänze die fehlende Antwort"; case 4: return "Complète la réponse manquante"; case 5: return "Complete a resposta que falta"; default: return "Complete the Missing Reply"; } } string GetText(string key) { int lang = optionLangIndex; if (key == "choose") { if (lang == 0) return "BİR CEVAP SEÇ"; if (lang == 1) return "CHOOSE AN ANSWER"; if (lang == 2) return "ELIGE UNA RESPUESTA"; if (lang == 3) return "WÄHLE EINE ANTWORT"; if (lang == 4) return "CHOISIS UNE RÉPONSE"; if (lang == 5) return "ESCOLHA UMA RESPOSTA"; } if (key == "correct") { if (lang == 0) return "DOĞRU"; if (lang == 1) return "CORRECT"; if (lang == 2) return "CORRECTO"; if (lang == 3) return "RICHTIG"; if (lang == 4) return "CORRECT"; if (lang == 5) return "CORRETO"; } if (key == "wrong") { if (lang == 0) return "YANLIŞ"; if (lang == 1) return "WRONG"; if (lang == 2) return "INCORRECTO"; if (lang == 3) return "FALSCH"; if (lang == 4) return "FAUX"; if (lang == 5) return "ERRADO"; } if (key == "correctAnswer") { if (lang == 0) return "Doğru cevap"; if (lang == 1) return "Correct answer"; if (lang == 2) return "Respuesta correcta"; if (lang == 3) return "Richtige Antwort"; if (lang == 4) return "Bonne réponse"; if (lang == 5) return "Resposta correta"; } if (key == "dialogueLabel") { if (screenLangIndex == 0) return "Diyalog"; if (screenLangIndex == 1) return "Dialogue"; if (screenLangIndex == 2) return "Diálogo"; if (screenLangIndex == 3) return "Dialog"; if (screenLangIndex == 4) return "Dialogue"; if (screenLangIndex == 5) return "Diálogo"; } if (key == "answerLabel") { if (lang == 0) return "Cevap"; if (lang == 1) return "Answer"; if (lang == 2) return "Respuesta"; if (lang == 3) return "Antwort"; if (lang == 4) return "Réponse"; if (lang == 5) return "Resposta"; } 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"; } if (key == "hint") { if (lang == 0) return "İPUCU KULLANILDI"; if (lang == 1) return "HINT USED"; if (lang == 2) return "PISTA USADA"; if (lang == 3) return "HINWEIS GENUTZT"; if (lang == 4) return "INDICE UTILISÉ"; if (lang == 5) return "DICA USADA"; } return key; } void PrepareUI() { if (dialogueText != null) { dialogueText.alignment = TextAlignmentOptions.Center; dialogueText.textWrappingMode = TextWrappingModes.Normal; } if (feedbackText != null) { feedbackText.text = ""; feedbackText.alignment = TextAlignmentOptions.Center; feedbackText.textWrappingMode = TextWrappingModes.Normal; } originalButtonScales = new Vector3[answerButtons.Length]; originalButtonPositions = new Vector3[answerButtons.Length]; for (int i = 0; i < answerButtons.Length; i++) { if (answerButtons[i] == null) continue; originalButtonScales[i] = answerButtons[i].transform.localScale; originalButtonPositions[i] = answerButtons[i].transform.localPosition; answerButtons[i].transition = Selectable.Transition.None; if (answerButtons[i].image != null) answerButtons[i].image.color = 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 (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 < answerButtons.Length; i++) { int index = i; if (answerButtons[i] == null) continue; answerButtons[i].onClick.RemoveAllListeners(); answerButtons[i].onClick.AddListener(() => SelectAnswer(index)); } } void ResetQuestionPool() { questionPool.Clear(); questionPool.AddRange(allQuestions); Shuffle(questionPool); } void NextQuestion() { if (gameOver) return; if (questionPool.Count <= 0) ResetQuestionPool(); currentQuestion = questionPool[0]; questionPool.RemoveAt(0); questionNumber++; RefreshCurrentQuestion(); } void RefreshCurrentQuestion() { if (currentQuestion == null) return; waitingNextQuestion = false; selectedAnswer = -1; correctAnswerIndex = -1; ResetButtons(); string dialogueValue = currentQuestion.dialogues[screenLangIndex]; string correctAnswer = GetOption(currentQuestion, optionLangIndex, 0); if (dialogueText != null) dialogueText.text = GetText("dialogueLabel") + ":\n" + dialogueValue; List options = new List(); for (int i = 0; i < 4; i++) { string option = GetOption(currentQuestion, optionLangIndex, i); if (!string.IsNullOrWhiteSpace(option) && !options.Contains(option)) options.Add(option); } while (options.Count < 4) options.Add("?"); Shuffle(options); correctAnswerIndex = options.IndexOf(correctAnswer); if (correctAnswerIndex < 0) { correctAnswerIndex = 0; options[0] = correctAnswer; } for (int i = 0; i < 4; i++) { if (answerTexts[i] != null) answerTexts[i].text = options[i]; } if (feedbackText != null) feedbackText.text = ""; if (submitButton != null) submitButton.interactable = true; UpdateExtraStatsUI(); StartCoroutine(DialoguePopAnim()); } string GetOption(DialogueEntry entry, int langIndex, int optionIndex) { int index = langIndex * 4 + optionIndex; if (index < 0 || index >= entry.options.Length) return ""; return entry.options[index]; } void ResetButtons() { for (int i = 0; i < answerButtons.Length; i++) { if (answerButtons[i] == null) continue; answerButtons[i].interactable = true; answerButtons[i].transform.localScale = originalButtonScales[i]; answerButtons[i].transform.localPosition = originalButtonPositions[i]; if (answerButtons[i].image != null) answerButtons[i].image.color = normalButtonColor; if (i < answerTexts.Length && answerTexts[i] != null) answerTexts[i].text = ""; } } void SelectAnswer(int index) { if (gameOver || waitingNextQuestion) return; if (index < 0 || index >= answerButtons.Length) return; if (answerButtons[index] == null || !answerButtons[index].interactable) return; selectedAnswer = index; for (int i = 0; i < answerButtons.Length; i++) { if (answerButtons[i] == null) continue; if (answerButtons[i].image != null && answerButtons[i].interactable) answerButtons[i].image.color = normalButtonColor; answerButtons[i].transform.localScale = originalButtonScales[i]; } if (answerButtons[index].image != null) answerButtons[index].image.color = selectedButtonColor; answerButtons[index].transform.localScale = originalButtonScales[index] * 0.96f; } void OnSubmit() { if (gameOver || waitingNextQuestion) return; if (selectedAnswer < 0) { ShowFeedback(GetText("choose"), wrongButtonColor); return; } waitingNextQuestion = true; if (submitButton != null) submitButton.interactable = false; for (int i = 0; i < answerButtons.Length; i++) { if (answerButtons[i] != null) answerButtons[i].interactable = false; } if (selectedAnswer == correctAnswerIndex) CorrectAnswer(); else WrongAnswer(); UpdateScoreUI(); UpdateComboUI(); UpdateExtraStatsUI(); SaveProgressOnly(); StartCoroutine(NextQuestionDelay()); } void CorrectAnswer() { if (answerButtons[selectedAnswer].image != null) answerButtons[selectedAnswer].image.color = correctButtonColor; combo++; correctCount++; if (combo > bestComboThisRun) bestComboThisRun = combo; int earned = Mathf.RoundToInt(basePoints * GetComboMultiplier(combo)); score += earned; timeLeft += correctTimeBonus; ShowFeedback(GetText("correct") + " +" + earned, correctButtonColor); StartCoroutine(ButtonPop(answerButtons[selectedAnswer])); } void WrongAnswer() { if (answerButtons[selectedAnswer].image != null) answerButtons[selectedAnswer].image.color = wrongButtonColor; if (correctAnswerIndex >= 0 && correctAnswerIndex < answerButtons.Length) { if (answerButtons[correctAnswerIndex].image != null) answerButtons[correctAnswerIndex].image.color = correctButtonColor; } wrongCount++; combo = 0; score -= wrongPenalty; if (score < 0) score = 0; if (wrongTimePenalty > 0f) { timeLeft -= wrongTimePenalty; if (timeLeft < 0f) timeLeft = 0f; } string correctText = ""; if (correctAnswerIndex >= 0 && correctAnswerIndex < answerTexts.Length && answerTexts[correctAnswerIndex] != null) correctText = answerTexts[correctAnswerIndex].text; ShowFeedback(GetText("wrong") + "\n" + GetText("correctAnswer") + ": " + correctText, wrongButtonColor); StartCoroutine(ButtonShake(answerButtons[selectedAnswer])); } 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; int removed = 0; for (int i = 0; i < answerButtons.Length && removed < 2; i++) { if (i == correctAnswerIndex) continue; if (i == selectedAnswer) continue; if (answerButtons[i] == null) continue; if (!answerButtons[i].interactable) continue; answerButtons[i].interactable = false; if (answerButtons[i].image != null) answerButtons[i].image.color = disabledButtonColor; if (answerTexts != null && i < answerTexts.Length && answerTexts[i] != null) answerTexts[i].text = "—"; removed++; } ShowFeedback(GetText("hint"), Color.white); 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("Mod22Skor", score); PlayerPrefs.SetInt("Mod22Score", score); PlayerPrefs.SetInt("Mod22Correct", correctCount); PlayerPrefs.SetInt("Mod22Wrong", 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("Mod22LeaderScore", 0)) PlayerPrefs.SetInt("Mod22LeaderScore", score); if (score > PlayerPrefs.GetInt("Mod22BestScore", 0)) PlayerPrefs.SetInt("Mod22BestScore", 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 UpdateExtraStatsUI() { int total = correctCount + wrongCount; int accuracy = total > 0 ? Mathf.RoundToInt((correctCount / (float)total) * 100f) : 0; if (questionCounterText != null) questionCounterText.text = questionNumber + " / " + allQuestions.Count; if (accuracyText != null) accuracyText.text = "%" + accuracy; if (streakText != null) streakText.text = bestComboThisRun.ToString(); } 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 = 0; while (t < 1) { t += Time.deltaTime / 0.15f; feedbackText.transform.localScale = Vector3.Lerp(normal, big, t); yield return null; } t = 0; while (t < 1) { t += Time.deltaTime / 0.15f; feedbackText.transform.localScale = Vector3.Lerp(big, normal, t); yield return null; } feedbackText.transform.localScale = normal; } IEnumerator ButtonPop(Button btn) { if (btn == null) yield break; Vector3 normal = btn.transform.localScale; Vector3 big = normal * 1.12f; float t = 0; while (t < 1) { t += Time.deltaTime / 0.10f; btn.transform.localScale = Vector3.Lerp(normal, big, t); yield return null; } t = 0; while (t < 1) { t += Time.deltaTime / 0.10f; btn.transform.localScale = Vector3.Lerp(big, normal, t); yield return null; } btn.transform.localScale = normal; } IEnumerator ButtonShake(Button btn) { if (btn == null) yield break; Vector3 original = btn.transform.localPosition; float duration = 0.20f; float elapsed = 0f; float power = 8f; while (elapsed < duration) { elapsed += Time.deltaTime; float x = Mathf.Sin(elapsed * 80f) * power; btn.transform.localPosition = original + new Vector3(x, 0f, 0f); yield return null; } btn.transform.localPosition = original; } IEnumerator DialoguePopAnim() { if (dialogueText == null) yield break; Vector3 normal = Vector3.one; Vector3 small = Vector3.one * 0.92f; dialogueText.transform.localScale = small; float t = 0; while (t < 1) { t += Time.deltaTime / 0.16f; dialogueText.transform.localScale = Vector3.Lerp(small, normal, t); yield return null; } dialogueText.transform.localScale = normal; } Color FullAlpha(Color c) { c.a = 1f; return c; } void Shuffle(List list) { for (int i = 0; i < list.Count; i++) { int rnd = Random.Range(i, list.Count); T temp = list[i]; list[i] = list[rnd]; list[rnd] = temp; } } }