0% found this document useful (0 votes)
48 views159 pages

Kuromi Command Center Pygame Code

source code

Uploaded by

preranampkr
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
48 views159 pages

Kuromi Command Center Pygame Code

source code

Uploaded by

preranampkr
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

SOURCE CODE

1. [Link]
# [Link]

import sys, os

ROOT_DIR = [Link]([Link](__file__))

if ROOT_DIR not in [Link]: [Link](0, ROOT_DIR)

for sub in ["learning_centre","quiz_engine","minigames","ui"]:

p=[Link](ROOT_DIR,sub)

2. ui/[Link]
import pygame

# --- Colour palette ---

PINK = (255, 140, 180)

LIGHT_PINK = (255, 182, 193)

DARK_PINK = (199, 21, 133)

WHITE = (255, 255, 255)

SHADOW = (235, 170, 190)


# --- Helper ---

def safe_color(value):

"""Return a valid RGB tuple for pygame."""

presets = {

"pink": PINK,

"light_pink": LIGHT_PINK,

"dark_pink": DARK_PINK,

"white": WHITE,

if isinstance(value, tuple) and len(value) == 3:

return tuple(int(max(0, min(255, c))) for c in value)

if isinstance(value, str):

return [Link]([Link](), WHITE)

return WHITE

# --- Button class ---

class Button:

def __init__(self, text, x, y, w, h,

color=PINK, hover=LIGHT_PINK,
text_color=WHITE, font_name="segoeui", font_size=28,

action=None):

[Link] = text

[Link] = [Link](x, y, w, h)

[Link] = safe_color(color)

[Link] = safe_color(hover)

self.text_color = safe_color(text_color)

[Link] = action

[Link] = h // 2

[Link] = [Link](font_name, font_size, bold=True)

self.shadow_offset = 4

def draw(self, screen):

mouse_pos = [Link].get_pos()

hovered = [Link](mouse_pos)

base_col = [Link] if hovered else [Link]

shadow_rect = [Link]()

shadow_rect.x += self.shadow_offset
shadow_rect.y += self.shadow_offset

[Link](screen, SHADOW, shadow_rect, border_radius=[Link])

[Link](screen, base_col, [Link], border_radius=[Link])

[Link](screen, (255, 220, 230), [Link], width=2,


border_radius=[Link])

try:

txt = [Link]([Link], True, self.text_color)

except Exception:

txt = [Link]("arial", 24).render(str([Link]), True, WHITE)

[Link](

txt,

([Link] - txt.get_width() // 2,

[Link] - txt.get_height() // 2)

def click(self, pos):

if [Link](pos):
print(f"🩷 CLICKED BUTTON: {[Link]}")

if [Link]:

[Link]()

3. ui/simple_scene.py

# F:\hello kitty detectibve gsame\ui\simple_scene.py

import pygame

class SceneBase:

def __init__(self, screen, width, height):

[Link] = screen

[Link] = width

[Link] = height

self.next_scene = None

def handle_event(self, event):

"""Handle pygame events."""

pass
def update(self, dt=0):

"""Update logic per frame. Return scene key if switching."""

return self.next_scene

def draw(self):

"""Draw everything."""

Pass

4. Kuromi Command Center (kuromi_chaos_center_pygame.py)


# kuromi_chaos_center_pygame.py

# One-window Kuromi Command Center (Pygame)

# - Main Menu with two big buttons

# - Progress HQ scene (monitor players + time tracking to daily_activity)

# - Lessons Manager scene (add/view/edit/delete lessons by grade & subject)

# Palette: black + purples + white only

import pygame

import [Link]

import time

from datetime import datetime

# ───────────────────────── CONFIG
─────────────────────────
DB_NAME = "CASE_FILE_0X67"

WIDTH, HEIGHT = 1200, 720

FPS = 60

# Colors (purple/black/white only)

BLACK_PURPLE = (10, 0, 15)

MID_PURPLE = (30, 0, 45)

ROYAL_PURPLE = (80, 0, 110)

GLOW_PURPLE = (140, 80, 190)

LAVENDER = (210, 190, 240)

WHITE = (255, 255, 255)

MUTED = (180, 160, 200)

# ─────────────────────── DB HELPERS
───────────────────────

def db_conn():

try:

return [Link](

host="localhost", user="root", password="Tikku17@#$",

database=DB_NAME, autocommit=True

except Exception as e:

print("DB error:", e)

return None
def ensure_daily_activity():

con = db_conn()

if not con: return

cur = [Link]()

[Link]("""

CREATE TABLE IF NOT EXISTS daily_activity (

id INT AUTO_INCREMENT PRIMARY KEY,

username VARCHAR(100) NOT NULL,

seconds INT NOT NULL DEFAULT 0,

activity_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

""")

[Link](); [Link]()

def fetch_players():

con = db_conn()

if not con: return []

cur = [Link](dictionary=True, buffered=True)

[Link]("SELECT username, coins, completed_levels, last_played FROM


quiz_progress ORDER BY coins DESC, username ASC")

rows = [Link]() or []

[Link](); [Link]()

return rows

def fetch_player(username):
con = db_conn()

if not con: return None

cur = [Link](dictionary=True, buffered=True)

[Link]("SELECT * FROM quiz_progress WHERE username=%s", (username,))

row = [Link]()

[Link](); [Link]()

return row

def update_player(username, **fields):

if not fields: return

parts = [f"{k}=%s" for k in [Link]()]

vals = list([Link]()) + [username]

sql = f"UPDATE quiz_progress SET {', '.join(parts)}, last_played=NOW() WHERE


username=%s"

con = db_conn()

if not con: return

cur = [Link]()

[Link](sql, tuple(vals))

[Link]()

[Link](); [Link]()

def add_activity_seconds(username, seconds):

if not username or seconds <= 0: return

con = db_conn()

if not con: return


cur = [Link]()

[Link]("INSERT INTO daily_activity (username, seconds) VALUES (%s,%s)",


(username, int(seconds)))

[Link]()

[Link](); [Link]()

def minutes_total(username):

con = db_conn()

if not con: return 0

cur = [Link](dictionary=True, buffered=True)

[Link]("SELECT COALESCE(SUM(seconds),0) AS s FROM daily_activity


WHERE username=%s", (username,))

r = [Link]()

[Link](); [Link]()

s = int(r["s"] or 0)

return s // 60

def active_days(username):

con = db_conn()

if not con: return 0

cur = [Link](dictionary=True, buffered=True)

[Link]("SELECT COUNT(DISTINCT DATE(activity_time)) AS d FROM


daily_activity WHERE username=%s", (username,))

r = [Link]()

[Link](); [Link]()

return int(r["d"] or 0)
# Lessons/Grades/Subjects helpers

def fetch_grades():

con = db_conn()

if not con: return []

cur = [Link](dictionary=True, buffered=True)

[Link]("SELECT id, name FROM grades ORDER BY id")

rows = [Link]() or []

[Link](); [Link]()

return rows

def fetch_subjects_by_grade(grade_id):

con = db_conn()

if not con: return []

cur = [Link](dictionary=True, buffered=True)

[Link]("SELECT id, name FROM subjects WHERE grade_id=%s ORDER BY


id", (grade_id,))

rows = [Link]() or []

[Link](); [Link]()

return rows

def fetch_lessons_by_grade(grade_name):

con = db_conn()

if not con: return []

cur = [Link](dictionary=True, buffered=True)


[Link]("""

SELECT [Link], [Link], [Link] AS subject

FROM lessons l

JOIN subjects s ON l.subject_id = [Link]

JOIN grades g ON s.grade_id = [Link]

WHERE [Link]=%s

ORDER BY [Link] DESC

""", (grade_name,))

rows = [Link]() or []

[Link](); [Link]()

return rows

def fetch_lesson(lesson_id):

con = db_conn()

if not con: return None

cur = [Link](dictionary=True, buffered=True)

[Link]("SELECT * FROM lessons WHERE id=%s", (lesson_id,))

row = [Link]()

[Link](); [Link]()

return row

def insert_lesson(title, desc, content, subject_id):

con = db_conn()

if not con: return

cur = [Link]()
[Link]("INSERT INTO lessons (title, description, content, subject_id) VALUES
(%s,%s,%s,%s)",

(title, desc, content, subject_id))

[Link]()

[Link](); [Link]()

def update_lesson(lesson_id, title, desc, content):

con = db_conn()

if not con: return

cur = [Link]()

[Link]("UPDATE lessons SET title=%s, description=%s, content=%s WHERE


id=%s",

(title, desc, content, lesson_id))

[Link]()

[Link](); [Link]()

def delete_lesson(lesson_id):

con = db_conn()

if not con: return

cur = [Link]()

[Link]("DELETE FROM lessons WHERE id=%s", (lesson_id,))

[Link]()

[Link](); [Link]()

# ─────────────────────── UI COMPONENTS
───────────────────────
class PillButton:

def __init__(self, rect, text, font, fill=ROYAL_PURPLE, fg=WHITE):

[Link] = [Link](rect)

[Link] = text

[Link] = font

[Link] = fill

[Link] = fg

[Link] = False

def draw(self, surf):

color = [Link] if not [Link] else tuple(min(255, c+35) for c in [Link])

[Link](surf, color, [Link], border_radius=40)

t = [Link]([Link], True, [Link])

[Link](t, ([Link] - t.get_width()//2, [Link] - t.get_height()//2))

def hit(self, pos): return [Link](pos)

class TextInput:

# simple single-line input

def __init__(self, rect, font, text="", placeholder="", bg=MID_PURPLE, fg=WHITE):

[Link] = [Link](rect)

[Link] = font

[Link] = text

[Link] = placeholder

[Link] = fg

[Link] = bg

[Link] = False
[Link] = len(text)

[Link] = 0

def handle(self, e):

if [Link] == [Link]:

[Link] = [Link]([Link])

if [Link] and [Link] == [Link]:

if [Link] == pygame.K_BACKSPACE and [Link] > 0:

[Link] = [Link][:[Link]-1] + [Link][[Link]:]

[Link] -= 1

elif [Link] == pygame.K_DELETE and [Link] < len([Link]):

[Link] = [Link][:[Link]] + [Link][[Link]+1:]

elif [Link] == pygame.K_LEFT:

[Link] = max(0, [Link]-1)

elif [Link] == pygame.K_RIGHT:

[Link] = min(len([Link]), [Link]+1)

elif [Link] == pygame.K_HOME:

[Link] = 0

elif [Link] == pygame.K_END:

[Link] = len([Link])

elif [Link] == pygame.K_RETURN:

pass

else:

if [Link] and [Link]():

[Link] = [Link][:[Link]] + [Link] + [Link][[Link]:]

[Link] += 1
def draw(self, surf):

[Link](surf, [Link], [Link], border_radius=20)

show = [Link] if [Link] else [Link]

color = [Link] if [Link] else MUTED

t = [Link](show, True, color)

[Link](t, ([Link].x+14, [Link].y+10))

# cursor

[Link] = ([Link] + 1) % 60

if [Link] and [Link] < 30:

cx = [Link].x + 14 + [Link]([Link][:[Link]])[0]

[Link](surf, WHITE, (cx, [Link].y+8), (cx,


[Link].y+[Link]-8), 2)

class TextArea:

# multi-line naive text area (Enter inserts newline)

def __init__(self, rect, font, text="", placeholder="", bg=MID_PURPLE, fg=WHITE):

[Link] = [Link](rect)

[Link] = font

[Link] = [Link]("\n") if text else [""]

[Link] = placeholder

[Link] = fg

[Link] = bg

[Link] = False

self.cursor_row = 0

self.cursor_col = 0
[Link] = 0

def get_text(self): return "\n".join([Link])

def set_text(self, t):

[Link] = [Link]("\n") if t else [""]

self.cursor_row = min(self.cursor_row, len([Link])-1)

self.cursor_col = min(self.cursor_col, len([Link][self.cursor_row]))

def handle(self, e):

if [Link] == [Link]:

[Link] = [Link]([Link])

if [Link] and [Link] == [Link]:

if [Link] == pygame.K_BACKSPACE:

if self.cursor_col > 0:

line = [Link][self.cursor_row]

[Link][self.cursor_row] = line[:self.cursor_col-1] + line[self.cursor_col:]

self.cursor_col -= 1

elif self.cursor_row > 0:

prev_len = len([Link][self.cursor_row-1])

[Link][self.cursor_row-1] += [Link][self.cursor_row]

[Link](self.cursor_row)

self.cursor_row -= 1

self.cursor_col = prev_len

elif [Link] == pygame.K_DELETE:

line = [Link][self.cursor_row]

if self.cursor_col < len(line):

[Link][self.cursor_row] = line[:self.cursor_col] + line[self.cursor_col+1:]


elif self.cursor_row < len([Link])-1:

[Link][self.cursor_row] += [Link][self.cursor_row+1]

[Link](self.cursor_row+1)

elif [Link] == pygame.K_RETURN:

line = [Link][self.cursor_row]

new_line = line[self.cursor_col:]

[Link][self.cursor_row] = line[:self.cursor_col]

[Link](self.cursor_row+1, new_line)

self.cursor_row += 1

self.cursor_col = 0

elif [Link] == pygame.K_LEFT:

if self.cursor_col > 0:

self.cursor_col -= 1

elif self.cursor_row > 0:

self.cursor_row -= 1

self.cursor_col = len([Link][self.cursor_row])

elif [Link] == pygame.K_RIGHT:

if self.cursor_col < len([Link][self.cursor_row]):

self.cursor_col += 1

elif self.cursor_row < len([Link])-1:

self.cursor_row += 1

self.cursor_col = 0

elif [Link] == pygame.K_UP:

if self.cursor_row > 0:

self.cursor_row -= 1
self.cursor_col = min(self.cursor_col, len([Link][self.cursor_row]))

elif [Link] == pygame.K_DOWN:

if self.cursor_row < len([Link])-1:

self.cursor_row += 1

self.cursor_col = min(self.cursor_col, len([Link][self.cursor_row]))

else:

if [Link] and [Link]():

line = [Link][self.cursor_row]

[Link][self.cursor_row] = line[:self.cursor_col] + [Link] +


line[self.cursor_col:]

self.cursor_col += 1

def draw(self, surf):

[Link](surf, [Link], [Link], border_radius=16)

y = [Link].y + 8

if len(self.get_text().strip()) == 0 and not [Link]:

t = [Link]([Link], True, MUTED)

[Link](t, ([Link].x+10, y))

else:

for line in [Link]:

t = [Link](line, True, WHITE)

[Link](t, ([Link].x+10, y))

y += [Link].get_height()+4

# cursor blink

[Link] = ([Link] + 1) % 60

if [Link] and [Link] < 30:


cx = [Link].x + 10 + [Link]([Link][self.cursor_row][:self.cursor_col])
[0]

cy = [Link].y + 8 + self.cursor_row*([Link].get_height()+4)

[Link](surf, WHITE, (cx, cy), (cx, cy+[Link].get_height()), 2)

# ─────────────────────── SCENE SYSTEM


───────────────────────

class SceneBase:

def __init__(self, screen):

[Link] = screen

def handle(self, e): pass

def update(self): pass

def draw(self): pass

# ─────────────────────── MAIN MENU SCENE


────────────────────

class MainMenu(SceneBase):

def __init__(self, screen, goto_progress, goto_lessons):

super().__init__(screen)

[Link]()

[Link] = [Link]("Comic Sans MS", 56, bold=True)

[Link] = [Link]("Comic Sans MS", 26, bold=True)

self.btn_progress = PillButton((WIDTH//2-220, HEIGHT//2-30, 440, 60), "💀


Monitor Player Progress", [Link], ROYAL_PURPLE)

self.btn_lessons = PillButton((WIDTH//2-220, HEIGHT//2+60, 440, 60), "📚


Manage Lessons", [Link], ROYAL_PURPLE)

self.goto_progress = goto_progress
self.goto_lessons = goto_lessons

def handle(self, e):

if [Link] == [Link]:

self.btn_progress.hover = self.btn_progress.hit([Link])

self.btn_lessons.hover = self.btn_lessons.hit([Link])

if [Link] == [Link]:

if self.btn_progress.hit([Link]): self.goto_progress()

if self.btn_lessons.hit([Link]): self.goto_lessons()

def draw(self):

[Link](BLACK_PURPLE)

[Link]([Link], MID_PURPLE, (0, 0, WIDTH, 100))

[Link]([Link], GLOW_PURPLE, (0, 98, WIDTH, 2))

t = [Link]("KUROMI CHAOS CENTER 🖤", True, LAVENDER)

[Link](t, (WIDTH//2 - t.get_width()//2, 24))

# card

[Link]([Link], MID_PURPLE, (WIDTH//2-300, HEIGHT//2-120,


600, 280), border_radius=30)

self.btn_progress.draw([Link])

self.btn_lessons.draw([Link])

hint = [Link]("Choose your domain of mischief…", True, LAVENDER)

[Link](hint, (WIDTH//2 - hint.get_width()//2, HEIGHT//2-150))

# ─────────────────────── PROGRESS HQ SCENE


──────────────────

class ProgressHQ(SceneBase):

def __init__(self, screen, go_back):


super().__init__(screen)

ensure_daily_activity()

self.go_back = go_back

[Link] = [Link]("Comic Sans MS", 40, bold=True)

[Link] = [Link]("Comic Sans MS", 28, bold=True)

[Link] = [Link]("Comic Sans MS", 22)

[Link] = fetch_players()

[Link] = None

[Link] = 0

[Link] = 0 # 0 Progress, 1 Coins, 2 Time, 3 Achievements, 4 Deep

[Link] = []

self.btn_back = PillButton((30, 24, 140, 42), "← Back", [Link],


ROYAL_PURPLE)

# time tracking

self.view_start_ts = None # start time viewing current user

# utility

def _start_tracking(self):

if [Link]:

self.view_start_ts = [Link]()

def _flush_tracking(self):

if [Link] and self.view_start_ts:

secs = int([Link]() - self.view_start_ts)

add_activity_seconds([Link], secs)

self.view_start_ts = None

def handle(self, e):


if [Link] == [Link]:

self.btn_back.hover = self.btn_back.hit([Link])

for _, b in [Link]: [Link] = [Link]([Link])

if [Link] == [Link]:

[Link] = max(0, [Link] - e.y*40)

if [Link] == [Link]:

if self.btn_back.hit([Link]):

self._flush_tracking()

self.go_back()

return

# select player

y = 170 - [Link]

for row in [Link]:

r = [Link](40, y, 330, 50)

if [Link]([Link]):

# flush old user time

self._flush_tracking()

[Link] = row["username"]

self._start_tracking()

return

y += 60

# tabs

if hasattr(self, "tab_rects"):

for r, idx in self.tab_rects:

if [Link]([Link]):
[Link] = idx

return

# actions

if [Link]:

for key, b in [Link]:

if [Link]([Link]):

self._act(key)

return

def _act(self, key):

p = fetch_player([Link])

if not p: return

c = int([Link]("coins",0)); l = int([Link]("completed_levels",0))

t = int([Link]("tools_unlocked",0)); f = int([Link]("finale_unlocked",0))

if key == "lvl+": update_player([Link], completed_levels=min(7, l+1))

if key == "lvl-": update_player([Link], completed_levels=max(0, l-1))

if key == "c+10": update_player([Link], coins=c+10)

if key == "c-10": update_player([Link], coins=max(0, c-10))

if key == "c+100": update_player([Link], coins=c+100)

if key == "c-100": update_player([Link], coins=max(0, c-100))

if key == "toggle_tools": update_player([Link], tools_unlocked=0 if t else 1)

if key == "toggle_finale": update_player([Link], finale_unlocked=0 if f else 1)

if key == "reset": update_player([Link], coins=0, clues_unlocked=0,


tools_unlocked=0, finale_unlocked=0, completed_levels=0)

[Link] = fetch_players()

def draw(self):
[Link](BLACK_PURPLE)

[Link]([Link], MID_PURPLE, (0,0,WIDTH,90))

title = [Link]("💀 KUROMI PROGRESS HQ — Chaos Observatory",


True, LAVENDER)

[Link](title, (WIDTH//2 - title.get_width()//2, 22))

[Link]([Link], GLOW_PURPLE, (0, 88, WIDTH, 2))

self.btn_back.draw([Link])

# left panel: players

[Link]([Link], MID_PURPLE, (20, 110, 380, HEIGHT-140),


border_radius=24)

[Link]([Link]("🎭 Players", True, GLOW_PURPLE), (40, 120))

y = 170 - [Link]

for row in [Link]:

r = [Link](40, y, 340, 50)

col = GLOW_PURPLE if [Link] == row["username"] else


ROYAL_PURPLE

[Link]([Link], col, r, border_radius=40)

t = [Link](f"{row['username']} 💰{row['coins']}", True, WHITE)

[Link](t, (r.x+16, r.y+10))

y += 60

# right panel

[Link]([Link], MID_PURPLE, (420, 110, WIDTH-440, HEIGHT-


140), border_radius=24)

# tabs

self.tab_rects = []

x = 440

tabs = ["🪪 Progress","💰 Coins"," Time","🏆 Achievements","🔮 Deep"]


for i, name in enumerate(tabs):

r = [Link](x, 120, 150, 36)

[Link]([Link], GLOW_PURPLE if [Link]==i else


ROYAL_PURPLE, r, border_radius=30)

tt = [Link](name, True, WHITE)

[Link](tt, ([Link]-tt.get_width()//2, [Link]-tt.get_height()//2))

self.tab_rects.append((r, i))

x += 160

# inner content

inner = [Link](440, 165, WIDTH-480, HEIGHT-200)

[Link]([Link], BLACK_PURPLE, inner, border_radius=20)

if not [Link]:

hint = [Link]("Pick a player to start spying ", True, LAVENDER)

[Link](hint, ([Link] - hint.get_width()//2, [Link] - 10))

return

p = fetch_player([Link])

if not p:

[Link]([Link]("⚠️Player not found", True, WHITE),


(inner.x+20, inner.y+20))

return

if [Link] == 0: self._tab_progress(inner, p)

elif [Link] == 1: self._tab_coins(inner, p)

elif [Link] == 2: self._tab_time(inner, p)

elif [Link] == 3: self._tab_achievements(inner, p)

elif [Link] == 4: self._tab_deep(inner, p)

def _tab_progress(self, area, p):


x, y = area.x+20, area.y+20

lines = [

f"🪪 {p['username']}",

f"✅ Levels: {p['completed_levels']}/7",

f"🧩 Clues: {p['clues_unlocked']}",

f"🪄 Tools: {'ON' if p['tools_unlocked'] else 'OFF'}",

f"🌟 Finale: {'Unlocked' if p['finale_unlocked'] else 'Locked'}",

f"🕓 Last Played: {str(p['last_played'])[:19]}",

for line in lines:

[Link]([Link](line, True, LAVENDER), (x, y)); y += 42

[Link] = [

("lvl+", PillButton((x, y+10, 140, 44), "+ Level", [Link])),

("lvl-", PillButton((x+150, y+10, 140, 44), "- Level", [Link])),

("toggle_tools", PillButton((x+300, y+10, 180, 44), "Toggle Tools", [Link])),

("toggle_finale", PillButton((x+490, y+10, 200, 44), "Toggle Finale", [Link])),

("reset", PillButton((x, y+70, 220, 44), "💀 Reset Progress", [Link])),

for _, b in [Link]: [Link]([Link])

def _tab_coins(self, area, p):

x, y = area.x+20, area.y+30

[Link]([Link](f"💰 {int(p['coins'])} Coins", True, LAVENDER),


(x, y))

y += 70

[Link] = [
("c+10", PillButton((x, y, 130, 44), "+10", [Link])),

("c-10", PillButton((x+140, y, 130, 44), "-10", [Link])),

("c+100", PillButton((x+280, y, 130, 44), "+100", [Link])),

("c-100", PillButton((x+420, y, 130, 44), "-100", [Link])),

for _, b in [Link]: [Link]([Link])

def _tab_time(self, area, p):

x, y = area.x+20, area.y+20

mins = minutes_total([Link])

hrs, mm = mins//60, mins%60

days = active_days([Link])

lines = [

" TIME SPENT",

f"Total: {hrs}h {mm}m ({mins} minutes)",

f"Active Days: {days}",

"Time auto-logs while this player's page is open."

cols = [LAVENDER, WHITE, WHITE, MUTED]

for i, line in enumerate(lines):

[Link]([Link](line, True, cols[i]), (x, y)); y += 48

# progress bar (10h full)

barw = min(640, max(20, int((mins/600.0)*640)))

[Link]([Link], ROYAL_PURPLE, (x, y+10, 640, 20),


border_radius=10)

[Link]([Link], GLOW_PURPLE, (x, y+10, barw, 20),


border_radius=10)
def _tab_achievements(self, area, p):

x, y = area.x+20, area.y+20

mins = minutes_total([Link]); days = active_days([Link])

ach = [

("🎀 Clue Hunter", p["clues_unlocked"]>=1),

(" Toolsmith", p["tools_unlocked"]==1),

("💀 Apprentice", p["completed_levels"]>=1),

("👑 Grade Crusher", p["completed_levels"]>=4),

("🌟 Finale Finder", p["finale_unlocked"]==1),

("💰 Rich Kitty", p["coins"]>=100),

(" Loyal Detective", days>=7),

("📚 Study Buddy", mins>=120),

("🧠 Marathon Mind", mins>=600),

for name, ok in ach:

mark = "✅" if ok else "▫"

col = LAVENDER if ok else MUTED

[Link]([Link](f"{mark} {name}", True, col), (x, y))

y += 38

def _tab_deep(self, area, p):

x, y = area.x+20, area.y+20

keys =
["username","coins","clues_unlocked","tools_unlocked","finale_unlocked","completed_l
evels","last_played"]

for k in keys:

v = [Link](k)
[Link]([Link](f"{k}: {v}", True, LAVENDER), (x, y)); y += 36

# ───────────────────── LESSONS MANAGER SCENE


───────────────────

class LessonsManager(SceneBase):

def __init__(self, screen, go_back):

super().__init__(screen)

self.go_back = go_back

[Link] = [Link]("Comic Sans MS", 40, bold=True)

[Link] = [Link]("Comic Sans MS", 28, bold=True)

[Link] = [Link]("Comic Sans MS", 22)

[Link] = [Link]("Comic Sans MS", 20)

# data

[Link] = fetch_grades()

self.selected_grade_idx = 0 if [Link] else -1

[Link] = []

[Link] = []

self.selected_lesson_id = None

# controls

self.btn_back = PillButton((30, 24, 140, 42), "← Back", [Link],


ROYAL_PURPLE)

self.btn_refresh = PillButton((WIDTH-180, 24, 140, 42), "↻ Refresh", [Link],


ROYAL_PURPLE)

self._load_grade_related()

# modals

[Link] = None # ("add", widgets) or ("edit", lesson_id, widgets)


def _load_grade_related(self):

if self.selected_grade_idx < 0 or self.selected_grade_idx >= len([Link]):

[Link], [Link] = [], []

return

g = [Link][self.selected_grade_idx]

[Link] = fetch_subjects_by_grade(g["id"])

[Link] = fetch_lessons_by_grade(g["name"])

self.selected_lesson_id = None

def handle(self, e):

if [Link]:

self._handle_modal(e); return

if [Link] == [Link]:

self.btn_back.hover = self.btn_back.hit([Link])

self.btn_refresh.hover = self.btn_refresh.hit([Link])

if [Link] == [Link]:

if self.btn_back.hit([Link]): self.go_back(); return

if self.btn_refresh.hit([Link]): self._load_grade_related(); return

# grade chips

gx, gy = 40, 120

for i, g in enumerate([Link]):

r = [Link](gx, gy, 140, 36)

if [Link]([Link]):

self.selected_grade_idx = i

self._load_grade_related()

return
gx += 150

if gx > WIDTH-200: gx, gy = 40, gy+46

# lessons list click

area = [Link](30, 200, 500, HEIGHT-230)

if [Link]([Link]):

rel_y = [Link][1] - area.y

idx = rel_y // 48

if 0 <= idx < len([Link]):

self.selected_lesson_id = [Link][idx]["id"]

# action buttons

ax = 560; ay = 200

btns = [

("add", [Link](ax, ay, 180, 44)),

("edit", [Link](ax+200, ay, 180, 44)),

("delete", [Link](ax+400, ay, 180, 44)),

for k, r in btns:

if [Link]([Link]):

if k == "add": self._open_add_modal()

if k == "edit" and self.selected_lesson_id:


self._open_edit_modal(self.selected_lesson_id)

if k == "delete" and self.selected_lesson_id:


delete_lesson(self.selected_lesson_id); self._load_grade_related()

return

def draw(self):

[Link](BLACK_PURPLE)
[Link]([Link], MID_PURPLE, (0,0,WIDTH,90))

t = [Link]("📚 KUROMI LESSONS LAB — Rewrite Reality", True,


LAVENDER)

[Link](t, (WIDTH//2 - t.get_width()//2, 22))

[Link]([Link], GLOW_PURPLE, (0, 88, WIDTH, 2))

self.btn_back.draw([Link]); self.btn_refresh.draw([Link])

# grade chips

[Link]([Link]("🎓 Grades", True, GLOW_PURPLE), (30, 100))

gx, gy = 40, 140

for i, g in enumerate([Link]):

r = [Link](gx, gy, 140, 36)

[Link]([Link], GLOW_PURPLE if i==self.selected_grade_idx


else ROYAL_PURPLE, r, border_radius=30)

tt = [Link](g["name"], True, WHITE)

[Link](tt, ([Link]-tt.get_width()//2, [Link]-tt.get_height()//2))

gx += 150

if gx > WIDTH-200: gx, gy = 40, gy+46

# lessons list

list_area = [Link](30, 200, 500, HEIGHT-230)

[Link]([Link], MID_PURPLE, list_area, border_radius=16)

[Link]([Link]("🧾 Lessons", True, LAVENDER), (40, 210))

y = 250

for row in [Link]:

line = f"#{row['id']} — {row['title']} | {row['subject']}"

col = GLOW_PURPLE if self.selected_lesson_id == row["id"] else WHITE

[Link]([Link](line, True, col), (40, y)); y += 48


# action buttons

ax, ay = 560, 200

for label, off in [("➕ Add Lesson",0), ("✏️Edit Lesson",200), (" Delete
Lesson",400)]:

[Link]([Link], ROYAL_PURPLE, (ax+off, ay, 180, 44),


border_radius=30)

tt = [Link](label, True, WHITE)

[Link](tt, (ax+off+90-tt.get_width()//2, ay+22-tt.get_height()//2))

# subject hint

if self.selected_grade_idx >= 0 and [Link]:

g = [Link][self.selected_grade_idx]

subs = ", ".join(s["name"] for s in [Link]) if [Link] else "No subjects


(add in DB)"

[Link]([Link](f"📂 Subjects in {g['name']}: {subs}", True,


MUTED), (560, 260))

# modal

if [Link]: self._draw_modal()

# ── Modals (Add/Edit) ──

def _open_add_modal(self):

if self.selected_grade_idx < 0: return

g = [Link][self.selected_grade_idx]

subs = [Link]

if not subs: return

[Link] = ("add", {

"title": TextInput((150, 240, 500, 44), [Link], "", "Title"),

"desc": TextArea((150, 300, 500, 100), [Link], "", "Short description"),


"content": TextArea((150, 410, 500, 180), [Link], "", "Lesson content (quiz
source)"),

"subject_index": 0,

"subjects": subs,

"grade": g

})

def _open_edit_modal(self, lesson_id):

row = fetch_lesson(lesson_id)

if not row: return

# find subject index within current grade list

subj_idx = 0

subs = [Link]

for i, s in enumerate(subs):

if s["id"] == row["subject_id"]:

subj_idx = i; break

[Link] = ("edit", lesson_id, {

"title": TextInput((150, 240, 500, 44), [Link], row["title"], "Title"),

"desc": TextArea((150, 300, 500, 100), [Link], row["description"], "Short


description"),

"content": TextArea((150, 410, 500, 180), [Link], row["content"], "Lesson


content (quiz source)"),

"subject_index": subj_idx,

"subjects": subs

})

def _handle_modal(self, e):

kind = [Link][0]
if kind == "add":

widgets = [Link][1]

for w in (widgets["title"], widgets["desc"], widgets["content"]): [Link](e)

if [Link] == [Link]:

# subject dropdown simple cycling on click area

drop = [Link](150, 205, 300, 28)

if [Link]([Link]):

widgets["subject_index"] = (widgets["subject_index"] + 1) %
max(1,len(widgets["subjects"]))

# buttons

save = [Link](150, 610, 180, 44)

cancel = [Link](370, 610, 180, 44)

if [Link]([Link]):

title = widgets["title"].[Link]()

desc = widgets["desc"].get_text().strip()

content = widgets["content"].get_text().strip()

if title and desc and content and widgets["subjects"]:

subject_id = widgets["subjects"][widgets["subject_index"]]["id"]

insert_lesson(title, desc, content, subject_id)

[Link] = None

self._load_grade_related()

if [Link]([Link]):

[Link] = None

elif kind == "edit":

lesson_id, widgets = [Link][1], [Link][2]


for w in (widgets["title"], widgets["desc"], widgets["content"]): [Link](e)

if [Link] == [Link]:

drop = [Link](150, 205, 300, 28)

if [Link]([Link]):

widgets["subject_index"] = (widgets["subject_index"] + 1) %
max(1,len(widgets["subjects"]))

save = [Link](150, 610, 180, 44)

cancel = [Link](370, 610, 180, 44)

if [Link]([Link]):

title = widgets["title"].[Link]()

desc = widgets["desc"].get_text().strip()

content = widgets["content"].get_text().strip()

# Note: we keep subject the same grade scope; if needed you can also update
subject_id here

if title and desc and content:

update_lesson(lesson_id, title, desc, content)

[Link] = None

self._load_grade_related()

if [Link]([Link]):

[Link] = None

def _draw_modal(self):

# overlay

overlay = [Link]((WIDTH, HEIGHT), [Link])

[Link]((0,0,0,160))

[Link](overlay, (0,0))

box = [Link](120, 120, WIDTH-240, HEIGHT-200)


[Link]([Link], MID_PURPLE, box, border_radius=24)

[Link]([Link], GLOW_PURPLE, box, 2, border_radius=24)

kind = [Link][0]

title = "➕ Add Lesson" if kind=="add" else "✏️Edit Lesson"

tt = [Link](title, True, LAVENDER)

[Link](tt, ([Link] - tt.get_width()//2, 140))

if kind == "add":

widgets = [Link][1]

# subject chooser

subs = widgets["subjects"]; idx = widgets["subject_index"]

subj_name = subs[idx]["name"] if subs else "No subjects"

tag = [Link](f"Subject: {subj_name}", True, LAVENDER)

[Link]([Link], ROYAL_PURPLE, (150, 205, 300, 28),


border_radius=14)

[Link](tag, (160, 206))

widgets["title"].draw([Link])

widgets["desc"].draw([Link])

widgets["content"].draw([Link])

# buttons

for (x,label) in [(150,"Save"), (370,"Cancel")]:

[Link]([Link], ROYAL_PURPLE, (x, 610, 180, 44),


border_radius=30)

t = [Link](label, True, WHITE)

[Link](t, (x+90 - t.get_width()//2, 632 - t.get_height()//2))

elif kind == "edit":

lesson_id, widgets = [Link][1], [Link][2]


subs = widgets["subjects"]; idx = widgets["subject_index"]

subj_name = subs[idx]["name"] if subs else "No subjects"

tag = [Link](f"Subject: {subj_name}", True, LAVENDER)

[Link]([Link], ROYAL_PURPLE, (150, 205, 300, 28),


border_radius=14)

[Link](tag, (160, 206))

widgets["title"].draw([Link])

widgets["desc"].draw([Link])

widgets["content"].draw([Link])

for (x,label) in [(150,"Save"), (370,"Cancel")]:

[Link]([Link], ROYAL_PURPLE, (x, 610, 180, 44),


border_radius=30)

t = [Link](label, True, WHITE)

[Link](t, (x+90 - t.get_width()//2, 632 - t.get_height()//2))

# ─────────────────────── APP BOOTSTRAP


───────────────────────

class App:

def __init__(self):

[Link]()

[Link] = [Link].set_mode((WIDTH, HEIGHT))

[Link].set_caption("💀 Kuromi Chaos Center — One Window of Cute


Doom")

[Link] = [Link]()

[Link] = None

self.main_menu()

def main_menu(self):
[Link] = MainMenu(

[Link],

goto_progress=lambda: self.progress_hq(),

goto_lessons=lambda: self.lessons_lab()

def progress_hq(self):

[Link] = ProgressHQ([Link], go_back=self.main_menu)

def lessons_lab(self):

[Link] = LessonsManager([Link], go_back=self.main_menu)

def run(self):

running = True

while running:

for e in [Link]():

if [Link] == [Link]: running = False

else: [Link](e)

[Link]()

[Link]()

[Link](FPS)

[Link]()

if __name__ == "__main__":

ensure_daily_activity()

App().run()kuromi_chaos_center_pygame.py CODE HERE>


5. Quiz UI (quiz_ui.py)

import pygame

import random

import time

import [Link]

import pathfix

from ui.simple_scene import SceneBase

from learning_centre.ending import EndingScene # 🩷 cinematic finale

# ───────────────────────────────────────────────

# HELLO KITTY DETECTIVE QUIZ — Sequential Unlock Build

# ───────────────────────────────────────────────

GRADE_ORDER = [

{"name": "My Melody", "grade": 6, "color": (255,182,193)},


{"name": "Keroppi", "grade": 7, "color": (152,251,152)},

{"name": "Pochacco", "grade": 8, "color": (255,255,153)},

{"name": "Badtz-Maru", "grade": 9, "color": (176,196,222)},

{"name": "Cinnamoroll", "grade": 10, "color": (173,216,230)},

{"name": "Kuromi", "grade": 11, "color": (216,191,216)},

{"name": "Chococat", "grade": 12, "color": (139,69,19)},

FINALE = {"name": "Hello Kitty", "grade": "Finale", "color": (255,192,203)}

CLUE_THRESHOLD = 10

TOOLS_THRESHOLD = 25

FINALE_THRESHOLD = 40

class QuizUI(SceneBase):

def __init__(self, screen, width, height, username):


super().__init__(screen, width, height)

[Link] = screen

[Link] = width

[Link] = height

[Link] = username

[Link]()

[Link] = [Link]("Comic Sans MS", 36)

[Link] = [Link]("Comic Sans MS", 24)

[Link] = [Link]("Comic Sans MS", 18)

# DB setup (buffered cursors avoid unread-result errors; ping to auto-reconnect)

[Link] = None

self._db_connect()

self._ensure_tables()
self._load_progress()

# State

[Link] = "hub"

[Link] = None

self.active_host = None

[Link] = []

self.q_index = 0

self.option_rects = []

self.disabled_options = set()

self.hint_used_this_q = False

self.ending_scene = None # 🎬 holds the cinematic finale scene

# UI

self.back_button = [Link](40, 40, 160, 50)

self.hint_button = [Link]([Link] - 200, 40, 140, 50)


self.hub_cards = []

# Animation

self.anim_t0 = 0

self.anim_dur = 1.5

self.anim_text = ""

# ───────────────────────────────────────────────

# DATABASE UTILITIES

# ───────────────────────────────────────────────

def _db_connect(self):

try:

[Link] = [Link](

host="localhost",

user="root",

password="Tikku17@#$",
database="CASE_FILE_0X67",

autocommit=True,

connection_timeout=8,

raise_on_warnings=False,

except [Link] as e:

# Graceful offline mode; game still runs

[Link] = None

[Link] = (f"DB offline: {[Link] if hasattr(e,'msg') else str(e)}", (200,60,60))

def _cursor(self):

"""Fresh buffered cursor every query. Handles reconnects."""

if [Link] is None:

return None

try:

[Link](reconnect=True, attempts=1, delay=0)


return [Link](dictionary=True, buffered=True)

except Exception:

# Try one reconnect

self._db_connect()

if [Link] is None:

return None

return [Link](dictionary=True, buffered=True)

# ───────────────────────────────────────────────

# DATABASE SETUP + PROGRESS

# ───────────────────────────────────────────────

def _ensure_tables(self):

cur = self._cursor()

if not cur:

return

try:
[Link]("""

CREATE TABLE IF NOT EXISTS quiz_progress (

id INT AUTO_INCREMENT PRIMARY KEY,

username VARCHAR(100) UNIQUE,

coins INT DEFAULT 0,

clues_unlocked INT DEFAULT 0,

tools_unlocked BOOLEAN DEFAULT FALSE,

finale_unlocked BOOLEAN DEFAULT FALSE,

completed_levels INT DEFAULT 0,

last_played DATETIME DEFAULT CURRENT_TIMESTAMP

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

""")

finally:

[Link]()

def _load_progress(self):
"""Load or create per-user quiz progress with safe defaults."""

cur = self._cursor()

if not cur:

# Offline defaults

[Link] = 0

[Link] = 0

[Link] = False

[Link] = False

self.completed_levels = 0

return

try:

[Link]("SELECT * FROM quiz_progress WHERE username=%s",


([Link],))

r = [Link]()

if not r:

# --- NEW USER: start clean, from Grade 6 only ---


[Link]("INSERT INTO quiz_progress (username) VALUES (%s)",
([Link],))

[Link] = 0

[Link] = 0

[Link] = False

[Link] = False

self.completed_levels = 0

else:

# --- RETAINED: existing progress load ---

[Link] = int([Link]("coins", 0))

[Link] = int([Link]("clues_unlocked", 0))

[Link] = bool([Link]("tools_unlocked", 0))

[Link] = bool([Link]("finale_unlocked", 0))

self.completed_levels = int([Link]("completed_levels", 0))

# --- NEW: clamp completed_levels so it's always in valid range ---

if self.completed_levels < 0:
self.completed_levels = 0

if self.completed_levels > len(GRADE_ORDER):

self.completed_levels = len(GRADE_ORDER)

finally:

[Link]()

def _save_progress(self):

cur = self._cursor()

if not cur:

return

try:

[Link]("""

UPDATE quiz_progress

SET coins=%s, clues_unlocked=%s, tools_unlocked=%s,

finale_unlocked=%s, completed_levels=%s, last_played=NOW()

WHERE username=%s
""", ([Link], [Link], int([Link]), int([Link]),

self.completed_levels, [Link]))

try:

[Link]()

except Exception:

pass

finally:

[Link]()

# ───────────────────────────────────────────────

# EVENT HANDLING

# ───────────────────────────────────────────────

def handle_event(self, event):

if [Link] == "ending" and self.ending_scene:

self.ending_scene.handle_event(event)

return
if [Link] == [Link]:

mx, my = [Link].get_pos()

# Back button

if self.back_button.collidepoint(mx, my):

self._return_to_hub("Returned to quiz plaza 🩷")

return

# Hint button

if [Link] in ("quiz", "finale") and [Link] and


self.hint_button.collidepoint(mx, my):

self._use_hint()

return

# Hub click logic

if [Link] == "hub":
for rect, kind, idx in self.hub_cards:

if [Link](mx, my):

if kind == "level":

# --- UPDATED: strict unlock by index ---

# Only levels with index <= completed_levels are playable.

if idx <= self.completed_levels:

self.start_quiz(idx)

else:

[Link] = ("Level locked. Complete previous level first!",


(200,60,60))

elif kind == "finale" and [Link]:

self.start_finale()

return

# Quiz options

elif [Link] == "quiz":

if 0 <= self.q_index < len([Link]):


for i, r in enumerate(self.option_rects):

if [Link](mx, my) and i not in self.disabled_options:

self._answer(i)

return

# Finale options

elif [Link] == "finale":

if self.q_index >= len([Link]):

self._return_to_hub("✨ The town sparkles again! Case closed.")

return

for i, r in enumerate(self.option_rects):

if [Link](mx, my):

self._answer(i)

return

# ───────────────────────────────────────────────
# QUIZ FLOW

# ───────────────────────────────────────────────

def start_quiz(self, level_index):

# safety clamps

level_index = max(0, min(level_index, len(GRADE_ORDER) - 1))

self.active_host = GRADE_ORDER[level_index]

[Link] = self._generate_mcqs(self.active_host["grade"])

if not [Link]:

# Always ensure at least 1 question exists

[Link] = [{"q": "Which language is used to write Python programs?",

"options": ["Python", "C++", "HTML", "Ruby"], "answer": 0}]

self.q_index = 0

self.disabled_options.clear()

self.hint_used_this_q = False

[Link] = "quiz"

[Link] = (f"{self.active_host['name']}’s quiz begins!", (90,50,120))


def start_finale(self):

self.active_host = FINALE

[Link] = [

{"q": "What restores sparkle to Sugarvale?", "options": ["Magic", "Kindness",


"Coins", "Dreams"], "answer": 1},

{"q": "What was Hello Kitty’s real goal?", "options": ["Teamwork", "Treasure",
"Revenge", "Fun"], "answer": 0},

{"q": "What’s the detective’s true tool?", "options": ["Curiosity", "Speed",


"Anger", "Luck"], "answer": 0},

self.q_index = 0

self.disabled_options.clear()

self.hint_used_this_q = False

[Link] = "finale"

[Link] = ("🌟 Finale unlocked — answer from the heart!", (180,70,180))

def _answer(self, choice_idx):


if not (0 <= self.q_index < len([Link])):

return

q = [Link][self.q_index]

correct = (choice_idx == q["answer"])

payout = 2 + min(self._current_level_index(), 3)

if correct:

[Link] += payout

[Link] = (f"✨ Correct! +{payout} coins", (80,150,80))

else:

[Link] = ("❌ Wrong! Try again!", (200,60,60))

self.q_index += 1

self.disabled_options.clear()

self.hint_used_this_q = False
# Handle endings

if self.q_index >= len([Link]):

if [Link] == "quiz":

self._on_quiz_complete()

elif [Link] == "finale":

self.start_finale_ending() # 🎬 trigger cinematic ending

self._handle_unlocks()

self._save_progress()

def start_finale_ending(self):

"""Launch the ending cinematic after the Hello Kitty finale quiz."""

self.ending_scene = EndingScene(

[Link],

[Link],
[Link],

on_complete=lambda: self._return_to_hub("💫 New mystery awaits…")

[Link] = "ending"

# ───────────────────────────────────────────────

# HELPERS + UNLOCKS

# ───────────────────────────────────────────────

def _return_to_hub(self, msg):

[Link] = "hub"

self.active_host = None

[Link]()

self.option_rects = []

self.q_index = 0

self.disabled_options.clear()

self.hint_used_this_q = False
[Link] = (msg, (120,70,120))

def _current_level_index(self):

if not self.active_host or self.active_host is FINALE:

return 0

for i, c in enumerate(GRADE_ORDER):

if c["grade"] == self.active_host["grade"]:

return i

return 0

def _on_quiz_complete(self):

idx = self._current_level_index()

# --- RETAINED: only advance if this level was the "current frontier" ---

if idx == self.completed_levels:

self.completed_levels += 1

if self.completed_levels >= len(GRADE_ORDER):


[Link] = True

self._save_progress()

self._play_unlock_animation(self._next_unlock_name())

else:

self._return_to_hub("✅ Level complete!")

def _next_unlock_name(self):

nxt = self.completed_levels

if nxt < len(GRADE_ORDER):

ch = GRADE_ORDER[nxt]

return f"{ch['name']} — Grade {ch['grade']}"

return "Finale: Hello Kitty"

def _handle_unlocks(self):

updated = False

if [Link] >= CLUE_THRESHOLD and [Link] < 1:


[Link] = 1

[Link] = ("🧩 First clue found!", (255,105,180))

updated = True

if [Link] >= TOOLS_THRESHOLD and not [Link]:

[Link] = True

[Link] = ("🪄 Detective Tools unlocked!", (255,182,193))

updated = True

if ([Link] >= FINALE_THRESHOLD or self.completed_levels >=


len(GRADE_ORDER)) and not [Link]:

[Link] = True

[Link] = ("🌟 Finale unlocked — Hello Kitty awaits!", (255,192,203))

updated = True

if updated:

self._save_progress()

def _use_hint(self):

"""Remove one wrong option once per question when Tools are ON."""
if self.hint_used_this_q or not (0 <= self.q_index < len([Link])):

return

q = [Link][self.q_index]

wrongs = [i for i in range(len(q["options"])) if i != q["answer"] and i not in


self.disabled_options]

if wrongs:

to_disable = [Link](wrongs)

self.disabled_options.add(to_disable)

self.hint_used_this_q = True

[Link] = ("💡 Hint used! One wrong option removed.", (120,60,120))

# ───────────────────────────────────────────────

# QUESTION GENERATION

# ───────────────────────────────────────────────

def _generate_mcqs(self, grade_num):

lessons = []

cur = self._cursor()
if cur:

try:

[Link]("""

SELECT [Link], [Link], [Link], [Link] AS subject

FROM lessons l

JOIN subjects s ON l.subject_id = [Link]

JOIN grades g ON s.grade_id = [Link]

WHERE [Link] = %s

""", (f"Grade {grade_num}",))

lessons = [Link]() or []

except Exception:

lessons = []

finally:

[Link]()

if not lessons:
# Safe fallback bank

return [

{"q": "Which language is used to write Python programs?",

"options": ["Python", "C++", "HTML", "Ruby"], "answer": 0},

{"q": "What does SQL stand for?",

"options": ["Structured Query Language", "Simple Quick Loop", "Super Query


Line", "System Queue Logic"], "answer": 0},

{"q": "Sum of angles in a triangle?",

"options": ["180°", "360°", "90°", "120°"], "answer": 0},

{"q": "CPU stands for…",

"options": ["Central Processing Unit", "Core Program Utility", "Computer


Power Unit", "Central Print Unit"], "answer": 0},

qs = []

for row in lessons:

subj = ([Link]("subject") or "").lower()

q = self._subject_to_question(subj)
if q:

[Link](q)

[Link](qs)

# Always guarantee at least 2 qs

if len(qs) < 2:

[Link]([

{"q": "Which language is used to write Python programs?",

"options": ["Python", "C++", "HTML", "Ruby"], "answer": 0},

{"q": "What does SQL stand for?",

"options": ["Structured Query Language", "Simple Quick Loop", "Super Query


Line", "System Queue Logic"], "answer": 0},

])

return qs[:8]

def _subject_to_question(self, subject):

banks = {

"math": [
("What is 12 × 8?", ["96", "108", "84", "112"], 0),

("Sum of angles in a triangle?", ["180°", "360°", "90°", "120°"], 0)

],

"science": [

("What gas do plants release?", ["Oxygen", "Nitrogen", "CO2", "Hydrogen"],


0),

("H₂O is the formula of…", ["Water", "Oxygen", "Salt", "Acid"], 0)

],

"english": [

("Which is a verb?", ["Run", "Cat", "Bright", "Fast"], 0),

("What punctuation ends a question?", ["?", "!", ".", ","], 0)

],

"history": [

("Who led India’s non-violence movement?", ["Gandhi", "Nehru", "Tagore",


"Bose"], 0),

("When did India gain independence?", ["1947", "1857", "1950", "1939"], 0)

],

"computer": [
("CPU stands for…", ["Central Processing Unit", "Core Program Utility",
"Computer Power Unit", "Central Print Unit"], 0),

("HTML is used for…", ["Web structure", "Drawing", "Maths", "Games"], 0)

if subject in banks:

qtext, opts, ans = [Link](banks[subject])

return {"q": qtext, "options": opts, "answer": ans}

return None

# ───────────────────────────────────────────────

# UPDATE + DRAW

# ───────────────────────────────────────────────

def update(self):

if [Link] == "anim":

if [Link]() - self.anim_t0 >= self.anim_dur:

[Link] = "hub"
elif [Link] == "ending" and self.ending_scene:

self.ending_scene.update()

return self.next_scene

def draw(self):

if [Link] == "ending" and self.ending_scene:

self.ending_scene.draw()

return

[Link]((255,240,245))

title = [Link]("🎀 Quiz Adventure 🎀", True, (255,105,180))

[Link](title, ([Link]//2 - title.get_width()//2, 40))

# Back

[Link]([Link], (255,182,193), self.back_button, border_radius=15)

[Link]([Link]("Back", True, (0,0,0)), (self.back_button.x+35,


self.back_button.y+10))
# HUD

y = 110

[Link]([Link](f"💰 Coins: {[Link]}", True, (90,0,90)), (50, y))

[Link]([Link](f"✅ Levels: {self.completed_levels}/7", True,


(90,0,90)), (230, y))

if [Link]: [Link]([Link]("🧩 Clues", True, (120,60,120)), (420,


y))

if [Link]: [Link]([Link]("🪄 Tools ON", True, (120,60,120)),


(520, y))

if [Link]: [Link]([Link]("🌟 Finale Unlocked", True,


(150,60,150)), (660, y))

if [Link] and [Link] in ("quiz","finale"):

[Link]([Link], (255,223,247), self.hint_button, border_radius=15)

[Link]([Link]("Hint", True, (0,0,0)), (self.hint_button.x+42,


self.hint_button.y+10))

if [Link] == "hub":
self._draw_hub_two_columns()

elif [Link] == "quiz":

self._draw_quiz()

elif [Link] == "finale":

self._draw_finale()

elif [Link] == "anim":

self._draw_unlock_anim()

if [Link]:

msg, col = [Link]

surf = [Link](msg, True, col)

[Link](surf, ([Link]//2 - surf.get_width()//2, [Link] - 60))

def _draw_hub_two_columns(self):

self.hub_cards = []

left_x, right_x = [Link]//2 - 480, [Link]//2 + 40


y0, gap = 150, 90

left, right = 0, 0

# --- UPDATED: only show levels up to completed_levels (strict, no +1) ---

max_index = 0

if self.completed_levels <= 0:

max_index = 0 # new user: only Level 6 visible

else:

max_index = min(self.completed_levels, len(GRADE_ORDER) - 1)

for idx in range(max_index + 1):

ch = GRADE_ORDER[idx]

x, y = (left_x, y0 + left*gap) if idx % 2 == 0 else (right_x, y0 + right*gap)

if idx % 2 == 0: left += 1

else: right += 1

rect = [Link](x, y, 440, 70)


locked = idx > self.completed_levels

color = (220,200,200) if locked else ch["color"]

[Link]([Link], color, rect, border_radius=16)

text = f"{idx+1}. {ch['name']} — Grade {ch['grade']}"

[Link]([Link](text, True, (0,0,0)), (rect.x+20, rect.y+20))

self.hub_cards.append((rect, "level", idx))

# Finale card (unchanged)

if self.completed_levels >= len(GRADE_ORDER) or [Link] >=


FINALE_THRESHOLD:

rect = [Link]([Link]//2 - 220, y0 + max(left,right)*gap + 30, 440, 70)

[Link]([Link], FINALE["color"], rect, border_radius=16)

label = "Finale: Hello Kitty (Unlocked)" if [Link] else "Finale: Hello Kitty
(Locked)"

[Link]([Link](label, True, (0,0,0)), (rect.x+20, rect.y+20))

self.hub_cards.append((rect, "finale", -1))


def _draw_quiz(self):

if not (0 <= self.q_index < len([Link])):

empty = [Link]("No questions found.", True, (120,60,120))

[Link](empty, ([Link]//2 - empty.get_width()//2, 220))

return

q = [Link][self.q_index]

qsurf = [Link](q["q"], True, (0,0,0))

[Link](qsurf, ([Link]//2 - qsurf.get_width()//2, 180))

self.option_rects = []

for i, opt in enumerate(q["options"]):

r = [Link]([Link]//2 - 300, 240 + i*70, 600, 50)

fill = (220,220,220) if i in self.disabled_options else self.active_host["color"]

[Link]([Link], fill, r, border_radius=14)

[Link]([Link](opt, True, (0,0,0)), (r.x+16, r.y+12))

self.option_rects.append(r)
ptxt = [Link](f"Q {self.q_index+1}/{len([Link])}", True,
(90,70,110))

[Link](ptxt, ([Link] - 130, 115))

def _draw_finale(self):

q_done = self.q_index >= len([Link])

area = [Link](70, 160, [Link]-140, [Link]-260)

[Link]([Link], (255,230,240), area, border_radius=24)

[Link]([Link], FINALE["color"], area, 4, border_radius=24)

if q_done:

msg = [Link]("✨ Finale complete! Case closed!", True, (120,60,160))

[Link](msg, ([Link] - msg.get_width()//2, [Link]))

return

q = [Link][self.q_index]

qsurf = [Link](q["q"], True, (60,30,60))

[Link](qsurf, ([Link]//2 - qsurf.get_width()//2, area.y + 50))

self.option_rects = []
for i, opt in enumerate(q["options"]):

r = [Link]([Link]//2 - 250, area.y + 120 + i*70, 500, 50)

fill = (220,220,220) if i in self.disabled_options else FINALE["color"]

[Link]([Link], fill, r, border_radius=14)

[Link]([Link](opt, True, (0,0,0)), (r.x+20, r.y+10))

self.option_rects.append(r)

def _play_unlock_animation(self, next_name):

[Link] = "anim"

self.anim_t0 = [Link]()

self.anim_text = f"✨ Unlocked: {next_name}!"

def _draw_unlock_anim(self):

overlay = [Link](([Link], [Link]), [Link])

[Link]((0,0,0,120))

[Link](overlay, (0,0))
box = [Link]([Link]//2 - 260, [Link]//2 - 60, 520, 120)

[Link]([Link], (255,255,255), box, border_radius=20)

[Link]([Link], (255,182,193), box, 6, border_radius=20)

msg = [Link]("Unlocked!", True, (200,80,140))

sub = [Link](self.anim_text, True, (80,40,80))

[Link](msg, ([Link] - msg.get_width()//2, box.y + 18))

[Link](sub, ([Link] - sub.get_width()//2, box.y + 70))


6. Learning Centre — learning_ui.py

# learning_centre/learning_ui.py

# ------------------------------------------------------------

# Pastel Learning Centre — with Progress Dashboard + Coins

# ------------------------------------------------------------

# Notes:

# - Existing screens kept intact. New features are marked with "# --- NEW:"

# - Uses DB: CASE_FILE_0X67 (tables: grades, subjects, lessons, players, progress)

# - No emojis to avoid missing-font rectangles

# ------------------------------------------------------------

import pygame

import time

import [Link]

from [Link] import Error

from [Link] import Button, WHITE, PINK, LIGHT_PINK, DARK_PINK


# ------------------------------------------------------------

# DB connection (UNCHANGED)

# ------------------------------------------------------------

def get_connection():

try:

return [Link](

host="localhost",

user="root",

password="Tikku17@#$",

database="CASE_FILE_0X67",

autocommit=True,

except Error as e:

print(f"DB error: {e}")

return None
class LearningUI:

def __init__(self, screen, width, height, save=None):

[Link] = screen

[Link] = width

[Link] = height

# fonts

self.font_big = [Link]("comicsansms", 38, bold=True)

self.font_small = [Link]("comicsansms", 22)

# navigation state (UNCHANGED)

[Link] = "menu" # menu | grade | subject | topic | lesson | done | progress

self.selected_grade = None

self.selected_subject = None
self.selected_lesson = None

[Link] = []

[Link] = True

self.db_error = None

# --- NEW: username & coins header

[Link] = "Player1"

if save:

try:

# accept dict-like or SaveData

[Link] = [Link]("username", "Player1") if isinstance(save, dict) \

else getattr(save, "load", lambda: {})().get("username", "Player1")

except Exception:

[Link] = "Player1"

self.session_start_ts = None # lesson timer


# ------------------------------------------------------------

# DB helpers (UNCHANGED APIs)

# ------------------------------------------------------------

def query(self, sql, params=None, dictionary=True):

conn = cur = None

try:

conn = get_connection()

if not conn:

raise Error("No DB connection")

cur = [Link](dictionary=dictionary, buffered=True)

[Link](sql, params or ())

rows = [Link]()

self.db_error = None

return rows

except Error as e:

self.db_error = str(e)
print("SQL error:", e)

return []

finally:

if cur: [Link]()

if conn: [Link]()

def execute(self, sql, params=None):

conn = cur = None

try:

conn = get_connection()

if not conn:

raise Error("No DB connection")

cur = [Link](buffered=True)

[Link](sql, params or ())

[Link]()

self.db_error = None
return [Link]

except Error as e:

self.db_error = str(e)

print("Exec error:", e)

return 0

finally:

if cur: [Link]()

if conn: [Link]()

# --- NEW: player coins helpers ------------------------------------------

def ensure_player_row(self):

# create row if not exists

got = [Link]("SELECT id FROM players WHERE username=%s",


([Link],))

if not got:

[Link]("INSERT INTO players (username) VALUES (%s)",


([Link],))
def get_player_coins(self):

self.ensure_player_row()

row = [Link]("SELECT coins FROM players WHERE username=%s",


([Link],))

return (row[0]["coins"] if row else 0)

def add_player_coins(self, delta):

self.ensure_player_row()

[Link]("UPDATE players SET coins = coins + %s WHERE username=%s",


(delta, [Link]))

# ------------------------------------------------------------

# drawing

# ------------------------------------------------------------

def draw_bg(self):

# pastel vertical gradient

for y in range([Link]):

r = 255
g = max(225, 248 - y // 20)

b = max(235, 252 - y // 25)

[Link]([Link], (r, g, b), (0, y), ([Link], y))

# --- NEW: small header strip with username + coins

def draw_header(self):

bar_h = 52

[Link]([Link], (255, 230, 240), (0, 0, [Link], bar_h))

name_txt = self.font_small.render(f"User: {[Link]}", True, (120, 40, 80))

coins = self.get_player_coins()

coins_txt = self.font_small.render(f"Coins: {coins}", True, (120, 40, 80))

[Link](name_txt, (20, 14))

[Link](coins_txt, ([Link] - coins_txt.get_width() - 20, 14))

# events

def handle_event(self, event):


if [Link] == [Link]:

[Link] = False

elif [Link] == [Link]:

pos = [Link].get_pos()

for b in [Link]:

[Link](pos)

# main draw dispatcher

def draw(self):

self.draw_bg()

self.draw_header() # --- NEW

if [Link] == "menu":

self.draw_main_learning_menu()

elif [Link] == "grade":

self.draw_grade()

elif [Link] == "subject":


self.draw_subject()

elif [Link] == "topic":

self.draw_topic()

elif [Link] == "lesson":

self.draw_lesson()

elif [Link] == "done":

self.draw_done()

elif [Link] == "progress":

self.draw_progress()

[Link]()

# ------------------------------------------------------------

# MAIN MENU (UNCHANGED + small polish)

# ------------------------------------------------------------

def draw_main_learning_menu(self):

[Link]()
title = self.font_big.render("Learning Centre", True, DARK_PINK)

[Link](title, ([Link] // 2 - title.get_width() // 2, 100))

btn1 = Button("Select Grade", [Link] // 2 - 160, 250, 320, 70,

color=PINK, action=lambda: self.change_stage("grade"))

btn2 = Button("View Progress", [Link] // 2 - 160, 350, 320, 70,

color=LIGHT_PINK, action=lambda: self.change_stage("progress"))

back = Button("Main Menu", [Link] // 2 - 140, 480, 280, 60,

color=LIGHT_PINK, action=self.quit_to_menu)

for b in [btn1, btn2, back]:

[Link](b); [Link]([Link])

def change_stage(self, s):

[Link] = s
# ------------------------------------------------------------

# GRADE (UNCHANGED)

# ------------------------------------------------------------

def draw_grade(self):

[Link]()

title = self.font_big.render("Select Your Grade", True, DARK_PINK)

[Link](title, ([Link] // 2 - title.get_width() // 2, 80))

grades = [Link]("SELECT id, name FROM grades ORDER BY id ASC")

if not grades:

self._draw_error("No grades found.")

else:

for i, g in enumerate(grades):

btn = Button(g["name"], [Link] // 2 - 150, 180 + i * 72, 300, 56,

color=PINK, action=lambda g=g: self.select_grade(g))

[Link](btn); [Link]([Link])
back = Button("Back", 40, [Link] - 80, 200, 56,

color=LIGHT_PINK, action=lambda: self.change_stage("menu"))

[Link](back); [Link]([Link])

def select_grade(self, grade_row):

self.selected_grade = grade_row

[Link] = "subject"

# ------------------------------------------------------------

# SUBJECT (UNCHANGED)

# ------------------------------------------------------------

def draw_subject(self):

[Link]()

header = f"{self.selected_grade['name']} — Subjects"

title = self.font_big.render(header, True, DARK_PINK)


[Link](title, ([Link] // 2 - title.get_width() // 2, 70))

subjects = [Link]("SELECT id, name FROM subjects WHERE grade_id=%s


ORDER BY name ASC",

(self.selected_grade["id"],))

if not subjects:

self._draw_error("No subjects found.")

else:

for i, s in enumerate(subjects):

btn = Button(s["name"], [Link] // 2 - 150, 180 + i * 72, 300, 56,

color=PINK, action=lambda s=s: self.select_subject(s))

[Link](btn); [Link]([Link])

back = Button("Back", 40, [Link] - 80, 200, 56,

color=LIGHT_PINK, action=self.go_back_grade)

[Link](back); [Link]([Link])
def go_back_grade(self):

[Link] = "grade"

def select_subject(self, subject_row):

self.selected_subject = subject_row

[Link] = "topic"

# ------------------------------------------------------------

# TOPIC (UNCHANGED)

# ------------------------------------------------------------

def draw_topic(self):

[Link]()

header = f"{self.selected_subject['name']} — Topics"

title = self.font_big.render(header, True, DARK_PINK)

[Link](title, ([Link] // 2 - title.get_width() // 2, 60))


lessons = [Link](

"SELECT id, title, description, content FROM lessons WHERE subject_id=%s


ORDER BY id ASC",

(self.selected_subject["id"],),

y = 140

if not lessons:

self._draw_error("No topics found.")

else:

for l in lessons:

label = f"{l['title']} — {l['description']}"

btn = Button(label, 80, y, [Link] - 160, 56, color=PINK,

action=lambda l=l: self.select_topic(l))

[Link](btn); [Link]([Link])

y += 68

back = Button("Back", 40, [Link] - 80, 200, 56,


color=LIGHT_PINK, action=self.go_back_subject)

[Link](back); [Link]([Link])

def go_back_subject(self):

[Link] = "subject"

def select_topic(self, lesson_row):

self.selected_lesson = lesson_row

self.session_start_ts = [Link]() # --- NEW: start timer

[Link] = "lesson"

# ------------------------------------------------------------

# LESSON (UNCHANGED + completion writes)

# ------------------------------------------------------------

def draw_lesson(self):

[Link]()
if not self.selected_lesson:

self._draw_error("No lesson selected.")

return

title = self.font_big.render(self.selected_lesson['title'], True, DARK_PINK)

[Link](title, ([Link] // 2 - title.get_width() // 2, 60))

desc = self.font_small.render(self.selected_lesson["description"], True, (70, 70, 70))

[Link](desc, (80, 118))

self._draw_wrapped_text(self.selected_lesson["content"], 80, 160, self.font_small,


[Link] - 160)

complete = Button("Mark Topic Completed", [Link] // 2 - 200, [Link] - 150,


400, 56,

color=PINK, action=self.complete_topic)

back = Button("Back", 40, [Link] - 80, 200, 56,

color=LIGHT_PINK, action=self.go_back_to_topics)
for b in [complete, back]:

[Link](b); [Link]([Link])

def complete_topic(self):

# --- NEW: write/aggregate progress + award coins

elapsed = 0

if self.session_start_ts:

elapsed = max(0, int([Link]() - self.session_start_ts))

self.session_start_ts = None

grade_name = self.selected_grade["name"]

subject_name = self.selected_subject["name"]

topic_title = self.selected_lesson["title"]

# Try UPDATE first

updated = [Link]("""
UPDATE progress

SET completed=1, time_spent=time_spent + %s, date_completed=NOW()

WHERE username=%s AND grade=%s AND subject=%s AND lesson_title=%s

""", (elapsed, [Link], self._grade_number(grade_name), subject_name,


topic_title))

if updated == 0:

# Insert if no existing row

[Link]("""

INSERT INTO progress (username, grade, subject, lesson_title, completed,


time_spent)

VALUES (%s, %s, %s, %s, 1, %s)

""", ([Link], self._grade_number(grade_name), subject_name, topic_title,


elapsed))

# Coins: +5 per topic (tweak if you like)

self.add_player_coins(5)
# Subject-complete bonus: if all topics of the subject are completed at least once

if self._is_subject_fully_completed(self.selected_grade["id"],
self.selected_subject["id"]):

self.add_player_coins(20)

[Link] = "done"

def go_back_to_topics(self):

[Link] = "topic"

# --- NEW: helper to detect subject full completion

def _is_subject_fully_completed(self, grade_id, subject_id):

total = [Link]("SELECT COUNT(*) AS c FROM lessons WHERE subject_id=


%s", (subject_id,))

if not total or total[0]["c"] == 0:

return False

# subject name + grade num

srow = [Link]("SELECT name FROM subjects WHERE id=%s", (subject_id,))


grow = [Link]("SELECT name FROM grades WHERE id=%s", (grade_id,))

if not srow or not grow:

return False

subj = srow[0]["name"]

grdnum = self._grade_number(grow[0]["name"])

done = [Link]("""

SELECT COUNT(*) AS c

FROM progress

WHERE username=%s AND grade=%s AND subject=%s AND completed=1

""", ([Link], grdnum, subj))

return (done and done[0]["c"] == total[0]["c"])

# --- NEW: map "Grade 6" -> 6

def _grade_number(self, grade_name):

try:

return int(str(grade_name).split()[-1])
except Exception:

return 0

# ------------------------------------------------------------

# DONE (UNCHANGED + encouragement)

# ------------------------------------------------------------

def draw_done(self):

[Link]()

msg = self.font_big.render("Topic Completed", True, DARK_PINK)

[Link](msg, ([Link] // 2 - msg.get_width() // 2, 200))

# short encouragement, based on total completions

total = [Link]("""

SELECT COUNT(*) AS c FROM progress

WHERE username=%s AND completed=1

""", ([Link],))
c = total[0]["c"] if total else 0

if c == 0:

tip = "Great start. Keep going!"

elif c < 5:

tip = "Nice momentum. You're getting there!"

elif c < 15:

tip = "Strong streak. Proud of you!"

else:

tip = "Amazing consistency. You're unstoppable!"

tip_s = self.font_small.render(tip, True, (90, 90, 90))

[Link](tip_s, ([Link] // 2 - tip_s.get_width() // 2, 260))

done = Button("Back to Topics", [Link] // 2 - 190, 360, 380, 56, color=PINK,


action=self.go_back_to_topics)

home = Button("Main Menu", [Link] // 2 - 160, 430, 320, 56,


color=LIGHT_PINK, action=self.quit_to_menu)

for b in [done, home]:


[Link](b); [Link]([Link])

# ------------------------------------------------------------

# # ------------------------------------------------------------

# 🌸 PROGRESS DASHBOARD (UPDATED WITH CLEAN ALIGNMENT)

# ------------------------------------------------------------

def draw_progress(self):

[Link]()

title = self.font_big.render("📊 Your Learning Progress", True, DARK_PINK)

[Link](title, ([Link] // 2 - title.get_width() // 2, 50))

progress_data = [Link]("""

SELECT subject, COUNT(*) AS completed

FROM progress

WHERE username=%s AND completed=1

GROUP BY subject
ORDER BY subject

""", ([Link],))

total = sum(p["completed"] for p in progress_data)

total_msg = self.font_small.render(f"Total Topics Completed: {total}", True, (70,


70, 70))

[Link](total_msg, (80, 120))

# 🎨 Bar chart area setup

bar_x, bar_y = 100, 170

bar_width = 600

max_bar_height = 35

gap = 20

if not progress_data:

tip = self.font_small.render("No progress yet. Start your journey! 🌟", True, (130,
130, 130))

[Link](tip, ([Link] // 2 - tip.get_width() // 2, [Link] // 2))


else:

max_completed = max(p["completed"] for p in progress_data)

total_height = len(progress_data) * (max_bar_height + gap)

y_offset = ([Link] - total_height) // 2 # Center vertically

# Alternate soft pastel backgrounds for readability

row_colors = [(255, 240, 245), (255, 230, 250)] # pastel pinks

for i, p in enumerate(progress_data):

subject = p["subject"]

completed = p["completed"]

percentage = int((completed / max_completed) * 100) if max_completed else 0

bg_rect = [Link](bar_x - 40, y_offset + i * (max_bar_height + gap) - 5,

bar_width + 300, max_bar_height + 10)

[Link]([Link], row_colors[i % 2], bg_rect, border_radius=10)


# Bar length

filled_width = int((completed / max_completed) * bar_width)

bar_rect = [Link](bar_x, y_offset + i * (max_bar_height + gap),

filled_width, max_bar_height)

[Link]([Link], (255, 182, 193), bar_rect, border_radius=10)

# Subject name

subj_text = self.font_small.render(f"{subject}", True, (80, 0, 60))

[Link](subj_text, (bar_x - 90, y_offset + i * (max_bar_height + gap)))

# Completion %

pct_text = self.font_small.render(f"{percentage}%", True, (100, 50, 100))

[Link](pct_text, (bar_x + bar_width + 20, y_offset + i *


(max_bar_height + gap)))

# 💰 Coins Display
player_data = [Link]("SELECT coins FROM players WHERE username=%s",
([Link],))

coins = player_data[0]["coins"] if player_data else 0

coin_text = self.font_small.render(f"Current Coins: {coins}", True, (100, 70, 90))

[Link](coin_text, (80, [Link] - 140))

# 🩷 Encouragement Message

if total == 0:

msg = "Let's start learning together!"

elif total < 5:

msg = "You’re doing great! Keep going!"

elif total < 10:

msg = "Impressive progress 🌟"

else:

msg = "Super learner alert! 🚀"

tip = self.font_small.render(msg, True, (90, 90, 90))

[Link](tip, (80, [Link] - 100))


# Back button

back = Button("⬅ Back", 50, [Link] - 70, 200, 50,

color=LIGHT_PINK, action=lambda: self.change_stage("menu"))

[Link](back)

[Link]([Link])

# ------------------------------------------------------------

# helpers (UNCHANGED)

# ------------------------------------------------------------

def _draw_error(self, message, y=150):

surf = self.font_small.render(message, True, (120, 0, 0))

[Link](surf, (80, y))

def _draw_wrapped_text(self, text, x, y, font, max_width):

words = (text or "").split()

lines, current = [], ""


for w in words:

test = (current + " " + w).strip()

if [Link](test)[0] <= max_width:

current = test

else:

if current: [Link](current)

current = w

if current: [Link](current)

for i, line in enumerate(lines):

surf = [Link](line, True, (60, 60, 60))

[Link](surf, (x, y + i * 28))

# ------------------------------------------------------------

# main loop (UNCHANGED but returns a value for SceneManager)

# ------------------------------------------------------------

def run(self):
clock = [Link]()

[Link] = True

result = "exit"

while [Link]:

for event in [Link]():

self.handle_event(event)

[Link]()

[Link](60)

# when quit_to_menu called, we jump back to main menu

return result

def quit_to_menu(self):

# SceneManager will set the menu after this returns

[Link] = False

7. Intro System (run_intro + all scenes)


import pygame, cv2, sys, time, [Link], tkinter as tk, os

from tkinter import messagebox

from PIL import Image, ImageTk

from [Link] import *

# -------------------

# CONFIG

# -------------------

DB_NAME = "CASE_FILE_0X67"

WIDTH, HEIGHT = 1280, 720

FPS = 30

# Media files

BONANZA_BG = "bonanza_bg.mp4"

OFFICE_BG = "[Link]"

HKITTY_IMG = "[Link]"
SCARY_VIDEO = "scary.mp4"

SUSPECTS_BG = "suspects_bg.png"

# -------------------

# FONT HELPER

# -------------------

def get_font(size, bold=False):

return [Link]("Times New Roman", size, bold)

# -------------------

# DATABASE

# -------------------

def db_connect():

try:

conn = [Link](

host="localhost",
user="root",

passwd="Tikku17@#$",

database=DB_NAME,

auth_plugin="caching_sha2_password"

return conn

except Exception as e:

print("❌ Database error:", e)

return None

def ensure_users_table():

conn = db_connect()

if not conn:

return

cur = [Link]()

[Link]("""
CREATE TABLE IF NOT EXISTS users (

id INT AUTO_INCREMENT PRIMARY KEY,

username VARCHAR(100) UNIQUE,

password_hash VARCHAR(255),

created_at DATETIME DEFAULT CURRENT_TIMESTAMP

""")

[Link]()

[Link]()

def save_user(username, password):

conn = db_connect()

if not conn:

return False

try:

cur = [Link]()
[Link]("INSERT IGNORE INTO users (username, password_hash) VALUES
(%s, %s)", (username, password))

[Link]()

[Link]()

return True

except Exception as e:

print("DB insert error:", e)

return False

# -------------------

# HELPERS

# -------------------

def play_video_with_overlay(filename, title_text=None, middle_text=None,


duration=None):

cap = [Link](filename)

if not [Link]():

print("⚠ Cannot open video:", filename)

return
screen = [Link].get_surface()

clock = [Link]()

start_time = [Link]()

title_font = get_font(68, True)

font = get_font(36)

while [Link]():

ret, frame = [Link]()

if not ret:

break

frame = [Link](frame, (WIDTH, HEIGHT))

frame = [Link](frame, cv2.COLOR_BGR2RGB)

surf = [Link].make_surface([Link](0, 1))


[Link](surf, (0, 0))

# overlay text

if title_text:

title = title_font.render(title_text, True, (255, 255, 255))

[Link](title, (WIDTH // 2 - title.get_width() // 2, 80))

if middle_text:

msg = [Link](middle_text, True, (255, 255, 255))

[Link](msg, (WIDTH // 2 - msg.get_width() // 2, HEIGHT // 2))

[Link]()

for e in [Link]():

if [Link] == QUIT:

[Link]()

if duration and [Link]() - start_time > duration:


break

[Link](FPS)

[Link]()

def typewriter(surface, text, pos, font, color, speed=35, line_spacing=40):

x, y = pos

for line in [Link]("\n"):

rendered = ""

for ch in line:

rendered += ch

txt = [Link](rendered, True, color)

[Link](txt, (x, y))

[Link]()

[Link](speed)

y += line_spacing
# -------------------

# SCENES

# -------------------

def scene1_system_connection(screen):

play_video_with_overlay(

BONANZA_BG,

title_text="BRAINSTORM BONANZA",

middle_text="Connecting to SANRIO DETECTIVE NETWORK...",

duration=8

def scene2_office_check(screen):

bg = [Link](OFFICE_BG).convert()

bg = [Link](bg, (WIDTH, HEIGHT))

[Link](bg, (0, 0))

font = get_font(36, True)


top_text = "SUCCESSFULLY CONNECTED — CHECKING MISSING
REPORTS..."

overlay = [Link]((WIDTH, 60))

[Link]((0, 0, 0))

overlay.set_alpha(180)

[Link](overlay, (0, 0))

text_surf = [Link](top_text, True, (255, 255, 255))

[Link](text_surf, (WIDTH // 2 - text_surf.get_width() // 2, 10))

[Link]()

[Link](1500)

def scene3_kitty_alert(screen):

bg = [Link](HKITTY_IMG).convert_alpha()

bg = [Link](bg, (WIDTH, HEIGHT))

clock = [Link]()

font = get_font(40, True)

button_font = get_font(30, True)


button = [Link](WIDTH // 2 - 160, HEIGHT - 120, 320, 70)

flash = True

while True:

for e in [Link]():

if [Link] == QUIT:

[Link]()

if [Link] == MOUSEBUTTONDOWN and [Link]([Link]):

return True # ✅ Return something to continue

[Link](bg, (0, 0))

if flash:

alert = [Link]("⚠ ALERT! HELLO KITTY REPORTED MISSING ⚠",


True, (255, 0, 0))

[Link](alert, (WIDTH // 2 - alert.get_width() // 2, 80))

flash = not flash


[Link](screen, (255, 182, 193), button, border_radius=35)

txt = button_font.render("Investigate Case 🩷", True, (0, 0, 0))

[Link](txt, (button.x + 45, button.y + 20))

[Link]()

[Link](2)

def scene4_suspects(screen):

clock = [Link]()

font_title = get_font(48, True)

font_btn = get_font(26, True)

font_hint = get_font(26)

small = get_font(22)

# Load background safely

try:

bg = [Link]("suspects_bg.png").convert()
bg = [Link](bg, (WIDTH, HEIGHT))

except Exception as e:

print("⚠ Background load failed:", e)

bg = None

# Suspect definitions (name, short description)

suspects = [

("Chococat", "Smart and shy, loves science!"),

("Kuromi", "Cheeky troublemaker, but fun!"),

("Cinnamoroll", "Loves to fly and is super cuddly!"),

("Pompompurin", "Chill and pudding-loving pup!"),

("Hello Kitty", "Kind-hearted and curious!"),

("My Melody", "Always sweet and gentle!"),

("Badtz-Maru", "Sassy and cool penguin!"),

("Pochacco", "Sporty dog who loves carrots!"),

("Keroppi", "Happy frog flying the kite!"),


]

# Create a grid of buttons (3x3)

cols, rows = 3, 3

grid_w, grid_h = 900, 420

grid_x = (WIDTH - grid_w) // 2

grid_y = 230 # shifted slightly down for spacing

pad = 20

btn_w = (grid_w - pad * (cols - 1)) // cols

btn_h = (grid_h - pad * (rows - 1)) // rows

buttons = []

for i, (name, desc) in enumerate(suspects):

r = i // cols

c = i % cols

x = grid_x + c * (btn_w + pad)


y = grid_y + r * (btn_h + pad)

[Link]({"rect": [Link](x, y, btn_w, btn_h), "name": name, "desc":


desc})

# Continue button

cont_rect = [Link](WIDTH // 2 - 200, HEIGHT - 100, 400, 60)

# Toast message (shows when clicking a suspect)

toast = ""

toast_timer = 0

while True:

for e in [Link]():

if [Link] == QUIT:

[Link]()

[Link]()

if [Link] == MOUSEBUTTONDOWN:
pos = [Link].get_pos()

for b in buttons:

if b["rect"].collidepoint(pos):

toast = f"{b['name']}: {b['desc']}"

toast_timer = 1800

break

if cont_rect.collidepoint(pos):

return True

# Draw background

if bg:

[Link](bg, (0, 0))

veil = [Link]((WIDTH, HEIGHT), [Link])

[Link]((0, 0, 0, 80))

[Link](veil, (0, 0))

else:
[Link]((255, 240, 246))

# Title

title = font_title.render("Suspect Board ‍♀️", True, (255, 255, 255))

title_shadow = font_title.render("Suspect Board ‍♀️", True, (199, 21, 133))

[Link](title_shadow, (WIDTH // 2 - title.get_width() // 2 + 2, 95 + 2))

[Link](title, (WIDTH // 2 - title.get_width() // 2, 95))

# Hint (aligned right under title)

hint = font_hint.render(

"Tap a suspect to view their vibe, then start your investigation!",

True,

(255, 255, 255)

hint_bg = [Link]((hint.get_width() + 40, hint.get_height() + 10),


[Link])

hint_bg.fill((0, 0, 0, 120))
hint_x = WIDTH // 2 - hint.get_width() // 2

hint_y = 165

[Link](hint_bg, (hint_x - 20, hint_y - 5))

[Link](hint, (hint_x, hint_y))

# Buttons (suspects)

mouse = [Link].get_pos()

for b in buttons:

hovered = b["rect"].collidepoint(mouse)

base = (255, 182, 193) if hovered else (255, 160, 190)

[Link](screen, base, b["rect"], border_radius=20)

[Link](screen, (255, 110, 160), b["rect"], width=2, border_radius=20)

label = font_btn.render(b["name"], True, (60, 20, 40))

[Link](label, (b["rect"].centerx - label.get_width() // 2,

b["rect"].centery - label.get_height() // 2))


# Continue button

[Link](screen, (255, 105, 180), cont_rect, border_radius=28)

[Link](screen, (255, 255, 255), cont_rect, width=3, border_radius=28)

cont_lbl = font_btn.render("Start Investigation ➜", True, (255, 255, 255))

[Link](cont_lbl, (cont_rect.centerx - cont_lbl.get_width() // 2,

cont_rect.centery - cont_lbl.get_height() // 2))

# Toast popup when a suspect is clicked

dt = [Link](60)

if toast_timer > 0:

toast_timer -= dt

tw = min(900, WIDTH - 80)

tx = (WIDTH - tw) // 2

ty = grid_y - 70

[Link](screen, (0, 0, 0, 200), (tx, ty, tw, 50), border_radius=16)

txt = [Link](toast, True, (255, 255, 255))


[Link](txt, (tx + 20, ty + 14))

[Link]()

def scene5_scary_transition(screen):

play_video_with_overlay(SCARY_VIDEO, title_text="⚠ WARNING ⚠",


middle_text="UNKNOWN PRESENCE DETECTED...", duration=5)

def scene6_terms(screen):

[Link]((0, 0, 0))

font = get_font(30)

typewriter(screen,

"👻 Beware, young detective...\nOnce you start, there's no going back.\nSolve


the quiz, or the truth stays buried...",

(200, 250), font, (255, 0, 0))

[Link](500)
green_btn = [Link](WIDTH // 2 - 220, HEIGHT - 180, 200, 70)

red_btn = [Link](WIDTH // 2 + 40, HEIGHT - 180, 200, 70)

font_b = get_font(26, True)

while True:

for e in [Link]():

if [Link] == QUIT:

[Link]()

if [Link] == MOUSEBUTTONDOWN:

if green_btn.collidepoint([Link]): return True

if red_btn.collidepoint([Link]):

[Link]()

[Link]()

[Link](screen, (0, 180, 0), green_btn, border_radius=30)

[Link](screen, (180, 0, 0), red_btn, border_radius=30)

[Link](font_b.render("Accept & Continue", True, (255, 255, 255)), (green_btn.x


+ 15, green_btn.y + 20))
[Link](font_b.render("Decline & Run Away", True, (255, 255, 255)), (red_btn.x
+ 10, red_btn.y + 20))

[Link]()

def scene7_login(screen):

ensure_users_table()

username, password = "", ""

font = get_font(30)

active = "user"

while True:

[Link]((0, 0, 0))

title = [Link]("🔐 DETECTIVE LOGIN REQUIRED", True, (255, 182, 193))

[Link](title, (WIDTH // 2 - title.get_width() // 2, 150))

user_rect = [Link](WIDTH // 2 - 150, 300, 300, 50)

pwd_rect = [Link](WIDTH // 2 - 150, 380, 300, 50)


[Link](screen, (255, 255, 255), user_rect, 2)

[Link](screen, (255, 255, 255), pwd_rect, 2)

[Link]([Link]("Username:", True, (255, 255, 255)), (user_rect.x - 150,


305))

[Link]([Link]("Password:", True, (255, 255, 255)), (pwd_rect.x - 150, 385))

[Link]([Link](username, True, (255, 255, 255)), (user_rect.x + 10, 305))

[Link]([Link]("*" * len(password), True, (255, 255, 255)), (pwd_rect.x +


10, 385))

btn = [Link](WIDTH // 2 - 100, 480, 200, 60)

[Link](screen, (255, 182, 193), btn, border_radius=25)

[Link]([Link]("Login", True, (0, 0, 0)), (btn.x + 70, btn.y + 15))

[Link]()

for e in [Link]():

if [Link] == QUIT:

[Link]()

if [Link] == MOUSEBUTTONDOWN:
if user_rect.collidepoint([Link]): active = "user"

elif pwd_rect.collidepoint([Link]): active = "pass"

elif [Link]([Link]):

if username and password:

save_user(username, password)

return True

if [Link] == KEYDOWN:

if [Link] == K_TAB:

active = "pass" if active == "user" else "user"

elif [Link] == K_BACKSPACE:

if active == "user": username = username[:-1]

else: password = password[:-1]

elif [Link] == K_RETURN:

if username and password:

save_user(username, password)

return True
else:

if active == "user": username += [Link]

else: password += [Link]

def scene8_main_menu(screen):

import main

[Link]() # ✅ Connects cleanly

# -------------------

# MAIN FLOW

# -------------------

def run_intro():

[Link]()

screen = [Link].set_mode((WIDTH, HEIGHT))

[Link].set_caption("Case 0X67: Kitty Missing")


sequence = [

scene1_system_connection,

scene2_office_check,

scene3_kitty_alert,

scene4_suspects,

scene5_scary_transition,

scene6_terms,

scene7_login,

scene8_main_menu

for func in sequence:

print(f"🎬 Running: {func.__name__}")

res = func(screen)

if res is False or res == "quit":

break
[Link]()

if __name__ == "__main__":

run_intro()

8. Ending Cinematic — [Link]


import pygame

import cv2
import time

import random

class EndingScene:

def __init__(self, screen, width, height, on_complete=None):

[Link] = screen

[Link] = width

[Link] = height

self.on_complete = on_complete

# 🎬 Video config

self.video_path = "assets/videos/ending.mp4"

[Link] = None

self.frame_surf = None

[Link] = True

self.glitch_phase = False

[Link] = False

self.start_time = [Link]()

# Fonts

[Link]()

self.font_big = [Link]("Impact", 72)

self.font_small = [Link]("Comic Sans MS", 32)

# Timing

self.glitch_trigger_time = 12.0 # seconds to start glitch


self.teaser_display_time = 5.0 # seconds after glitch

# Video setup

try:

[Link] = [Link](self.video_path)

except Exception:

[Link] = None

# ─────────────────────────────

# Update Loop

# ─────────────────────────────

def update(self):

if [Link]:

return

now = [Link]()

elapsed = now - self.start_time

# Glitch time!

if not self.glitch_phase and elapsed > self.glitch_trigger_time:

self.glitch_phase = True

self._trigger_glitch()

# End completely
if self.glitch_phase and elapsed > (self.glitch_trigger_time +
self.teaser_display_time):

[Link] = True

if self.on_complete:

self.on_complete()

# ─────────────────────────────

# Draw Loop

# ─────────────────────────────

def draw(self):

if [Link] and [Link] and not self.glitch_phase:

ret, frame = [Link]()

if not ret:

[Link] = False

else:

frame = [Link](frame, ([Link], [Link]))

frame = [Link](frame, cv2.COLOR_BGR2RGB)

frame = [Link].make_surface([Link](0, 1))

self.frame_surf = frame

if self.frame_surf:

[Link](self.frame_surf, (0, 0))

else:

[Link]((255, 200, 230))

if self.glitch_phase:
self._draw_glitch_overlay()

[Link]()

# ─────────────────────────────

# Event Handling

# ─────────────────────────────

def handle_event(self, event):

if [Link] == [Link] or [Link] ==


[Link]:

if not self.glitch_phase:

# skip to glitch manually

self.glitch_phase = True

self._trigger_glitch()

elif [Link]:

if self.on_complete:

self.on_complete()

# ─────────────────────────────

# Glitch Visual

# ─────────────────────────────

def _trigger_glitch(self):

self.glitch_sound_played = False

self.glitch_start = [Link]()
def _draw_glitch_overlay(self):

t = [Link]() - self.glitch_start

# Flash effect

flash = (abs(int(255 * (0.5 + 0.5 * ((t * 20) % 1)))), 0, 0)

overlay = [Link](([Link], [Link]))

[Link](flash)

[Link](overlay, (0, 0), special_flags=pygame.BLEND_RGBA_ADD)

# Static noise

for _ in range(400):

x = int(([Link]) * (0.5 + 0.5 * ([Link].get_ticks() % 100 / 100)))

y = int(([Link]) * (0.5 + 0.5 * ([Link].get_ticks() % 200 / 200)))

color = ([Link](150, 255), 0, 0)

[Link]([Link], color, (x, y), 2)

# Blood red text

msg = "CASE 0X69"

sub = "KUROMI KIDNAPPED"

next_ = "COMING SOON..."

surf1 = self.font_big.render(msg, True, (255, 0, 0))

surf2 = self.font_big.render(sub, True, (255, 20, 20))

surf3 = self.font_small.render(next_, True, (255, 80, 80))

[Link](surf1, ([Link]//2 - surf1.get_width()//2, [Link]//2 - 140))

[Link](surf2, ([Link]//2 - surf2.get_width()//2, [Link]//2 - 60))


[Link](surf3, ([Link]//2 - surf3.get_width()//2, [Link]//2 + 40))
9. [Link] (launcher)

# [Link] — FINAL CLEAN VERSION (no minigames, fully synced)

import pathfix

import pygame, cv2, sys, json

# ---------------------------------------------------------

# Imports for main components ONLY (minigames removed)

# ---------------------------------------------------------

from learning_centre.learning_ui import LearningUI

from quiz_engine.quiz_ui import QuizUI

from ui.simple_scene import SceneBase

from [Link] import Button

SCREEN_WIDTH, SCREEN_HEIGHT = 1200, 800

FPS = 60
# ---------------------------------------------------------

# Save system (unchanged)

# ---------------------------------------------------------

class SaveData:

FILE = "data/[Link]"

def load(self):

try:

with open([Link], "r") as f:

return [Link](f)

except Exception:

return {"username": "Player1"}

def save(self, data):

with open([Link], "w") as f:


[Link](data, f)

# Shim so LearningUI can read [Link]["username"]

class _SaveShim:

def __init__(self, data: dict):

[Link] = data

# ---------------------------------------------------------

# MENU SCENE — minigames removed

# ---------------------------------------------------------

class MenuScene(SceneBase):

def __init__(self, screen, width, height, save):

super().__init__(screen, width, height)

[Link] = save
[Link] = [Link]("comicsansms", 40, bold=True)

self.next_scene = None

[Link] = []

# Safe background video loader

try:

[Link] = [Link]("menu_bg.mp4")

if not [Link]():

[Link] = None

except:

[Link] = None

self.create_buttons()

def create_buttons(self):

y_start, gap = 260, 95


# ⭐⭐ ONLY LEARNING + QUIZ NOW ⭐⭐

labels = [

("Learning Centre", "learning"),

("Quiz Adventure", "quiz"),

[Link]()

for i, (label, key) in enumerate(labels):

btn = Button(

label,

[Link]//2 - 180, y_start + i * gap,

360, 65,

(255, 140, 180), (255, 182, 193),

action=lambda k=key: self.set_scene(k)

)
[Link](btn)

def set_scene(self, key):

print(f"🌸 Switching to: {key}")

self.next_scene = key

def handle_event(self, event):

if [Link] == [Link]:

pos = [Link].get_pos()

for b in [Link]:

[Link](pos)

def update(self):

return self.next_scene

def draw(self):
# Draw background video or pastel fallback

if [Link]:

ret, frame = [Link]()

if not ret:

[Link](cv2.CAP_PROP_POS_FRAMES, 0)

ret, frame = [Link]()

if ret:

frame = [Link](frame, cv2.COLOR_BGR2RGB)

frame = [Link].make_surface([Link](0, 1))

frame = [Link](frame, ([Link], [Link]))

[Link](frame, (0, 0))

else:

[Link]((255, 248, 252))

# Title

title = [Link]("HELLO KITTY CASE 0X67 💖", True, (199, 21, 133))
[Link](title, ([Link]//2 - title.get_width()//2, 100))

# Buttons

for b in [Link]:

[Link]([Link])

# ---------------------------------------------------------

# SCENE MANAGER (clean & stable)

# ---------------------------------------------------------

class SceneManager:

def __init__(self, screen):

[Link] = screen

[Link] = SaveData()

[Link] = {}

[Link] = None
self.create_scenes()

self.change_scene("menu")

def create_scenes(self):

username = [Link]().get("username", "Player1")

[Link]["menu"] = MenuScene([Link], SCREEN_WIDTH,


SCREEN_HEIGHT, [Link])

[Link]["quiz"] = QuizUI([Link], SCREEN_WIDTH, SCREEN_HEIGHT,


username)

# ⭐ Learning Centre is special — launched manually, not registered here ⭐

def change_scene(self, key):

if key in [Link]:

print(f"🎀 SceneManager switched to: {key}")

[Link] = [Link][key]

else:

print(f"⚠️Scene '{key}' not found")


def handle_event(self, event):

if not [Link]:

return

[Link].handle_event(event)

next_scene = [Link]()

# Normal scene switching

if next_scene and next_scene in [Link]:

self.change_scene(next_scene)

# ⭐ OPEN LEARNING CENTRE ⭐

elif next_scene == "learning":

username = [Link]().get("username", "Player1")

shim = _SaveShim({"username": username})


ui = LearningUI([Link], SCREEN_WIDTH, SCREEN_HEIGHT, shim)

[Link]() # blocking

# Return to menu

self.change_scene("menu")

def draw(self):

if [Link]:

[Link]()

# ---------------------------------------------------------

# MAIN LOOP

# ---------------------------------------------------------

def main():
[Link]()

screen = [Link].set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

[Link].set_caption("Hello Kitty Detective 💖")

clock = [Link]()

manager = SceneManager(screen)

running = True

while running:

for event in [Link]():

if [Link] == [Link]:

running = False

manager.handle_event(event)

[Link]()

[Link]()
[Link](FPS)

[Link]()

[Link]()

if __name__ == "__main__":

main()
MYSQL DATABASE COMMANDS (FULL)
========================================
1. CREATE DATABASE
========================================
CREATE DATABASE IF NOT EXISTS CASE_FILE_0X67;
USE CASE_FILE_0X67;

========================================
2. SHOW ALL DATABASES
========================================
SHOW DATABASES;

========================================
3. SHOW ALL TABLES IN THE DATABASE
========================================
SHOW TABLES;

========================================
4. DESCRIBE EACH TABLE
========================================
DESCRIBE badges;
DESCRIBE daily_activity;
DESCRIBE grades;
DESCRIBE lessons;
DESCRIBE players;
DESCRIBE progress;
DESCRIBE quiz_progress;
DESCRIBE streaks;
DESCRIBE subjects;
DESCRIBE users;

========================================
5. SHOW CREATE TABLE (FULL STRUCTURE)
========================================
SHOW CREATE TABLE badges;
SHOW CREATE TABLE daily_activity;
SHOW CREATE TABLE grades;
SHOW CREATE TABLE lessons;
SHOW CREATE TABLE players;
SHOW CREATE TABLE progress;
SHOW CREATE TABLE quiz_progress;
SHOW CREATE TABLE streaks;
SHOW CREATE TABLE subjects;
SHOW CREATE TABLE users;

========================================
6. SHOW COLUMN DETAIL FOR ALL TABLES
========================================
SELECT
TABLE_NAME,
COLUMN_NAME,
COLUMN_TYPE,
IS_NULLABLE,
COLUMN_KEY,
EXTRA
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'CASE_FILE_0X67'
ORDER BY TABLE_NAME, ORDINAL_POSITION;

You might also like