extends Node const XP_PER_LEVEL := 500 var badge_catalog := { "First Block": "Complete your first question block.", "First Run": "Answer your first core mode question.", "Hot Streak": "Answer 5 questions correctly in a row.", "Tenacious": "Complete 10 total questions.", "Sharp Shooter": "Score at least 80% on a block.", "Clock Ready": "Complete a timed block." } func level_for_xp(xp: int) -> int: return int(floor(float(xp) / float(XP_PER_LEVEL))) + 1 func xp_into_level(xp: int) -> int: return xp % XP_PER_LEVEL func calculate_block_rewards(answers: Array, mode: String, system_name: String) -> Dictionary: var correct := 0 var longest_streak := 0 var running_streak := int(ProfileService.get_profile().get("current_streak", 0)) var ending_streak := running_streak for answer in answers: if bool(answer.get("first_attempt_is_correct", answer.get("is_correct", false))): correct += 1 ending_streak += 1 longest_streak = max(longest_streak, ending_streak) else: ending_streak = 0 var total: int = max(answers.size(), 1) var accuracy := float(correct) / float(total) var xp := answers.size() * 25 + correct * 35 + longest_streak * 10 if accuracy >= 0.8: xp += 100 if mode == "Timed": xp += 50 var profile: Dictionary = ProfileService.get_profile() var badges: Array[String] = [] _add_badge_if_needed(badges, profile, "First Block", true) _add_badge_if_needed(badges, profile, "Hot Streak", longest_streak >= 5) _add_badge_if_needed(badges, profile, "Tenacious", profile.get("completed_question_ids", []).size() + answers.size() >= 10) _add_badge_if_needed(badges, profile, "Sharp Shooter", accuracy >= 0.8) _add_badge_if_needed(badges, profile, "Clock Ready", mode == "Timed") return { "mode": mode, "system": system_name, "correct": correct, "total": answers.size(), "accuracy": accuracy, "xp_earned": xp, "ending_streak": ending_streak, "longest_streak": longest_streak, "badges_unlocked": badges, "answers": answers } func calculate_question_rewards(answer: Dictionary, elapsed_seconds: float, target_seconds: float, score_delta: int) -> Dictionary: var is_correct := bool(answer.get("is_correct", false)) var profile: Dictionary = ProfileService.get_profile() var ending_streak := int(profile.get("current_streak", 0)) + 1 if is_correct else 0 var xp := 20 if is_correct: xp += 35 if elapsed_seconds <= target_seconds: xp += 10 elif elapsed_seconds > target_seconds * 1.5: xp = max(10, xp - 10) var badges: Array[String] = [] _add_badge_if_needed(badges, profile, "First Run", true) _add_badge_if_needed(badges, profile, "Hot Streak", ending_streak >= 5) _add_badge_if_needed(badges, profile, "Tenacious", profile.get("completed_question_ids", []).size() + 1 >= 10) return { "mode": "Core", "system": str(answer.get("question", {}).get("system", "All Systems")), "correct": 1 if is_correct else 0, "total": 1, "accuracy": 1.0 if is_correct else 0.0, "xp_earned": xp, "score_delta": score_delta, "ending_streak": ending_streak, "longest_streak": ending_streak, "badges_unlocked": badges, "answers": [answer] } func _add_badge_if_needed(badges: Array[String], profile: Dictionary, badge_name: String, condition: bool) -> void: if condition and not profile.get("badges", []).has(badge_name): badges.append(badge_name)