soul-symphony-ling
↓ 0 downloadsSoul Symphony — Ling Edition. A spiritual 3D adventure in the soul realm: collect the letters of the world-song, clear the monster lattice, and duel in the arcade arena. Wind Waker-style toon renderer with volumetric light pools, SSAO, bloom and oil-slick tilt-shift — all ling-lang vectors.
Keywords game, 3d, toon, music, soul-symphony
lingfu install soul-symphony-lingCode / Files (1947)
game/title.ling
# ────────────────────────────────────────────────────────────────────────────
# title.ling — บูตโลโก้ + ชื่อเรื่อง + ตัวช่วยเมนู 3D + ระบบฟอนต์/ภาษา
# ────────────────────────────────────────────────────────────────────────────
ใช้ "../font/Daemon"
ใช้ "../font/English"
ใช้ "../font/Daemon3D"
ใช้ "../font/English3D"
ใช้ "../font/Thai"
ใช้ "../font/Korean"
ใช้ "../font/Japanese"
ใช้ "../font/Chinese"
ใช้ "../font/MenuTH"
ใช้ "../font/MenuKO"
ใช้ "../font/MenuJA"
ใช้ "../font/MenuZH"
ใช้ "../font/ArcadeTH"
ใช้ "../font/ArcadeKO"
ใช้ "../font/ArcadeJA"
ใช้ "../font/ArcadeZH"
ใช้ "../font/SS2EN"
ใช้ "../font/SS2TH"
ใช้ "../font/SS2KO"
ใช้ "../font/SS2JA"
ใช้ "../font/SS2ZH"
ใช้ "../font/OnlineTH"
ใช้ "../font/OnlineKO"
ใช้ "../font/OnlineJA"
ใช้ "../font/OnlineZH"
ใช้ "../game/lattice"
bind glyph = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
bind ฝูงInit = 0
bind ฝูงN = 12
bind ฝูงX = []
bind ฝูงY = []
bind ฝูงZ = []
bind ฝูงVx = []
bind ฝูงVy = []
bind ฝูงVz = []
bind หมึกRB = liquid_new(48.0, 48.0)
bind _inkRB = สีของเหลว(หมึกRB, 220, 34, 52, 44, 96, 220)
bind หมึกGold = liquid_new(48.0, 48.0)
bind _inkGold = สีของเหลว(หมึกGold, 235, 182, 58, 148, 76, 20)
# ปราสาท 5 ชิ้น (เฟรมร่วม) นั่งบนขอบฟ้าหมึกไตเติล — หมุนสีคนละเฟส (หมุนสีเมช)
bind _วังไต0 = mesh_load("game/palace_p0.lmesh")
bind _วังไต1 = mesh_load("game/palace_p1.lmesh")
bind _วังไต2 = mesh_load("game/palace_p2.lmesh")
bind _วังไต3 = mesh_load("game/palace_p3.lmesh")
bind _วังไต4 = mesh_load("game/palace_p4.lmesh")
bind คำSS2 = [18,14,20,11,0.0-1.0,18,24,12,15,7,14,13,24,0.0-1.0,28]
# ── คำ (ดัชนีกลิฟ a=0..z=25, -1 = ช่องว่าง) ─────────────────────────────────
bind คำ_บูต = [12,0,3,4,-1,8,13,-1,11,8,13,6,-1,2,14,20,13,19,17,24] # made in ling country
bind คำ_ปุ่ม = [4,13,19,4,17,-1,19,14,-1,18,19,0,17,19] # enter to start
bind คำ_โหลด = [11,14,0,3,-1,18,0,21,4] # load save
bind คำ_เกมใหม่ = [13,4,22,-1,6,0,12,4] # new game
bind คำ_มัลติ = [12,20,11,19,8,15,11,0,24,4,17] # multiplayer
bind คำ_ตัวเลือก= [14,15,19,8,14,13,18] # options
bind คำ_ออก = [4,23,8,19] # exit
bind คำ_เมนูหลัก= [12,0,8,13,-1,12,4,13,20] # main menu
bind คำ_เล่นต่อ = [17,4,18,20,12,4] # resume
bind คำ_พัก = [15,0,20,18,4] # pause
bind คำ_โฮสต์ = [7,14,18,19,-1,6,0,12,4] # host game
bind คำ_จอยน์ = [9,14,8,13,-1,6,0,12,4] # join game
bind คำ_โคออป = [2,14,14,15,-1,15,19,22,14,-1,0,17,17,14,22,18] # coop p two arrows
bind คำ_โลคัล = [11,14,2,0,11,-1,2,14,14,15] # local coop
bind คำ_วีเอส = [21,18,-1,12,14,3,4] # vs mode
bind คำ_โหมดโคออป = [2,14,14,15,-1,12,14,3,4] # coop mode
bind คำ_เชื่อม = [2,14,13,13,4,2,19,8,13,6] # connecting
bind คำ_พร้อม = [2,14,13,13,4,2,19,4,3] # connected
bind คำ_เซฟ = [18,0,21,4] # save
bind คำ_ยกเลิก = [2,0,13,2,4,11] # cancel
bind คำ_เพลง = [12,20,18,8,2] # music
bind คำ_ภาษาคำ = [11,0,13,6,20,0,6,4] # language
bind คำ_ช่อง = [18,11,14,19] # slot
bind คำ_ว่าง = [4,12,15,19,24] # empty
bind คำ_vsync = [21,18,24,13,2] # vsync
bind คำ_บันทึก = [18,0,21,4,3] # saved
bind คำ_บทหนึ่ง = [2,7,0,15,19,4,17,-1,14,13,4] # chapter one
bind คำ_โหลดดิ้ง = [11,14,0,3,8,13,6] # loading
bind คำ_sfx = [18,5,23] # sfx
bind คำ_bgm = [1,6,12] # bgm
bind คำ_บทพูด = [18,20,1,19,8,19,11,4,18] # subtitles
bind คำ_เลือกเลเวล = [11,4,21,4,11,-1,18,4,11,4,2,19] # level select
bind คำ_อาร์เคด = [0,17,2,0,3,4] # arcade
# บรรทัดบูต (train-track): Daemon = โรมาจิ, English = อังกฤษ
bind คำ_โรมาจิ = [17,8,13,6,20,-1,10,20,13,8,-1,10,0,17,0,-1,19,18,20,10,20,19,19,0] # ringu kuni kara tsukutta
bind คำ_บรร3 = [15,17,4,18,18,-1,4,13,19,4,17] # press enter
bind ไชม์ = [523.3, 587.3, 659.3, 784.0, 880.0, 1046.5, 1174.7, 1318.5, 1568.0] # pentatonic ขึ้น
# ── ชื่อภาษา ────────────────────────────────────────────────────────────────
bind คำ_เดมอน = [3,0,4,12,14,13] # daemon
bind คำ_อังกฤษ = [4,13,6,11,8,18,7] # english
bind คำ_ไทย = [19,7,0,8] # thai
bind คำ_เกาหลี = [10,14,17,4,0,13] # korean
bind คำ_ญี่ปุ่น = [9,0,15,0,13,4,18,4] # japanese
bind คำ_จีน = [2,7,8,13,4,18,4] # chinese
# เมนู
bind เมนูหลักรายการ = [คำ_โหลด, คำ_เกมใหม่, คำ_เลือกเลเวล, คำ_มัลติ, คำ_ตัวเลือก, คำ_ออก]
bind เมนูพักรายการ = [คำ_เล่นต่อ, คำ_ตัวเลือก, คำ_เมนูหลัก, คำ_ออก]
bind เมนูตัวเลือก = [คำ_เพลง, คำ_ภาษาคำ, คำ_เซฟ, คำ_ยกเลิก]
bind เมนูมัลติ = [คำ_โฮสต์, คำ_จอยน์]
bind เมนูภาษา = [คำ_เดมอน, คำ_อังกฤษ, คำ_ไทย, คำ_เกาหลี, คำ_ญี่ปุ่น, คำ_จีน]
bind เมนูเซฟ = [คำ_ช่อง, คำ_ช่อง, คำ_ช่อง]
# ── เมนูหลักหลายภาษา: ดัชนีตรงกับ MenuTH/KO/JA/ZH item 0-5 ──
# Daemon = โรมาจิ (ตามคู่มือ), English = a-z, อื่น ๆ = ฟอนต์วลี
bind คำRM_โหลด = [17,14,3,14] # rodo
bind คำRM_เกมใหม่ = [13,24,20,-1,6,4,12,20] # nyu gemu
bind คำRM_เลเวล = [17,4,1,4,17,20] # reberu
bind คำRM_มัลติ = [12,0,17,20,2,7,8] # maruchi
bind คำRM_ตัวเลือก = [14,15,20,18,7,14,13] # opushon
bind คำRM_ออก = [18,7,20,20,17,24,14,20] # shuuryou
bind คำRM_ช่อง = [18,20,17,14,19,19,14] # surotto
bind คำRM_ว่าง = [10,0,17,0] # kara
bind คำRM_บันทึก = [7,14,25,14,13] # hozon
bind คำRM_เล่นต่อ = [18,0,8,10,0,8] # saikai
bind คำRM_เมนูหลัก = [12,4,8,13,-1,12,4,13,24,20] # mein menyu
bind คำRM_เพลง = [14,13,6,0,10,20] # ongaku
bind คำRM_ภาษา = [6,4,13,6,14] # gengo
bind คำRM_ยกเลิก = [10,24,0,13,18,4,17,20] # kyanseru
bind คำRM_พัก = [15,14,25,20] # pozu
# 18 รายการ — ดัชนีตรงกับ MenuTH/KO/JA/ZH
# item 19 = "online" (special-cased in วาดป้าย, never reads this slot) · item 20 = vsync
# (item > 18 always renders via the English word list regardless of `lang` —
# the existing phrasebake fallback for labels not yet baked per-language.)
bind เมนูEN = [คำ_โหลด, คำ_เกมใหม่, คำ_เลือกเลเวล, คำ_มัลติ, คำ_ตัวเลือก, คำ_ออก, คำ_อังกฤษ, คำ_โหลด, คำ_ช่อง, คำ_ว่าง, คำ_บันทึก, คำ_เล่นต่อ, คำ_เมนูหลัก, คำ_เพลง, คำ_ภาษาคำ, คำ_เซฟ, คำ_ยกเลิก, คำ_พัก, คำ_อาร์เคด, [], คำ_vsync]
bind เมนูRM = [คำRM_โหลด, คำRM_เกมใหม่, คำRM_เลเวล, คำRM_มัลติ, คำRM_ตัวเลือก, คำRM_ออก, คำ_เดมอน, คำRM_โหลด, คำRM_ช่อง, คำRM_ว่าง, คำRM_บันทึก, คำRM_เล่นต่อ, คำRM_เมนูหลัก, คำRM_เพลง, คำRM_ภาษา, คำRM_บันทึก, คำRM_ยกเลิก, คำRM_พัก, คำ_อาร์เคด]
# ── ฟอนต์ดิสแพตช์: 0 = Daemon, อื่นๆ = English (ไทย/เกา/ญี่/จีน fallback) ─────
# up = (0,-1,0) เพราะ Y+ = ลง → ตัวอักษรตั้งตรง (ไม่กลับหัว)
# ข้อความทั่วไป (เมนู/บูต/บทกวี) ใช้ฟอนต์แบน (เบา) — กลิฟ 3D เก็บไว้ที่
# วงแหวนชื่อเรื่อง + ตัวเก็บในโลกเท่านั้น
# อบกลิฟทั้งฟอนต์ลงดิสเพลย์ลิสต์ครั้งเดียวตอนเริ่ม → เล่นซ้ำแบบเนทีฟทุกเฟรม
# (เลี่ยงคำนวณเวกเตอร์กลิฟใหม่ในล่ามทุกครั้ง)
ฟังก์ชัน อบกลิฟ(ฟอนต์, n) {
bind cache = []
bind i = 0
ขณะที่ i < n {
เริ่มอบเมช()
ถ้า ฟอนต์ == 0 { วาดอักขระDaemon(i, 0.0,0.0,0.0, 1.0,0.0,0.0, 0.0,1.0,0.0, 1.0) }
มิฉะนั้น { วาดอักขระEnglish(i, 0.0,0.0,0.0, 1.0,0.0,0.0, 0.0,1.0,0.0, 1.0) }
bind cache = list_push(cache, จบอบเมช())
bind i = i + 1
}
คืน cache
}
ฟังก์ชัน อบกลิฟ3มิติ(n) {
bind cache = []
bind i = 0
ขณะที่ i < n {
เริ่มอบเมช()
วาดอักขระDaemon3D(i, 0.0,0.0,0.0, 1.0,0.0,0.0, 0.0,1.0,0.0, 1.0)
bind cache = list_push(cache, จบอบเมช())
bind i = i + 1
}
คืน cache
}
bind _กลิฟเดมอน = อบกลิฟ(0, 26)
bind _กลิฟอังกฤษ = อบกลิฟ(1, 48)
bind _กลิฟเดมอน3มิติ = อบกลิฟ3มิติ(26)
# UI/boot/menu text is 2D-facing ink, not lit 3D geometry — flat_shade skips
# both the lighting compute and the toon cel-ramp so cycling hues stay exact.
ฟังก์ชัน boot_text_style() {
set_depth_test(0)
set_flat_shade(1.0)
ตั้งแสงรอบข้าง(0.58)
}
ฟังก์ชัน ui_text_color(idx, selected, t) {
bind h = t*1.45 + idx*0.72
ถ้า selected > 0.5 {
สีดินสอ(floor((ไซน์(h)*0.5+0.5)*80+175), floor((ไซน์(h+2.094)*0.5+0.5)*80+175), floor((ไซน์(h+4.189)*0.5+0.5)*80+175))
}
มิฉะนั้น {
สีดินสอ(floor((ไซน์(h)*0.5+0.5)*95+85), floor((ไซน์(h+2.094)*0.5+0.5)*95+85), floor((ไซน์(h+4.189)*0.5+0.5)*95+85))
}
}
ฟังก์ชัน วาดกลิฟ(lang, code, x, y, z, s) {
boot_text_style()
ถ้า lang == 0 {
ถ้า code < 26 { วาดอบเมช(list_get(_กลิฟเดมอน, code), x,y,z, 1,0,0, 0,0.0-1.0,0, s) }
}
มิฉะนั้น {
ถ้า code < 48 { วาดอบเมช(list_get(_กลิฟอังกฤษ, code), x,y,z, 1,0,0, 0,0.0-1.0,0, s) }
}
ตั้งแฟลตเชด(0)
}
# ── กล้องมองเป้า ─────────────────────────────────────────────────────────────
ฟังก์ชัน ตั้งกล้องมอง(cpx, cpy, cpz, tx, ty, tz) {
bind ldx = tx - cpx; bind ldy = ty - cpy; bind ldz = tz - cpz
bind ll = รากที่สอง(ldx*ldx + ldy*ldy + ldz*ldz)
bind ry = atan2(ldx / ll, ldz / ll)
bind rx = asin(จำกัด(ldy / ll, 0.0-0.98, 0.98))
ตั้งกล้อง(โคไซน์(ry), ไซน์(ry), โคไซน์(rx), ไซน์(rx))
ตั้งตำแหน่งกล้อง(cpx, cpy, cpz)
ผู้ฟัง(โคไซน์(ry), ไซน์(ry), โคไซน์(rx), ไซน์(rx))
}
# ── วาดข้อความ: กลิฟจากรายการดัชนี จัดกึ่งกลาง (lang เลือกฟอนต์) ────────────
ฟังก์ชัน วาดข้อความ(row, ox, oy, oz, scale, lang) {
boot_text_style()
bind n = ความยาว(row)
bind adv = scale * 0.66
bind startx = ox - (n - 1) * adv * 0.5
# ── ฮาโลเรืองแสง (emission): ผ่านบวกกลิฟใหญ่ขึ้น → แกนทึบทับ ──
โหมดผสม(1)
bind ig = 0
ขณะที่ ig < n {
bind gc = list_get(row, ig)
ถ้า gc >= 0 { วาดกลิฟ(lang, gc, startx + ig * adv, oy, oz + 0.15, scale*1.16) }
bind ig = ig + 1
}
โหมดผสม(0)
bind i = 0
ขณะที่ i < n {
bind code = list_get(row, i)
ถ้า code >= 0 {
วาดกลิฟ(lang, code, startx + i * adv, oy, oz, scale)
}
bind i = i + 1
}
}
# ── ลูกศร ">" ───────────────────────────────────────────────────────────────
ฟังก์ชัน วาดลูกศร(x, y, z, s) {
วาดเส้น3มิติ(x - s, y - s, z, x + s*0.6, y, z)
วาดเส้น3มิติ(x + s*0.6, y, z, x - s, y + s, z)
}
# ── เคอร์เซอร์หมึก 3D: ลิ่มหมึก (พีระมิด 4 หน้าชี้ขวา รับแสง = มีมิติ) + ออร์บของเหลววาว ──
# ใช้ liquid ink shader จริง (liquid_draw_surface) ที่โคนลิ่ม → เปียกวาวหมุนวน
bind เคอร์เซอร์ลิค = liquid_new(36.0, 36.0)
bind _curInk = สีของเหลว(เคอร์เซอร์ลิค, 95, 130, 215, 14, 12, 26) # หมึก: น้ำเงินวาว + ดำสนิท
ฟังก์ชัน เคอร์เซอร์หมึก(x, y, z, s, t) {
liquid_step(เคอร์เซอร์ลิค, 0.016)
liquid_splat(เคอร์เซอร์ลิค, 18.0+ไซน์(t*2.3)*7.0, 18.0+โคไซน์(t*1.9)*7.0, 0.0, 0.22, 4.0)
liquid_splat(เคอร์เซอร์ลิค, 18.0+โคไซน์(t*1.6)*7.0, 18.0+ไซน์(t*2.1)*7.0, 1.0, 0.18, 3.5)
bind bob = ไซน์(t*3.0)*0.10*s
bind d = s*0.55; bind bx = x - s*0.7; bind ax = x + s*1.0; bind ay = y + bob
# ลิ่มหมึก 3D (พีระมิดชี้ +x): 4 หน้าด้านข้าง → รับแสงต่างมุม = ดูเป็น 3 มิติ
โหมดผสม(0); สีดินสอ(24, 22, 40)
วาดสามเหลี่ยม3มิติ(ax, ay, z, bx, y-s+bob, z-d, bx, y+s+bob, z-d)
วาดสามเหลี่ยม3มิติ(ax, ay, z, bx, y+s+bob, z-d, bx, y+s+bob, z+d)
วาดสามเหลี่ยม3มิติ(ax, ay, z, bx, y+s+bob, z+d, bx, y-s+bob, z+d)
วาดสามเหลี่ยม3มิติ(ax, ay, z, bx, y-s+bob, z+d, bx, y-s+bob, z-d)
flush_3d()
# ออร์บหมึกเหลววาว (liquid ink shader) ที่โคนลิ่ม — ทิ้งโหมดผสมไว้ที่ 1 (เมนูวาดข้อความแบบบวกแสง)
โหมดผสม(1)
liquid_draw_surface(เคอร์เซอร์ลิค, 1.0, bx, y+bob, z, s*0.95, s*0.95)
flush_3d()
}
# วงแหวนเติม: แอนนูลัสเติม (rIn..rOut, seg ส่วน) บนระนาบ XZ ที่ y
ฟังก์ชัน วงแหวนเติม(x, y, z, rOut, rIn, seg, r, g, b) {
สีดินสอ(r, g, b)
bind k = 0
ขณะที่ k < seg {
bind a0 = (k / seg) * 6.28318; bind a1 = ((k + 1) / seg) * 6.28318
bind c0 = โคไซน์(a0); bind s0 = ไซน์(a0); bind c1 = โคไซน์(a1); bind s1 = ไซน์(a1)
วาดสามเหลี่ยม3มิติ(x+c0*rIn, y, z+s0*rIn, x+c0*rOut, y, z+s0*rOut, x+c1*rOut, y, z+s1*rOut)
วาดสามเหลี่ยม3มิติ(x+c0*rIn, y, z+s0*rIn, x+c1*rOut, y, z+s1*rOut, x+c1*rIn, y, z+s1*rIn)
bind k = k + 1
}
}
# ── เอฟเฟกต์อาวุธ AoE: คลื่นกระแทกเติมทึบ + สำเนียงต่างกันต่อชนิด (3-9) ──
ฟังก์ชัน วาดเอฟเฟกต์อาวุธ(typ, prog, rad, x, y, z) {
bind ex = (1.0 - prog) * rad + 4.0
bind h = typ * 0.9
bind br = prog
bind r = floor((ไซน์(h)*0.5+0.5)*205*br+30)
bind g = floor((ไซน์(h+2.094)*0.5+0.5)*205*br+30)
bind b = floor((ไซน์(h+4.189)*0.5+0.5)*205*br+30)
วงแหวนเติม(x, y, z, ex, ex*0.74, 20, r, g, b)
ถ้า typ == 3.0 { วาดสามเหลี่ยม3มิติ(x-3.0, y, z, x+3.0, y, z, x, y, z+ex*1.35) } # Torpedo: ลิ่มพุ่ง
ถ้า typ == 5.0 { วงแหวนเติม(x, y, z, ex*0.55, ex*0.34, 4, r, g, b) } # DualSword: กากบาท
ถ้า typ == 6.0 { # Burn: เปลวรอบวง
bind fk = 0
ขณะที่ fk < 8 { bind fa = (fk/8.0)*6.28318
วาดสามเหลี่ยม3มิติ(x+โคไซน์(fa)*ex*0.8, y, z+ไซน์(fa)*ex*0.8, x+โคไซน์(fa+0.25)*ex, y, z+ไซน์(fa+0.25)*ex, x+โคไซน์(fa)*ex*0.85, y-5.0, z+ไซน์(fa)*ex*0.85)
bind fk = fk + 1 }
}
ถ้า typ == 7.0 { วงแหวนเติม(x, y, z, ex*0.5, ex*0.18, 6, floor(r*0.5+120), floor(g*0.5+120), 255) } # Freeze: หกเหลี่ยมน้ำแข็ง
ถ้า typ == 8.0 { วงแหวนเติม(x, y, z, ex*0.56, ex*0.42, 24, floor(r*0.6+90), floor(g*0.6+90), floor(b*0.6+90)) } # Nova: วงซ้อน
ถ้า typ == 9.0 { # Quake: หนามแตกรัศมี
bind qk = 0
ขณะที่ qk < 10 { bind qa = (qk/10.0)*6.28318
วาดสามเหลี่ยม3มิติ(x+โคไซน์(qa-0.14)*ex*0.4, y, z+ไซน์(qa-0.14)*ex*0.4, x+โคไซน์(qa+0.14)*ex*0.4, y, z+ไซน์(qa+0.14)*ex*0.4, x+โคไซน์(qa)*ex*1.18, y, z+ไซน์(qa)*ex*1.18)
bind qk = qk + 1 }
}
}
# ── แถบปริมาณเสียง (สไลเดอร์ 0..1) ที่แถว yy: พื้นเทา + เติมฟ้า ──
ฟังก์ชัน แถบปริมาณ(vol, yy) {
สีดินสอ(45, 45, 62)
วาดสามเหลี่ยม3มิติ(2.0, yy-0.35, 0.0, 8.0, yy-0.35, 0.0, 8.0, yy+0.35, 0.0)
วาดสามเหลี่ยม3มิติ(2.0, yy-0.35, 0.0, 8.0, yy+0.35, 0.0, 2.0, yy+0.35, 0.0)
bind fw = 6.0 * vol
สีดินสอ(80, 200, 255)
วาดสามเหลี่ยม3มิติ(2.0, yy-0.35, 0.0, 2.0+fw, yy-0.35, 0.0, 2.0+fw, yy+0.35, 0.0)
วาดสามเหลี่ยม3มิติ(2.0, yy-0.35, 0.0, 2.0+fw, yy+0.35, 0.0, 2.0, yy+0.35, 0.0)
}
# ── วาดเมนูแนวตั้ง ────────────────────────────────────────────────────────────
ฟังก์ชัน วาดเมนู(items, sel, scale, spacing, t, lang) {
bind n = ความยาว(items)
bind oy = 0.0 - (n - 1) * spacing * 0.5
bind i = 0
ขณะที่ i < n {
bind row = list_get(items, i)
bind yy = oy + i * spacing
ถ้า i == sel {
ui_text_color(i, 1.0, t)
bind aw = (ความยาว(row) - 1) * scale * 0.66 * 0.5
เคอร์เซอร์หมึก(0.0 - aw - 1.4, yy, 0.0, 0.7, t)
ui_text_color(i, 1.0, t)
}
มิฉะนั้น {
ui_text_color(i, 0.0, t)
}
วาดข้อความ(row, 0.0, yy, 0.0, scale, lang)
bind i = i + 1
}
flush_3d()
}
# ── เมนูหลายภาษา ────────────────────────────────────────────────────────────
# วลี CJK (lang 2-5) item ที่ x กึ่งกลาง (สีตั้งไว้ก่อนเรียก)
ฟังก์ชัน วาดวลีเมนู(lang, item, x, y, sc) {
boot_text_style()
bind n = 0; bind adv = []
ถ้า lang == 2 { bind n = จำนวนอักขระ_MenuTH(item); bind adv = กว้าง_MenuTH(item) }
ถ้า lang == 3 { bind n = จำนวนอักขระ_MenuKO(item); bind adv = กว้าง_MenuKO(item) }
ถ้า lang == 4 { bind n = จำนวนอักขระ_MenuJA(item); bind adv = กว้าง_MenuJA(item) }
ถ้า lang == 5 { bind n = จำนวนอักขระ_MenuZH(item); bind adv = กว้าง_MenuZH(item) }
bind tw = 0.0; bind a0 = 0
ขณะที่ a0 < n { bind tw = tw + list_get(adv, a0) * sc; bind a0 = a0 + 1 }
bind cur = x - tw * 0.5; bind j = 0
ขณะที่ j < n {
bind w = list_get(adv, j) * sc
bind cxp = cur + w * 0.5
ถ้า lang == 2 { วาดอักขระ_MenuTH(item, j, cxp, y, 0.0, 1,0,0, 0,0.0-1.0,0, sc) }
ถ้า lang == 3 { วาดอักขระ_MenuKO(item, j, cxp, y, 0.0, 1,0,0, 0,0.0-1.0,0, sc) }
ถ้า lang == 4 { วาดอักขระ_MenuJA(item, j, cxp, y, 0.0, 1,0,0, 0,0.0-1.0,0, sc) }
ถ้า lang == 5 { วาดอักขระ_MenuZH(item, j, cxp, y, 0.0, 1,0,0, 0,0.0-1.0,0, sc) }
bind cur = cur + w; bind j = j + 1
}
ตั้งแฟลตเชด(0)
}
# ป้าย: รายการ item ในภาษา lang ที่ (x,y) (สีตั้งไว้ก่อนเรียก)
# นำ(ปุ่มคีย์, ขอบจอย): คีย์บอร์ด(Bool) หรือ จอย(ขอบ ≥0) → Bool — ใช้ทุกเมนูให้จอยเลื่อนได้
ฟังก์ชัน นำ(kb, gp) {
bind r = 0.0
ถ้า กดปุ่ม(kb) { bind r = 1.0 } # กดปุ่ม คืน Bool → ใช้ใน ถ้า ตรง ๆ
ถ้า gp > 0.5 { bind r = 1.0 }
คืน r > 0.5 # คืน Bool (ให้ ถ้า นำ(...) ใช้ได้)
}
# หมายเหตุ: ตั้งแฟลตเชด(1) ครอบทั้งฟังก์ชัน — ป้ายเมนู 2D ไม่ควรผ่านแสง/toon ramp
# จึงต้องไม่มี คืน กลางฟังก์ชัน (จะข้าม ตั้งแฟลตเชด(0) ปิดท้าย ทำให้ค้างเปิด)
ฟังก์ชัน วาดป้าย(lang, item, x, y, sc) {
boot_text_style()
ถ้า item == 19 {
ถ้า lang == 0 { วาดสตริง("online", x, y, 0.0, sc, 0) }
ถ้า lang == 1 { วาดสตริง("online", x, y, 0.0, sc, 1) }
ถ้า lang == 2 { วาดOnlineTH(x, y, sc*0.85, เวลาปัจจุบัน()) }
ถ้า lang == 3 { วาดOnlineKO(x, y, sc*0.85, เวลาปัจจุบัน()) }
ถ้า lang == 4 { วาดOnlineJA(x, y, sc*0.85, เวลาปัจจุบัน()) }
ถ้า lang == 5 { วาดOnlineZH(x, y, sc*0.85, เวลาปัจจุบัน()) }
}
มิฉะนั้น { ถ้า item == 18 { # อาร์เคด: เบคแล้วทุกภาษา (phrasebake)
ถ้า lang == 0 { วาดข้อความ(list_get(เมนูRM, item), x, y, 0.0, sc, 0) }
ถ้า lang == 1 { วาดข้อความ(list_get(เมนูEN, item), x, y, 0.0, sc, 1) }
ถ้า lang == 2 { วาดArcadeTH(x, y, sc*0.85) }
ถ้า lang == 3 { วาดArcadeKO(x, y, sc*0.85) }
ถ้า lang == 4 { วาดArcadeJA(x, y, sc*0.85) }
ถ้า lang == 5 { วาดArcadeZH(x, y, sc*0.85) }
}
มิฉะนั้น { ถ้า item > 18 { วาดข้อความ(list_get(เมนูEN, item), x, y, 0.0, sc, 1) }
มิฉะนั้น {
ถ้า lang == 0 { วาดข้อความ(list_get(เมนูRM, item), x, y, 0.0, sc, 0) }
ถ้า lang == 1 { วาดข้อความ(list_get(เมนูEN, item), x, y, 0.0, sc, 1) }
ถ้า lang >= 2 { วาดวลีเมนู(lang, item, x, y, sc) }
} } }
ตั้งแฟลตเชด(0)
}
# เมนูแนวตั้งหลายภาษา: ids = รายการดัชนี item; ไฮไลต์ที่ sel
ฟังก์ชัน วาดเมนูภาษา(ids, sel, lang, y0, dy, sc, t) {
bind n = ความยาว(ids)
bind i = 0
ขณะที่ i < n {
bind yy = y0 + i * dy
ถ้า i == sel {
เคอร์เซอร์หมึก(0.0-9.0, yy, 0.0, 0.7, t)
ui_text_color(i, 1.0, t)
}
มิฉะนั้น { ui_text_color(i, 0.0, t) }
วาดป้าย(lang, list_get(ids, i), 0.0, yy, sc)
bind i = i + 1
}
flush_3d()
}
# ดัชนี item สำหรับแต่ละเมนู
bind idsหลัก = [0, 1, 18, 2, 3, 19, 4, 14, 5]
bind idsพัก = [11, 4, 12, 5] # resume,options,mainmenu,exit
bind idsตัวเลือก = [13, 15, 16] # music,save,cancel (language ย้ายไปเมนูหลัก)
# เลขโรมัน i..xii (a-z: i=8 v=21 x=23) — ใช้ Daemon glyphs บนหน้าเต๋า
bind โรมัน = [[8],[8,8],[8,8,8],[8,21],[21],[21,8],[21,8,8],[21,8,8,8],[8,23],[23],[23,8],[23,8,8]]
# หน้าเลือกด่าน 10 ช่อง (tutorial=i + 9 levels) — ตาราง 2×5, เลขโรมัน, หัวข้อหลายภาษา
ฟังก์ชัน วาดเลือกด่าน(sel, lang, t, ปลดล็อก) {
สีดินสอ(200, 210, 245)
วาดป้าย(lang, 2, 0.0, 0.0-7.8, 1.0) # "level select" (localized)
bind k = 0
ขณะที่ k < 10 {
bind col = k - ปัดลง(k/5.0)*5.0
bind row = ปัดลง(k/5.0)
bind x = 0.0 - 10.0 + col*5.0
bind y = 0.0 - 1.5 + row*4.0
bind locked = 0; ถ้า k > ปลดล็อก { bind locked = 1 } # ด่านที่ยังไม่เล่นผ่าน = ล็อก
ถ้า k == sel {
bind h = t*3.0
ถ้า locked == 1 { สีดินสอ(120, 60, 60) } # เลือกด่านล็อก = แดงหรี่
มิฉะนั้น { สีดินสอ(floor((ไซน์(h)*0.5+0.5)*155+100), floor((ไซน์(h+2.094)*0.5+0.5)*155+100), floor((ไซน์(h+4.189)*0.5+0.5)*155+100)) }
วงเส้น(x, y, 2.0)
}
มิฉะนั้น {
ถ้า locked == 1 { สีดินสอ(55, 45, 55) } มิฉะนั้น { สีดินสอ(90, 100, 130) }
วงเส้น(x, y, 1.6)
}
ถ้า locked == 1 { สีดินสอ(70, 55, 70) } # เลขด่านล็อก = หรี่ + กุญแจ
วาดข้อความ(list_get(โรมัน, k), x, y, 0.0, 0.7, 1)
ถ้า locked == 1 { สีดินสอ(150, 90, 90); วงเส้น(x, y+0.55, 0.4); วาดเส้น3มิติ(x-0.4, y+0.55, 0.0, x+0.4, y+0.05, 0.0) } # ไอคอนกุญแจง่าย ๆ
bind k = k + 1
}
flush_3d()
}
# ════════════════════════════════════════════════════════════════════════════
# ลูกเต๋า 12 หน้า (dodecahedron) เลือกด่าน — ตัวอักษร A–L หมุนรอบแกนหน้า (UV หมุน)
# หน้า i (0–11) = ด่าน i+1 : 1–9 เนื้อเรื่อง · 10–12 โบนัส (หน้าทอง)
# ════════════════════════════════════════════════════════════════════════════
# 12 ทิศศูนย์กลางหน้า = จุดยอด icosahedron (perms ของ {0,±1,±φ})
ฟังก์ชัน ทิศหน้าเต๋า(i) {
bind P = 1.618034; bind N = 0.0 - 1.618034
bind d = [0.0,1.0,P, 0.0,1.0,N, 0.0,0.0-1.0,P, 0.0,0.0-1.0,N,
1.0,P,0.0, 1.0,N,0.0, 0.0-1.0,P,0.0, 0.0-1.0,N,0.0,
P,0.0,1.0, P,0.0,0.0-1.0, N,0.0,1.0, N,0.0,0.0-1.0]
bind b = i*3; bind m = 1.902113 # |(1,φ,0)| = √(1+φ²)
คืน [list_get(d,b)/m, list_get(d,b+1)/m, list_get(d,b+2)/m]
}
# หมุนเวกเตอร์รอบ Y(yaw) แล้ว X(pitch)
ฟังก์ชัน หมุนเต๋า(ax, ay, az, yaw, pit) {
bind cy = โคไซน์(yaw); bind sy = ไซน์(yaw)
bind rx = ax*cy + az*sy; bind rz = 0.0 - ax*sy + az*cy
bind cp = โคไซน์(pit); bind sp = ไซน์(pit)
bind ny = ay*cp - rz*sp; bind nz = ay*sp + rz*cp
คืน [rx, ny, nz]
}
# (yaw,pitch) ที่ทำให้หน้า target หันเข้ากล้อง (−Z) → ใช้หมุนเต๋าไปเลือกด่านปัจจุบัน
ฟังก์ชัน เป้าหมุนเต๋า(target) {
bind d = ทิศหน้าเต๋า(target)
bind dx = list_get(d,0); bind dy = list_get(d,1); bind dz = list_get(d,2)
bind yaw = atan2(0.0 - dx, dz) # หมุน Y ให้ x→0
bind zc = 0.0 - dx*ไซน์(yaw) + dz*โคไซน์(yaw)
ถ้า zc > 0.0 { bind yaw = yaw + 3.14159265 } # ให้หันด้าน −Z
bind zc2 = 0.0 - dx*ไซน์(yaw) + dz*โคไซน์(yaw)
bind pitch = atan2(0.0 - dy, 0.0 - zc2) # หมุน X ให้ (dy,zc2)→(0,−1)
คืน [yaw, pitch]
}
# บิตที่ b (b=1,2,4,…) ของ m
ฟังก์ชัน บิตเลข(m, b) { คืน floor(m/b) - floor(m/(b*2.0))*2.0 }
# เส้นเซกเมนต์ใน (u,v) กึ่งกลาง → โลก ตามฐาน right×up (s=สเกล)
ฟังก์ชัน เส้นเลข(cx,cy,cz, rx,ry,rz, ux,uy,uz, s, u0,v0, u1,v1) {
วาดเส้น3มิติ(cx+rx*u0*s+ux*v0*s, cy+ry*u0*s+uy*v0*s, cz+rz*u0*s+uz*v0*s, cx+rx*u1*s+ux*v1*s, cy+ry*u1*s+uy*v1*s, cz+rz*u1*s+uz*v1*s)
}
# ตัวเลข 7-seg d (0-9) — กึ่งกลางตัวเลขอยู่ที่ (cx,cy,cz), หมุนรอบกึ่งกลางตามฐาน right×up
ฟังก์ชัน วาดเลข3มิติ(d, cx,cy,cz, rx,ry,rz, ux,uy,uz, s) {
bind masks = [63,6,91,79,102,109,125,7,127,111] # a..g bitmask ต่อหลัก
bind m = list_get(masks, floor(d)); bind hw = 0.30; bind hh = 0.52
ถ้า บิตเลข(m,1) > 0.5 { เส้นเลข(cx,cy,cz, rx,ry,rz, ux,uy,uz, s, 0.0-hw,hh, hw,hh) } # a
ถ้า บิตเลข(m,2) > 0.5 { เส้นเลข(cx,cy,cz, rx,ry,rz, ux,uy,uz, s, hw,hh, hw,0.0) } # b
ถ้า บิตเลข(m,4) > 0.5 { เส้นเลข(cx,cy,cz, rx,ry,rz, ux,uy,uz, s, hw,0.0, hw,0.0-hh) } # c
ถ้า บิตเลข(m,8) > 0.5 { เส้นเลข(cx,cy,cz, rx,ry,rz, ux,uy,uz, s, 0.0-hw,0.0-hh, hw,0.0-hh) } # d
ถ้า บิตเลข(m,16) > 0.5 { เส้นเลข(cx,cy,cz, rx,ry,rz, ux,uy,uz, s, 0.0-hw,0.0, 0.0-hw,0.0-hh) }# e
ถ้า บิตเลข(m,32) > 0.5 { เส้นเลข(cx,cy,cz, rx,ry,rz, ux,uy,uz, s, 0.0-hw,hh, 0.0-hw,0.0) } # f
ถ้า บิตเลข(m,64) > 0.5 { เส้นเลข(cx,cy,cz, rx,ry,rz, ux,uy,uz, s, 0.0-hw,0.0, hw,0.0) } # g
คืน 0
}
# เลขด่าน 1-12 จัดกึ่งกลางหน้า (1 หรือ 2 หลัก) — กึ่งกลางกลุ่มอยู่ที่ (cx,cy,cz)
ฟังก์ชัน วาดเลขเต๋า(num, cx,cy,cz, rx,ry,rz, ux,uy,uz, s) {
ถ้า num < 10 { วาดเลข3มิติ(num, cx,cy,cz, rx,ry,rz, ux,uy,uz, s); คืน 0 }
bind o = 0.42*s
วาดเลข3มิติ(1, cx - rx*o, cy - ry*o, cz - rz*o, rx,ry,rz, ux,uy,uz, s*0.9)
วาดเลข3มิติ(num-10, cx + rx*o, cy + ry*o, cz + rz*o, rx,ry,rz, ux,uy,uz, s*0.9)
คืน 0
}
ฟังก์ชัน วาดเลขเต๋าเดมอน(num, cx,cy,cz, rx,ry,rz, ux,uy,uz, s) {
boot_text_style()
bind row = list_get(โรมัน, floor(num)-1)
bind n = ความยาว(row)
bind adv = s * 0.48
bind start = 0.0 - (n - 1.0) * adv * 0.5
bind j = 0
ขณะที่ j < n {
bind code = list_get(row, j)
bind off = start + j*adv
วาดอบเมช(list_get(_กลิฟเดมอน, code), cx+rx*off, cy+ry*off, cz+rz*off, rx,ry,rz, ux,uy,uz, s)
bind j = j + 1
}
ตั้งแฟลตเชด(0)
คืน 0
}
# คืน index หน้าที่หันเข้ากล้องมากสุด ( = ด่านที่เลือก )
# selFace = หน้าที่เลือก (ไฮไลต์ + เต๋าหมุนมาหา) ; คืน selFace
ฟังก์ชัน วาดลูกเต๋าด่าน(dieYaw, diePitch, t, ปลดล็อก, selFace) {
bind R = 4.6; bind dcx = 0.0; bind dcy = 0.0 - 0.5; bind dcz = 0.0
bind front = floor(selFace) # หน้าที่เลือก (เต๋าเอียงมาให้หันหน้า)
ตั้งแสงรอบข้าง(0.95) # (หน้าเต๋าเป็น วาดสามเหลี่ยม3มิติ = ไม่กินไฟเอนจิน — คุมสว่างเองด้านล่าง)
# ── ไฟส่องหน้าเต๋า: ดวงไฟอยู่ "ข้างหน้า" ลูกเต๋า (ฝั่งกล้อง -z) เยื้องซ้าย-บน ──
# เดิมความสว่างเป็น 0.62 + (-nz)*0.38 = แลมเบิร์ตของไฟที่ทับตำแหน่งกล้องพอดี
# ทุกหน้าจึงสว่างตามความ "ตรงหน้า" อย่างเดียว ไม่มีการโมเดลรูปทรง — ย้ายไฟออก
# มาเยื้องแล้วคิดแลมเบิร์ตจากตำแหน่งจริงต่อหน้า หน้าที่หันเข้าไฟจึงสว่างไล่ระดับ
bind ไฟx = 0.0 - 6.0; bind ไฟy = 0.0 - 7.5; bind ไฟz = 0.0 - 13.0
# หน้าเต๋าวาดด้วย วาดสามเหลี่ยม3มิติ ซึ่ง "กินแสงฉาก" จริง ไม่ใช่สีล้วน —
# ก่อนหน้านี้ตั้งแต่แอมเบียนต์อย่างเดียวโดยไม่เคยมี เพิ่มแสง เลย (และหน้าเมนู
# ก่อนหน้าอาจ ล้างแสง ทิ้งไว้) ทุกหน้าจึงออกมาเกือบดำสนิท เห็นแค่เสี้ยวที่บังเอิญ
# โดนแสงค้างจากฉากก่อน ใส่ไฟจริงที่ตำแหน่งเดียวกับที่ใช้คิดแลมเบิร์ตด้านล่าง
ล้างแสง()
เพิ่มแสง(ไฟx, ไฟy, ไฟz, 1.0, 0.97, 0.92, 1.55, 90.0) # คีย์หน้าเต๋า
เพิ่มแสง(9.0, 4.0, 0.0 - 16.0, 0.55, 0.65, 1.0, 0.75, 80.0) # ฟิลเย็นอีกฝั่ง กันหน้าข้างดำสนิท
# ── วาดหน้า (z-buffer = ทึบถูกต้อง) ──
set_depth_test(1)
bind i = 0
ขณะที่ i < 12 {
bind dd = ทิศหน้าเต๋า(i)
bind nn = หมุนเต๋า(list_get(dd,0), list_get(dd,1), list_get(dd,2), dieYaw, diePitch)
bind nx = list_get(nn,0); bind ny = list_get(nn,1); bind nz = list_get(nn,2)
ถ้า nz < 0.06 { # เฉพาะหน้าหน้า (cull หลัง)
bind cx = dcx + nx*R; bind cy = dcy + ny*R; bind cz = dcz + nz*R
# ฐานสัมผัสในระนาบหน้า: T = norm(up × N), B = N × T
bind tx = nz; bind ty = 0.0; bind tz = 0.0 - nx
bind tl = รากที่สอง(tx*tx + tz*tz); ถ้า tl < 0.001 { bind tx = 1.0; bind tz = 0.0; bind tl = 1.0 }
bind tx = tx/tl; bind tz = tz/tl
bind bx = ny*tz - nz*ty; bind by = nz*tx - nx*tz; bind bz = nx*ty - ny*tx
bind lvl = i + 1
bind locked = 0; ถ้า lvl > ปลดล็อก { bind locked = 1 }
# ── สีหน้า: ROYGBIV ประจำหน้า · ล็อก=หม่น · หน้าหน้า=สว่างเต้น ──
# เดิมหน้า 10-12 ถูกทาทองรวดเป็น "โบนัส" — ตอนนี้ 10-12 คือไฟนอล 1-3
# และโบนัสย้ายไปเป็นเลเวล 13 (หลังตอนจบ) ซึ่งไม่มีหน้าบนทรงสิบสองหน้า
# ทุกหน้าจึงได้สีประจำตัวตามลำดับสีรุ้งเหมือนกันหมด
bind hue = i * 0.5236
bind fr = floor((ไซน์(hue)*0.5+0.5)*165+85); bind fg = floor((ไซน์(hue+2.094)*0.5+0.5)*165+85); bind fb = floor((ไซน์(hue+4.189)*0.5+0.5)*165+85)
# ปลดล็อกโบนัส (เลเวล 13) แล้ว: หน้าสุดท้าย (เลเวล 12 = จบเกม) ไล่สีวน
# เป็นสัญญาณว่ายังมีรอบพิเศษต่อจากตอนจบ
ถ้า ปลดล็อก > 12.0 { ถ้า i == 11 {
bind bh = t * 2.2
bind fr = floor((ไซน์(bh)*0.5+0.5)*160+95)
bind fg = floor((ไซน์(bh+2.094)*0.5+0.5)*160+95)
bind fb = floor((ไซน์(bh+4.189)*0.5+0.5)*160+95)
} }
# แลมเบิร์ตจากดวงไฟหน้าเต๋า + แอมเบียนต์พื้น (ยังคุมพื้นไว้ไม่ให้หน้าข้างดำจนอ่านเลขไม่ออก)
bind lvx = ไฟx - cx; bind lvy = ไฟy - cy; bind lvz = ไฟz - cz
bind lvd = รากที่สอง(lvx*lvx + lvy*lvy + lvz*lvz); ถ้า lvd < 0.001 { bind lvd = 0.001 }
bind ndl = (nx*lvx + ny*lvy + nz*lvz) / lvd
ถ้า ndl < 0.0 { bind ndl = 0.0 }
bind sh = 0.58 + ndl*0.62 # พื้น 0.58: หน้าที่หันหนีไฟก็ยังอ่านเลขออก ไม่ดำสนิท
ถ้า sh > 1.18 { bind sh = 1.18 }
ถ้า i == front { bind sh = sh*0.45 + (0.94 + ไซน์(t*5.0)*0.08) } # หน้าที่เลือกเด่นไว้เหมือนเดิม
ถ้า locked == 1 { bind fr = floor(fr*0.28); bind fg = floor(fg*0.28); bind fb = floor(fb*0.30) }
สีดินสอ(floor(fr*sh), floor(fg*sh), floor(fb*sh))
# ── เพนตากอนหน้า (พัด 5 สามเหลี่ยมจากศูนย์กลาง) ──
bind pr = 1.95; bind fa = t*0.25 + i
bind k = 0
ขณะที่ k < 5 {
bind a0 = k*1.2566 + fa; bind a1 = (k+1)*1.2566 + fa
bind p0x = cx + (โคไซน์(a0)*tx + ไซน์(a0)*bx)*pr; bind p0y = cy + (โคไซน์(a0)*ty + ไซน์(a0)*by)*pr; bind p0z = cz + (โคไซน์(a0)*tz + ไซน์(a0)*bz)*pr
bind p1x = cx + (โคไซน์(a1)*tx + ไซน์(a1)*bx)*pr; bind p1y = cy + (โคไซน์(a1)*ty + ไซน์(a1)*by)*pr; bind p1z = cz + (โคไซน์(a1)*tz + ไซน์(a1)*bz)*pr
วาดสามเหลี่ยม3มิติ(cx, cy, cz, p0x, p0y, p0z, p1x, p1y, p1z)
bind k = k + 1
}
# ── เลขด่าน: Daemon roman glyphs จัดกึ่งกลางบน face tangent plane ──
bind rxL = tx; bind ryL = ty; bind rzL = tz
bind uxL = bx; bind uyL = by; bind uzL = bz
bind ls = 1.00; ถ้า i == front { bind ls = 1.25 }
ถ้า locked == 1 { สีดินสอ(135, 105, 110) }
มิฉะนั้น {
ถ้า i == front { bind hg = t*3.0; สีดินสอ(floor((ไซน์(hg)*0.5+0.5)*95+160), floor((ไซน์(hg+2.094)*0.5+0.5)*95+160), floor((ไซน์(hg+4.189)*0.5+0.5)*95+160)) }
มิฉะนั้น { สีดินสอ(245, 248, 255) }
}
bind lo = 0.45
วาดเลขเต๋าเดมอน(lvl, cx+nx*lo, cy+ny*lo, cz+nz*lo, rxL,ryL,rzL, uxL,uyL,uzL, ls)
set_depth_test(1)
set_flat_shade(0.0)
}
bind i = i + 1
}
flush_3d()
set_depth_test(0)
# ── หางเรืองแสงของเลขไวร์เฟรม (พาสเสริม additive, painter's — หางไม่ขาดเพราะไม่มี z-reject) ──
โหมดผสม(1)
bind i2 = 0
ขณะที่ i2 < 12 {
bind dd2 = ทิศหน้าเต๋า(i2)
bind nn2 = หมุนเต๋า(list_get(dd2,0), list_get(dd2,1), list_get(dd2,2), dieYaw, diePitch)
bind nx2 = list_get(nn2,0); bind ny2 = list_get(nn2,1); bind nz2 = list_get(nn2,2)
ถ้า nz2 < 0.02 {
bind cx2 = dcx + nx2*R; bind cy2 = dcy + ny2*R; bind cz2 = dcz + nz2*R
bind tx2 = nz2; bind ty2 = 0.0; bind tz2 = 0.0 - nx2
bind tl2 = รากที่สอง(tx2*tx2 + tz2*tz2); ถ้า tl2 < 0.001 { bind tx2 = 1.0; bind tz2 = 0.0; bind tl2 = 1.0 }
bind tx2 = tx2/tl2; bind tz2 = tz2/tl2
bind bx2 = ny2*tz2 - nz2*ty2; bind by2 = nz2*tx2 - nx2*tz2; bind bz2 = nx2*ty2 - ny2*tx2
bind lvl2 = i2 + 1
bind lck2 = 0; ถ้า lvl2 > ปลดล็อก { bind lck2 = 1 }
bind hue2 = i2*0.5236 + t
bind gr = ไซน์(hue2)*0.5+0.5; bind gg = ไซน์(hue2+2.094)*0.5+0.5; bind gb = ไซน์(hue2+4.189)*0.5+0.5
ถ้า lck2 == 1 { bind gr = 0.35; bind gg = 0.18; bind gb = 0.2 }
bind lo2 = 0.45; bind lsG = 1.00; ถ้า i2 == front { bind lsG = 1.25 }
bind td2 = 5
ขณะที่ td2 >= 1 {
bind gf = (1.0 - td2/6.0) * 65.0
สีดินสอ(floor(gr*gf), floor(gg*gf), floor(gb*gf))
วาดเลขเต๋าเดมอน(lvl2, cx2+nx2*lo2, cy2+ny2*lo2, cz2+nz2*lo2, tx2,ty2,tz2, bx2,by2,bz2, lsG)
bind td2 = td2 - 1
}
}
bind i2 = i2 + 1
}
flush_3d()
โหมดผสม(0)
# ── ป้าย 2D: ด่านที่เลือก + สถานะล็อก ──
bind fl = front + 1
ถ้า fl > ปลดล็อก { สีดินสอ(190, 110, 110); วาดสตริง("locked - clear the level before", 0.0, 7.6, 0.0, 0.5, 1) }
มิฉะนั้น {
ถ้า front > 8 { สีดินสอ(255, 210, 110); วาดสตริง("bonus level " + to_str(fl), 0.0, 7.6, 0.0, 0.6, 1) }
มิฉะนั้น { สีดินสอ(170, 220, 200); วาดสตริง("level " + to_str(fl), 0.0, 7.6, 0.0, 0.6, 1) }
}
สีดินสอ(150, 160, 195); วาดสตริง("[<-/->] spin [enter] play [esc] back", 0.0, 8.6, 0.0, 0.42, 1)
flush_3d()
คืน front
}
# เมนูเลือกภาษา: แต่ละตัวเลือกเป็นชื่อภาษาของตัวเอง (endonym, ฟอนต์ของภาษานั้น)
# ชื่อภาษาแต่ละภาษา เขียนด้วยสคริปต์ของภาษานั้นเอง (ใช้ทั้งจอเลือกภาษาและ
# แถวสรุปค่าปัจจุบันในหน้าตัวเลือก)
ฟังก์ชัน วาดชื่อภาษา(lang, x, y, sc) {
ถ้า lang == 0 { วาดข้อความ(คำ_เดมอน, x, y, 0.0, sc, 0) }
ถ้า lang == 1 { วาดข้อความ(คำ_อังกฤษ, x, y, 0.0, sc, 1) }
ถ้า lang == 2 { วาดวลีเมนู(2, 6, x, y, sc*1.53) }
ถ้า lang == 3 { วาดวลีเมนู(3, 6, x, y, sc*1.76) }
ถ้า lang == 4 { วาดวลีเมนู(4, 6, x, y, sc*1.76) }
ถ้า lang == 5 { วาดวลีเมนู(5, 6, x, y, sc*1.76) }
}
# หัวข้อจอเลือกภาษา — บอกว่ากำลังตั้งค่าอันไหนอยู่
# 0 = ตั้งภาษารวมทุกอย่าง (เมนูหลัก → Language)
# 1 = ภาษา UI/เมนู · 2 = ภาษาพากย์ · 3 = ภาษาซับ (ทั้งสามมาจากหน้า Options)
ฟังก์ชัน วาดหัวข้อเลือกภาษา(หัวข้อ, y) {
สีดินสอ(245, 232, 170)
ถ้า หัวข้อ == 0 { วาดสตริง("set global language", 0.0, y, 0.0, 0.62, 1) }
ถ้า หัวข้อ == 1 { วาดสตริง("ui / menu language", 0.0, y, 0.0, 0.62, 1) }
ถ้า หัวข้อ == 2 { วาดสตริง("voiceover language", 0.0, y, 0.0, 0.62, 1) }
ถ้า หัวข้อ == 3 { วาดสตริง("subtitle language", 0.0, y, 0.0, 0.62, 1) }
สีดินสอ(120, 125, 155)
ถ้า หัวข้อ == 0 { วาดสตริง("sets dub, subtitles and menus", 0.0, y + 1.05, 0.0, 0.34, 1) }
ถ้า หัวข้อ == 2 { วาดสตริง("spoken dialogue audio", 0.0, y + 1.05, 0.0, 0.34, 1) }
ถ้า หัวข้อ == 3 { วาดสตริง("on-screen dialogue text", 0.0, y + 1.05, 0.0, 0.34, 1) }
ถ้า หัวข้อ == 1 { วาดสตริง("menus and interface text", 0.0, y + 1.05, 0.0, 0.34, 1) }
flush_3d()
}
ฟังก์ชัน วาดเมนูเลือกภาษา(sel, t, หัวข้อ) {
วาดหัวข้อเลือกภาษา(หัวข้อ, 0.0 - 7.6)
bind i = 0
ขณะที่ i < 6 {
bind yy = 0.0 - 4.2 + i * 1.92
ถ้า i == sel {
เคอร์เซอร์หมึก(0.0-7.0, yy, 0.0, 0.7, t)
สีดินสอ(235, 220, 145)
}
มิฉะนั้น { สีดินสอ(110, 110, 140) }
วาดชื่อภาษา(i, 0.0, yy, 0.85)
bind i = i + 1
}
flush_3d()
}
# ── พื้นหลังเมนู ──────────────────────────────────────────────────────────────
ฟังก์ชัน วาดพื้นหลังเมนู(กรอบ) {
เติม(2, 2, 9)
ตั้งหมอก(0, 0, 0, 0.0, 0.0) # ปิดหมอก (กันหมอกน้ำเงินจากไตเติลรั่วเข้าเมนู)
set_flat_shade(0.0) # LIT (เซล): เมนูรับแสง → มีมิติ/สี (ไม่แบนตาย/unlit)
ล้างแสง() # เคลียร์ไฟทุกเฟรม (ไฟไม่สะสม/ไม่ลากค้าง) แล้วตั้งใหม่ด้านล่าง
ตั้งแสงรอบข้าง(0.62)
เพิ่มแสง(0.0, 0.0-5.0, 0.0-13.0, 1.0, 0.92, 0.82, 1.25, 280.0) # ไฟนุ่มหน้าฉาก (เมนูสว่าง+มีมิติ)
# ── โซ่ไฟ 3 ดวงวิ่งตามเส้นปมเซลติก (ส่องเมนูจริง — เส้นทางเดียวกับ วาดมณฑล) ──
bind lt = กรอบ * 0.01
bind li = 0
ขณะที่ li < 3 {
bind lf = lt*0.06 + li/3.0; bind lf = lf - floor(lf)
bind ls2 = 6.2832 * lf
bind lx = 6.0*โคไซน์(ls2) + 2.4*โคไซน์(5.0*ls2)
bind ly = 6.0*ไซน์(ls2) - 2.4*ไซน์(5.0*ls2)
bind lz = 2.2*ไซน์(10.0*ls2) - 4.0
bind lh = lf*6.2832 + lt
เพิ่มแสง(lx, ly, lz, ไซน์(lh)*0.5+0.5, ไซน์(lh+2.094)*0.5+0.5, ไซน์(lh+4.189)*0.5+0.5, 1.2, 120.0)
bind li = li + 1
}
ตั้งกล้องมอง(0.0, 0.0, -22.0, 0.0, 0.0, 0.0)
ตั้งระยะห่าง(2.8)
โหมดผสม(1)
วาดมณฑล(กรอบ)
flush_3d()
โหมดผสม(0)
}
# ── พรีโหลด: หน้าจอโหลด (วงแหวนลูกบาศก์สีรุ้ง + "loading") นาน dur วินาที ──
ฟังก์ชัน พรีโหลด(dur) {
bind t0 = เวลาปัจจุบัน()
bind go = 1
ขณะที่ go == 1 {
bind tt = เวลาปัจจุบัน() - t0
ถ้า tt >= dur { bind go = 0 }
เติม(3, 2, 10)
ตั้งแสงรอบข้าง(0.5)
ตั้งกล้องมอง(0.0, 0.0, -22.0, 0.0, 0.0, 0.0)
ตั้งระยะห่าง(2.8)
โหมดผสม(1)
bind k = 0
ขณะที่ k < 16 {
bind h = tt*1.6 + k*0.3
# ── หางดาวหาง: สำเนาอดีต 7 ตำแหน่งตามวงโคจร จางลงไปทางหาง (additive) ──
bind td = 6
ขณะที่ td >= 0 {
bind aa = tt*3.5 + k*0.3927 - td*0.09
bind rr = 4.5 + ไซน์(tt*4.0 + k*0.5 - td*0.09)*0.7
bind fade = 1.0 - td/7.0
สีดินสอ(floor(((ไซน์(h)*0.5+0.5)*200+40)*fade), floor(((ไซน์(h+2.094)*0.5+0.5)*200+40)*fade), floor(((ไซน์(h+4.189)*0.5+0.5)*200+40)*fade))
วาดลูกบาศก์(โคไซน์(aa)*rr, ไซน์(aa)*rr, 0.0, 0.45*(0.35+0.65*fade))
bind td = td - 1
}
bind k = k + 1
}
สีดินสอ(220, 225, 255)
วาดข้อความ(คำ_โหลดดิ้ง, 0.0, 9.0, 0.0, 0.8, 1)
flush_3d()
โหมดผสม(0)
แสดงผล()
}
}
# ── เสียงชนพื้น/ผนัง: ระฆังจูนกับโน้ตเพลงปัจจุบัน; ดัง+สูงขึ้นตามแรงปะทะ ──
# freqs = เก็บความถี่ (โน้ต MIDI ของเพลงเลเวล), n = จำนวนโน้ต, impact = ความเร็วเข้าผิว
ฟังก์ชัน เสียงชน(freqs, n, impact, vol, x, y, z) {
ถ้า impact > 0.08 { ถ้า n > 0.5 {
bind ni = ปัดลง(impact * 26.0); bind ni = ni - ปัดลง(ni / n) * n # แรงขึ้น = โน้ตสูงขึ้น
bind v = impact * 5.0; ถ้า v > 1.0 { bind v = 1.0 } # ดังขึ้นมาก ๆ ตามแรง
bind v = v * vol # คูณระดับ SFX
เสียงเอฟเฟกต์(x, y, z, 1.0, list_get(freqs, ni) * 4.0, v, 0.32 + impact*0.9, "sine") # ×4 = สูงขึ้น 2 ออกเทฟ (เสียงเด้งลูก)
} }
}
# ════════════════════════════════════════════════════════════════════════════
# บูตโลโก้ "made in ling country" (Daemon font)
# ════════════════════════════════════════════════════════════════════════════
# บูต: 4 บรรทัด "made / in ling / country / press start" ไถลเข้าตามรางรถไฟ 3D
# (ฟอนต์อังกฤษ legible). NOTE: เวอร์ชัน 5 ภาษา (ไทย/เกา/ญี่/จีน) ต้องมีฟอนต์ CJK
# ซึ่งดาวน์โหลด/เบคไม่ได้ที่นี่ (glyph baker = a-z) — ใช้ละติน
# (ฟอนต์ CJK เบคแล้ว: Thai/Korean/Japanese/Chinese — แต่ละบรรทัดเป็นวลีแยก)
# ride-in ต่อตัวอักษร: ตัว j เข้าจากซ้าย(คู่)/ขวา(คี่) ไปยังตำแหน่ง, ease-out
# แทร็กละติน: row = อาเรย์ดัชนีกลิฟ (English/Daemon); dim = ความสว่าง (เฟดจบ)
ฟังก์ชัน แทร็กละติน(row, y, lang, sc, prog, t, dim) {
bind n = ความยาว(row)
bind adv = sc * 0.66
bind sx = 0.0 - (n - 1) * adv * 0.5
bind j = 0
ขณะที่ j < n {
bind code = list_get(row, j)
ถ้า code >= 0 {
bind lp = (prog - j*0.02) / 0.3
ถ้า lp < 0.0 { bind lp = 0.0 }
ถ้า lp > 1.0 { bind lp = 1.0 }
bind ease = 1.0 - (1.0-lp)*(1.0-lp)
bind side = 1.0
ถ้า j - ปัดลง(j/2.0)*2.0 == 1.0 { bind side = 0.0-1.0 }
bind lx = (sx + j*adv) + side*46.0*(1.0-ease)
bind hu = t*1.6 + j*0.5
สีดินสอ(floor(((ไซน์(hu)*0.5+0.5)*185+70)*dim), floor(((ไซน์(hu+2.094)*0.5+0.5)*185+70)*dim), floor(((ไซน์(hu+4.189)*0.5+0.5)*185+70)*dim))
วาดกลิฟ(lang, code, lx, y, 0.0, sc)
}
bind j = j + 1
}
}
# แทร็กวลี (CJK): lid 2=Thai 3=Korean 4=Japanese 5=Chinese
ฟังก์ชัน แทร็กวลี(lid, y, sc, prog, t, dim) {
ตั้งแฟลตเชด(1)
bind n = 0; bind adv = []
ถ้า lid == 2 { bind n = จำนวนอักขระ_Thai(); bind adv = กว้าง_Thai() }
ถ้า lid == 3 { bind n = จำนวนอักขระ_Korean(); bind adv = กว้าง_Korean() }
ถ้า lid == 4 { bind n = จำนวนอักขระ_Japanese(); bind adv = กว้าง_Japanese() }
ถ้า lid == 5 { bind n = จำนวนอักขระ_Chinese(); bind adv = กว้าง_Chinese() }
bind tw = 0.0; bind a0 = 0
ขณะที่ a0 < n { bind tw = tw + list_get(adv, a0) * sc; bind a0 = a0 + 1 }
bind cur = 0.0 - tw * 0.5
bind j = 0
ขณะที่ j < n {
bind w = list_get(adv, j) * sc
bind lp = (prog - j*0.03) / 0.3
ถ้า lp < 0.0 { bind lp = 0.0 }
ถ้า lp > 1.0 { bind lp = 1.0 }
bind ease = 1.0 - (1.0-lp)*(1.0-lp)
bind side = 1.0
ถ้า j - ปัดลง(j/2.0)*2.0 == 1.0 { bind side = 0.0-1.0 }
bind lx = (cur + w*0.5) + side*46.0*(1.0-ease)
bind hu = t*1.6 + j*0.6 + lid
สีดินสอ(floor(((ไซน์(hu)*0.5+0.5)*185+70)*dim), floor(((ไซน์(hu+2.094)*0.5+0.5)*185+70)*dim), floor(((ไซน์(hu+4.189)*0.5+0.5)*185+70)*dim))
ถ้า lid == 2 { วาดอักขระ_Thai(j, lx, y, 0.0, 1,0,0, 0,0.0-1.0,0, sc) }
ถ้า lid == 3 { วาดอักขระ_Korean(j, lx, y, 0.0, 1,0,0, 0,0.0-1.0,0, sc) }
ถ้า lid == 4 { วาดอักขระ_Japanese(j, lx, y, 0.0, 1,0,0, 0,0.0-1.0,0, sc) }
ถ้า lid == 5 { วาดอักขระ_Chinese(j, lx, y, 0.0, 1,0,0, 0,0.0-1.0,0, sc) }
bind cur = cur + w
bind j = j + 1
}
ตั้งแฟลตเชด(0)
}
ฟังก์ชัน วาดบูต(prog, t) {
# ตัวอักษรลงตัว ~0.62 → ค้างไว้ → eased fade to black; no grey flash frame
bind fadeIn = prog / 0.16; ถ้า fadeIn > 1.0 { bind fadeIn = 1.0 }; ถ้า fadeIn < 0.0 { bind fadeIn = 0.0 }
bind fadeOut = 1.0
ถ้า prog > 0.78 { bind fadeOut = 1.0 - (prog-0.78)/0.22; ถ้า fadeOut < 0.0 { bind fadeOut = 0.0 } }
bind fadeIn = fadeIn*fadeIn*(3.0 - 2.0*fadeIn)
bind fadeOut = fadeOut*fadeOut*(3.0 - 2.0*fadeOut)
bind dim = fadeIn * fadeOut
เติม(0, 0, 0)
ตั้งกล้องมอง(0.0, 0.0, -30.0, 0.0, 0.0, 0.0)
ตั้งระยะห่าง(3.0)
# ── ตัวอักษร LIT (เซล): รับแสง → สี + มิติ; painter's + stable sort กันกะพริบ ──
set_flat_shade(0.0) # 0 = รับแสง (เซล) → กลิฟมีสี+มิติ (ไม่แบนตาย)
set_depth_test(0) # painter's (stable sort กันไตรฯ โคเพลนาร์กะพริบ)
ล้างแสง()
ตั้งแสงรอบข้าง(0.58) # ฟิลสว่างพอ (ตัวอักษรไม่มืด)
bind lp = t*0.6
เพิ่มแสง(โคไซน์(lp)*16.0, 0.0-9.0, 0.0-14.0, 1.0, 0.85, 0.7, 1.25, 300.0) # คีย์อุ่น หมุนช้า
เพิ่มแสง(โคไซน์(lp+3.14)*16.0, 9.0, 0.0-14.0, 0.7, 0.85, 1.0, 1.15, 300.0) # ฟิลเย็น
# 6 ราง — English, Daemon, Thai, Korean, Japanese, Chinese (เส้นสีรุ้งไล่ แบนล้วน ไม่ลิต)
โหมดผสม(0)
bind r = 0
ขณะที่ r < 6 {
bind ry = 0.0 - 7.5 + r * 3.0
bind rh = t*0.6 + r*0.5
สีดินสอ(floor(((ไซน์(rh)*0.5+0.5)*200+55)*dim), floor(((ไซน์(rh+2.094)*0.5+0.5)*200+55)*dim), floor(((ไซน์(rh+4.189)*0.5+0.5)*205+50)*dim))
วาดเส้น3มิติ(0.0-22.0, ry + 1.3, 0.0, 22.0, ry + 1.3, 0.0)
bind r = r + 1
}
flush_3d()
# ── ตัวอักษร 3D: โหมดปกติ + รับแสง (เซล) → สีคมชัด มีมิติ ไม่กะพริบ ──
โหมดผสม(0)
# ทยอยเข้า (settle ~prog 0.6) → ถือไว้ → smooth fade to black
แทร็กละติน(คำ_บูต, 0.0-7.5, 1, 0.95, prog - 0.00, t, dim) # English
แทร็กละติน(คำ_โรมาจิ, 0.0-4.5, 0, 0.85, prog - 0.04, t, dim) # Daemon โรมาจิ
แทร็กวลี(2, 0.0-1.5, 1.5, prog - 0.08, t, dim) # Thai
แทร็กวลี(3, 1.5, 1.7, prog - 0.12, t, dim) # Korean
แทร็กวลี(4, 4.5, 1.7, prog - 0.16, t, dim) # Japanese
แทร็กวลี(5, 7.5, 1.7, prog - 0.20, t, dim) # Chinese
flush_3d()
# ── คืนสถานะ: ปิดพาสบวก + แบนดิบ + ล้างไฟบูต (ไม่รั่วเข้าไตเติล) ──
โหมดผสม(0)
set_flat_shade(1.0)
ล้างแสง()
}
# ════════════════════════════════════════════════════════════════════════════
# หน้าชื่อเรื่อง: มณฑล + วงแหวนกลิฟ 8 วง (Daemon art)
# ════════════════════════════════════════════════════════════════════════════
ฟังก์ชัน วาดลูกบาศก์(cx, cy, cz, a) {
วาดเส้น3มิติ(cx-a,cy-a,cz-a, cx+a,cy-a,cz-a)
วาดเส้น3มิติ(cx+a,cy-a,cz-a, cx+a,cy-a,cz+a)
วาดเส้น3มิติ(cx+a,cy-a,cz+a, cx-a,cy-a,cz+a)
วาดเส้น3มิติ(cx-a,cy-a,cz+a, cx-a,cy-a,cz-a)
วาดเส้น3มิติ(cx-a,cy+a,cz-a, cx+a,cy+a,cz-a)
วาดเส้น3มิติ(cx+a,cy+a,cz-a, cx+a,cy+a,cz+a)
วาดเส้น3มิติ(cx+a,cy+a,cz+a, cx-a,cy+a,cz+a)
วาดเส้น3มิติ(cx-a,cy+a,cz+a, cx-a,cy+a,cz-a)
วาดเส้น3มิติ(cx-a,cy-a,cz-a, cx-a,cy+a,cz-a)
วาดเส้น3มิติ(cx+a,cy-a,cz-a, cx+a,cy+a,cz-a)
วาดเส้น3มิติ(cx+a,cy-a,cz+a, cx+a,cy+a,cz+a)
วาดเส้น3มิติ(cx-a,cy-a,cz+a, cx-a,cy+a,cz+a)
}
ฟังก์ชัน วาดมณฑล(กรอบ) {
# ── โซ่แสงไหลไปตามเส้นปมเซลติก (knotwork rosette) — เรืองแสงแบบ additive ──
# เส้นทางปิด: x = a·cos s + b·cos(k·s) , y = a·sin s − b·sin(k·s) (k=5 → 6 กลีบปม)
bind tt = กรอบ * 0.01
bind N = 30.0
bind i = 0
ขณะที่ i < N {
bind f = tt*0.06 + i/N; bind f = f - floor(f) # เฟสไหลของแต่ละดวง (0..1)
bind s = 6.2832 * f
bind ex = 6.0*โคไซน์(s) + 2.4*โคไซน์(5.0*s)
bind ey = 6.0*ไซน์(s) - 2.4*ไซน์(5.0*s)
bind ez = 2.2*ไซน์(10.0*s) # สานขึ้น/ลง (ปมทับกัน)
bind br = 0.55 + 0.45*ไซน์(s*2.5 + tt*2.0) # กะพริบนุ่มไล่ไปตามโซ่
bind ขนาด = 0.26 + 0.16*(ไซน์(f*12.566 + tt*3.0)*0.5+0.5)
bind h = f*6.2832 + tt # ROYGBIV ตามตำแหน่งบนเส้น
สีดินสอ(
floor((ไซน์(h) * 0.5 + 0.5) * 205 * br + 15),
floor((ไซน์(h + 2.094) * 0.5 + 0.5) * 205 * br + 15),
floor((ไซน์(h + 4.189) * 0.5 + 0.5) * 205 * br + 15)
)
วาดลูกบาศก์(ex, ey, ez, ขนาด)
bind i = i + 1
}
}
ฟังก์ชัน เริ่มฝูง() {
ถ้า ฝูงInit == 1 { คืน 0 }
bind i = 0
bind nx = []
bind ny = []
bind nz = []
bind nvx = []
bind nvy = []
bind nvz = []
ขณะที่ i < ฝูงN {
bind a = i * 2.39996
bind r = 2.8 + (i - ปัดลง(i/5.0)*5.0) * 0.7
bind px = โคไซน์(a) * r
bind py = (i - ปัดลง(i/4.0)*4.0 - 1.5) * 0.75
bind pz = ไซน์(a) * r
bind vx = ไซน์(i*1.7) * 0.08
bind vy = โคไซน์(i*1.3) * 0.05
bind vz = โคไซน์(i*1.9) * 0.08
bind nx = list_push(nx, px)
bind ny = list_push(ny, py)
bind nz = list_push(nz, pz)
bind nvx = list_push(nvx, vx)
bind nvy = list_push(nvy, vy)
bind nvz = list_push(nvz, vz)
bind i = i + 1
}
bind ฝูงX = nx; bind ฝูงY = ny; bind ฝูงZ = nz
bind ฝูงVx = nvx; bind ฝูงVy = nvy; bind ฝูงVz = nvz
bind ฝูงInit = 1
คืน 0
}
ฟังก์ชัน อัปเดตฝูง(t) {
เริ่มฝูง()
bind nx = []
bind ny = []
bind nz = []
bind nvx = []
bind nvy = []
bind nvz = []
bind i = 0
ขณะที่ i < ฝูงN {
bind xi = list_get(ฝูงX, i); bind yi = list_get(ฝูงY, i); bind zi = list_get(ฝูงZ, i)
bind vxi = list_get(ฝูงVx, i); bind vyi = list_get(ฝูงVy, i); bind vzi = list_get(ฝูงVz, i)
bind cx = 0.0; bind cy = 0.0; bind cz = 0.0
bind avx = 0.0; bind avy = 0.0; bind avz = 0.0
bind sx = 0.0; bind sy = 0.0; bind sz = 0.0
bind c = 0.0
bind j = 0
ขณะที่ j < ฝูงN {
ถ้า j != i {
bind dx = list_get(ฝูงX, j) - xi
bind dy = list_get(ฝูงY, j) - yi
bind dz = list_get(ฝูงZ, j) - zi
bind d2 = dx*dx + dy*dy + dz*dz
ถ้า d2 < 56.25 {
bind c = c + 1.0
bind cx = cx + list_get(ฝูงX, j)
bind cy = cy + list_get(ฝูงY, j)
bind cz = cz + list_get(ฝูงZ, j)
bind avx = avx + list_get(ฝูงVx, j)
bind avy = avy + list_get(ฝูงVy, j)
bind avz = avz + list_get(ฝูงVz, j)
ถ้า d2 < 4.0 {
bind dd = รากที่สอง(d2) + 0.001
bind sx = sx - dx / dd
bind sy = sy - dy / dd
bind sz = sz - dz / dd
}
}
}
bind j = j + 1
}
bind ax = 0.0; bind ay = 0.0; bind az = 0.0
ถ้า c > 0.5 {
bind cx = cx / c; bind cy = cy / c; bind cz = cz / c
bind avx = avx / c; bind avy = avy / c; bind avz = avz / c
bind ax = ax + (cx - xi) * 0.018 + (avx - vxi) * 0.08 + sx * 0.11
bind ay = ay + (cy - yi) * 0.018 + (avy - vyi) * 0.08 + sy * 0.11
bind az = az + (cz - zi) * 0.018 + (avz - vzi) * 0.08 + sz * 0.11
}
# หมุนวนรอบแกน Y + โยกขึ้นลงเล็กน้อย
bind ax = ax + (0.0 - zi) * 0.012 + ไซน์(t*2.6 + i*0.7) * 0.006
bind ay = ay + ไซน์(t*4.7 + i*0.9) * 0.009
bind az = az + xi * 0.012 + โคไซน์(t*2.2 + i*0.8) * 0.006
# ขอบโดมลูกหมึก
bind rr = รากที่สอง(xi*xi + yi*yi + zi*zi)
ถ้า rr > 8.4 {
bind ax = ax + (0.0 - xi) * 0.05
bind ay = ay + (0.0 - yi) * 0.05
bind az = az + (0.0 - zi) * 0.05
}
bind vxi = (vxi + ax) * 0.985
bind vyi = (vyi + ay) * 0.985
bind vzi = (vzi + az) * 0.985
bind sp = รากที่สอง(vxi*vxi + vyi*vyi + vzi*vzi) + 0.0001
ถ้า sp > 0.55 { bind vxi = vxi / sp * 0.55; bind vyi = vyi / sp * 0.55; bind vzi = vzi / sp * 0.55 }
ถ้า sp < 0.05 { bind vxi = vxi / sp * 0.05; bind vyi = vyi / sp * 0.05; bind vzi = vzi / sp * 0.05 }
bind xi = xi + vxi
bind yi = yi + vyi
bind zi = zi + vzi
bind nx = list_push(nx, xi); bind ny = list_push(ny, yi); bind nz = list_push(nz, zi)
bind nvx = list_push(nvx, vxi); bind nvy = list_push(nvy, vyi); bind nvz = list_push(nvz, vzi)
bind i = i + 1
}
bind ฝูงX = nx; bind ฝูงY = ny; bind ฝูงZ = nz
bind ฝูงVx = nvx; bind ฝูงVy = nvy; bind ฝูงVz = nvz
คืน 0
}
# ── ตำแหน่งฝูงตัวอักษร (procedural) — ling ฟังก์ชันแก้ตัวแปรโกลบอลไม่ได้ จึงคำนวณจาก t ──
# โคจรมุมทอง + รัศมีหายใจ + ส่ายเล็กน้อย → ดูเป็นฝูงหมุนวน (stateless, ทำงานทุกเฟรม)
ฟังก์ชัน ตำแหน่งฝูง(i, t) {
bind a = i * 2.39996 + t * 0.55
bind rad = 4.6 + ไซน์(t*0.5 + i*0.7) * 2.6
bind px = โคไซน์(a) * rad + ไซน์(t*1.3 + i*1.1) * 0.6
bind pz = ไซน์(a) * rad + โคไซน์(t*1.1 + i*0.9) * 0.6
bind py = ไซน์(t*0.8 + i*0.9) * 3.2 + โคไซน์(t*1.7 + i*0.5) * 0.8
คืน [px, py, pz]
}
ฟังก์ชัน วาดวงแหวนตัวอักษร(กรอบ, pulse) {
bind t = กรอบ * 0.01
ถ้า pulse < 0.0 { bind pulse = 0.0 }
ถ้า pulse > 1.0 { bind pulse = 1.0 }
liquid_step(หมึกRB, 0.016)
liquid_step(หมึกGold, 0.016)
liquid_splat(หมึกRB, 24.0 + ไซน์(t*1.7)*11.0, 24.0 + โคไซน์(t*1.3)*9.0, 0.0, 0.22, 3.1)
liquid_splat(หมึกRB, 24.0 + โคไซน์(t*1.1)*10.5, 24.0 + ไซน์(t*1.9)*8.0, 1.0, 0.20, 2.9)
liquid_splat(หมึกGold, 24.0 + ไซน์(t*1.5+1.2)*9.5, 24.0 + โคไซน์(t*1.8+0.7)*7.5, 0.0, 0.20, 2.8)
liquid_splat(หมึกGold, 24.0 + โคไซน์(t*1.4+2.0)*9.0, 24.0 + ไซน์(t*1.6+0.3)*8.5, 1.0, 0.20, 2.8)
ถ้า pulse > 0.04 {
bind ba = t * 1.7
bind bx = 24.0 + โคไซน์(ba) * 17.0
bind by = 24.0 + ไซน์(ba * 1.31) * 17.0
liquid_splat(หมึกRB, bx, by, 0.0, 0.16 + pulse*0.34, 2.2 + pulse*4.8)
liquid_splat(หมึกGold, 48.0-bx, 48.0-by, 1.0, 0.14 + pulse*0.30, 2.0 + pulse*4.2)
}
bind i = 0
ขณะที่ i < ฝูงN {
bind p = ตำแหน่งฝูง(i, t)
bind px = list_get(p, 0)
bind py = list_get(p, 1)
bind pz = list_get(p, 2)
bind u = 24.0 + px * 1.95
bind v = 24.0 + pz * 1.95
bind w = 24.0 + py * 1.8
liquid_splat(หมึกRB, u, v, i - ปัดลง(i/2.0)*2.0, 0.08, 1.1)
liquid_splat(หมึกGold, u, w, (i+1) - ปัดลง((i+1)/2.0)*2.0, 0.07, 1.0)
bind i = i + 1
}
# ระนาบหมึกใหญ่ (kind 0) ที่ระดับฉาก = พื้นหลังหมึกเต็มจอ (เดิมแผ่นเล็กลอยกลาง)
bind inkPulse = 1.0 + pulse * 0.16
set_flat_shade(0.0)
liquid_draw_surface(หมึกRB, 0.0, 0.0, 1.0, 0.0, 42.0*inkPulse, 42.0*inkPulse)
liquid_draw_surface(หมึกGold, 0.0, 0.0, 1.5, 0.0, 36.0*inkPulse, 36.0*inkPulse)
set_flat_shade(0.0)
bind j = 0
ขณะที่ j < ฝูงN {
bind p2 = ตำแหน่งฝูง(j, t)
bind px2 = list_get(p2, 0)
bind py2 = list_get(p2, 1)
bind pz2 = list_get(p2, 2)
bind hh = t * 10.5 + j * 0.9
สีดินสอ(
floor((ไซน์(hh) * 0.5 + 0.5) * 200 + 55),
floor((ไซน์(hh + 2.094) * 0.5 + 0.5) * 200 + 55),
floor((ไซน์(hh + 4.189) * 0.5 + 0.5) * 200 + 55)
)
bind code = (j * 7 + ปัดลง(t * 9.0)) % 26
bind s = 0.43 + (j - ปัดลง(j/3.0)*3.0) * 0.06
วาดกลิฟ3มิติ(code, px2, py2 + ไซน์(t*6.0 + j) * 0.22, pz2, t*2.4 + j*0.35, s)
bind j = j + 1
}
}
# ── เบิร์สต์ลูกบาศก์ 6 ใบ ตามจังหวะ MIDI (burst 1→0 = เพิ่งโดนโน้ต) ──
# ท่าเต้นวิวัฒน์ตามเวลา: 4 ฟอร์เมชัน วนทีละ ~9 วิ มอร์ฟต่อเนื่อง
# 0 ระเบิด 6 ทิศ · 1 วงโคจรแหวน · 2 เกลียวเสาตั้ง · 3 เลขแปดลิสซาจู
bind ทิศ6 = [1.0,0.0,0.0, 0.0-1.0,0.0,0.0, 0.0,1.0,0.0, 0.0,0.0-1.0,0.0, 0.0,0.0,1.0, 0.0,0.0,0.0-1.0]
ฟังก์ชัน ตำแหน่งเบิร์สต์(m, k, t) {
ถ้า m == 1 { # วงโคจรแหวนเอียง
bind a1 = t*1.4 + k*1.047
bind r1 = 7.4 + ไซน์(t*0.9 + k)*1.3
คืน [โคไซน์(a1)*r1, ไซน์(t*1.8 + k*2.1)*2.4 + ไซน์(a1*2.0)*1.1, ไซน์(a1)*r1]
}
ถ้า m == 2 { # เกลียวเสาตั้ง (ไหลขึ้นวนซ้ำ)
bind a2 = t*2.1 + k*1.047
bind hy = t*3.1 + k*2.33
bind hy2 = (hy - ปัดลง(hy/14.0)*14.0) - 7.0
คืน [โคไซน์(a2)*4.4, hy2, ไซน์(a2)*4.4]
}
ถ้า m == 3 { # เลขแปดลิสซาจู 3 มิติ
คืน [ไซน์(t*1.3 + k*1.047)*7.2, ไซน์(t*2.6 + k*2.094)*3.4, ไซน์(t*1.7 + k*0.7 + 1.5708)*5.2]
}
bind dx = list_get(ทิศ6, k*3); bind dy = list_get(ทิศ6, k*3+1); bind dz = list_get(ทิศ6, k*3+2)
bind d0 = 4.6 + ไซน์(t*1.1 + k*0.9)*1.7 # ระเบิด 6 ทิศ หายใจเข้าออก
คืน [dx*d0, dy*d0, dz*d0]
}
ฟังก์ชัน วาดเบิร์สต์(burst, t) {
bind ph = t / 9.0
bind ph = ph - ปัดลง(ph/4.0)*4.0 # เฟส 0..4 วน
bind m0 = ปัดลง(ph)
bind mf = ph - m0
bind mf = mf*mf*(3.0 - 2.0*mf) # smoothstep มอร์ฟทั้งช่วง
bind m1 = m0 + 1; ถ้า m1 > 3 { bind m1 = 0 }
bind sz = 0.5 + burst * 2.4
bind k = 0
ขณะที่ k < 6 {
bind pA = ตำแหน่งเบิร์สต์(m0, k, t)
bind pB = ตำแหน่งเบิร์สต์(m1, k, t)
bind px = list_get(pA,0) + (list_get(pB,0) - list_get(pA,0))*mf
bind py = list_get(pA,1) + (list_get(pB,1) - list_get(pA,1))*mf
bind pz = list_get(pA,2) + (list_get(pB,2) - list_get(pA,2))*mf
bind dx = list_get(ทิศ6, k*3); bind dy = list_get(ทิศ6, k*3+1); bind dz = list_get(ทิศ6, k*3+2)
bind px = px + dx*burst*3.6; bind py = py + dy*burst*3.6; bind pz = pz + dz*burst*3.6 # โน้ต MIDI ยังเตะกล่องออกทุกฟอร์เมชัน
bind h = t*1.5 + k*1.047
bind br = burst*0.8 + 0.2
สีดินสอ(floor(((ไซน์(h)*0.5+0.5)*200+30)*br), floor(((ไซน์(h+2.094)*0.5+0.5)*200+30)*br), floor(((ไซน์(h+4.189)*0.5+0.5)*200+30)*br))
วาดลูกบาศก์(px, py, pz, sz)
# เงาตาม (echo) — ลูกเล็กไล่หลังบนเส้นทางเดียวกัน = หางเคลื่อนไหว
bind pE = ตำแหน่งเบิร์สต์(m0, k, t - 0.16)
สีดินสอ(floor(((ไซน์(h)*0.5+0.5)*110+15)*br), floor(((ไซน์(h+2.094)*0.5+0.5)*110+15)*br), floor(((ไซน์(h+4.189)*0.5+0.5)*110+15)*br))
วาดลูกบาศก์(list_get(pE,0), list_get(pE,1), list_get(pE,2), sz*0.5)
bind k = k + 1
}
}
# ── ชื่อเรื่องใหญ่ "Soul Symphony 2" หลายภาษา (วลีเบคจาก phrasebake) ──
# lang 0/1=Latin · 2=ไทย · 3=เกาหลี · 4=ญี่ปุ่น · 5=จีน
# targetW = ความกว้างเป้าหมายบนจอ → ปรับ sc ตามความกว้าง em ของแต่ละภาษา (จัดกึ่งกลาง)
ฟังก์ชัน วาดSS2(lang, ox, oy, targetW) {
ถ้า lang == 2 { วาดSS2TH(ox, oy, targetW/6.46); คืน 0 }
ถ้า lang == 3 { วาดSS2KO(ox, oy, targetW/5.36); คืน 0 }
ถ้า lang == 4 { วาดSS2JA(ox, oy, targetW/9.84); คืน 0 }
ถ้า lang == 5 { วาดSS2ZH(ox, oy, targetW/5.65); คืน 0 }
วาดSS2EN(ox, oy, targetW/7.18) # 0,1 = โรมัน/อังกฤษ
คืน 0
}
ฟังก์ชัน วาดSS2รายตัว(ox, oy, targetW, t) {
bind n = ความยาว(คำSS2)
bind sc = targetW / 7.9
bind adv = sc * 0.70
bind sx = ox - (n - 1) * adv * 0.5
bind i = 0
ขณะที่ i < n {
bind code = list_get(คำSS2, i)
ถ้า code >= 0 {
bind hh = t * 12.0 + i * 1.15
สีดินสอ(
floor((ไซน์(hh) * 0.5 + 0.5) * 205 + 50),
floor((ไซน์(hh + 2.094) * 0.5 + 0.5) * 205 + 50),
floor((ไซน์(hh + 4.189) * 0.5 + 0.5) * 205 + 50)
)
bind lx = sx + i * adv + ไซน์(t*3.8 + i*1.3) * sc * 0.18
bind ly = oy + ไซน์(t*5.7 + i*0.95) * sc * 0.36
วาดกลิฟ3มิติหน้า(code, lx, ly, 0.0, t*2.2 + i*0.45, sc, t + i*0.11)
}
bind i = i + 1
}
คืน 0
}
ฟังก์ชัน วาดSS2ไดนามิก(lang, ox, oy, targetW, t) {
ถ้า lang == 0 { วาดSS2รายตัว(ox, oy, targetW, t); คืน 0 }
bind h = t * 10.0
สีดินสอ(
floor((ไซน์(h) * 0.5 + 0.5) * 180 + 70),
floor((ไซน์(h + 2.094) * 0.5 + 0.5) * 180 + 70),
floor((ไซน์(h + 4.189) * 0.5 + 0.5) * 180 + 70)
)
วาดSS2(lang, ox, oy + ไซน์(t*5.2) * 0.22, targetW)
คืน 0
}
ฟังก์ชัน วาดฉากชื่อเรื่อง(กรอบ, burst, lang) {
bind t = กรอบ*0.01
bind pulse = burst
ถ้า pulse < 0.0 { bind pulse = 0.0 }
ถ้า pulse > 1.0 { bind pulse = 1.0 }
bind bgH = floor(ไซน์(กรอบ * 0.022) * 3.0 + 4.0)
เติม(bgH, 0, 8)
ตั้งกล้องมอง(0.0, 0.0, -22.0, 0.0, 0.0, 0.0)
ตั้งระยะห่าง(2.8 + pulse*0.12)
set_depth_test(1)
ตั้งแสงรอบข้าง(0.4)
ตั้งหมอก(30, 72, 158, 8.0, 34.0) # หมอกน้ำเงิน: ตัวอักษร/ลูกบาศก์ไกล จางเป็นน้ำเงิน (เข้มขึ้น)
โหมดผสม(1)
ล้างแสง()
เพิ่มแสง(ไซน์(กรอบ*0.011)*5.0, 4.0, โคไซน์(กรอบ*0.011)*3.0, 1.0,0.88,0.65, 3.0 + pulse*1.2,14.0)
เพิ่มแสง(0.0-4.0, 2.5, 2.0, 0.30,0.80,1.0, 1.5 + pulse*0.8,10.0)
# ── ปราสาทบนขอบฟ้าหมึก (วาด "ก่อน" กล่อง/วงแหวน → ของ additive ทับหน้าได้เสมอ) ──
โหมดผสม(0) # ทึบ — ไม่ใช่ additive แบบวงแหวน
ตั้งหมอก(0, 0, 0, 0.0, 0.0) # ปิดหมอกเฉพาะพาสนี้ — สีวนต้องสด
bind วยอ = 3.1416 + ไซน์(t*0.21)*0.05
bind วเด่น = ปัดลง(t*4.3) - ปัดลง(ปัดลง(t*4.3)/5.0)*5.0 # ชิ้นเด่นวนสลับ
bind วชิ้น = 0
ขณะที่ วชิ้น < 5 {
bind วม = _วังไต0
ถ้า วชิ้น == 1 { bind วม = _วังไต1 }; ถ้า วชิ้น == 2 { bind วม = _วังไต2 }
ถ้า วชิ้น == 3 { bind วม = _วังไต3 }; ถ้า วชิ้น == 4 { bind วม = _วังไต4 }
bind วเกน = 1.05 + pulse*0.6 # ทุกชิ้นวูบตามโน้ต MIDI
ถ้า วชิ้น == วเด่น { bind วเกน = 1.15 + pulse*1.6 } # ชิ้นเด่นแฟลชแรงสุด
หมุนสีเมช(t*0.85 + วชิ้น*1.257, วเกน) # วนครบวงคนละเฟสต่อชิ้น + เกนสว่างตามโน้ต
mesh_draw(วม, 0.0, 1.02, 6.0, 12.0, วยอ, ไซน์(t*0.33)*0.008, 0.0, 0.0, 0.0, 0.0)
bind วชิ้น = วชิ้น + 1
}
หมุนสีเมช(0.0, 1.0)
flush_3d()
แอ่งแสง(0.0, 1.0, 6.0, 11.0, 185, 205, 255, 0.45 + pulse*0.25) # แสงจันทร์นวลสะท้อนหมึกใต้ปราสาท
# ── ไฟวังเต้นตามโน้ต MIDI: ออร่าเสริมชิ้นเด่น + แอ่งแฟลร์ (เกนเมชคือแสงหลัก) ──
โหมดผสม(1)
bind วp = 0
ขณะที่ วp < 5 {
bind วGlow = 0.25 + pulse*0.7
ถ้า วp == วเด่น { bind วGlow = 0.50 + pulse*1.5 }
bind วh = t*0.85 + วp*1.257
bind วr = floor(((ไซน์(วh)*0.5+0.5)*205+50)*วGlow); ถ้า วr > 255 { bind วr = 255 }
bind วg = floor(((ไซน์(วh+2.094)*0.5+0.5)*205+50)*วGlow); ถ้า วg > 255 { bind วg = 255 }
bind วb = floor(((ไซน์(วh+4.189)*0.5+0.5)*205+50)*วGlow); ถ้า วb > 255 { bind วb = 255 }
อนุภาคทรงกลม(0.0, 1.0 - 2.2 - วp*1.35, 6.0, 2.5 + วp*0.4, 8, t*2.0 + วp, วr, วg, วb)
ถ้า วp == วเด่น { แอ่งแสง(0.0, 1.0, 6.0, 6.0 + pulse*5.0, วr, วg, วb, 0.25 + pulse*0.45) }
bind วp = วp + 1
}
flush_3d()
ตั้งหมอก(30, 72, 158, 8.0, 34.0)
วาดวงแหวนตัวอักษร(กรอบ, pulse)
วาดเบิร์สต์(pulse, t)
flush_3d()
set_depth_test(0)
set_flat_shade(1.0)
ตั้งหมอก(0, 0, 0, 0.0, 0.0)
โหมดผสม(1)
วาดSS2ไดนามิก(lang, 0.0, 0.0-4.8 + pulse*0.22, 15.8 + pulse*1.1, t + pulse*0.3)
ถ้า (floor(กรอบ * 0.04) % 2) == 0 {
สีดินสอ(230, 230, 255)
วาดข้อความ(คำ_ปุ่ม, 0.0, 11.0, 0.0, 0.7, 0)
}
flush_3d()
โหมดผสม(0)
set_depth_test(0)
แสดงผล()
}
# ════════════════════════════════════════════════════════════════════════════
# ข้อความจากสตริง (a-z) + สโนว์โกลบดาว สำหรับคัตซีน
# ════════════════════════════════════════════════════════════════════════════
ฟังก์ชัน ตัวอักษรเป็นดัชนี(ch) {
ถ้า ch == "a" { คืน 0 }
ถ้า ch == "b" { คืน 1 }
ถ้า ch == "c" { คืน 2 }
ถ้า ch == "d" { คืน 3 }
ถ้า ch == "e" { คืน 4 }
ถ้า ch == "f" { คืน 5 }
ถ้า ch == "g" { คืน 6 }
ถ้า ch == "h" { คืน 7 }
ถ้า ch == "i" { คืน 8 }
ถ้า ch == "j" { คืน 9 }
ถ้า ch == "k" { คืน 10 }
ถ้า ch == "l" { คืน 11 }
ถ้า ch == "m" { คืน 12 }
ถ้า ch == "n" { คืน 13 }
ถ้า ch == "o" { คืน 14 }
ถ้า ch == "p" { คืน 15 }
ถ้า ch == "q" { คืน 16 }
ถ้า ch == "r" { คืน 17 }
ถ้า ch == "s" { คืน 18 }
ถ้า ch == "t" { คืน 19 }
ถ้า ch == "u" { คืน 20 }
ถ้า ch == "v" { คืน 21 }
ถ้า ch == "w" { คืน 22 }
ถ้า ch == "x" { คืน 23 }
ถ้า ch == "y" { คืน 24 }
ถ้า ch == "z" { คืน 25 }
ถ้า ch == "0" { คืน 26 }
ถ้า ch == "1" { คืน 27 }
ถ้า ch == "2" { คืน 28 }
ถ้า ch == "3" { คืน 29 }
ถ้า ch == "4" { คืน 30 }
ถ้า ch == "5" { คืน 31 }
ถ้า ch == "6" { คืน 32 }
ถ้า ch == "7" { คืน 33 }
ถ้า ch == "8" { คืน 34 }
ถ้า ch == "9" { คืน 35 }
ถ้า ch == "." { คืน 36 }
ถ้า ch == "," { คืน 37 }
ถ้า ch == "!" { คืน 38 }
ถ้า ch == "?" { คืน 39 }
ถ้า ch == "'" { คืน 40 }
ถ้า ch == "-" { คืน 41 }
ถ้า ch == ":" { คืน 42 }
ถ้า ch == ";" { คืน 43 }
ถ้า ch == "(" { คืน 44 }
ถ้า ch == ")" { คืน 45 }
ถ้า ch == "/" { คืน 46 }
ถ้า ch == "+" { คืน 47 }
คืน 0.0 - 1.0
}
# ── ขอบดำบทพูด (เรียกก่อน วาดสตริง ที่ตำแหน่ง/สเกลเดียวกัน): วาดซ้ำ 8 ทิศเป็นสีดำ
# ล้วน offset ~1-2px (ประมาณจากความกว้างตัวอักษร adv=scale*0.66 ต่อความกว้างจอ
# ทั่วไป ~1920px) ก่อนพื้นผิวสีจริงทับด้านบน — ไม่มีฮาโลเรืองแสง (ขอบต้องคมชัด) ──
ฟังก์ชัน วาดสตริงขอบ(s, ox, oy, oz, scale, lang) {
boot_text_style()
bind n = ความยาว(s)
bind adv = scale * 0.66
bind startx = ox - (n - 1) * adv * 0.5
bind d = 0.013 # ~1-2px ที่ระยะกล้อง HUD ปกติ
สีดินสอ(0, 0, 0)
bind oi2 = 0
ขณะที่ oi2 < 8 {
bind ang = oi2 * 0.7854 # 8 ทิศรอบตัว (ทุก 45°)
bind dx = โคไซน์(ang) * d; bind dy = ไซน์(ang) * d
bind i = 0
ขณะที่ i < n {
bind ch = ส่วนสตริง(s, i, 1)
bind code = ตัวอักษรเป็นดัชนี(ch)
ถ้า code >= 0 {
วาดกลิฟ(lang, code, startx + i * adv + dx, oy + dy, oz + 0.02, scale)
}
bind i = i + 1
}
bind oi2 = oi2 + 1
}
}
ฟังก์ชัน วาดสตริง(s, ox, oy, oz, scale, lang) {
boot_text_style()
bind n = ความยาว(s)
bind adv = scale * 0.66
bind startx = ox - (n - 1) * adv * 0.5
# ── ฮาโลเรืองแสง (emission): ผ่านบวก กลิฟใหญ่ขึ้น → แกนทึบทับ (ตัวอักษรเรืองแสงในตัว) ──
โหมดผสม(1)
bind ig = 0
ขณะที่ ig < n {
bind gch = ส่วนสตริง(s, ig, 1)
bind gcode = ตัวอักษรเป็นดัชนี(gch)
ถ้า gcode >= 0 { วาดกลิฟ(lang, gcode, startx + ig * adv, oy, oz + 0.15, scale*1.16) }
bind ig = ig + 1
}
โหมดผสม(0)
bind i = 0
ขณะที่ i < n {
bind ch = ส่วนสตริง(s, i, 1)
bind code = ตัวอักษรเป็นดัชนี(ch)
ถ้า code >= 0 {
วาดกลิฟ(lang, code, startx + i * adv, oy, oz, scale)
}
bind i = i + 1
}
}
# สโนว์โกลบดาว: ทรงกลมอนุภาคหนาแน่น + สัญลักษณ์เครื่องดนตรี + ตัวอักษรเดี่ยวลอย
# gather ∈ [0,1] → ดึงสัญลักษณ์/ตัวอักษรเข้าหาดาวเคราะห์ (0,-14,0) ช่วงท้าย
# ── วนสีรอบเฉดเดิม ────────────────────────────────────────────────────────────
# หมุนเฉดสีของสีฐาน (r,g,b) ไปตาม h โดยคุมความแรงด้วย แรง (0..1)
# ใช้กับอนุภาค/เส้นที่ "สีมีความหมาย" อยู่แล้ว (น้ำเงิน=ราชา, ชมพู=ราชินี,
# ขาว=แสงเย็น, อุ่น=โคมไฟ) — วนสีเต็มสเกลจะทำลายความหมายนั้น จึงเบลนด์สีฐาน
# เข้ากับสายรุ้งที่ความสว่างเท่ากัน สีเลยยังอ่านออกว่าเป็นสีเดิม แต่ไล่เฉดตลอด
# ทำให้หางที่ เบลอเฟรม ค้างไว้มีสีเคลื่อน (เรียกตอนวาด = ก่อนพาสเบลอเฟรมเสมอ)
ฟังก์ชัน วนสีอ่อน(r, g, b, h, แรง) {
bind สว่าง = (r + g + b) / 3.0
bind cr = (ไซน์(h) * 0.5 + 0.5) * สว่าง * 1.55
bind cg = (ไซน์(h + 2.094) * 0.5 + 0.5) * สว่าง * 1.55
bind cb = (ไซน์(h + 4.189) * 0.5 + 0.5) * สว่าง * 1.55
bind orr = r*(1.0 - แรง) + cr*แรง
bind og = g*(1.0 - แรง) + cg*แรง
bind ob = b*(1.0 - แรง) + cb*แรง
ถ้า orr > 255.0 { bind orr = 255.0 }
ถ้า og > 255.0 { bind og = 255.0 }
ถ้า ob > 255.0 { bind ob = 255.0 }
ถ้า orr < 0.0 { bind orr = 0.0 }
ถ้า og < 0.0 { bind og = 0.0 }
ถ้า ob < 0.0 { bind ob = 0.0 }
คืน [floor(orr), floor(og), floor(ob)]
}
# สีหมุนเวียนหนึ่งเฉด (h เรเดียน) → [r,g,b] คูณ fade แล้ว
# ใช้ร่วมกันทั้งอนุภาคและไวร์เฟรมของฉากอินโทร ให้ทุกชั้นวนสีด้วยสูตรเดียวกัน
ฟังก์ชัน เมฆสีวน(h, fade, ฐาน, ช่วง) {
คืน [
floor(((ไซน์(h) * 0.5 + 0.5) * ช่วง + ฐาน) * fade),
floor(((ไซน์(h + 2.094) * 0.5 + 0.5) * ช่วง + ฐาน) * fade),
floor(((ไซน์(h + 4.189) * 0.5 + 0.5) * ช่วง + ฐาน) * fade)
]
}
ฟังก์ชัน เมฆดาว(t, fade, gather) {
# ── สามชั้นอนุภาควนสีคนละเฟส (เดิมสองชั้นในเป็นสีตายตัว ขาว/ชมพู ไม่วนเลย) ──
# วนสีตรงนี้คือ "ก่อนพาสเบลอเฟรม" — เบลอเฟรมคอมโพสิต max(เฟรมนี้, เฟรมก่อน*retention)
# ตอน present ฉะนั้นเฉดที่เปลี่ยนไปเรื่อย ๆ จะทิ้งหางเป็นสายรุ้งค้างจริง ๆ
bind c1 = เมฆสีวน(t*0.55, fade, 120, 120)
bind c2 = เมฆสีวน(t*0.75 + 2.1, fade, 110, 140)
bind c3 = เมฆสีวน(t*0.95 + 4.2, fade, 100, 150)
อนุภาคทรงกลม(0,0,0, 44.0, 360.0, t*0.4, list_get(c1,0), list_get(c1,1), list_get(c1,2))
อนุภาคทรงกลม(0,0,0, 28.0, 240.0, t*0.6+10.0, list_get(c2,0), list_get(c2,1), list_get(c2,2))
อนุภาคทรงกลม(0,0,0, 15.0, 150.0, t*0.9+20.0, list_get(c3,0), list_get(c3,1), list_get(c3,2))
# เครื่องดนตรี/สัญลักษณ์ลอย — lerp เข้าหาดาวเคราะห์ด้วย gather
bind ig = 1.0 - gather
# อาร์กิวเมนต์ตัวท้ายของลาย* คือ hue — เดิมส่งค่าคงที่ทุกตัว ไวร์เฟรมเลยสีนิ่ง
# ใส่พจน์เวลาคนละอัตราให้แต่ละลายไล่สีเหลื่อมกัน (เร็วกว่าอนุภาคเล็กน้อยเพื่อให้
# หางเบลอเฟรมของเส้นเป็นริ้วสีชัดกว่ากลุ่มอนุภาค)
ลายดาว(18.0*ig, (0.0-8.0)*ig + (0.0-14.0)*gather, 12.0*ig, 1,0,0, 0,1,0, 7, 3.0, 1.5, 0.05, t, 0.05 + t*0.95)
ลายยันต์((0.0-20.0)*ig, 6.0*ig + (0.0-14.0)*gather, (0.0-10.0)*ig, 1,0,0, 0,0,1, 5, 4.0, t, 1.2 + t*1.25)
ลายจักร(10.0*ig, 14.0*ig + (0.0-14.0)*gather, (0.0-18.0)*ig, 1,0,0, 0,0,1, 4.0, 10, t, 2.4 + t*0.80)
ลายดอกบัว((0.0-14.0)*ig, (0.0-14.0)*ig + (0.0-14.0)*gather, 16.0*ig, 1,0,0, 0,0,1, 1.5, 5.0, 12, t, 0.6 + t*1.10)
ลายจักร((0.0-22.0)*ig, (0.0-4.0)*ig + (0.0-14.0)*gather, 8.0*ig, 0,1,0, 0,0,1, 3.0, 8, t*1.3, 3.5 + t*1.45)
# ── ตัวอักษรเดี่ยวลอยฟ้า สีหมุนเวียนเร็ว (lerp เข้าหาดาวเคราะห์) ──
bind i = 0
ขณะที่ i < 14 {
bind a = i * 2.39996
bind rad = 12.0 + (i % 6) * 5.0
bind lx = โคไซน์(a) * rad
bind ly = 0.0 - 4.0 - (i % 7) * 3.0
bind lz = ไซน์(a) * rad
bind fx = lx * ig
bind fy = ly * ig + (0.0-14.0) * gather
bind fz = lz * ig
bind hh = t * 2.6 + i * 0.7
สีดินสอ(
floor(((ไซน์(hh) * 0.5 + 0.5) * 200 + 40) * fade),
floor(((ไซน์(hh + 2.094) * 0.5 + 0.5) * 200 + 40) * fade),
floor(((ไซน์(hh + 4.189) * 0.5 + 0.5) * 200 + 40) * fade)
)
bind code = (i * 7) % 26
วาดกลิฟ(0, code, fx, fy, fz, 0.9)
bind i = i + 1
}
}
# ════════════════════════════════════════════════════════════════════════════
# ดาวหางดนตรี — พุ่งเร็วสุ่มทิศผ่านกล้อง; ปลายฉาก (endf→1) สไปรัลเข้าโคจรดาวเคราะห์
# ════════════════════════════════════════════════════════════════════════════
# ตำแหน่งดาวหางที่เวลา tt (deterministic-สุ่มต่อดวง) — คืน [x,y,z]
ฟังก์ชัน ตำแหน่งดาวหาง(tt, L, endf) {
# ทิศพุ่งสุ่มต่อดวง
bind dx = ไซน์(L*1.7 + 0.5)
bind dy = ไซน์(L*2.3 + 1.1) * 0.6
bind dz = โคไซน์(L*1.9 + 0.3)
bind dl = รากที่สอง(dx*dx + dy*dy + dz*dz) + 0.0001
# เฟสพุ่ง (เร็ว) → วิ่งจาก -40..40 ตามทิศ ผ่านบริเวณกลาง
bind raw = tt * 1.3 + L * 0.37
bind ph = raw - floor(raw)
bind d = (ph - 0.5) * 80.0
bind sx = dx/dl*d + โคไซน์(L*3.1) * 7.0
bind sy = dy/dl*d + ไซน์(L*2.0) * 5.0 - 4.0
bind sz = dz/dl*d + ไซน์(L*4.2) * 7.0
# วงโคจรรอบดาวเคราะห์ (0,-14,0) — สไปรัลเข้า เมื่อ endf→1
bind oa = tt * 1.6 + L * 0.785
bind orad = 5.0 + (1.0 - endf) * 22.0
bind ox2 = โคไซน์(oa) * orad
bind oy2 = 0.0 - 14.0 + ไซน์(L + tt*0.5) * orad * 0.25
bind oz2 = ไซน์(oa) * orad
คืน [sx*(1.0-endf) + ox2*endf, sy*(1.0-endf) + oy2*endf, sz*(1.0-endf) + oz2*endf]
}
ฟังก์ชัน เมฆดาวหาง(t, L, mag, fade, endf) {
bind m = mag
ถ้า m > 2.5 { bind m = 2.5 }
bind pa = ตำแหน่งดาวหาง(t, L, endf)
bind pb = ตำแหน่งดาวหาง(t - 0.05, L, endf)
bind ax = list_get(pa,0); bind ay = list_get(pa,1); bind az = list_get(pa,2)
bind tdx = ax - list_get(pb,0); bind tdy = ay - list_get(pb,1); bind tdz = az - list_get(pb,2)
# hue เดิมเป็นค่าคงที่ต่อดวง (L*0.785) ดาวหางเลยไม่เคยไล่สีเลย — เติมพจน์เวลา
# เข้าไป หัวและหางจึงวนสีระหว่างพุ่ง หางที่เบลอเฟรมค้างไว้กลายเป็นริ้วสายรุ้ง
bind hue = L * 0.785 + t * 1.15
bind cc = เมฆสีวน(hue, fade, 55, 200)
bind rr = list_get(cc,0); bind gg = list_get(cc,1); bind bb = list_get(cc,2)
bind sz = 0.7 + m * 2.2
# หัวดาวหาง
อนุภาคทรงกลม(ax, ay, az, sz, 22, t*0.5 + L, rr, gg, bb)
# หางพุ่งตามทิศเคลื่อน (จางลง 2 ช่วง)
สีดินสอ(rr, gg, bb)
วาดเส้น3มิติ(ax, ay, az, ax - tdx*5.0, ay - tdy*5.0, az - tdz*5.0)
สีดินสอ(floor(rr*0.45), floor(gg*0.45), floor(bb*0.45))
วาดเส้น3มิติ(ax - tdx*5.0, ay - tdy*5.0, az - tdz*5.0, ax - tdx*10.0, ay - tdy*10.0, az - tdz*10.0)
}
# เป่านกหวีด — เสียงนกหวีดของดาวหางขณะสไปรัลเข้า (vibrato)
ฟังก์ชัน เป่านกหวีด(ch, freq, endf, mag) {
bind v = endf * (0.05 + mag * 0.04)
ถ้า v > 0.18 { bind v = 0.18 }
เสียงโทน(ch, 0,0,0, 1.0, freq, v, 7.0, 0.5)
}
# เล่นเลน — เล่นโน้ต 1 เลน (ส่งอาเรย์ความถี่ครั้งเดียว เลี่ยง clone ซ้อน)
ฟังก์ชัน เล่นเลน(ch, freqL, slot, amp) {
bind fr = list_get(freqL, slot)
ถ้า fr > 0.0 { เสียงโทน(ch, 0,0,0, 1.0, fr, amp, 0.0, 0.0) }
มิฉะนั้น { เสียงโทน(ch, 0,0,0, 1.0, 220.0, 0.0, 0.0, 0.0) }
}
# ── คำ + เมนูเลือกเลเวล + ตัวช่วยของเก็บ/แถบคะแนน ────────────────────────────
bind คำ_เลเวล = [11,4,21,4,11,-1,18,4,11,4,2,19] # level select
bind คำ_เลฺว1 = [11,4,21,4,11,-1,14,13,4] # level one
bind คำ_เลฺว2 = [11,4,21,4,11,-1,19,22,14] # level two
bind คำ_เลฺว3 = [11,4,21,4,11,-1,19,7,17,4,4] # level three
bind เมนูเลเวล = [คำ_เลฺว1, คำ_เลฺว2, คำ_เลฺว3]
# ตั้งค่าสมาชิกที่ idx ของรายการ (สร้างใหม่ — รายการ ling แก้ในที่ไม่ได้)
# ตั้งรายการ(lst, idx, val) — ตอนนี้เป็น engine builtin (O(n) สำเนาเดียว) แทน
# ฟังก์ชัน ling แบบเดิมที่วน list_push/list_get เป็น O(n²) ต่อการเซ็ต (คอขวดต่อเฟรม)
# แถบคะแนน (pip ต่อของเก็บ) — ใช้กล้องโอเวอร์เลย์
ฟังก์ชัน วาดแถบคะแนน(เก็บแล้ว, n, t) {
bind i = 0
ขณะที่ i < n {
bind px = 0.0 - 11.0 + i * (22.0 / (n - 1))
bind py = 0.0 - 10.0
ถ้า list_get(เก็บแล้ว, i) > 0 {
bind h = t*2.0 + i*0.3
สีดินสอ(floor((ไซน์(h)*0.5+0.5)*170+85), floor((ไซน์(h+2.094)*0.5+0.5)*170+85), floor((ไซน์(h+4.189)*0.5+0.5)*170+85))
}
มิฉะนั้น { สีดินสอ(45, 45, 62) }
bind s = 0.34
วาดสามเหลี่ยม3มิติ(px-s, py-s, 0, px+s, py-s, 0, px+s, py+s, 0)
วาดสามเหลี่ยม3มิติ(px-s, py-s, 0, px+s, py+s, 0, px-s, py+s, 0)
bind i = i + 1
}
flush_3d()
}
# วาดกลิฟ3มิติ — กลิฟหนา: ปูหลายชั้นบาง ๆ ตามแนวตั้งฉาก (ชั้นซ้อนกัน = ด้านข้างทึบ)
# นูนน้อยลง (ลึกรวม ~0.32) แต่ 5 ชั้นทำให้ขอบ/ด้านข้างดูตัน ไม่โปร่ง
ฟังก์ชัน วาดกลิฟ3มิติ(code, x, y, z, sp, scale) {
ถ้า code < 26 { วาดอบเมช(list_get(_กลิฟเดมอน3มิติ, code), x, y, z, โคไซน์(sp),0,ไซน์(sp), 0,0.0-1.0,0, scale) }
}
ฟังก์ชัน วาดกลิฟ3มิติหน้า(code, x, y, z, sp, scale, t) {
ถ้า code < 26 {
bind rx = โคไซน์(sp); bind rz = ไซน์(sp)
bind nx = rz; bind nz = 0.0 - rx
bind h = t*4.0 + code*0.53
set_flat_shade(0.0)
สีดินสอ(floor((ไซน์(h)*0.5+0.5)*170+85), floor((ไซน์(h+2.094)*0.5+0.5)*170+85), floor((ไซน์(h+4.189)*0.5+0.5)*170+85))
วาดอบเมช(list_get(_กลิฟเดมอน3มิติ, code), x, y, z, rx,0,rz, 0,0.0-1.0,0, scale)
สีดินสอ(floor((ไซน์(h+2.094)*0.5+0.5)*150+70), floor((ไซน์(h+4.189)*0.5+0.5)*150+70), floor((ไซน์(h)*0.5+0.5)*150+70))
วาดอบเมช(list_get(_กลิฟเดมอน3มิติ, code), x+nx*scale*0.045, y, z+nz*scale*0.045, rx,0,rz, 0,0.0-1.0,0, scale*0.99)
สีดินสอ(floor((ไซน์(h+4.189)*0.5+0.5)*130+55), floor((ไซน์(h)*0.5+0.5)*130+55), floor((ไซน์(h+2.094)*0.5+0.5)*130+55))
วาดอบเมช(list_get(_กลิฟเดมอน3มิติ, code), x-nx*scale*0.045, y+scale*0.018, z-nz*scale*0.045, rx,0,rz, 0,0.0-1.0,0, scale*0.99)
}
}
# ตำแหน่งเก็บ(ci) — กระจายของเก็บไป 5 ห้อง (ci%5) + ออฟเซ็ตจาก MIDI → [gx, gz]
ฟังก์ชัน ตำแหน่งเก็บ(ci) {
bind room = ci % 5
bind rcx = 0.0; bind rcz = 0.0
ถ้า room == 1 { bind rcz = 0.0 - 704.0 }
ถ้า room == 2 { bind rcz = 704.0 }
ถ้า room == 3 { bind rcx = 704.0 }
ถ้า room == 4 { bind rcx = 0.0 - 704.0 }
คืน [rcx + list_get(เก็บX, ci) * 6.0, rcz + list_get(เก็บZ, ci) * 6.0]
}
# ── ไอคอนดาบเวกเตอร์ (โชว์ในช่องเซฟว่าได้ดาบแล้ว) ───────────────────────────
ฟังก์ชัน วาดไอคอนดาบ(x, y) {
สีดินสอ(210, 228, 255)
วาดเส้น3มิติ(x, y-1.0, 0.0, x, y+0.5, 0.0) # ใบมีด
สีดินสอ(180, 170, 120)
วาดเส้น3มิติ(x-0.45, y+0.5, 0.0, x+0.45, y+0.5, 0.0) # การ์ด
วาดเส้น3มิติ(x, y+0.5, 0.0, x, y+1.0, 0.0) # ด้าม
}
# ช่องเซฟนี้มีดาบไหม (ฟิลด์ที่ 4 ของ "x,y,z,skill" >= 1)
ฟังก์ชัน ช่องมีดาบ(data) {
ถ้า data == "empty" { คืน 0 }
bind pp = แยก(data, ",")
ถ้า ความยาว(pp) > 3 { ถ้า list_get(pp, 3) * 1.0 >= 1.0 { คืน 1 } }
คืน 0
}
# ════════════════════════════════════════════════════════════════════════════
# ดาบ: อาร์คฟัน (คอมโบ 0=แนวนอน 1=แนวตั้ง 2=แทง) + ไอคอนไอเทม + HUD
# ════════════════════════════════════════════════════════════════════════════
ฟังก์ชัน วาดสแลช(cx, cy, cz, yaw, typ, prog, bright, rad) {
bind fwx = ไซน์(yaw); bind fwz = โคไซน์(yaw)
สีดินสอ(floor(220*bright), floor(238*bright), floor(255*bright))
ถ้า typ == 2 {
bind ext = rad * (0.5 + prog*1.6) # แทง: พุ่งไปข้างหน้า
วาดเส้น3มิติ(cx, cy, cz, cx+fwx*ext, cy, cz+fwz*ext)
วาดเส้น3มิติ(cx, cy-1.2, cz, cx+fwx*ext, cy-1.2, cz+fwz*ext)
คืน 0
}
bind k = 1
bind ppx = cx; bind ppy = cy; bind ppz = cz
ขณะที่ k < 10 {
bind a = 0.0-1.3 + (k/9.0)*2.6*prog
bind px = cx; bind py = cy; bind pz = cz
ถ้า typ == 0 {
bind aa = yaw + a
bind px = cx + ไซน์(aa)*rad; bind pz = cz + โคไซน์(aa)*rad
}
มิฉะนั้น {
bind px = cx + fwx*โคไซน์(a)*rad; bind pz = cz + fwz*โคไซน์(a)*rad
bind py = cy - ไซน์(a)*rad
}
ถ้า k > 1 { วาดเส้น3มิติ(ppx, ppy, ppz, px, py, pz) }
bind ppx = px; bind ppy = py; bind ppz = pz
bind k = k + 1
}
คืน 0
}
# วงกลมจากเส้น 3 มิติ (ใช้กับไอคอน — วาดวงกลม builtin เป็น 2D พิกเซล ใช้ไม่ได้)
ฟังก์ชัน วงเส้น(x, y, r) {
bind k = 0; bind ppx = x + r; bind ppy = y
ขณะที่ k < 9 {
bind a = (k / 8.0) * 6.28318
bind px = x + โคไซน์(a)*r; bind py = y + ไซน์(a)*r
ถ้า k > 0 { วาดเส้น3มิติ(ppx, ppy, 0.0, px, py, 0.0) }
bind ppx = px; bind ppy = py; bind k = k + 1
}
}
# ไอคอนไอเทมเวกเตอร์ (id 1..10) ที่ (x,y) สเกล s — เส้นล้วน (overlay 3D)
ฟังก์ชัน ไอคอนไอเทม(id, x, y, s) {
ถ้า id == 1 { สีดินสอ(210,228,255); วาดเส้น3มิติ(x,y-s,0, x,y+s*0.4,0); สีดินสอ(180,170,120); วาดเส้น3มิติ(x-s*0.5,y+s*0.4,0, x+s*0.5,y+s*0.4,0) }
ถ้า id == 2 { สีดินสอ(255,120,60); วงเส้น(x, y+s*0.2, s*0.6); วาดเส้น3มิติ(x,y-s*0.4,0, x+s*0.4,y-s,0) }
ถ้า id == 3 { สีดินสอ(120,200,255); วาดเส้น3มิติ(x-s,y,0, x+s,y,0); วาดเส้น3มิติ(x+s,y,0, x+s*0.5,y-s*0.4,0); วาดเส้น3มิติ(x+s,y,0, x+s*0.5,y+s*0.4,0) }
ถ้า id == 4 { สีดินสอ(200,200,120); วาดเส้น3มิติ(x,y-s,0, x-s*0.6,y-s*0.3,0); วาดเส้น3มิติ(x-s*0.6,y-s*0.3,0, x-s*0.6,y+s*0.5,0); วาดเส้น3มิติ(x-s*0.6,y+s*0.5,0, x,y+s,0); วาดเส้น3มิติ(x,y+s,0, x+s*0.6,y+s*0.5,0); วาดเส้น3มิติ(x+s*0.6,y+s*0.5,0, x+s*0.6,y-s*0.3,0); วาดเส้น3มิติ(x+s*0.6,y-s*0.3,0, x,y-s,0) }
ถ้า id == 5 { สีดินสอ(210,228,255); วาดเส้น3มิติ(x-s*0.3,y-s,0, x-s*0.3,y+s*0.4,0); วาดเส้น3มิติ(x+s*0.3,y-s,0, x+s*0.3,y+s*0.4,0) }
ถ้า id == 6 { สีดินสอ(255,90,30); วาดเส้น3มิติ(x,y+s,0, x-s*0.4,y,0); วาดเส้น3มิติ(x-s*0.4,y,0, x,y-s,0); วาดเส้น3มิติ(x,y-s,0, x+s*0.4,y,0); วาดเส้น3มิติ(x+s*0.4,y,0, x,y+s,0) }
ถ้า id == 7 { สีดินสอ(150,220,255); วาดเส้น3มิติ(x,y-s,0, x,y+s,0); วาดเส้น3มิติ(x-s,y,0, x+s,y,0); วาดเส้น3มิติ(x-s*0.7,y-s*0.7,0, x+s*0.7,y+s*0.7,0); วาดเส้น3มิติ(x-s*0.7,y+s*0.7,0, x+s*0.7,y-s*0.7,0) }
ถ้า id == 8 { สีดินสอ(220,180,255); วงเส้น(x, y, s*0.7); วาดเส้น3มิติ(x,y-s,0, x,y+s,0); วาดเส้น3มิติ(x-s,y,0, x+s,y,0) }
ถ้า id == 9 { สีดินสอ(255,210,140); วงเส้น(x, y, s*0.8); วงเส้น(x, y, s*0.4) }
ถ้า id == 10 { สีดินสอ(255,70,90); วงเส้น(x, y, s*0.7); วาดเส้น3มิติ(x-s*0.4,y+s*0.3,0, x+s*0.4,y+s*0.3,0) }
}
# HUD: แถวไอคอนสกิลที่ได้ (1..สกิล) ล่างจอ; ไฮไลต์ที่เลือก
ฟังก์ชัน วาดHUDสกิล(สกิล, เลือก, t) {
bind i = 1
ขณะที่ i <= สกิล {
bind x = 0.0 - 11.0 + (i-1) * 2.4
bind y = 9.0
ถ้า i == เลือก {
สีดินสอ(255,255,180); วงเส้น(x, y, 1.3)
}
ไอคอนไอเทม(i, x, y, 0.85)
bind i = i + 1
}
flush_3d()
}