initial commit

This commit is contained in:
mr0xb 2025-12-27 00:20:33 -05:00
commit 94847a50a2
42 changed files with 2063 additions and 0 deletions

View file

@ -0,0 +1,48 @@
extends PanelContainer
signal answer_submitted(is_correct: bool)
@onready var question_label = $MarginContainer/VBoxContainer/QuestionPanel/MarginContainer/QuestionLabel
@onready var answer_panel = $MarginContainer/VBoxContainer/AnswerPanel
@onready var answer_label = $MarginContainer/VBoxContainer/AnswerPanel/MarginContainer/AnswerLabel
@onready var show_answer_btn = $MarginContainer/VBoxContainer/Controls/ShowAnswerButton
@onready var rating_buttons = $MarginContainer/VBoxContainer/Controls/RatingButtons
@onready var incorrect_btn = $MarginContainer/VBoxContainer/Controls/RatingButtons/IncorrectButton
@onready var correct_btn = $MarginContainer/VBoxContainer/Controls/RatingButtons/CorrectButton
var current_card: Flashcard
var answer_revealed: bool = false
func _ready() -> void:
show_answer_btn.pressed.connect(_on_show_answer_pressed)
incorrect_btn.pressed.connect(_on_incorrect_pressed)
correct_btn.pressed.connect(_on_correct_pressed)
answer_panel.hide()
rating_buttons.hide()
func set_card(card: Flashcard) -> void:
current_card = card
answer_revealed = false
question_label.text = card.question_text
question_label.modulate = card.question_color
answer_label.text = card.answer_text
answer_label.modulate = card.answer_color
answer_panel.hide()
rating_buttons.hide()
show_answer_btn.show()
func _on_show_answer_pressed() -> void:
answer_revealed = true
answer_panel.show()
show_answer_btn.hide()
rating_buttons.show()
func _on_incorrect_pressed() -> void:
answer_submitted.emit(false)
func _on_correct_pressed() -> void:
answer_submitted.emit(true)

View file

@ -0,0 +1 @@
uid://lobty8kshx4c

View file

@ -0,0 +1,83 @@
[gd_scene load_steps=2 format=3 uid="uid://b4nnkfplcdxkp"]
[ext_resource type="Script" path="res://scenes/ui/quiz_mode/flashcard_display.gd" id="1_8xp2n"]
[node name="FlashcardDisplay" type="PanelContainer"]
custom_minimum_size = Vector2(600, 400)
script = ExtResource("1_8xp2n")
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 2
theme_override_constants/margin_left = 30
theme_override_constants/margin_top = 30
theme_override_constants/margin_right = 30
theme_override_constants/margin_bottom = 30
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
layout_mode = 2
theme_override_constants/separation = 20
[node name="QuestionPanel" type="PanelContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/QuestionPanel"]
layout_mode = 2
theme_override_constants/margin_left = 20
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 20
theme_override_constants/margin_bottom = 20
[node name="QuestionLabel" type="Label" parent="MarginContainer/VBoxContainer/QuestionPanel/MarginContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 24
text = "Question goes here"
horizontal_alignment = 1
vertical_alignment = 1
autowrap_mode = 3
[node name="AnswerPanel" type="PanelContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/AnswerPanel"]
layout_mode = 2
theme_override_constants/margin_left = 20
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 20
theme_override_constants/margin_bottom = 20
[node name="AnswerLabel" type="Label" parent="MarginContainer/VBoxContainer/AnswerPanel/MarginContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 24
text = "Answer goes here"
horizontal_alignment = 1
vertical_alignment = 1
autowrap_mode = 3
[node name="Controls" type="VBoxContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="ShowAnswerButton" type="Button" parent="MarginContainer/VBoxContainer/Controls"]
custom_minimum_size = Vector2(0, 50)
layout_mode = 2
theme_override_font_sizes/font_size = 20
text = "Show Answer"
[node name="RatingButtons" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Controls"]
layout_mode = 2
theme_override_constants/separation = 20
alignment = 1
[node name="IncorrectButton" type="Button" parent="MarginContainer/VBoxContainer/Controls/RatingButtons"]
custom_minimum_size = Vector2(200, 50)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "❌ Incorrect"
[node name="CorrectButton" type="Button" parent="MarginContainer/VBoxContainer/Controls/RatingButtons"]
custom_minimum_size = Vector2(200, 50)
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "✓ Correct"

View file

@ -0,0 +1,67 @@
extends PanelContainer
signal answer_submitted(is_correct: bool)
@onready var question_label = $MarginContainer/VBoxContainer/QuestionPanel/MarginContainer/QuestionLabel
@onready var choices_container = $MarginContainer/VBoxContainer/ChoicesContainer
@onready var feedback_panel = $MarginContainer/VBoxContainer/FeedbackPanel
@onready var feedback_label = $MarginContainer/VBoxContainer/FeedbackPanel/MarginContainer/FeedbackLabel
var current_card: Flashcard
var choice_buttons: Array[Button] = []
var answered: bool = false
func _ready() -> void:
feedback_panel.hide()
func set_card(card: Flashcard) -> void:
current_card = card
answered = false
question_label.text = card.question_text
question_label.modulate = card.question_color
for button in choice_buttons:
button.queue_free()
choice_buttons.clear()
for i in range(card.choices.size()):
var choice = card.choices[i]
var button = Button.new()
button.text = choice.text
button.custom_minimum_size = Vector2(0, 50)
button.add_theme_font_size_override("font_size", 18)
button.pressed.connect(_on_choice_selected.bind(i))
choices_container.add_child(button)
choice_buttons.append(button)
feedback_panel.hide()
func _on_choice_selected(choice_index: int) -> void:
if answered:
return
answered = true
var is_correct = current_card.choices[choice_index].is_correct
for button in choice_buttons:
button.disabled = true
if is_correct:
choice_buttons[choice_index].modulate = Color.GREEN
feedback_label.text = "✓ Correct! " + current_card.answer_text
feedback_panel.self_modulate = Color(0.2, 0.6, 0.2, 1.0)
else:
choice_buttons[choice_index].modulate = Color.RED
var correct_index = current_card.get_correct_choice_index()
if correct_index >= 0:
choice_buttons[correct_index].modulate = Color.GREEN
feedback_label.text = "❌ Incorrect. The answer is: " + current_card.answer_text
feedback_panel.self_modulate = Color(0.6, 0.2, 0.2, 1.0)
feedback_panel.show()
await get_tree().create_timer(2.0).timeout
answer_submitted.emit(is_correct)

View file

@ -0,0 +1 @@
uid://2cccr5qtjk2c

View file

@ -0,0 +1,58 @@
[gd_scene load_steps=2 format=3 uid="uid://b0qexkdgxksek"]
[ext_resource type="Script" path="res://scenes/ui/quiz_mode/multiple_choice_display.gd" id="1_a2ghr"]
[node name="MultipleChoiceDisplay" type="PanelContainer"]
custom_minimum_size = Vector2(600, 400)
script = ExtResource("1_a2ghr")
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 2
theme_override_constants/margin_left = 30
theme_override_constants/margin_top = 30
theme_override_constants/margin_right = 30
theme_override_constants/margin_bottom = 30
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
layout_mode = 2
theme_override_constants/separation = 20
[node name="QuestionPanel" type="PanelContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/QuestionPanel"]
layout_mode = 2
theme_override_constants/margin_left = 20
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 20
theme_override_constants/margin_bottom = 20
[node name="QuestionLabel" type="Label" parent="MarginContainer/VBoxContainer/QuestionPanel/MarginContainer"]
custom_minimum_size = Vector2(0, 80)
layout_mode = 2
theme_override_font_sizes/font_size = 24
text = "Question goes here"
horizontal_alignment = 1
vertical_alignment = 1
autowrap_mode = 3
[node name="ChoicesContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="FeedbackPanel" type="PanelContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/FeedbackPanel"]
layout_mode = 2
theme_override_constants/margin_left = 20
theme_override_constants/margin_top = 15
theme_override_constants/margin_right = 20
theme_override_constants/margin_bottom = 15
[node name="FeedbackLabel" type="Label" parent="MarginContainer/VBoxContainer/FeedbackPanel/MarginContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "Feedback"
horizontal_alignment = 1
autowrap_mode = 3

View file

@ -0,0 +1,95 @@
extends Control
@onready var exit_btn = $MarginContainer/VBoxContainer/Header/ExitButton
@onready var progress_label = $MarginContainer/VBoxContainer/Header/ProgressLabel
@onready var score_label = $MarginContainer/VBoxContainer/ScorePanel/ScoreLabel
@onready var card_container = $MarginContainer/VBoxContainer/CardContainer
var quiz_session: QuizSession
var current_card_display: Node
const FlashcardDisplayScene = preload("res://scenes/ui/quiz_mode/flashcard_display.tscn")
const MultipleChoiceDisplayScene = preload("res://scenes/ui/quiz_mode/multiple_choice_display.tscn")
func _ready() -> void:
exit_btn.pressed.connect(_on_exit_pressed)
func start_quiz(deck: Deck) -> void:
if not deck or deck.cards.is_empty():
push_error("Cannot start quiz with empty or null deck")
return
quiz_session = QuizSession.new()
quiz_session.question_answered.connect(_on_question_answered)
quiz_session.session_completed.connect(_on_session_completed)
quiz_session.progress_updated.connect(_on_progress_updated)
quiz_session.start_session(deck, true)
var progress = DataManager.get_or_create_progress(deck.id)
progress.start_session()
DataManager.save_progress()
_show_next_card()
_update_ui()
func _show_next_card() -> void:
var card = quiz_session.get_current_card()
if not card:
return
if current_card_display:
current_card_display.queue_free()
current_card_display = null
if card.card_type == Flashcard.QuestionType.BASIC:
current_card_display = FlashcardDisplayScene.instantiate()
else:
current_card_display = MultipleChoiceDisplayScene.instantiate()
card_container.add_child(current_card_display)
current_card_display.set_card(card)
current_card_display.answer_submitted.connect(_on_answer_submitted)
func _on_answer_submitted(is_correct: bool) -> void:
var card = quiz_session.get_current_card()
if quiz_session.deck:
DataManager.record_quiz_result(quiz_session.deck.id, card.id, is_correct)
quiz_session.answer_question(is_correct)
func _on_question_answered(is_correct: bool, card: Flashcard) -> void:
await get_tree().create_timer(0.5).timeout
_update_ui()
_show_next_card()
func _on_progress_updated(current: int, total: int) -> void:
_update_ui()
func _on_session_completed(results: Dictionary) -> void:
print("Quiz completed! Results:")
print(" Total: %d" % results.total_questions)
print(" Correct: %d" % results.correct)
print(" Incorrect: %d" % results.incorrect)
print(" Accuracy: %.1f%%" % results.accuracy)
print(" Duration: %.1f seconds" % results.duration_seconds)
await get_tree().create_timer(1.0).timeout
GameManager.return_to_main_menu()
func _update_ui() -> void:
if quiz_session:
progress_label.text = "Card %d / %d" % [
quiz_session.current_index + 1,
quiz_session.shuffled_cards.size()
]
score_label.text = "Score: %d correct, %d incorrect (%.1f%%)" % [
quiz_session.session_correct,
quiz_session.session_incorrect,
quiz_session.get_session_accuracy()
]
func _on_exit_pressed() -> void:
GameManager.return_to_main_menu()

View file

@ -0,0 +1 @@
uid://sfunbafcelku

View file

@ -0,0 +1,57 @@
[gd_scene load_steps=2 format=3 uid="uid://bjldqy3e3m3yj"]
[ext_resource type="Script" path="res://scenes/ui/quiz_mode/quiz_scene.gd" id="1_vu2ha"]
[node name="QuizScene" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_vu2ha")
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 40
theme_override_constants/margin_top = 40
theme_override_constants/margin_right = 40
theme_override_constants/margin_bottom = 40
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
layout_mode = 2
theme_override_constants/separation = 20
[node name="Header" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
[node name="ExitButton" type="Button" parent="MarginContainer/VBoxContainer/Header"]
custom_minimum_size = Vector2(100, 50)
layout_mode = 2
text = "Exit Quiz"
[node name="ProgressLabel" type="Label" parent="MarginContainer/VBoxContainer/Header"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 24
text = "Card 1 / 10"
horizontal_alignment = 1
vertical_alignment = 1
[node name="ScorePanel" type="PanelContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
[node name="ScoreLabel" type="Label" parent="MarginContainer/VBoxContainer/ScorePanel"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "Score: 0 correct, 0 incorrect (0.0%)"
horizontal_alignment = 1
[node name="CardContainer" type="CenterContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3