starOfWords/Assets/Scripts/4.0/game/PronunciationMatch29Mod.cs
portakal ecb1c9edea Initial commit: Star of Words Unity project
Snapshot of the existing Unity 6 language-learning word game before any
refactoring. Adds Unity .gitignore and .gitattributes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 15:31:20 +03:00

1128 lines
31 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.SceneManagement;
using System.Collections;
using System.Collections.Generic;
public class PronunciationMatch29Mod : MonoBehaviour
{
[Header("DATA")]
public TextAsset wordFile;
public string wordsResourcePath = "Mod29Words";
[Header("PRONUNCIATION TEXTS")]
[Tooltip("Ekranda okunuş ipucu burada gösterilecek.")]
public TMP_Text pronunciationText;
[Tooltip("Oyuncuya verilecek yönerge burada gösterilecek.")]
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("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 29";
public string resultSceneName = "modres 29";
[Header("LANGUAGE TEST")]
[Tooltip("-1 otomatik. 0 TR, 1 EN, 2 ES, 3 DE, 4 FR, 5 PT | QuestionLangID = okunuş ve yönerge dili")]
public int forcedQuestionLanguageIndex = -1;
[Tooltip("-1 otomatik. 0 TR, 1 EN, 2 ES, 3 DE, 4 FR, 5 PT | AnswerLangID = şıkların dili")]
public int forcedAnswerLanguageIndex = -1;
[Header("GAME SETTINGS")]
public float startTime = 60f;
public int basePoints = 50;
public int wrongPenalty = 50;
public float correctTimeBonus = 2f;
public float nextQuestionDelay = 1.25f;
[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 = "Mod29";
class PronunciationEntry
{
public string[] pronunciations = new string[6];
public string[] instructions = new string[6];
// Her dil için 4 şık:
// 0 doğru
// 1 yanlış
// 2 yanlış
// 3 yanlış
public string[] options = new string[24];
}
readonly List<PronunciationEntry> allQuestions = new List<PronunciationEntry>();
readonly List<PronunciationEntry> questionPool = new List<PronunciationEntry>();
PronunciationEntry currentQuestion;
int pronunciationLangIndex = 1;
int optionLangIndex = 0;
int selectedAnswer = -1;
int correctAnswerIndex = -1;
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 = PlayerPrefs.GetFloat("SelectedGameTime", startTime);
if (timeLeft <= 0f)
timeLeft = startTime;
if (allQuestions.Count < 1)
{
Debug.LogError("Mod29: En az 1 geçerli TXT satırı gerekli. Yüklenen soru sayısı: " + allQuestions.Count);
enabled = false;
return;
}
if (pronunciationText == null)
{
Debug.LogError("Mod29: pronunciationText atanmadı.");
enabled = false;
return;
}
if (instructionText == null)
{
Debug.LogError("Mod29: instructionText atanmadı.");
enabled = false;
return;
}
if (answerButtons == null || answerButtons.Length < 4 || answerTexts == null || answerTexts.Length < 4)
{
Debug.LogError("Mod29: 4 answerButtons ve 4 answerTexts atanmalı.");
enabled = false;
return;
}
PrepareUI();
BindButtons();
ResetQuestionPool();
UpdateLanguageUI();
UpdateScoreUI();
UpdateComboUI();
UpdateTimerUI();
NextQuestion();
Debug.Log("Mod29 Okunuş Dili: " + pronunciationLangIndex + " / " + langNames[pronunciationLangIndex]);
Debug.Log("Mod29 Şık Dili: " + optionLangIndex + " / " + langNames[optionLangIndex]);
}
void Update()
{
if (gameOver)
return;
timeLeft -= Time.deltaTime;
if (timeLeft <= 0f)
{
timeLeft = 0f;
UpdateTimerUI();
GameOver();
return;
}
UpdateTimerUI();
}
// TXT FORMAT:
// 0-5 okunuş ipucu:
// trPronunciation|enPronunciation|esPronunciation|dePronunciation|frPronunciation|ptPronunciation
//
// 6-11 görev / yönerge:
// trInstruction|enInstruction|esInstruction|deInstruction|frInstruction|ptInstruction
//
// 12-35 cevap şıkları:
// trCorrectWord|trWrong1|trWrong2|trWrong3
// enCorrectWord|enWrong1|enWrong2|enWrong3
// esCorrectWord|esWrong1|esWrong2|esWrong3
// deCorrectWord|deWrong1|deWrong2|deWrong3
// frCorrectWord|frWrong1|frWrong2|frWrong3
// ptCorrectWord|ptWrong1|ptWrong2|ptWrong3
void LoadQuestions()
{
allQuestions.Clear();
TextAsset txt = wordFile;
if (txt == null)
txt = Resources.Load<TextAsset>(wordsResourcePath);
if (txt == null)
{
Debug.LogError("Mod29: TXT bulunamadı. Şuraya koy: 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[] p = SplitLineSmart(line);
if (p.Length < 36)
{
Debug.LogWarning("Mod29 TXT eksik satır atlandı. Satır: " + (i + 1) + " Alan sayısı: " + p.Length);
continue;
}
PronunciationEntry entry = new PronunciationEntry();
bool valid = true;
for (int l = 0; l < 6; l++)
{
entry.pronunciations[l] = CleanField(p[l]);
if (string.IsNullOrWhiteSpace(entry.pronunciations[l]))
valid = false;
}
for (int l = 0; l < 6; l++)
{
entry.instructions[l] = CleanField(p[6 + l]);
if (string.IsNullOrWhiteSpace(entry.instructions[l]))
valid = false;
}
for (int q = 0; q < 24; q++)
{
entry.options[q] = CleanField(p[12 + q]);
if (string.IsNullOrWhiteSpace(entry.options[q]))
valid = false;
}
if (valid)
allQuestions.Add(entry);
}
Debug.Log("Mod29 yüklenen soru sayısı: " + allQuestions.Count);
}
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]", "____");
}
void ResolveLanguages()
{
// QuestionLangID = ekrandaki okunuş ve yönerge dili
// AnswerLangID = şıklardaki cevap dili
if (forcedQuestionLanguageIndex >= 0 && forcedQuestionLanguageIndex <= 5)
pronunciationLangIndex = forcedQuestionLanguageIndex;
else
pronunciationLangIndex = PlayerPrefs.GetInt("QuestionLangID", 1);
if (forcedAnswerLanguageIndex >= 0 && forcedAnswerLanguageIndex <= 5)
optionLangIndex = forcedAnswerLanguageIndex;
else
optionLangIndex = PlayerPrefs.GetInt("AnswerLangID", 0);
pronunciationLangIndex = ClampLanguage(pronunciationLangIndex, 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;
pronunciationLangIndex = 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 =
"OKUNUŞ: " + langNames[pronunciationLangIndex] +
" | CEVAP: " + langNames[optionLangIndex];
}
if (titleText != null)
titleText.text = GetTitleText();
}
string GetTitleText()
{
switch (optionLangIndex)
{
case 0: return "Okunuştan Kelimeyi Bul";
case 1: return "Find the Word from Pronunciation";
case 2: return "Encuentra la palabra por pronunciación";
case 3: return "Finde das Wort nach Aussprache";
case 4: return "Trouve le mot par la prononciation";
case 5: return "Encontre a palavra pela pronúncia";
default: return "Find the Word from Pronunciation";
}
}
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 == "pronunciationLabel")
{
if (pronunciationLangIndex == 0) return "Okunuş";
if (pronunciationLangIndex == 1) return "Pronunciation";
if (pronunciationLangIndex == 2) return "Pronunciación";
if (pronunciationLangIndex == 3) return "Aussprache";
if (pronunciationLangIndex == 4) return "Prononciation";
if (pronunciationLangIndex == 5) return "Pronúncia";
}
if (key == "instructionLabel")
{
if (pronunciationLangIndex == 0) return "Görev";
if (pronunciationLangIndex == 1) return "Task";
if (pronunciationLangIndex == 2) return "Tarea";
if (pronunciationLangIndex == 3) return "Aufgabe";
if (pronunciationLangIndex == 4) return "Tâche";
if (pronunciationLangIndex == 5) return "Tarefa";
}
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 (pronunciationText != null)
{
pronunciationText.alignment = TextAlignmentOptions.Center;
pronunciationText.textWrappingMode = TextWrappingModes.Normal;
}
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[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 = 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 (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);
RefreshCurrentQuestion();
}
void RefreshCurrentQuestion()
{
if (currentQuestion == null)
return;
waitingNextQuestion = false;
selectedAnswer = -1;
correctAnswerIndex = -1;
ResetButtons();
string pronunciationValue = currentQuestion.pronunciations[pronunciationLangIndex];
string instructionValue = currentQuestion.instructions[pronunciationLangIndex];
string correctAnswer = GetOption(currentQuestion, optionLangIndex, 0);
if (pronunciationText != null)
pronunciationText.text = GetText("pronunciationLabel") + ":\n" + pronunciationValue;
if (instructionText != null)
instructionText.text = GetText("instructionLabel") + ":\n" + instructionValue;
List<string> options = new List<string>();
for (int i = 0; i < 4; i++)
{
string option = GetOption(currentQuestion, optionLangIndex, i);
if (!string.IsNullOrWhiteSpace(option))
options.Add(option);
}
while (options.Count < 4)
options.Add("?");
Shuffle(options);
correctAnswerIndex = options.IndexOf(correctAnswer);
if (correctAnswerIndex < 0)
correctAnswerIndex = 0;
for (int i = 0; i < 4; i++)
{
if (answerTexts != null && i < answerTexts.Length && answerTexts[i] != null)
answerTexts[i].text = options[i];
}
if (feedbackText != null)
feedbackText.text = "";
if (submitButton != null)
submitButton.interactable = true;
StartCoroutine(MainTextPopAnim());
}
string GetOption(PronunciationEntry 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 = FullAlpha(normalButtonColor);
if (answerTexts != null && i < answerTexts.Length && answerTexts[i] != null)
answerTexts[i].text = "";
}
}
void SelectAnswer(int index)
{
if (gameOver || waitingNextQuestion)
return;
selectedAnswer = index;
for (int i = 0; i < answerButtons.Length; i++)
{
if (answerButtons[i] == null)
continue;
if (answerButtons[i].image != null)
answerButtons[i].image.color = FullAlpha(normalButtonColor);
answerButtons[i].transform.localScale = originalButtonScales[i];
}
if (answerButtons[index].image != null)
answerButtons[index].image.color = FullAlpha(selectedButtonColor);
answerButtons[index].transform.localScale = originalButtonScales[index] * 0.94f;
}
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();
SaveProgressOnly();
StartCoroutine(NextQuestionDelay());
}
void CorrectAnswer()
{
if (answerButtons[selectedAnswer].image != null)
answerButtons[selectedAnswer].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);
StartCoroutine(ButtonPop(answerButtons[selectedAnswer]));
}
void WrongAnswer()
{
if (answerButtons[selectedAnswer].image != null)
answerButtons[selectedAnswer].image.color = FullAlpha(wrongButtonColor);
if (correctAnswerIndex >= 0 && correctAnswerIndex < answerButtons.Length)
{
if (answerButtons[correctAnswerIndex].image != null)
answerButtons[correctAnswerIndex].image.color = FullAlpha(correctButtonColor);
}
wrongCount++;
combo = 0;
score -= wrongPenalty;
if (score < 0)
score = 0;
string correctText = "";
if (correctAnswerIndex >= 0 && correctAnswerIndex < answerTexts.Length && answerTexts[correctAnswerIndex] != null)
correctText = answerTexts[correctAnswerIndex].text;
ShowFeedback(GetText("wrong") + "\n" + GetText("correctAnswer") + ": " + correctText, 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;
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 = FullAlpha(disabledButtonColor);
if (answerTexts != null && i < answerTexts.Length && answerTexts[i] != null)
answerTexts[i].text = "—";
removed++;
}
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("Mod29Skor", score);
PlayerPrefs.SetInt("Mod29Score", score);
PlayerPrefs.SetInt("Mod29Correct", correctCount);
PlayerPrefs.SetInt("Mod29Wrong", 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("Mod29LeaderScore", 0))
PlayerPrefs.SetInt("Mod29LeaderScore", score);
if (score > PlayerPrefs.GetInt("Mod29BestScore", 0))
PlayerPrefs.SetInt("Mod29BestScore", 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 = 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.12f;
btn.transform.localScale = Vector3.Lerp(normal, big, t);
yield return null;
}
t = 0;
while (t < 1)
{
t += Time.deltaTime / 0.12f;
btn.transform.localScale = Vector3.Lerp(big, normal, t);
yield return null;
}
btn.transform.localScale = normal;
}
IEnumerator MainTextPopAnim()
{
if (pronunciationText == null)
yield break;
Vector3 normal = Vector3.one;
Vector3 small = Vector3.one * 0.92f;
pronunciationText.transform.localScale = small;
if (instructionText != null)
instructionText.transform.localScale = small;
float t = 0;
while (t < 1)
{
t += Time.deltaTime / 0.18f;
pronunciationText.transform.localScale = Vector3.Lerp(small, normal, t);
if (instructionText != null)
instructionText.transform.localScale = Vector3.Lerp(small, normal, t);
yield return null;
}
pronunciationText.transform.localScale = normal;
if (instructionText != null)
instructionText.transform.localScale = normal;
}
Color FullAlpha(Color c)
{
c.a = 1f;
return c;
}
void Shuffle<T>(List<T> 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;
}
}
}