extends VBoxContainer const Style := preload("res://scripts/ui/ui_style.gd") var main: Control var score_label: Label var summary_label: Label var category_list: VBoxContainer var outcome_score: SpinBox var outcome_date: LineEdit var outcome_consent: CheckBox var outcome_status: Label var outcome_delete_button: Button var current_simulation := {} func _ready() -> void: set_anchors_preset(Control.PRESET_FULL_RECT) add_theme_constant_override("separation", 12) var eyebrow := Label.new() eyebrow.text = "STEP 3 DAY 1 SIMULATION COMPLETE" Style.set_label(eyebrow, 14, Style.CYAN) add_child(eyebrow) score_label = Label.new() Style.set_label(score_label, 36, Style.LIME) add_child(score_label) summary_label = Label.new() summary_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART Style.set_label(summary_label, 17, Style.TEXT) add_child(summary_label) var scroll := ScrollContainer.new() scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL add_child(scroll) var content := VBoxContainer.new() content.size_flags_horizontal = Control.SIZE_EXPAND_FILL content.add_theme_constant_override("separation", 10) scroll.add_child(content) var category_heading := Label.new() category_heading.text = "Performance by content area" Style.set_label(category_heading, 22, Style.TEXT) content.add_child(category_heading) category_list = VBoxContainer.new() content.add_child(category_list) var review_button := Button.new() review_button.text = "Review Questions" review_button.custom_minimum_size = Vector2(240, 50) review_button.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN Style.style_primary_button(review_button) review_button.pressed.connect(func(): main.show_screen("simulation_review", current_simulation)) content.add_child(review_button) var outcome_heading := Label.new() outcome_heading.text = "Help calibrate future predictions" Style.set_label(outcome_heading, 22, Style.TEXT) content.add_child(outcome_heading) var outcome_note := Label.new() outcome_note.text = "After receiving your official result, you may voluntarily submit it. You can edit or delete it at any time; calibration uses de-identified aggregates." outcome_note.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART Style.set_label(outcome_note, 15, Style.MUTED) content.add_child(outcome_note) var outcome_row := HBoxContainer.new() outcome_row.add_theme_constant_override("separation", 10) content.add_child(outcome_row) outcome_score = SpinBox.new() outcome_score.min_value = 1 outcome_score.max_value = 300 outcome_score.value = 200 outcome_score.custom_minimum_size = Vector2(120, 44) outcome_row.add_child(outcome_score) outcome_date = LineEdit.new() outcome_date.placeholder_text = "Exam date: YYYY-MM-DD" outcome_date.custom_minimum_size = Vector2(220, 44) outcome_row.add_child(outcome_date) outcome_consent = CheckBox.new() outcome_consent.text = "I consent to calibration use" outcome_row.add_child(outcome_consent) var save_outcome := Button.new() save_outcome.text = "Save outcome" Style.style_chip(save_outcome, Style.CYAN) save_outcome.pressed.connect(_save_outcome) outcome_row.add_child(save_outcome) outcome_delete_button = Button.new() outcome_delete_button.text = "Delete outcome" Style.style_chip(outcome_delete_button, Style.RED) outcome_delete_button.pressed.connect(ExamSimulationService.delete_outcome) outcome_row.add_child(outcome_delete_button) outcome_status = Label.new() Style.set_label(outcome_status, 15, Style.MUTED) content.add_child(outcome_status) if not ExamSimulationService.outcome_changed.is_connected(_refresh_outcome): ExamSimulationService.outcome_changed.connect(_refresh_outcome) var done := Button.new() done.text = "Return to study modes" done.custom_minimum_size = Vector2(240, 50) done.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN Style.style_primary_button(done) done.pressed.connect(func(): main.show_screen("selection", "step3")) add_child(done) func on_show(payload: Variant = null) -> void: var simulation: Dictionary = payload if typeof(payload) == TYPE_DICTIONARY else ExamSimulationService.simulation current_simulation = simulation var score: Dictionary = simulation.get("score", {}) var predicted := int(score.get("predictedScore", 0)) var low := int(score.get("rangeLow", 0)) var high := int(score.get("rangeHigh", 0)) var probability := int(round(float(score.get("passProbability", 0.0)) * 100.0)) score_label.text = "Predicted Step 3 score: %d (%d-%d)" % [predicted, low, high] summary_label.text = "%d/%d correct | Estimated probability of reaching 200: %d%% | Previously seen questions: %d\nThis provisional educational estimate is not an official USMLE or NBME score and excludes CCS performance." % [ int(score.get("correct", 0)), int(score.get("total", 0)), probability, int(score.get("seenCount", 0))] _clear(category_list) for category in score.get("categories", {}): var value: Dictionary = score["categories"][category] var label := Label.new() label.text = "%s: %d/%d" % [category, int(value.get("correct", 0)), int(value.get("total", 0))] Style.set_label(label, 16, Style.TEXT) category_list.add_child(label) ExamSimulationService.load_outcome() func _clear(container: Control) -> void: for child in container.get_children(): child.queue_free() func _save_outcome() -> void: if not outcome_consent.button_pressed: outcome_status.text = "Consent is required before saving an outcome." return if outcome_date.text.length() != 10: outcome_status.text = "Enter the exam date as YYYY-MM-DD." return ExamSimulationService.save_outcome(int(outcome_score.value), outcome_date.text) outcome_status.text = "Saving..." func _refresh_outcome() -> void: if ExamSimulationService.outcome.is_empty(): outcome_status.text = "No official outcome is stored." outcome_delete_button.visible = false return outcome_score.value = int(ExamSimulationService.outcome.get("officialScore", 200)) outcome_date.text = str(ExamSimulationService.outcome.get("examDate", "")).left(10) outcome_consent.button_pressed = true outcome_delete_button.visible = true outcome_status.text = "Official outcome saved."