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/online_world.ling
# online_world.ling — โลก "ออนไลน์" : ผังกระเบื้อง 16×16 ที่ "งอก" ตามเวลาจริง (datetime)
# เวลาโลก() = วินาที epoch → กำหนดการกำเนิดแบบคงเส้น แต่ค่อย ๆ วิวัฒน์:
# ต้นไม้ งอก→โต→แก่→ผุ→กลายเป็นพื้น เป็นวัฏจักรช้า ๆ; ดวงอาทิตย์/จันทร์ ปั๊มพลังงาน
# เร่ง/หน่วงการเติบโต-ผุพัง; ดาว = ตำแหน่งผู้เล่นบนแผนที่. ลุคทริปปี้ สโลว์โมชัน.
#
# STATE THREADING: ฟังก์ชัน calls in this language see module `bind` globals as
# a read-only snapshot taken at load time — any reassignment inside a function
# body is local to that call and discarded on return (no shared mutable
# globals across a function-call boundary). So every value that must survive
# from one frame to the next travels as an explicit "state bundle" list,
# passed in and returned out by วาดโลกออนไลน์ every frame, and the caller
# (main.ling) is the one holding the persistent `bind`. Index layout below.
bind OW_X = 0
bind OW_Y = 1
bind OW_Z = 2
bind OW_VX = 3
bind OW_VY = 4
bind OW_VZ = 5
bind OW_YAW = 6
bind OW_ROLL = 7
bind OW_LASTT = 8
bind OW_SYNCT = 9
bind OW_RIDS = 10
bind OW_RX = 11
bind OW_RY = 12
bind OW_RZ = 13
bind OW_RYAW = 14
bind OW_RNAME = 15
bind OW_TILE = 40.0
bind OW_WALK = 10.0
bind OW_MAXP = 24.0
# แฮชคงที่ต่อช่อง (ใช้แค่ param + builtin → ทำงานได้ทุกที่ ไม่พึ่ง global)
ฟังก์ชัน สุ่มโลก(a, b) {
bind s = ไซน์(a*12.9898 + b*78.233) * 43758.5453
คืน s - ปัดลง(s)
}
ฟังก์ชัน รีเซ็ตโลกออนไลน์() {
คืน [
OW_TILE * 0.5, 0.0 - 2.1, OW_TILE * 0.5,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
list_new(), list_new(), list_new(), list_new(), list_new(), list_new()
]
}
ฟังก์ชัน owMod(a, m) { คืน a - ปัดลง(a / m) * m }
# ── remote player table: fixed-capacity parallel arrays, id == -1 means empty ──
# `rt` is [ids, x, y, z, yaw, name] — the six OW_R* slices of the state bundle.
ฟังก์ชัน owRemoteEnsureInit(rt) {
bind ids = list_get(rt, 0)
ถ้า ความยาว(ids) >= OW_MAXP { คืน rt }
bind xs = list_get(rt, 1); bind ys = list_get(rt, 2); bind zs = list_get(rt, 3)
bind yaws = list_get(rt, 4); bind names = list_get(rt, 5)
bind i = 0.0
ขณะที่ i < OW_MAXP {
bind ids = list_push(ids, 0.0 - 1.0)
bind xs = list_push(xs, 0.0)
bind ys = list_push(ys, 0.0)
bind zs = list_push(zs, 0.0)
bind yaws = list_push(yaws, 0.0)
bind names = list_push(names, "")
bind i = i + 1.0
}
คืน [ids, xs, ys, zs, yaws, names]
}
ฟังก์ชัน owRemoteUpsert(rt, id, x, y, z, yaw, name) {
bind rt = owRemoteEnsureInit(rt)
bind ids = list_get(rt, 0); bind xs = list_get(rt, 1); bind ys = list_get(rt, 2)
bind zs = list_get(rt, 3); bind yaws = list_get(rt, 4); bind names = list_get(rt, 5)
bind slot = 0.0 - 1.0
bind i = 0.0
ขณะที่ i < OW_MAXP { ถ้า list_get(ids, i) == id { bind slot = i }; bind i = i + 1.0 }
ถ้า slot < 0.0 {
bind i = 0.0
ขณะที่ i < OW_MAXP { ถ้า slot < 0.0 { ถ้า list_get(ids, i) < 0.0 { bind slot = i } }; bind i = i + 1.0 }
}
ถ้า slot >= 0.0 {
bind ids = list_set(ids, slot, id)
bind xs = list_set(xs, slot, x)
bind ys = list_set(ys, slot, y)
bind zs = list_set(zs, slot, z)
bind yaws = list_set(yaws, slot, yaw)
bind names = list_set(names, slot, name)
}
คืน [ids, xs, ys, zs, yaws, names]
}
ฟังก์ชัน owRemoteRemove(rt, id) {
bind rt = owRemoteEnsureInit(rt)
bind ids = list_get(rt, 0)
bind i = 0.0
ขณะที่ i < OW_MAXP { ถ้า list_get(ids, i) == id { bind ids = list_set(ids, i, 0.0 - 1.0) }; bind i = i + 1.0 }
คืน [ids, list_get(rt,1), list_get(rt,2), list_get(rt,3), list_get(rt,4), list_get(rt,5)]
}
# Encode the whole live table as "id,x,y,z,yaw,name;id,x,y,z,yaw,name;..." for broadcast.
ฟังก์ชัน owEncodeSnapshot(rt, selfX, selfY, selfZ, selfYaw, selfName) {
bind ids = list_get(rt, 0); bind xs = list_get(rt, 1); bind ys = list_get(rt, 2)
bind zs = list_get(rt, 3); bind yaws = list_get(rt, 4); bind names = list_get(rt, 5)
bind out = "0," + to_str(selfX) + "," + to_str(selfY) + "," + to_str(selfZ) + "," + to_str(selfYaw) + "," + selfName
bind i = 0.0
ขณะที่ i < ความยาว(ids) {
ถ้า list_get(ids, i) >= 0.0 {
bind out = out + ";" + to_str(list_get(ids, i)) + "," + to_str(list_get(xs, i)) + "," + to_str(list_get(ys, i)) + "," + to_str(list_get(zs, i)) + "," + to_str(list_get(yaws, i)) + "," + list_get(names, i)
}
bind i = i + 1.0
}
คืน out
}
# Host: drain every queued client message this frame, update the live table,
# and retire anyone the transport just reported as disconnected.
ฟังก์ชัน owHostPumpNetwork(rt) {
bind rt = owRemoteEnsureInit(rt)
bind msg = เน็ตรับจาก()
bind guard = 0
ขณะที่ msg != "" { ถ้า guard < 64 {
bind pipe = แยก(msg, "|")
ถ้า ความยาว(pipe) >= 2 {
bind senderId = list_get(pipe, 0) * 1.0
bind fields = แยก(list_get(pipe, 1), ",")
ถ้า ความยาว(fields) >= 5 {
bind px = list_get(fields, 0) * 1.0
bind py = list_get(fields, 1) * 1.0
bind pz = list_get(fields, 2) * 1.0
bind pyaw = list_get(fields, 3) * 1.0
bind pname = list_get(fields, 4)
bind rt = owRemoteUpsert(rt, senderId, px, py, pz, pyaw, pname)
}
}
bind guard = guard + 1
bind msg = เน็ตรับจาก()
} มิฉะนั้น { bind msg = "" } }
bind evLines = แยก(เน็ตเหตุการณ์(), "\n")
bind ei = 0
ขณะที่ ei < ความยาว(evLines) {
bind el = list_get(evLines, ei)
ถ้า starts_with(el, "disconnect:") { bind rt = owRemoteRemove(rt, ส่วนสตริง(el, 11, ความยาว(el) - 11) * 1.0) }
bind ei = ei + 1
}
คืน rt
}
# Joiner: the host's broadcast snapshot replaces the whole table every frame,
# so there is nothing to age out — a dropped host just stops updating it.
# `selfName` excludes our own entry (the host echoes it back as one of the peers).
ฟังก์ชัน owClientPumpNetwork(rt, selfName) {
bind rt = owRemoteEnsureInit(rt)
bind latest = ""
bind msg = เน็ตรับ()
bind guard = 0
ขณะที่ msg != "" { ถ้า guard < 64 { bind latest = msg; bind guard = guard + 1; bind msg = เน็ตรับ() } มิฉะนั้น { bind msg = "" } }
ถ้า latest == "" { คืน rt }
bind ids = list_get(rt, 0)
bind i = 0.0
ขณะที่ i < ความยาว(ids) { bind ids = list_set(ids, i, 0.0 - 1.0); bind i = i + 1.0 }
bind rt = [ids, list_get(rt,1), list_get(rt,2), list_get(rt,3), list_get(rt,4), list_get(rt,5)]
bind entries = แยก(latest, ";")
bind ei = 0
ขณะที่ ei < ความยาว(entries) {
bind fields = แยก(list_get(entries, ei), ",")
ถ้า ความยาว(fields) >= 6 {
bind ename = list_get(fields, 5)
ถ้า ename != selfName {
bind rt = owRemoteUpsert(rt, list_get(fields,0)*1.0, list_get(fields,1)*1.0, list_get(fields,2)*1.0, list_get(fields,3)*1.0, list_get(fields,4)*1.0, ename)
}
}
bind ei = ei + 1
}
คืน rt
}
ฟังก์ชัน owHex(ch) {
ถ้า ch == "0" { คืน 0.0 }; ถ้า ch == "1" { คืน 1.0 }; ถ้า ch == "2" { คืน 2.0 }; ถ้า ch == "3" { คืน 3.0 }
ถ้า ch == "4" { คืน 4.0 }; ถ้า ch == "5" { คืน 5.0 }; ถ้า ch == "6" { คืน 6.0 }; ถ้า ch == "7" { คืน 7.0 }
ถ้า ch == "8" { คืน 8.0 }; ถ้า ch == "9" { คืน 9.0 }
ถ้า ch == "a" { คืน 10.0 }; ถ้า ch == "b" { คืน 11.0 }; ถ้า ch == "c" { คืน 12.0 }; ถ้า ch == "d" { คืน 13.0 }; ถ้า ch == "e" { คืน 14.0 }; ถ้า ch == "f" { คืน 15.0 }
ถ้า ch == "A" { คืน 10.0 }; ถ้า ch == "B" { คืน 11.0 }; ถ้า ch == "C" { คืน 12.0 }; ถ้า ch == "D" { คืน 13.0 }; ถ้า ch == "E" { คืน 14.0 }; ถ้า ch == "F" { คืน 15.0 }
คืน 0.0
}
ฟังก์ชัน owSeedFromHash(h) {
bind n = ความยาว(h); ถ้า n > 14 { bind n = 14 }
bind i = 0; bind seed = 0.0
ขณะที่ i < n {
bind seed = seed * 16.0 + owHex(ส่วนสตริง(h, i, 1))
ถ้า seed > 1000000.0 { bind seed = seed - ปัดลง(seed / 1000000.0) * 1000000.0 }
bind i = i + 1
}
คืน seed
}
ฟังก์ชัน owTileNoise(seed, ix, iz) { คืน สุ่มโลก(ix*1.731 + seed*0.013, iz*2.193 + seed*0.017) }
ฟังก์ชัน owRoad(ix, iz, seed) {
bind mx = owMod(ix + ปัดลง(seed / 11.0), 5.0)
bind mz = owMod(iz + ปัดลง(seed / 17.0), 5.0)
bind road = 0.0
ถ้า mx == 0.0 { bind road = 1.0 }
ถ้า mz == 0.0 { bind road = 1.0 }
ถ้า owMod(ix + iz + ปัดลง(seed / 23.0), 17.0) == 0.0 { bind road = 1.0 }
คืน road
}
ฟังก์ชัน owOpenTile(ix, iz, seed) {
ถ้า ix == 0.0 { ถ้า iz == 0.0 { คืน 1.0 } }
ถ้า ix > 0.0 - 3.0 { ถ้า ix < 3.0 { ถ้า iz > 0.0 - 3.0 { ถ้า iz < 3.0 { คืน 1.0 } } } }
ถ้า owRoad(ix, iz, seed) > 0.5 { คืน 1.0 }
ถ้า owTileNoise(seed + 77.0, ix, iz) > 0.84 { คืน 1.0 }
คืน 0.0
}
ฟังก์ชัน owBlockedAt(x, z, seed) {
bind ix = ปัดลง(x / OW_TILE)
bind iz = ปัดลง(z / OW_TILE)
ถ้า owOpenTile(ix, iz, seed) > 0.5 { คืน 0.0 }
bind lx = x - ix * OW_TILE
bind lz = z - iz * OW_TILE
ถ้า lx > OW_WALK { ถ้า lx < OW_TILE - OW_WALK { ถ้า lz > OW_WALK { ถ้า lz < OW_TILE - OW_WALK { คืน 1.0 } } } }
คืน 0.0
}
ฟังก์ชัน owGround(x, z, seed) { คืน 0.0 }
ฟังก์ชัน วาดตึกเมือง(x0, z0, x1, z1, baseY, h, r, g, b) {
bind topY = baseY - h
สีดินสอ(floor(r*1.18), floor(g*1.18), floor(b*1.18))
draw_quad_3d(x0,topY,z0, x1,topY,z0, x1,topY,z1, x0,topY,z1)
สีดินสอ(r, g, b)
draw_quad_3d(x0,baseY,z0, x1,baseY,z0, x1,topY,z0, x0,topY,z0)
draw_quad_3d(x1,baseY,z0, x1,baseY,z1, x1,topY,z1, x1,topY,z0)
สีดินสอ(floor(r*0.72), floor(g*0.72), floor(b*0.78))
draw_quad_3d(x1,baseY,z1, x0,baseY,z1, x0,topY,z1, x1,topY,z1)
draw_quad_3d(x0,baseY,z1, x0,baseY,z0, x0,topY,z0, x0,topY,z1)
}
# ต้นไม้ตามช่วงชีวิต ph (0..1): เกิด→โต→แก่→ผุ; สี เขียว→ทอง→น้ำตาล (ทริปปี้)
ฟังก์ชัน วาดต้นไม้(x, gy, z, ph, t) {
bind gr = ไซน์(ph * 3.14159) # 0 ตอนเกิด/ตาย, 1 กลางชีวิต
ถ้า gr < 0.05 { คืน 0 }
bind h = 0.7 + gr*3.4
bind fol = 0.35 + gr*1.9
โหมดผสม(0)
สีดินสอ(floor(95.0 - ph*35.0), floor(58.0 - ph*22.0), 32) # ลำต้น (แก่=เข้ม)
icosahedron(x, gy - h*0.5, z, 0.26, h*0.5, 0.26, 0.0, t*0.2, 0.0, 2, 0, 0, 0)
bind fr = floor(55.0 + ph*170.0)
bind fg = floor(210.0 - ph*150.0)
bind fb = floor(70.0 + (ไซน์(ph*6.283 + t*0.6)*0.5+0.5)*70.0) # เรืองสีทริปปี้
ถ้า ph > 0.78 { bind fg = floor(110.0 - (ph-0.78)*320.0) } # ผุ = น้ำตาลลง
สีดินสอ(fr, fg, fb)
icosahedron(x, gy - h, z, fol, fol*1.25, fol, 0.3, t*0.4 + x*0.2, 0.0, 2, 0, 0, 0)
คืน 0
}
# วาดโลกออนไลน์: playable procedural city shard (เรียกทุกเฟรมในสถานะ ST_ONLINE).
# `state` = the OW_* bundle above; returns the updated bundle for the caller
# to hold onto and pass back in next frame (see the state-threading note up top).
ฟังก์ชัน วาดโลกออนไลน์(t, playerName, netState, isHost, state) {
bind owX = list_get(state, OW_X); bind owY = list_get(state, OW_Y); bind owZ = list_get(state, OW_Z)
bind owVX = list_get(state, OW_VX); bind owVY = list_get(state, OW_VY); bind owVZ = list_get(state, OW_VZ)
bind owCamYaw = list_get(state, OW_YAW); bind owRoll = list_get(state, OW_ROLL)
bind owLastT = list_get(state, OW_LASTT); bind owSyncT = list_get(state, OW_SYNCT)
bind rt = [list_get(state,OW_RIDS), list_get(state,OW_RX), list_get(state,OW_RY), list_get(state,OW_RZ), list_get(state,OW_RYAW), list_get(state,OW_RNAME)]
bind ET = เวลาโลก() # วินาที epoch (datetime จริง)
bind WT = ET * 0.02 # เวลาโลกช้า ๆ (สโลว์โมชัน)
bind dayBucket = ปัดลง(ET / 86400.0)
bind owShardHash = แฮชเข้ารหัส("city:" + playerName + ":" + to_str(dayBucket))
bind owSeed = owSeedFromHash(owShardHash)
bind dt = t - owLastT; ถ้า dt < 0.001 { bind dt = 0.016 }; ถ้า dt > 0.05 { bind dt = 0.05 }; bind owLastT = t
bind step = dt * 60.0
# ── ดวงอาทิตย์/จันทร์: โคจรแนวตั้ง (กลางวัน/คืน) → พลังงานเร่ง/หน่วง ──
bind dayAng = WT * 0.10
bind sunE = ไซน์(dayAng) # >0 กลางวัน, <0 กลางคืน
bind sunX = โคไซน์(dayAng)*58.0; bind sunY = 0.0 - ไซน์(dayAng)*46.0; bind sunZ = 0.0 - 18.0
bind moonX = 0.0 - sunX; bind moonY = 0.0 - sunY; bind moonZ = sunZ
bind energy = sunE*0.5 + 0.5 # 0..1 พลังเติบโต (ขยาย/หด)
# ── ท้องฟ้า: ไล่สีกลางวัน↔คืน + ทริปปี้ ──
bind skR = floor(6.0 + energy*46.0 + (ไซน์(t*0.13)*0.5+0.5)*14.0)
bind skG = floor(8.0 + energy*38.0 + (ไซน์(t*0.11+2.0)*0.5+0.5)*16.0)
bind skB = floor(20.0 + energy*30.0 + (ไซน์(t*0.09+4.0)*0.5+0.5)*26.0)
เติม(skR, skG, skB)
ตั้งหมอก(skR, skG, skB, 180.0, 760.0) # หมอกฟ้ากลืนขอบ (ลึกขึ้น)
bind fx = ไซน์(owCamYaw); bind fz = โคไซน์(owCamYaw)
bind rgx = fz; bind rgz = 0.0 - fx
bind mvx = 0.0; bind mvz = 0.0
ถ้า กดค้าง("w") { bind mvx = mvx + fx; bind mvz = mvz + fz }
ถ้า กดค้าง("s") { bind mvx = mvx - fx; bind mvz = mvz - fz }
ถ้า กดค้าง("d") { bind mvx = mvx + rgx; bind mvz = mvz + rgz }
ถ้า กดค้าง("a") { bind mvx = mvx - rgx; bind mvz = mvz - rgz }
bind glx = จอยแกน("lx"); bind gly = จอยแกน("ly")
ถ้า glx*glx + gly*gly > 0.04 { bind mvx = mvx + fx*gly + rgx*glx; bind mvz = mvz + fz*gly + rgz*glx }
bind ml = รากที่สอง(mvx*mvx + mvz*mvz)
bind acc = 0.14 * step
ถ้า กดค้าง("lshift") { bind acc = 0.22 * step }
ถ้า กดค้าง("rshift") { bind acc = 0.22 * step }
ถ้า ml > 0.01 { bind owVX = owVX + (mvx/ml)*acc; bind owVZ = owVZ + (mvz/ml)*acc }
ถ้า กดค้าง("left") { bind owCamYaw = owCamYaw - 0.035*step }
ถ้า กดค้าง("right") { bind owCamYaw = owCamYaw + 0.035*step }
bind ballR = 2.1
bind groundY = owGround(owX, owZ, owSeed)
bind grounded = 0.0; ถ้า owY >= groundY - ballR - 0.05 { bind grounded = 1.0 }
ถ้า grounded > 0.5 { ถ้า กดปุ่ม("space") { bind owVY = 0.0 - 1.25 } }
bind owPrevX = owX; bind owPrevZ = owZ
bind owVY = owVY + 0.060*step
bind owVX = owVX * 0.93; bind owVZ = owVZ * 0.93; bind owVY = owVY * 0.998
bind owX = owX + owVX*step; bind owY = owY + owVY*step; bind owZ = owZ + owVZ*step
ถ้า owBlockedAt(owX, owZ, owSeed) > 0.5 {
bind sxTry = owX
bind szTry = owPrevZ
ถ้า owBlockedAt(sxTry, szTry, owSeed) < 0.5 {
bind owZ = owPrevZ
bind owVZ = owVZ * 0.25
}
มิฉะนั้น {
bind sxTry = owPrevX
bind szTry = owZ
ถ้า owBlockedAt(sxTry, szTry, owSeed) < 0.5 {
bind owX = owPrevX
bind owVX = owVX * 0.25
}
มิฉะนั้น {
bind owX = owPrevX; bind owZ = owPrevZ; bind owVX = 0.0 - owVX*0.18; bind owVZ = 0.0 - owVZ*0.18
}
}
}
bind groundY = owGround(owX, owZ, owSeed)
ถ้า owY > groundY - ballR { bind owY = groundY - ballR; ถ้า owVY > 0.0 { bind owVY = 0.0 } }
bind spd = รากที่สอง(owVX*owVX + owVZ*owVZ)
bind owRoll = owRoll + spd * step * 0.08
ถ้า spd > 0.08 {
bind targetYaw = atan2(owVX, owVZ)
bind dyaw = targetYaw - owCamYaw
ขณะที่ dyaw > 3.14159 { bind dyaw = dyaw - 6.28318 }
ขณะที่ dyaw < 0.0-3.14159 { bind dyaw = dyaw + 6.28318 }
bind owCamYaw = owCamYaw + dyaw*0.04
}
# ── network sync: ~20 Hz is plenty for LAN avatars, keeps bandwidth flat ──
bind owSyncT = owSyncT + dt
ถ้า netState >= 2.0 {
ถ้า isHost > 0.5 {
bind rt = owHostPumpNetwork(rt)
ถ้า owSyncT > 0.05 {
bind owSyncT = 0.0
เน็ตส่ง(owEncodeSnapshot(rt, owX, owY, owZ, owCamYaw, playerName))
}
} มิฉะนั้น {
bind rt = owClientPumpNetwork(rt, playerName)
ถ้า owSyncT > 0.05 {
bind owSyncT = 0.0
เน็ตส่ง(to_str(owX) + "," + to_str(owY) + "," + to_str(owZ) + "," + to_str(owCamYaw) + "," + playerName)
}
}
}
# ── กล้องติดตามลูก: เข้าเมืองได้จริง ไม่ใช่แค่มุม auto-tour ──
bind camX = owX - ไซน์(owCamYaw)*82.0
bind camZ = owZ - โคไซน์(owCamYaw)*82.0
ตั้งกล้องมอง(camX, owY - 54.0, camZ, owX, owY - 2.0, owZ)
ตั้งระยะห่าง(3.2)
ตั้งแสงรอบข้าง(0.45 + energy*0.4)
ล้างแสง()
เพิ่มแสง(sunX, sunY, sunZ, 1.0, 0.88, 0.62, 1.8, 680.0)
เพิ่มแสง(owX, owY - 8.0, owZ - 12.0, 0.5, 0.75, 1.0, 1.1, 150.0)
set_depth_test(1)
# ── ดาว (โดมฟ้า): จาง=ดาวพื้นหลัง ──
โหมดผสม(1)
bind sN = 0
ขณะที่ sN < 46 {
bind sa = สุ่มโลก(sN*1.3+0.7, 9.1)*6.283; bind sb = สุ่มโลก(sN*2.1+4.4, 3.3)
bind sx = โคไซน์(sa)*(40.0+sb*40.0); bind sz = ไซน์(sa)*(40.0+sb*40.0); bind sy = 0.0 - 36.0 - sb*14.0
bind tw = ไซน์(t*1.4 + sN)*0.5+0.5
สีดินสอ(floor(120+tw*120), floor(120+tw*120), floor(150+tw*100))
วาดเส้น3มิติ(sx, sy, sz, sx+0.3, sy, sz)
bind sN = sN + 1
}
โหมดผสม(0)
# ── Procedural city around the player: roads, plazas, buildings, living terrain ──
bind ci = ปัดลง(owX / OW_TILE); bind cj = ปัดลง(owZ / OW_TILE)
bind di = 0.0 - 6.0
ขณะที่ di <= 6.0 {
bind dj = 0.0 - 6.0
ขณะที่ dj <= 6.0 {
bind ix = ci + di; bind iz = cj + dj
bind x0 = ix*OW_TILE; bind z0 = iz*OW_TILE; bind x1 = x0+OW_TILE; bind z1 = z0+OW_TILE
bind baseY = 0.0
bind rn = owTileNoise(owSeed, ix, iz)
bind road = owRoad(ix, iz, owSeed)
bind plaza = 0.0; ถ้า rn > 0.84 { bind plaza = 1.0 }; ถ้า ix == 0.0 { ถ้า iz == 0.0 { bind plaza = 1.0; bind road = 0.0 } }
bind hue = owSeed*0.00017 + ix*0.07 + iz*0.11 + WT*0.004
ถ้า road > 0.5 {
สีดินสอ(floor(34 + (ไซน์(hue)*0.5+0.5)*22), floor(38 + energy*28), floor(52 + (ไซน์(hue+2.0)*0.5+0.5)*34))
draw_quad_3d(x0,baseY,z0, x1,baseY,z0, x1,baseY,z1, x0,baseY,z1)
สีดินสอ(120, 150, 190)
ถ้า owMod(ix + iz, 2.0) == 0.0 { วาดเส้น3มิติ(x0+OW_TILE*0.5, baseY-0.03, z0+OW_WALK*0.55, x0+OW_TILE*0.5, baseY-0.03, z1-OW_WALK*0.55) }
}
มิฉะนั้น { ถ้า plaza > 0.5 {
สีดินสอ(floor(38 + energy*70), floor(92 + energy*80), floor(78 + (ไซน์(hue)*0.5+0.5)*65))
draw_quad_3d(x0,baseY,z0, x1,baseY,z0, x1,baseY,z1, x0,baseY,z1)
bind life = WT*(0.035 + energy*0.06) + rn
วาดต้นไม้(x0+OW_TILE*0.5, baseY, z0+OW_TILE*0.5, life - ปัดลง(life), t)
}
มิฉะนั้น {
สีดินสอ(42, 45, 56)
draw_quad_3d(x0,baseY,z0, x1,baseY,z0, x1,baseY,z1, x0,baseY,z1)
bind bh = 14.0 + rn*78.0 + energy*16.0 + (ไซน์(WT*0.05 + ix)*0.5+0.5)*20.0
bind br = floor((ไซน์(hue)*0.5+0.5)*105+65)
bind bg = floor((ไซน์(hue+2.094)*0.5+0.5)*105+65)
bind bb = floor((ไซน์(hue+4.189)*0.5+0.5)*120+75)
วาดตึกเมือง(x0+OW_WALK, z0+OW_WALK, x1-OW_WALK, z1-OW_WALK, baseY, bh, br, bg, bb)
} }
bind dj = dj + 1.0
}
bind di = di + 1.0
}
flush_3d()
# ── Player ball in the shard ──
bind pc = สีจากเฉด((owSeed*0.00001 + t*0.025) - ปัดลง(owSeed*0.00001 + t*0.025))
วาดลูกแต่ง(owX, owY, owZ, ballR, list_get(pc,0), list_get(pc,1), list_get(pc,2), 220,235,255, 255,210,120, 1, 3, t+owRoll, 2.0)
flush_3d()
# ── other real players connected to this shard right now ──
bind rids = list_get(rt, 0); bind rxs = list_get(rt, 1); bind rys = list_get(rt, 2)
bind rzs = list_get(rt, 3); bind rnames = list_get(rt, 5)
bind ri = 0.0
ขณะที่ ri < ความยาว(rids) {
ถ้า list_get(rids, ri) >= 0.0 {
bind rid = list_get(rids, ri)
bind rx = list_get(rxs, ri); bind ry = list_get(rys, ri); bind rz = list_get(rzs, ri)
bind rname = list_get(rnames, ri)
bind rc = สีจากเฉด((owSeed*0.00001 + rid*0.137) - ปัดลง(owSeed*0.00001 + rid*0.137))
วาดลูกแต่ง(rx, ry, rz, ballR, list_get(rc,0), list_get(rc,1), list_get(rc,2), 200,220,255, 120,220,255, 1, 3, t + rid, 2.0)
สีดินสอ(200, 225, 255)
วาดสตริง(rname, rx, ry - ballR - 1.4, rz, 0.5, 1)
flush_3d()
}
bind ri = ri + 1.0
}
# ── ดวงอาทิตย์ + จันทร์ (เรืองแสง additive) ──
โหมดผสม(1)
สีดินสอ(255, floor(210 + ไซน์(t)*30.0), 90)
icosahedron(sunX, sunY, sunZ, 5.0, 5.0, 5.0, 0.0, t*0.3, 0.0, 2, 0, 0, 0)
อนุภาคทรงกลม(sunX, sunY, sunZ, 8.0, 40, t*2.0, 255, 220, 120)
สีดินสอ(170, 185, 230)
icosahedron(moonX, moonY, moonZ, 3.4, 3.4, 3.4, 0.0, t*0.2, 0.0, 2, 0, 0, 0)
อนุภาคทรงกลม(moonX, moonY, moonZ, 5.0, 22, t*1.4, 180, 200, 255)
flush_3d(); โหมดผสม(0)
set_depth_test(0)
# ── ป้าย ──
สีดินสอ(180, 210, 235); วาดสตริง("online city shard", 0.0, 0.0 - 9.2, 0.0, 0.72, 1)
สีดินสอ(140, 165, 200); วาดสตริง("crypto " + ส่วนสตริง(owShardHash, 0, 8) + " x " + to_str(ปัดลง(owX)) + " z " + to_str(ปัดลง(owZ)), 0.0, 0.0 - 8.1, 0.0, 0.42, 1)
สีดินสอ(120, 140, 175); วาดสตริง("wasd roll arrows camera space hop esc back", 0.0, 9.0, 0.0, 0.38, 1)
flush_3d()
คืน [
owX, owY, owZ, owVX, owVY, owVZ, owCamYaw, owRoll, owLastT, owSyncT,
list_get(rt,0), list_get(rt,1), list_get(rt,2), list_get(rt,3), list_get(rt,4), list_get(rt,5)
]
}