Add industrial metal soundtrack with seamless loop
- assets/audio/music/zombie_industrial_loop.ogg: 57.60 s Ogg Vorbis loop generated locally with YuE2-3B on the Tesla V100 (score written for this track; vocals removed with HTDemucs). The loop is spliced at the track's structural repeat with a 0.6 s crossfade: measured seam dip <= 1.6 dB. - scripts/main.gd: "Music" AudioStreamPlayer at -11 dB, started at boot on desktop and on the start click on Web (browser autoplay policy). It forces stream.loop at runtime because the Web staging step re-imports the OGG with loop=false. - tools/test_music.gd: soundtrack test (loop, length, volume, playback, still playing after player death). - docs/MUSIC.md: source, loop construction, verification, licence. - docs/WEB-DEPLOY.md: release ab6054111f5919a8 notes. Initial commit of the project.
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
"""Extract local Half-Life assets; never alters the Steam installation."""
|
||||
import pathlib, struct
|
||||
from PIL import Image
|
||||
PROJECT = pathlib.Path(__file__).resolve().parents[1]
|
||||
SOURCE = pathlib.Path.home()/'.steam/steam/steamapps/common/Half-Life/valve'
|
||||
out = PROJECT/'assets/textures'
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
body = bytearray((SOURCE/'models/zombie.mdl').read_bytes())
|
||||
tex = bytearray((SOURCE/'models/zombiet.mdl').read_bytes())
|
||||
base = len(body)
|
||||
count, records, data, refs, families, skins = struct.unpack_from('<6i', tex, 180)
|
||||
for i in range(count):
|
||||
pos = records + i*80
|
||||
name, flags, w, h, pixel = struct.unpack_from('<64s4i', tex, pos)
|
||||
image = Image.frombytes('P', (w,h), bytes(tex[pixel:pixel+w*h]))
|
||||
image.putpalette(bytes(tex[pixel+w*h:pixel+w*h+768]))
|
||||
image.convert('RGB').save(out/('zombie_%02d.png'%i))
|
||||
struct.pack_into('<i', tex, pos+76, pixel+base)
|
||||
struct.pack_into('<6i', body, 180, count, records+base, data+base, refs, families, skins+base)
|
||||
body.extend(tex)
|
||||
struct.pack_into('<i', body, 72, len(body))
|
||||
(PROJECT/'assets/zombies/zombie_textured.mdl').write_bytes(body)
|
||||
wad = (SOURCE/'halflife.wad').read_bytes()
|
||||
n, directory = struct.unpack_from('<ii',wad,4)
|
||||
wanted = {'LAB1_W3':'wall.png','C1A0_LABFLR':'floor.png','C1A0_C1':'ceiling.png'}
|
||||
found = set()
|
||||
for i in range(n):
|
||||
offset, _, _, typ, compression, _, _, raw = struct.unpack_from('<iiiBBBB16s',wad,directory+32*i)
|
||||
name = raw.split(b'\0')[0].decode().upper()
|
||||
if name not in wanted or compression:
|
||||
continue
|
||||
_, w,h, a,b,c,d = struct.unpack_from('<16s6I',wad,offset)
|
||||
palette_offset = offset+d+(w//8)*(h//8)+2
|
||||
image = Image.frombytes('P',(w,h),wad[offset+a:offset+a+w*h])
|
||||
image.putpalette(wad[palette_offset:palette_offset+768])
|
||||
image.convert('RGB').save(out/wanted[name])
|
||||
found.add(name)
|
||||
print(name,w,h)
|
||||
assert found == set(wanted), ('Missing WAD textures',set(wanted)-found)
|
||||
print('Zombie textures:',count)
|
||||
Reference in New Issue
Block a user