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/proc_gen_level.ling
# ────────────────────────────────────────────────────────────────────────────
# proc_gen_level.ling — LEVEL 2: ลานสุ่ม + ชั้นยกสูง (ramp ขึ้นไป) + กล่องตัวอักษร
# ใช้ฟังก์ชันร่วมจาก level.ling (วาดผนังเต็ม, LVL_F, LVL_C) + builtins.
# ดิสแพตช์จาก main เมื่อ ด่าน >= 1 (วาดเลเวล2/หากล่อง2/ความสูงพื้น2/...).
#
# PARAMS (ปรับเพื่อ vary แต่ละเลเวล):
# PG_SEED — เมล็ดสุ่ม (ตำแหน่งกล่อง)
# PG_HALF — ครึ่งขนาดลาน
# PG_LEDGE — ความสูงพื้นชั้นยก (ลบ = สูงขึ้น เพราะ +y ลง)
# PG_BOXN — จำนวนกล่องตัวอักษร
# ────────────────────────────────────────────────────────────────────────────
bind PG_SEED = 7.0
bind PG_HALF = 220.0
bind PG_LEDGE = 0.0 - 46.0
bind PG_BOXN = 9
bind PG_LH = 80.0 # ครึ่งขนาดชั้นยกกลาง
bind PG_RW = 26.0 # ครึ่งความกว้าง ramp
bind PG_RAMPZ = 200.0 # ปลายล่าง ramp (z) — อยู่ในพื้น (< PG_HALF) ไม่ชนผนัง
# สุ่มเทียม 0..1 จากดัชนี + เลเวล (แต่ละ lvl ได้ผังต่างกัน)
ฟังก์ชัน pgRand(i, lvl) {
bind s = ไซน์(i * 12.9898 + (PG_SEED + lvl * 4.7) * 78.233) * 43758.5453
คืน s - ปัดลง(s)
}
# จำนวนกล่อง/มอนสเตอร์ ตามเลเวล
ฟังก์ชัน จำนวนกล่อง(lvl) { bind n = 5.0 + ปัดลง(lvl); ถ้า n > 14.0 { bind n = 14.0 } คืน n }
# กระจายจุดแบบซันฟลาวเวอร์ (even-ish) บนลาน
ฟังก์ชัน กระจายลาน(i, n, lvl, radius) {
bind ang = i * 2.3999632 + lvl * 0.91
bind rad = รากที่สอง((i + 0.5) / n) * radius
คืน [โคไซน์(ang) * rad, ไซน์(ang) * rad]
}
# ตำแหน่งกล่องตัวอักษร i → [x, z]
ฟังก์ชัน ตำแหน่งกล่อง(i, lvl) {
bind n = จำนวนกล่อง(lvl)
bind p = กระจายลาน(i, n, lvl, PG_HALF - 42.0)
bind rx = list_get(p, 0)
bind rz = list_get(p, 1)
คืน [rx, rz]
}
# ── ความสูงพื้นที่ (x,z): ฐาน LVL_F; วัด/สเก็ตพาร์ค — 3 ramp (ใต้/ตะวันตก/ตะวันออก) ──
ฟังก์ชัน ความสูงพื้น2(x, z) {
# ramp ใต้: z=PG_RAMPZ (พื้น) → z=PG_LH (ขอบชั้น)
ถ้า x > 0.0-PG_RW { ถ้า x < PG_RW { ถ้า z > PG_LH { ถ้า z < PG_RAMPZ {
คืน LVL_F + (PG_LEDGE - LVL_F) * ((PG_RAMPZ - z) / (PG_RAMPZ - PG_LH))
} } } }
# ramp ตะวันตก: x=-PG_RAMPZ (พื้น) → x=-PG_LH (ขอบชั้น)
ถ้า z > 0.0-PG_RW { ถ้า z < PG_RW { ถ้า x > 0.0-PG_RAMPZ { ถ้า x < 0.0-PG_LH {
คืน LVL_F + (PG_LEDGE - LVL_F) * ((x + PG_RAMPZ) / (PG_RAMPZ - PG_LH))
} } } }
# ramp ตะวันออก: x=PG_RAMPZ (พื้น) → x=PG_LH (ขอบชั้น)
ถ้า z > 0.0-PG_RW { ถ้า z < PG_RW { ถ้า x < PG_RAMPZ { ถ้า x > PG_LH {
คืน LVL_F + (PG_LEDGE - LVL_F) * ((PG_RAMPZ - x) / (PG_RAMPZ - PG_LH))
} } } }
# ชั้นยกกลาง (platform = วิหารกลาง)
ถ้า x > 0.0-PG_LH { ถ้า x < PG_LH { ถ้า z > 0.0-PG_LH { ถ้า z < PG_LH {
คืน PG_LEDGE
} } } }
คืน LVL_F
}
# ── กล่องชน: ลานนอก (1 กล่อง) — คืน [pen,qx,qz] ──
ฟังก์ชัน หากล่อง2(cx, cz, R) {
bind x0 = 0.0-PG_HALF; bind x1 = PG_HALF; bind z0 = 0.0-PG_HALF; bind z1 = PG_HALF
bind qx = cx; ถ้า qx < x0+R { bind qx = x0+R } ถ้า qx > x1-R { bind qx = x1-R }
bind qz = cz; ถ้า qz < z0+R { bind qz = z0+R } ถ้า qz > z1-R { bind qz = z1-R }
คืน [รากที่สอง((cx-qx)*(cx-qx) + (cz-qz)*(cz-qz)), qx, qz]
}
# ── กำแพงรอบชั้นยก: กันลูก "ปีน" ขึ้นชั้น 2 ตรง ๆ (ขึ้นได้เฉพาะทาง ramp) ──
# ใช้ cy: ถ้าลูกอยู่ระดับพื้นล่าง + อยู่ในรอยเท้าชั้นยก (ไม่ใช่ช่อง ramp) → ดันออก
ฟังก์ชัน หากล่องชั้น(cx, cz, cy, R) {
ถ้า cy - R > PG_LEDGE + 16.0 { # ลูกต่ำกว่าชั้นยก (อยู่พื้นล่าง)
bind gap = 0
ถ้า cx > 0.0-PG_RW-R { ถ้า cx < PG_RW+R { ถ้า cz > PG_LH-2.0 { bind gap = 1 } } } # ช่อง ramp
ถ้า gap == 0 {
bind L = PG_LH + R
ถ้า cx > 0.0-L { ถ้า cx < L { ถ้า cz > 0.0-L { ถ้า cz < L {
bind dl = cx + L; bind dr = L - cx; bind db = cz + L; bind dfr = L - cz
bind m = dl; bind qx = 0.0-L; bind qz = cz
ถ้า dr < m { bind m = dr; bind qx = L; bind qz = cz }
ถ้า db < m { bind m = db; bind qx = cx; bind qz = 0.0-L }
ถ้า dfr < m { bind m = dfr; bind qx = cx; bind qz = L }
คืน [1.0, qx, qz]
} } } }
}
}
คืน [0.0, cx, cz]
}
# ── จุดเก็บตัวอักษร i (จาก n) กระจายสม่ำเสมอ (เกลียวซันฟลาวเวอร์) → [x, y, z] ──
# ถ้าตำแหน่งพื้นล่างถูกบล็อก (ในกล่องตัวอักษร) → ย้ายขึ้นชั้น 2 (PG_LEDGE)
ฟังก์ชัน ตำแหน่งเก็บ2(i, n, lvl) {
bind p = กระจายลาน(i, n, lvl+31.0, PG_HALF - 36.0)
bind ang = i * 2.3999632 + (lvl+31.0) * 0.91
bind x = list_get(p, 0)
bind z = list_get(p, 1)
# บล็อกไหม? (อยู่ในรอยเท้ากล่องตัวอักษร half=13+ระยะเผื่อ)
bind blocked = 0
bind nb = จำนวนกล่อง(lvl)
bind k = 0
ขณะที่ k < nb {
bind p = ตำแหน่งกล่อง(k, lvl)
bind dx = x - list_get(p,0); bind dz = z - list_get(p,1)
ถ้า dx*dx + dz*dz < 400.0 { bind blocked = 1 }
bind k = k + 1
}
ถ้า blocked == 1 {
# ย้ายขึ้นชั้น 2: ยุบรัศมีให้อยู่ในรอยเท้าชั้นยก + ความสูง PG_LEDGE
bind rad2 = (PG_LH - 18.0) * ((i - ปัดลง(i/4.0)*4.0) / 4.0 + 0.2)
bind gx = โคไซน์(ang)*rad2
bind gz = ไซน์(ang)*rad2
คืน [gx, ความสูงพื้น2(gx, gz) - 2.2, gz]
}
คืน [x, ความสูงพื้น2(x, z) - 2.2, z]
}
# ── รายการ bumper (กล่องตัวอักษร) แบน [x,z,รัศมี, ...] สำหรับชนในฟิสิกส์ ──
ฟังก์ชัน กล่องเลเวล2(lvl) {
bind out = []
bind nb = จำนวนกล่อง(lvl)
bind i = 0
ขณะที่ i < nb {
bind p = ตำแหน่งกล่อง(i, lvl)
bind out = list_push(out, list_get(p,0))
bind out = list_push(out, list_get(p,1))
bind out = list_push(out, 13.0)
bind i = i + 1
}
คืน out
}
# ── กล่องตัวอักษร: ลูกบาศก์เติม (ลายผนัง) + กลิฟวางบนหน้าบน ──
ฟังก์ชัน วาดกล่องตัวอักษร(x, z, gi, t) {
bind w = 11.0
bind top = LVL_F - 22.0 # หน้าบน (ขึ้น)
วาดผนังเต็ม(x-w, z-w, x+w, z-w)
วาดผนังเต็ม(x+w, z-w, x+w, z+w)
วาดผนังเต็ม(x+w, z+w, x-w, z+w)
วาดผนังเต็ม(x-w, z+w, x-w, z-w)
# หน้าบน (filled, สีพื้น)
สีดินสอ(16, 52, 50)
draw_quad_3d(x-w, top, z-w, x+w, top, z-w, x+w, top, z+w, x-w, top, z+w)
# กลิฟวางราบบนหน้าบน (สีหมุนเวียน)
bind hh = t*1.2 + x*0.05
สีดินสอ(floor((ไซน์(hh)*0.5+0.5)*180+70), floor((ไซน์(hh+2.094)*0.5+0.5)*180+70), floor((ไซน์(hh+4.189)*0.5+0.5)*180+70))
วาดอักขระDaemon(gi, x, top-0.6, z, 1,0,0, 0,0,1, 7.0) # flat (เบากว่า 3D มาก) — FPS
}
# ── พื้นชั้นยก: กระเบื้องเติมบน platform (ที่ PG_LEDGE) ──
ฟังก์ชัน วาดชั้นยก(t) {
bind S = 20.0; bind n = 0.0 - PG_LH
bind iz = 0.0 - PG_LH
ขณะที่ iz < PG_LH {
bind ix = 0.0 - PG_LH
ขณะที่ ix < PG_LH {
ถ้า กระเบื้องหน้ากล้อง(ix, PG_LEDGE, iz, ix+S, iz+S) == 1 {
ถ้า (ปัดลง(ix/S) + ปัดลง(iz/S)) - ปัดลง((ปัดลง(ix/S)+ปัดลง(iz/S))/2.0)*2.0 == 0.0 { สีดินสอ(36,36,42) }
มิฉะนั้น { สีดินสอ(54,54,62) }
draw_quad_3d(ix, PG_LEDGE, iz, ix+S, PG_LEDGE, iz, ix+S, PG_LEDGE, iz+S, ix, PG_LEDGE, iz+S)
}
bind ix = ix + S
}
bind iz = iz + S
}
}
# ผนังเตี้ยช่วง y0..y1 (เติม)
ฟังก์ชัน ผนังช่วง(ax, az, bx, bz, y0, y1) {
สีดินสอ(20, 30, 70)
วาดสามเหลี่ยม3มิติ(ax, y0, az, bx, y0, bz, bx, y1, bz)
วาดสามเหลี่ยม3มิติ(ax, y0, az, bx, y1, bz, ax, y1, az)
}
# ── ภาพศิลป์เฟรมบนผนัง: กรอบทอง 2 ชั้น + ลายเวกเตอร์เคลื่อนไหวในกรอบ ──────────
# (cx,cy,cz)=กลางเฟรม; (rx,rz)=แกนขวาแนวนอนของผนัง; up=(0,-1,0); cull จาก (bx,bz)
ฟังก์ชัน วาดศิลป์ผนัง(cx, cy, cz, rx, rz, w, h, t, kind, hue, bx, bz) {
ถ้า (cx-bx)*(cx-bx) + (cz-bz)*(cz-bz) > 90000.0 { คืน 0 }
bind o = 1.6
สีดินสอ(190, 155, 75)
วาดเส้น3มิติ(cx-rx*(w+o), cy-h-o, cz-rz*(w+o), cx+rx*(w+o), cy-h-o, cz+rz*(w+o))
วาดเส้น3มิติ(cx-rx*(w+o), cy+h+o, cz-rz*(w+o), cx+rx*(w+o), cy+h+o, cz+rz*(w+o))
วาดเส้น3มิติ(cx-rx*(w+o), cy-h-o, cz-rz*(w+o), cx-rx*(w+o), cy+h+o, cz-rz*(w+o))
วาดเส้น3มิติ(cx+rx*(w+o), cy-h-o, cz+rz*(w+o), cx+rx*(w+o), cy+h+o, cz+rz*(w+o))
สีดินสอ(48, 44, 40)
วาดเส้น3มิติ(cx-rx*w, cy+h, cz-rz*w, cx+rx*w, cy+h, cz+rz*w)
วาดเส้น3มิติ(cx-rx*w, cy-h, cz-rz*w, cx-rx*w, cy+h, cz-rz*w)
วาดเส้น3มิติ(cx+rx*w, cy-h, cz+rz*w, cx+rx*w, cy+h, cz+rz*w)
# ลายเวกเตอร์เคลื่อนไหวภายในกรอบ (vector "texture overlay")
ถ้า kind == 0 { ลายจักร(cx,cy,cz, rx,0,rz, 0,0.0-1.0,0, w*0.8, 10, t, hue) }
ถ้า kind == 1 { ลายยันต์(cx,cy,cz, rx,0,rz, 0,0.0-1.0,0, 6, h*0.8, t, hue) }
ถ้า kind == 2 { ลายดาว(cx,cy,cz, rx,0,rz, 0,0.0-1.0,0, 7, w*0.8, w*0.4, 0.1, t, hue) }
ถ้า kind == 3 { ลายดอกบัว(cx,cy,cz, rx,0,rz, 0,0.0-1.0,0, 2.0, w*0.8, 8, t, hue) }
คืน 0
}
ฟังก์ชัน วาดเลเวล2(t, cx, cz, lvl) {
# ผนังลานนอก (กล่องเปิดด้านบน)
วาดผนังเต็ม(0.0-PG_HALF, 0.0-PG_HALF, PG_HALF, 0.0-PG_HALF)
วาดผนังเต็ม(PG_HALF, 0.0-PG_HALF, PG_HALF, PG_HALF)
วาดผนังเต็ม(PG_HALF, PG_HALF, 0.0-PG_HALF, PG_HALF)
วาดผนังเต็ม(0.0-PG_HALF, PG_HALF, 0.0-PG_HALF, 0.0-PG_HALF)
# ชั้นยกกลาง + ผนังขอบชั้น (ยกเว้นด้าน ramp ทางใต้)
วาดชั้นยก(t)
ผนังช่วง(0.0-PG_LH, 0.0-PG_LH, PG_LH, 0.0-PG_LH, PG_LEDGE, LVL_F) # เหนือ
ผนังช่วง(0.0-PG_LH, 0.0-PG_LH, 0.0-PG_LH, PG_LH, PG_LEDGE, LVL_F) # ตะวันตก
ผนังช่วง(PG_LH, 0.0-PG_LH, PG_LH, PG_LH, PG_LEDGE, LVL_F) # ตะวันออก
ผนังช่วง(0.0-PG_LH, PG_LH, 0.0-PG_RW, PG_LH, PG_LEDGE, LVL_F) # ใต้ ซ้าย (เว้น ramp)
ผนังช่วง(PG_RW, PG_LH, PG_LH, PG_LH, PG_LEDGE, LVL_F) # ใต้ ขวา
# ทางลาด (ramp) จาก z=PG_RAMPZ (ในห้อง) → ขึ้นขอบชั้นยก (z=PG_LH); ลาดพอกลิ้งขึ้นได้
สีดินสอ(20, 56, 54)
วาดสามเหลี่ยม3มิติ(0.0-PG_RW, LVL_F, PG_RAMPZ, PG_RW, LVL_F, PG_RAMPZ, PG_RW, PG_LEDGE, PG_LH)
วาดสามเหลี่ยม3มิติ(0.0-PG_RW, LVL_F, PG_RAMPZ, PG_RW, PG_LEDGE, PG_LH, 0.0-PG_RW, PG_LEDGE, PG_LH)
# ผนังข้าง ramp (เติม) — กันตก + ดูเป็นทางลาดจริง
สีดินสอ(16, 42, 40)
วาดสามเหลี่ยม3มิติ(PG_RW, LVL_F, PG_RAMPZ, PG_RW, PG_LEDGE, PG_LH, PG_RW, LVL_F, PG_LH)
วาดสามเหลี่ยม3มิติ(0.0-PG_RW, LVL_F, PG_RAMPZ, 0.0-PG_RW, LVL_F, PG_LH, 0.0-PG_RW, PG_LEDGE, PG_LH)
# โคมระย้ากลางเหนือชั้นยก
วาดโคมระย้า(0.0, 0.0, t)
# กล่องตัวอักษร (สุ่มตามเลเวล) — วาดเฉพาะตัวใกล้ (cull) เพื่อ FPS
bind nb = จำนวนกล่อง(lvl)
bind i = 0
ขณะที่ i < nb {
bind p = ตำแหน่งกล่อง(i, lvl)
bind px = list_get(p,0); bind pz = list_get(p,1)
ถ้า (px-cx)*(px-cx) + (pz-cz)*(pz-cz) < 160000.0 {
วาดกล่องตัวอักษร(px, pz, (i*7.0 + lvl*3.0) % 26.0, t)
}
bind i = i + 1
}
# คบไฟผนังลาน
วาดคบไฟ(0.0-PG_HALF+8.0, 0.0, t, 0.0)
วาดคบไฟ(PG_HALF-8.0, 0.0, t, 1.4)
วาดคบไฟ(0.0, 0.0-PG_HALF+8.0, t, 2.8)
วาดคบไฟ(0.0, PG_HALF-8.0, t, 4.2)
# ── ภาพศิลป์เฟรมบนผนัง (vector overlay เคลื่อนไหวในกรอบ) — cull ใกล้ ──
วาดศิลป์ผนัง(0.0-100.0, 0.0-44.0, 0.0-PG_HALF+1.5, 1,0, 14.0, 12.0, t, 0, lvl*0.7, cx, cz)
วาดศิลป์ผนัง(100.0, 0.0-44.0, 0.0-PG_HALF+1.5, 1,0, 14.0, 12.0, t, 2, lvl*0.7+1.5, cx, cz)
วาดศิลป์ผนัง(0.0-100.0, 0.0-44.0, PG_HALF-1.5, 1,0, 14.0, 12.0, t, 1, lvl*0.7+3.0, cx, cz)
วาดศิลป์ผนัง(100.0, 0.0-44.0, PG_HALF-1.5, 1,0, 14.0, 12.0, t, 3, lvl*0.7+4.5, cx, cz)
วาดศิลป์ผนัง(0.0-PG_HALF+1.5, 0.0-44.0, 0.0-100.0, 0,1, 14.0, 12.0, t, 2, lvl*0.7+0.8, cx, cz)
วาดศิลป์ผนัง(0.0-PG_HALF+1.5, 0.0-44.0, 100.0, 0,1, 14.0, 12.0, t, 0, lvl*0.7+2.3, cx, cz)
วาดศิลป์ผนัง(PG_HALF-1.5, 0.0-44.0, 0.0-100.0, 0,1, 14.0, 12.0, t, 3, lvl*0.7+3.8, cx, cz)
วาดศิลป์ผนัง(PG_HALF-1.5, 0.0-44.0, 100.0, 0,1, 14.0, 12.0, t, 1, lvl*0.7+5.3, cx, cz)
}
ฟังก์ชัน ดึงกล้อง2(cx, cz) {
คืน [cx, cz] # แลตทิซ: ห้องเปิดกว้าง — ไม่หนีบกล้องด้วยเรขาเก่า (กันกล้องเพี้ยน)
}
# ของเก็บกระจายในลาน (จาก MIDI offset ขยายเข้าลาน)
ฟังก์ชัน ตำแหน่งเก็บเพลง2(ci) {
คืน [list_get(เก็บX, ci) * 7.0, list_get(เก็บZ, ci) * 7.0]
}
ฟังก์ชัน procLightColor(idx) {
bind m = idx - floor(idx / 8.0) * 8.0
bind r = 1.0; bind g = 0.06; bind b = 0.02
ถ้า m == 1.0 { bind r = 0.02; bind g = 1.0; bind b = 0.24 }
ถ้า m == 2.0 { bind r = 0.03; bind g = 0.24; bind b = 1.0 }
ถ้า m == 3.0 { bind r = 1.0; bind g = 0.03; bind b = 0.92 }
ถ้า m == 4.0 { bind r = 1.0; bind g = 0.48; bind b = 0.02 }
ถ้า m == 5.0 { bind r = 0.04; bind g = 0.92; bind b = 1.0 }
ถ้า m == 6.0 { bind r = 0.36; bind g = 0.08; bind b = 1.0 }
ถ้า m == 7.0 { bind r = 0.82; bind g = 1.0; bind b = 0.04 }
คืน [r, g, b]
}
ฟังก์ชัน ตั้งแสงเลเวล2(cx, cz, t, lvl) {
ล้างแสง()
bind rc = ปัดลง(cx / ROOM_S); bind rr = ปัดลง(cz / ROOM_S)
bind hc = ROOM_S * 0.5
bind rad = ROOM_S * 0.78
bind ปัก = [0.0,0.0, 1.0,0.0, 0.0-1.0,0.0, 0.0,1.0, 0.0,0.0-1.0]
bind k = 0
ขณะที่ k < 5 {
bind dc = list_get(ปัก, k*2); bind dr = list_get(ปัก, k*2+1)
bind lx = (rc+dc)*ROOM_S + hc; bind lz = (rr+dr)*ROOM_S + hc
# ผูกสี/จังหวะกับพิกัดห้องจริง (rc+dc, rr+dr) ไม่ใช่ k (ลำดับเทียบกล้อง) —
# ห้องเดิมเคยเปลี่ยน k ทุกครั้งที่ผู้เล่นข้ามห้อง (0=ตัวเอง กลายเป็น 1..4=เพื่อนบ้าน)
# ทำให้สี/วูบไฟกระโดดกลางอากาศ ทั้งที่เป็นห้องเดียวกัน
bind roomSeed = (rc+dc)*7.0 + (rr+dr)*13.0
bind roomSeed = roomSeed - floor(roomSeed / 8.0) * 8.0
bind hue = roomSeed*1.2566 + lvl*0.8
bind ly = ความสูงพื้น2(lx, lz) - 30.0
bind fl = 0.66 + ไซน์(t*(3.7+roomSeed*0.8)+lvl+roomSeed*2.1)*0.22 + ไซน์(t*(9.0+roomSeed)+roomSeed*4.3)*0.09
ถ้า fl < 0.34 { bind fl = 0.34 }
ถ้า fl > 0.96 { bind fl = 0.96 }
bind col = procLightColor(roomSeed + floor(lvl))
bind lr = list_get(col, 0); bind lg = list_get(col, 1); bind lb = list_get(col, 2)
เพิ่มแสง(lx, ly, lz, lr, lg, lb, fl, rad)
bind k = k + 1
}
bind gems = [0.42,0.0, 0.30,0.30, 0.0,0.42, 0.0-0.30,0.30, 0.0-0.42,0.0, 0.0-0.30,0.0-0.30, 0.0,0.0-0.42, 0.30,0.0-0.30]
bind gk = 0
ขณะที่ gk < 8 {
bind gx = rc*ROOM_S + hc + list_get(gems, gk*2) * ROOM_S
bind gz = rr*ROOM_S + hc + list_get(gems, gk*2+1) * ROOM_S
bind gh = gk*0.7854 + lvl*1.17
bind gf = 0.46 + ไซน์(t*(5.2+gk*0.31)+gk*1.9)*0.16 + ไซน์(t*(13.0+gk*0.7))*0.06
ถ้า gf < 0.24 { bind gf = 0.24 }
ถ้า gf > 0.72 { bind gf = 0.72 }
bind gcol = procLightColor(gk + 3.0 + floor(lvl)*2.0)
bind grl = list_get(gcol, 0); bind ggl = list_get(gcol, 1); bind gbl = list_get(gcol, 2)
เพิ่มแสง(gx, ความสูงพื้น2(gx, gz) - 18.0, gz, grl, ggl, gbl, gf, ROOM_S*0.44)
bind gk = gk + 1
}
เพิ่มแสง(cx, ความสูงพื้น2(cx, cz) - 12.0, cz, 0.10, 0.28, 1.0, 0.26, ROOM_S * 0.38)
}
# ── โฮโลแมพ 3D บน HUD: เรดาร์โฮโลแกรม—มอนสเตอร์ (แดง) + ตัวอักษร/ของเก็บ (ทอง) ──
# วาดในสเปซ HUD (กล้อง z=-22): จานเอียง (ellipse) + สแกนหมุน + บลิปลำแสง (additive)
# world→radar: หมุนให้ทิศกล้อง (camYaw) = ขึ้น; หนีบขอบเมื่อไกลเกิน RANGE
ฟังก์ชัน วาดโฮโลแมพ(cx, cz, camYaw, monX, monZ, monAlive, monN, colX, colZ, colDone, colN, t) {
bind mcx = 10.3; bind mcy = 0.0 - 5.7; bind R = 2.7; bind squash = 0.5
bind RANGE = 440.0
bind fwdx = ไซน์(camYaw); bind fwdz = โคไซน์(camYaw)
bind rgtx = โคไซน์(camYaw); bind rgtz = 0.0 - ไซน์(camYaw)
โหมดผสม(1)
# จานโฮโล: วงแหวน 3 วง (ไซแอน)
bind ring = 1
ขณะที่ ring < 4 {
bind rr = R * ring / 3.0
สีดินสอ(20, floor(90 + ring*25), floor(120 + ring*30))
bind seg = 0
ขณะที่ seg < 26 {
bind a0 = seg*0.2417; bind a1 = (seg+1)*0.2417
วาดเส้น3มิติ(mcx+โคไซน์(a0)*rr, mcy+ไซน์(a0)*rr*squash, 0.0, mcx+โคไซน์(a1)*rr, mcy+ไซน์(a1)*rr*squash, 0.0)
bind seg = seg + 1
}
bind ring = ring + 1
}
# เส้นสแกนหมุน (holographic sweep)
bind sa = t * 1.6
สีดินสอ(80, 210, 255)
วาดเส้น3มิติ(mcx, mcy, 0.05, mcx+โคไซน์(sa)*R, mcy+ไซน์(sa)*R*squash, 0.05)
# ผู้เล่นกลาง (ลูกศรชี้ขึ้น = หน้า)
สีดินสอ(130, 255, 230)
วาดสามเหลี่ยม3มิติ(mcx, mcy-0.42, 0.1, mcx-0.24, mcy+0.22, 0.1, mcx+0.24, mcy+0.22, 0.1)
# บลิปมอนสเตอร์ (แดง)
bind i = 0
ขณะที่ i < monN {
ถ้า list_get(monAlive, i) > 0 {
bind dx = list_get(monX, i) - cx; bind dz = list_get(monZ, i) - cz
bind af = dx*fwdx + dz*fwdz; bind ar = dx*rgtx + dz*rgtz
bind d = รากที่สอง(af*af + ar*ar) + 0.001
bind scb = 1.0; ถ้า d > RANGE { bind scb = RANGE / d }
bind bx = mcx + (ar*scb/RANGE)*R
bind by = mcy - (af*scb/RANGE)*R*squash
สีดินสอ(255, 60, 70)
วาดเส้น3มิติ(bx, by+0.05, 0.15, bx, by-0.38-ไซน์(t*5.0+i)*0.12, 0.15)
อนุภาคทรงกลม(bx, by, 0.15, 0.15, 4, t*3.0+i, 255, 70, 80)
}
bind i = i + 1
}
# บลิปตัวอักษร/ของเก็บ (ทอง) — เฉพาะที่ยังไม่เก็บ
bind j = 0
ขณะที่ j < colN {
ถ้า list_get(colDone, j) < 0.5 {
bind cdx = list_get(colX, j) - cx; bind cdz = list_get(colZ, j) - cz
bind caf = cdx*fwdx + cdz*fwdz; bind car = cdx*rgtx + cdz*rgtz
bind cd = รากที่สอง(caf*caf + car*car) + 0.001
bind csb = 1.0; ถ้า cd > RANGE { bind csb = RANGE / cd }
bind cbx = mcx + (car*csb/RANGE)*R
bind cby = mcy - (caf*csb/RANGE)*R*squash
สีดินสอ(255, 210, 90)
วาดเส้น3มิติ(cbx, cby+0.05, 0.15, cbx, cby-0.32-ไซน์(t*4.0+j)*0.1, 0.15)
อนุภาคทรงกลม(cbx, cby, 0.15, 0.13, 4, t*2.5+j, 255, 215, 100)
}
bind j = j + 1
}
flush_3d(); โหมดผสม(0)
}