starOfWords/Assets/Scripts/4.0/game/ParagraphOrder27Mod.cs

1258 lines
33 KiB
C#
Raw Normal View History

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<ParagraphOrderEntry> allQuestions = new List<ParagraphOrderEntry>();
readonly List<ParagraphOrderEntry> questionPool = new List<ParagraphOrderEntry>();
readonly List<SentenceOption> currentOptions = new List<SentenceOption>();
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<TextAsset>(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<T>(List<T> 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;
}
}
}