灵符lingfu

soul-symphony-ling

↓ 0 downloads

Soul 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-ling
AuthorsLing Lin <taellinglin@gmail.com>
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / 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)
}

← Back to index