灵符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/monster.ling
# ════════════════════════════════════════════════════════════════════════════
# monster.ling — มอนสเตอร์คริสตัลไวรัส: สเตตัส/ชนิด/ตำแหน่ง(AI) + โมเดล 3D + หนวดวงจร
#   ย้ายมาจาก proc_gen_level.ling (อ้างอิงร่วม: pgRand, กระจายลาน, LVL_F เป็นโกลบอล)
#   ฟังก์ชันทั้งหมดเป็นโกลบอล → เรียก pgRand/กระจายลาน/LVL_F (นิยามใน proc_gen_level/level)
#   ได้ตราบที่ main.ling ใช้ทั้งสองไฟล์
# ════════════════════════════════════════════════════════════════════════════

# จำนวนมอนสเตอร์ ตามเลเวล (สูงสุด 31 — เกือบ 1 ตัว/ห้อง)
ฟังก์ชัน จำนวนมอน(lvl)   { bind n = 5.0 + ปัดลง(lvl)*2.0;  ถ้า n > 31.0 { bind n = 31.0 }  คืน n }   # ลาดชันเบาลง (เดิม 6+lvl*3)

# ── สปีชีส์มอน: 4 สายพันธุ์ × รูปคริสตัล × สี ROYGBIV × ระดับสเตตัส (โครงสร้าง) ──
#   คืน [species(0-3), shape(0-3), hue(0-6 ROYGBIV), speedMul, hpMul, dmgMul]
#   ช้า=อึด/แรง · เร็ว=เปราะ → สมดุล 4 ระดับ
ฟังก์ชัน สปีชีส์มอน(i, lvl) {
    bind sp = ปัดลง(pgRand(i + 700.0, lvl) * 4.0);  ถ้า sp > 3.0 { bind sp = 3.0 }
    bind hue = ปัดลง(pgRand(i + 800.0, lvl) * 7.0);  ถ้า hue > 6.0 { bind hue = 6.0 }   # 0=แดง..6=ม่วง
    คืน [sp, sp, hue, 0.6 + sp*0.3, 1.7 - sp*0.32, 0.7 + sp*0.4]
}

# สี ROYGBIV จาก hue index 0..6 → [r,g,b]
ฟังก์ชัน สีรุ้ง7(h) {
    bind a = h * 0.8976                                  # 7 ช่วงรอบวงล้อสี (2π/7)
    คืน [floor((ไซน์(a)*0.5+0.5)*205+45), floor((ไซน์(a+2.094)*0.5+0.5)*205+45), floor((ไซน์(a+4.189)*0.5+0.5)*205+45)]
}

# ชนิดมอน: 0 = drifter (ช้า เดินวน), 1 = hunter (เร็ว ไล่ผู้เล่น)
ฟังก์ชัน ชนิดมอน(i, lvl) {
    ถ้า lvl < 1.5 { คืน 0 }
    ถ้า pgRand(i + 500.0, lvl) > 0.55 { คืน 1 }
    คืน 0
}

# 8 สเตตัส [STR,AGI,VIT,FOC,DEF,LCK,SPD,PWR] (สเกลตามเลเวล)
ฟังก์ชัน สเตตัสมอน(seed, lvl) {
    bind b = 3.0 + lvl * 1.5
    คืน [
        floor(b + pgRand(seed+1.0, lvl)*lvl*3.0), floor(b + pgRand(seed+2.0, lvl)*lvl*3.0),
        floor(b + pgRand(seed+3.0, lvl)*lvl*3.0), floor(b + pgRand(seed+4.0, lvl)*lvl*3.0),
        floor(b + pgRand(seed+5.0, lvl)*lvl*3.0), floor(b + pgRand(seed+6.0, lvl)*lvl*3.0),
        floor(b + pgRand(seed+7.0, lvl)*lvl*3.0), floor(b + pgRand(seed+8.0, lvl)*lvl*3.0)
    ]
}

# ฐานมอน: จุดเกิดมอน i → [bx, bz]
#   ทิวทอเรียล (lvl<0.5): 1 ตัว/ห้อง — กลาง/เหนือ/ใต้/ออก/ตก ±704 (แมปห้องเดียวกับจุดเก็บอักษรใน main)
#   ด่านอื่น: กระจายซันฟลาวเวอร์รอบจุดเกิดตาม spread (เหมือนเดิม)
ฟังก์ชัน ฐานมอน(i, n, lvl, spread) {
    bind p = กระจายลาน(i, n, lvl+13.0, spread)
    bind bx = list_get(p, 0);  bind bz = list_get(p, 1)
    ถ้า lvl < 0.5 {
        bind bx = bx * 0.5;  bind bz = bz * 0.5          # จิตเตอร์เล็กรอบกลางห้อง (~±22)
        bind rm = i - ปัดลง(i/5.0)*5.0
        ถ้า rm == 1.0 { bind bz = bz - 704.0 }           # ห้องเหนือ
        ถ้า rm == 2.0 { bind bz = bz + 704.0 }           # ห้องใต้
        ถ้า rm == 3.0 { bind bx = bx + 704.0 }           # ห้องออก
        ถ้า rm == 4.0 { bind bx = bx - 704.0 }           # ห้องตก
    }
    คืน [bx, bz]
}

# ตำแหน่งมอน i → [x, z, anim]; AI ตามระยะ: idle/wander → walk → scurry(ไล่) → attack
#   anim: 0 idle · 1 walk · 2 scurry · 3 attack ; speedMul จากสปีชีส์
# โกรธ = ตัวจับเวลาความแค้น (วิ) ที่ main ส่งเข้ามา ตั้งเมื่อมอนโดนตี/เห็นผู้เล่นใกล้
# > 0 = ล็อกเป้าไล่ล่าไม่เลิก ไม่ว่าจะไกลแค่ไหน
ฟังก์ชัน ตำแหน่งมอน(i, lvl, t, spread, typ, px, pz, โกรธ) {
    bind sv = สปีชีส์มอน(i, lvl);  bind spd = list_get(sv, 3)        # speedMul สายพันธุ์
    bind n = จำนวนมอน(lvl)
    bind pB = ฐานมอน(i, n, lvl, spread)
    bind bx = list_get(pB, 0);  bind bz = list_get(pB, 1)
    bind wr = 36.0 + pgRand(i + 340.0, lvl) * 24.0
    bind a = t * (0.84 + pgRand(i + 420.0, lvl) * 0.64) * spd + i * 1.7
    # เดินเล่น: เดิมเป็นวงกลมสมบูรณ์ (cos,sin รัศมีคงที่) มอนเลยดู "วิ่งวนเป็นวงกลม"
    # ตลอดเวลา — ใส่ลิสซาจูส (คาบต่างกัน 0.61/0.83) + รัศมีที่หายใจเข้าออก
    # เส้นทางเลยเป็นวงรีบิดที่ไม่ซ้ำรอยเดิม ดูเหมือนเดินสำรวจมากกว่าโคจร
    bind wob = 1.0 + ไซน์(a*0.37 + i) * 0.35
    bind ox = bx + โคไซน์(a*0.61) * wr * wob
    bind oz = bz + ไซน์(a*0.83 + i*0.7) * wr * wob
    bind dpx = px - ox;  bind dpz = pz - oz;  bind dd = รากที่สอง(dpx*dpx + dpz*dpz) + 0.001
    bind anim = 0.0
    ถ้า dd < spread { bind anim = 1.0 }
    # ระยะล่า: กว้างขึ้นกว่าเดิม และ "โกรธ" = ล่าไม่จำกัดระยะ
    bind huntR = 130.0;  ถ้า typ > 0.5 { bind huntR = 200.0 }
    ถ้า โกรธ > 0.0 { bind huntR = 100000.0 }
    ถ้า dd < huntR {
        bind chase = (0.06 + spd*0.16)
        ถ้า typ < 0.5 { bind chase = chase * 0.6 }
        ถ้า โกรธ > 0.0 { bind chase = chase * 2.1 }                 # แค้นแล้วเร่งเข้าใส่
        ถ้า chase > 0.85 { bind chase = 0.85 }
        # เข้าหาเป้าแบบส่ายเล็กน้อย (ตั้งฉากกับแนวเข้าหา) — ไม่พุ่งเป็นเส้นตรงจนดูเป็นหุ่น
        bind nx = dpx/dd;  bind nz = dpz/dd
        bind weave = ไซน์(t*3.1 + i*2.2) * 0.22
        ถ้า dd < 30.0 { bind weave = weave * (dd/30.0) }            # ประชิดแล้วเลิกส่าย เข้าตรง ๆ
        bind ox = ox + (nx + (0.0-nz)*weave) * dd * chase
        bind oz = oz + (nz + nx*weave)      * dd * chase
        bind anim = 2.0
        ถ้า dd < 24.0 { bind anim = 3.0 }
    }
    คืน [ox, oz, anim]
}

# ── ออกตาฮีดรอนเติม (ลำตัวมอนแหลม 3D) ────────────────────────────────────────
ฟังก์ชัน วาดออคตา(cx,cy,cz, rx,ry,rz) {
    bind ty=cy-ry;  bind by=cy+ry;  bind ey=cy
    bind ax=cx+rx;  bind bx2=cx;     bind cx2=cx-rx;  bind dx2=cx
    bind az=cz;     bind bz2=cz+rz;  bind cz2=cz;     bind dz2=cz-rz
    วาดสามเหลี่ยม3มิติ(cx,ty,cz, ax,ey,az, bx2,ey,bz2)  วาดสามเหลี่ยม3มิติ(cx,ty,cz, bx2,ey,bz2, cx2,ey,cz2)
    วาดสามเหลี่ยม3มิติ(cx,ty,cz, cx2,ey,cz2, dx2,ey,dz2) วาดสามเหลี่ยม3มิติ(cx,ty,cz, dx2,ey,dz2, ax,ey,az)
    วาดสามเหลี่ยม3มิติ(cx,by,cz, bx2,ey,bz2, ax,ey,az)  วาดสามเหลี่ยม3มิติ(cx,by,cz, cx2,ey,cz2, bx2,ey,bz2)
    วาดสามเหลี่ยม3มิติ(cx,by,cz, dx2,ey,dz2, cx2,ey,cz2) วาดสามเหลี่ยม3มิติ(cx,by,cz, ax,ey,az, dx2,ey,dz2)
}

# ไอคอนบัฟ stat (0-7) ที่ (x,y) ระนาบ x-y — สีต่างกัน 8 แบบ (ใช้ทั้งมอน + ดรอป + HUD ผู้เล่น)
ฟังก์ชัน ไอคอนบัฟ(stat, x, y, z, s) {
    bind h = stat * 0.785
    สีดินสอ(floor((ไซน์(h)*0.5+0.5)*200+55), floor((ไซน์(h+2.094)*0.5+0.5)*200+55), floor((ไซน์(h+4.189)*0.5+0.5)*200+55))
    วาดสามเหลี่ยม3มิติ(x,y-s,z, x+s,y,z, x,y+s,z)
    วาดสามเหลี่ยม3มิติ(x,y-s,z, x,y+s,z, x-s,y,z)
}

# ── ท่อ (cylinder) ระหว่าง 2 จุด, รัศมี rad ──
ฟังก์ชัน วาดท่อ(ax, ay, az, bx, by, bz, rad, r, g, b) {
    bind dx = bx-ax;  bind dy = by-ay;  bind dz = bz-az
    bind ux = 0.0-dz;  bind uz = dx
    bind ul = รากที่สอง(ux*ux + uz*uz);  ถ้า ul < 0.001 { bind ux = 1.0;  bind uz = 0.0;  bind ul = 1.0 }
    bind uix = ux/ul;  bind uiy = 0.0;  bind uiz = uz/ul
    bind wx = dy*uiz - dz*uiy;  bind wy = dz*uix - dx*uiz;  bind wz = dx*uiy - dy*uix
    bind wl = รากที่สอง(wx*wx + wy*wy + wz*wz);  ถ้า wl < 0.001 { bind wl = 1.0 }
    bind wix = wx/wl;  bind wiy = wy/wl;  bind wiz = wz/wl
    สีดินสอ(r, g, b)
    bind sides = 4.0;  bind s = 0.0
    ขณะที่ s < sides {
        bind a0 = (s/sides)*6.2832;  bind a1 = ((s+1.0)/sides)*6.2832
        bind c0 = โคไซน์(a0);  bind n0 = ไซน์(a0);  bind c1 = โคไซน์(a1);  bind n1 = ไซน์(a1)
        bind o0x=(uix*c0+wix*n0)*rad;  bind o0y=(uiy*c0+wiy*n0)*rad;  bind o0z=(uiz*c0+wiz*n0)*rad
        bind o1x=(uix*c1+wix*n1)*rad;  bind o1y=(uiy*c1+wiy*n1)*rad;  bind o1z=(uiz*c1+wiz*n1)*rad
        วาดสามเหลี่ยม3มิติ(ax+o0x,ay+o0y,az+o0z, ax+o1x,ay+o1y,az+o1z, bx+o1x,by+o1y,bz+o1z)
        วาดสามเหลี่ยม3มิติ(ax+o0x,ay+o0y,az+o0z, bx+o1x,by+o1y,bz+o1z, bx+o0x,by+o0y,bz+o0z)
        bind s = s + 1.0
    }
}

# ── แขนวงจร (circuit limb): ท่อตรงหักมุมฉาก + โหนดเรืองแสง (สังเคราะห์ ไม่ออร์แกนิก) ──
ฟังก์ชัน วาดหนวด(bx, by, bz, ang, droop, len, t, phase, r, g, b) {
    bind segs = 3.0;  bind sg = len/segs
    bind px = bx;  bind py = by;  bind pz = bz;  bind k = 0.0
    ขณะที่ k < segs {
        bind f = (k+1.0)/segs
        bind bend = (k - ปัดลง(k/2.0)*2.0) * 0.95 - 0.475      # หักสลับ ±  (เทรซวงจร)
        bind nx = px + โคไซน์(ang + bend)*sg
        bind nz = pz + ไซน์(ang + bend)*sg
        bind ny = py + droop*sg
        วาดท่อ(px, py, pz, nx, ny, nz, 0.40*(1.0 - f*0.4), floor(r*0.5), floor(g*0.5), floor(b*0.5))   # เทรซบาง หรี่
        bind pls = ไซน์(t*6.0 + phase + k*1.7)*0.5+0.5                                                 # พัลส์ไฟฟ้า
        โหมดผสม(1);  อนุภาคทรงกลม(nx, ny, nz, 0.35+pls*0.4, 4, t*5.0, floor(60+pls*120), 255, floor(150+pls*100))   # โหนดไซแอน-เขียว
        flush_3d();  โหมดผสม(0)
        bind px = nx;  bind py = ny;  bind pz = nz;  bind k = k + 1.0
    }
    โหมดผสม(1);  สีดินสอ(120, 255, 200);  อนุภาคทรงกลม(px, py, pz, 0.7, 4, t*5.0+phase, 120, 255, 200);  flush_3d();  โหมดผสม(0)   # พินคอนเนกเตอร์
}

# ── มอนคริสตัลแวมไพร์มิติที่ 5 (5th-dimensional vampire crystal) ──
#   ผลึกลอยไร้ขา: แกนมืดแวมไพร์ (ออร่าเลือด) + สะเก็ดผลึกโคจรหลายแกน (เฟสเข้า-ออก)
#   + ปีกผลึกกระพือ + ประกายดิจิทัล (digital organism). anim: 0 idle·1 walk·2 scurry·3 attack
#   hitT>0 = โดนตี (สั่น+แฟลชขาว)  ·  dieT>0 (1→0) = กำลังตาย (ยุบ+เผาเป็นเถ้า)
ฟังก์ชัน วาดมอน(x, z, floorY, t, seed, typ, hpfrac, lvl, anim, hitT, dieT) {
    bind sv = สปีชีส์มอน(seed, lvl)                          # [sp, shape, hue, speedMul, hpMul, dmgMul]
    bind shape = list_get(sv, 1)
    bind col = สีรุ้ง7(list_get(sv, 2))
    bind r1 = list_get(col, 0);  bind g1 = list_get(col, 1);  bind b1 = list_get(col, 2)
    bind spin = t*0.8 + seed
    bind spin2 = t*1.3 + seed*2.0                           # แกนหมุนที่ 2 (มิติที่ 5)
    bind bob = ไซน์(t*1.6 + seed) * 0.7

    # ── กระโดด/กระโจน (pounce): scurry/attack → กระเด้งขึ้นเป็นจังหวะ ──
    bind hopH = 0.0
    ถ้า anim > 1.5 { bind hopH = 3.2 + anim*1.4 }
    bind hop = 0.0
    ถ้า hopH > 0.0 { bind hp0 = ไซน์(t*6.0 + seed);  ถ้า hp0 < 0.0 { bind hp0 = 0.0 - hp0 }  bind hop = hp0*hopH }
    bind by = (floorY - 8.0) - hop + bob                    # ลอยเหนือพื้น (up = -y → ลบ = สูง)

    # ── โดนตี: สั่น + แฟลชขาว (anim เล่นจนครบ hitT) ──
    bind hit = hitT / 0.35;  ถ้า hit > 1.0 { bind hit = 1.0 }  ถ้า hit < 0.0 { bind hit = 0.0 }
    bind mx = x + ไซน์(t*80.0 + seed)*hit*1.8
    bind mz = z + โคไซน์(t*74.0 + seed)*hit*1.8
    bind fr = floor(r1 + (255.0-r1)*hit);  bind fg = floor(g1 + (255.0-g1)*hit);  bind fb = floor(b1 + (255.0-b1)*hit)

    # ════ กำลังตาย: ยุบ (crumple) + เผาเป็นเถ้า (burn away) ════
    ถ้า dieT > 0.0 {
        bind burn = 1.0 - dieT                              # 0→1 ระหว่างตาย
        โหมดผสม(0)
        ถ้า burn < 0.6 {                                    # ครึ่งแรก: แกนผลึกหดหมุนบ้า
            bind cr = 3.0 * (1.0 - burn/0.6)
            สีดินสอ(floor(150*(1.0-burn)), floor(30*(1.0-burn)), floor(45*(1.0-burn)))
            วาดออคตา(mx, by, mz, cr, cr*2.0, cr)
        }
        bind dk = 0.0                                       # สะเก็ดกระเด็นออก (crumple)
        ขณะที่ dk < 6.0 {
            bind da = (dk/6.0)*6.2832 + spin
            bind dr2 = burn*7.0;  bind ds = (1.0 - burn)*1.3
            ถ้า ds > 0.05 {
                สีดินสอ(floor(fr*0.5), floor(fg*0.4), floor(fb*0.5))
                วาดออคตา(mx + โคไซน์(da)*dr2, by + burn*3.0 + ไซน์(dk), mz + ไซน์(da)*dr2, ds, ds*1.6, ds)
            }
            bind dk = dk + 1.0
        }
        โหมดผสม(1)                                          # เผา: เถ้าถ่านลอยขึ้น (ส้ม-แดง เฟดหาย)
        bind ek = 0.0
        ขณะที่ ek < 14.0 {
            bind ea = ek*0.9 + t*3.0;  bind erad = 1.0 + burn*4.5;  bind ef = 1.0 - burn
            อนุภาคทรงกลม(mx + โคไซน์(ea)*erad, by - burn*11.0 - ek*0.35, mz + ไซน์(ea)*erad, 0.7*ef, 3, t*5.0+ek, 255, floor(120*ef+40), 30)
            bind ek = ek + 1.0
        }
        flush_3d();  โหมดผสม(0)
        คืน 0
    }

    # ════ มีชีวิต: ผลึกแวมไพร์ ════
    # ── ออร่าเลือด + ประกายดิจิทัล + เงาซ้อนมิติที่ 5 (additive) ──
    โหมดผสม(1)
    bind aura = 0.6 + ไซน์(t*3.0 + seed)*0.25 + anim*0.15
    อนุภาคทรงกลม(mx, by, mz, 2.6*aura, floor(8+anim*3), t*2.0+seed, 150, 24, 44)              # แกนเลือด
    อนุภาคทรงกลม(mx, by, mz, 3.2, 6, t*7.0+seed, 55, 145, 190)                                 # ประกายไซแอน (ดิจิทัล)
    อนุภาคทรงกลม(mx + ไซน์(spin2)*2.0, by + โคไซน์(spin2)*1.5, mz + โคไซน์(spin2)*2.0, 2.4, 6, t*4.0+seed, floor(fr*0.6), floor(fg*0.4), floor(fb*0.7))   # เงาซ้อน (after-image)
    flush_3d()
    โหมดผสม(0)

    # ── แกนผลึกมืด (เพชรสูง) — แวมไพร์: มืด ขอบเรือง; สัดส่วนต่างตามสายพันธุ์ ──
    bind pulse = 1.0 + ไซน์(t*4.0 + seed)*0.08 + hit*0.3
    bind coreR = 3.0 * pulse;  ถ้า shape == 3.0 { bind coreR = 3.6 * pulse }
    bind coreH = coreR*2.1;  ถ้า shape == 2.0 { bind coreH = coreR*2.7 }
    set_flat_shade(0.0)
    set_material("emission", fr*65536.0 + fg*256.0 + fb)
    bind em = 0.24 + ไซน์(t*5.0 + seed)*0.08 + anim*0.04 + hit*0.22
    ถ้า em < 0.12 { bind em = 0.12 }
    ถ้า em > 0.58 { bind em = 0.58 }
    set_material("emission_strength", em)
    set_material("roughness", 0.42)
    set_material("specular", 0.38)
    สีดินสอ(floor(fr*0.35 + 20), floor(fg*0.18 + 8), floor(fb*0.32 + 18))
    วาดออคตา(mx, by, mz, coreR, coreH, coreR)
    # แกนใน (บัฟที่จะดรอป) เรือง
    โหมดผสม(1)
    bind bstat = floor(pgRand(seed+99.0, lvl) * 8.0)
    ไอคอนบัฟ(bstat, mx, by, mz-0.3, 1.4)
    flush_3d();  โหมดผสม(0)

    # ── สะเก็ดผลึกโคจรหลายแกน (5th-dim): เฟสเข้า-ออก + กางออกตอน attack ──
    bind splay = 0.0;  ถ้า anim > 2.5 { bind splay = 2.2 }                                     # attack → สะเก็ดพุ่งกาง
    bind shardN = 6.0;  bind sk = 0.0
    ขณะที่ sk < shardN {
        bind sa = (sk/shardN)*6.2832 + spin*1.6
        bind ring = sk*1.05 + spin2*0.5                                                        # เอียงวงต่อสะเก็ด (แกน 2)
        bind orbR = 4.6 + splay + ไซน์(t*2.0 + sk)*0.5
        bind pin = ไซน์(t*3.0 + sk*1.7)*0.5 + 0.5                                              # เฟสเข้า-ออก
        bind ss = 0.6 + pin*0.8;  bind br = 0.5 + pin*0.5
        สีดินสอ(floor(fr*br), floor(fg*br), floor(fb*br))
        วาดออคตา(mx + โคไซน์(sa)*orbR, by + ไซน์(sa)*orbR*ไซน์(ring), mz + ไซน์(sa)*orbR*โคไซน์(ring), ss, ss*1.7, ss)
        bind sk = sk + 1.0
    }

    # ── ปีกผลึกแวมไพร์: สะเก็ดสามเหลี่ยมสองข้าง กระพือช้า ──
    bind flap = ไซน์(t*2.4 + seed)*0.5 + 0.5                                                   # 0..1
    bind wyt = by - 2.0 - flap*2.0
    สีดินสอ(floor(fr*0.4 + 15), floor(fg*0.2 + 8), floor(fb*0.45 + 20))
    วาดสามเหลี่ยม3มิติ(mx+1.5, by, mz,  mx+5.5+splay, wyt, mz-1.0,  mx+6.5+splay, by+3.0, mz+0.5)   # ปีกขวา
    วาดสามเหลี่ยม3มิติ(mx+1.5, by, mz,  mx+6.5+splay, by+3.0, mz+0.5,  mx+4.0, by+4.5, mz)
    วาดสามเหลี่ยม3มิติ(mx-1.5, by, mz,  mx-5.5-splay, wyt, mz-1.0,  mx-6.5-splay, by+3.0, mz+0.5)   # ปีกซ้าย
    วาดสามเหลี่ยม3มิติ(mx-1.5, by, mz,  mx-6.5-splay, by+3.0, mz+0.5,  mx-4.0, by+4.5, mz)
    flush_3d()
    reset_material()

    # ── แถบเลือด เหนือหัว (กรอบ + แถบ) ──
    bind hy = by - 9.0
    bind hf = hpfrac;  ถ้า hf > 1.0 { bind hf = 1.0 }  ถ้า hf < 0.0 { bind hf = 0.0 }
    โหมดผสม(0)
    สีดินสอ(20, 6, 8)
    draw_quad_3d(mx-4.3,hy+0.15,mz, mx+4.3,hy+0.15,mz, mx+4.3,hy-0.95,mz, mx-4.3,hy-0.95,mz)
    flush_3d()
    bind hw = 8.0 * hf
    สีดินสอ(floor(235*(1.0-hf)+30), floor(60+180*hf), 70)                                     # เขียว(เต็ม) → แดง(ใกล้ตาย)
    draw_quad_3d(mx-4.0,hy,mz, mx-4.0+hw,hy,mz, mx-4.0+hw,hy-0.8,mz, mx-4.0,hy-0.8,mz)
    flush_3d()
}

# ── เสียงมอน: เสียง/คอลเอาต์เฉพาะตัว ตามสายพันธุ์ (sp 0-3) + สถานะ (anim) ──
#   anim: 0 idle (พึมพำเบา) · 1 walk · 2 scurry (จิ๊บ ๆ) · 3 attack (คำรามมืดดิจิทัล)
#   sp กำหนดวัสดุ/พิตช์ → 4 สายพันธุ์ฟังต่างกัน; ใช้ engine ใหม่ (โน้ตมอร์ฟ) + GM waves
ฟังก์ชัน เสียงมอน(sp, anim, x, y, z, vol) {
    bind hz = 84.0 + sp*52.0                         # พิตช์ฐานต่อสายพันธุ์
    bind mat = floor(sp)                              # วัสดุ 0-3 ต่อสายพันธุ์
    ถ้า anim > 2.5 {                                  # ── โจมตี: คำรามเปียก + กรี๊ดแตก ──
        # ซ้อนสามชั้น: ก้นคอต่ำ (เนื้อ) + ฟันเลื่อยกลาง (คำราม) + นอยส์แหลม (กรีดร้อง)
        โน้ตมอร์ฟ(x, y, z, 1.0, hz*0.55, vol*0.40, 0.42, 3.0, 1.0)
        เสียงเอฟเฟกต์(x, y, z, 1.0, hz*1.5, vol*0.30, 0.26, "saw")
        เสียงเอฟเฟกต์(x, y, z, 1.0, hz*3.0 + sp*40.0, vol*0.20, 0.12, "square")
        เสียงเอฟเฟกต์(x, y, z, 1.0, 2600.0 + sp*300.0, vol*0.13, 0.09, "noise")
        คืน 0
    }
    ถ้า anim < 0.5 {                                  # ── idle: พึมพำเบาออร์แกนิก ──
        โน้ตมอร์ฟ(x, y, z, 1.0, hz, vol*0.10, 0.7, mat, 0.22)
        คืน 0
    }
    # ── walk/scurry: จิ๊บสกิตเตอร์ (มืดขึ้นตามความเร็ว) ──
    bind mor = 0.45 + anim*0.18;  ถ้า mor > 1.0 { bind mor = 1.0 }
    โน้ตมอร์ฟ(x, y, z, 1.0, hz*2.0, vol*0.15, 0.16, 1.0, mor)
    เสียงเอฟเฟกต์(x, y, z, 1.0, hz*4.0, vol*0.08, 0.05, "triangle")
    คืน 0
}

# ── โดนตี: ครางเจ็บ — พิตช์ตกจากเสียงร้องลงไปหาก้นคอ + เศษคริสตัลแตก ─────────
# ความแรง (0..1) = ต่างกันตามอาวุธ ดาบ/ธนู/ระเบิด (main ส่งเข้ามา)
ฟังก์ชัน เสียงมอนเจ็บ(sp, x, y, z, vol, แรง) {
    bind hz = 84.0 + sp*52.0
    โน้ตมอร์ฟ(x, y, z, 1.0, hz*1.25, vol*(0.26 + แรง*0.24), 0.20 + แรง*0.16, 3.0, 1.0)
    เสียงเอฟเฟกต์(x, y, z, 1.0, hz*2.1, vol*(0.16 + แรง*0.18), 0.13, "saw")
    เสียงเอฟเฟกต์(x, y, z, 1.0, 3200.0, vol*(0.10 + แรง*0.14), 0.06, "noise")   # คริสตัลบิ่น
    คืน 0
}

# ── ตาย: กรี๊ดยาวจมลงต่ำ + คริสตัลระเบิด + หางลมหายใจ ──────────────────────
ฟังก์ชัน เสียงมอนตาย(sp, x, y, z, vol) {
    bind hz = 84.0 + sp*52.0
    เสียงเอฟเฟกต์(x, y, z, 1.0, hz*2.6, vol*0.42, 0.55, "saw")      # กรี๊ด
    โน้ตมอร์ฟ(x, y, z, 1.0, hz*0.5, vol*0.46, 0.85, 3.0, 1.0)       # จมลงก้นคอ
    เสียงเอฟเฟกต์(x, y, z, 1.0, 180.0, vol*0.34, 0.42, "square")    # เนื้อคริสตัลยุบ
    เสียงเอฟเฟกต์(x, y, z, 1.0, 4200.0, vol*0.24, 0.30, "noise")    # สะเก็ดแตกกระจาย
    คืน 0
}

← Back to index