
2026/04/06 7:32
**ボス戦概要(≤ 256 バイト)** - **名前:** *オブシディアン・ウォーデン* - **アリーナ:** クリスタルの洞窟、遠雷が響く。 - **フェーズ:** 1. **召喚フェーズ** – 幽霊ミニオンを呼び出す;レーザー光線は避ける。 2. **激怒フェーズ** – 攻撃速度上昇;渦巻くバリアを回避。 3. **最終打撃** – テレポートし、巨大な衝撃波を放つ―ブロックのタイミングを合わせる。 - **主な弱点:** シールドは120 HP 分吸収後に停止。 - **勝利条件:** HP をゼロに減らすと同時に、最低 30 % の体力を保持すること。 *ヒント:* 洞窟の鍾乳石を盾に使うと、ヒットした際にボスのエネルギーが一部反射される。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Endbotは256バイトのDOSイントロデモで、DosBox‑X上で動作します。リアルタイムにロボットスプライトを描画し、弾が次第にダメージを受ける様子や拡大する爆発、スクロールするチェッカーボード風景を表示しつつ、MIDIサウンドトラックを再生します。これらはすべて1つの .com ファイルから実行されます。プログラムはFASMで一括コンパイルされ、MIDIデータをポート 0x330へ書き込み、ディスプレイをVGAモード 13h(320×200ビットマップ)に切り替え(A000:0000)、PITタイマーへの書き込みと
hlt 命令の実行で約30FPSを同期させます。音はDosBox‑X の MPU‑401 エミュレーションに依存し、低レベル DOS インタラプト(int 10h、int 20h)と直接ポート I/O(0x60 からのキー入力)を使用します。また、 push/pop es、3で割るための乗算テクニック mul 0xCCCD、ビット操作 btc、ASCII 調整マクロ aam 9、パレットルックアップに xlat など、多彩なバイト節約トリックを採用しています。スプライトデータブロックには起動時に銃声楽器を初期化する MIDI プログラムチェンジ(0xC0 7F)も含まれています。チェッカーボード風景は透視補正スケーリングで描画され、爆発ロジックは拡大円公式(X²+Y² = 影響時間)を使用しています。ESC キーを押すと MIDI リセット(0xFF)が送信され、DOS にクリーンに制御が戻ります。Endbot はレトロデモの極端なサイズ最適化を示し、ミニマルフットプリントと低レベルハードウェア相互作用を重視する愛好家に有用な技術を提供します。本文
256‑byte DOS Intro – Endbot
by HellMood/Desire – Revision 2026
これは何ですか?
Endbot は、ちょうど 256 バイトに収まる完全なオーディオ―ビジュアルデモです。DOS(DosBox‑X 経由)上で実行され、リアルタイムで描画します:
- 段階的に弾薬ダメージが入るロボットスプライト
- 拡大する爆発
- スクロールするチェッカー風の景観
- MIDI サウンドトラック – すべて単一の小さな
ファイルから.com
ビルド方法
# FASM(Flat Assembler)が必要です fasm endbot.asm endbot.com
実行 – DosBox‑X の設定
イントロは MIDI ポート
0x330 に書き込みます。MPU‑401 を正しくエミュレートするため、DosBox‑X(単なる DOSBox ではなく)を使用してください。
dosbox-x.conf
[dosbox] machine=vgaonly memsize=4 [cpu] cputype=386 cycles=auto [midi] mpu401=uart mididevice=fluidsynth ; Windows なら win32、Linux/macOS なら fluidsynth fluid.soundfont= ; GM .sf2 のパス(例: /usr/share/sounds/sf2/FluidR3_GM.sf2) [sblaster] sbtype=none [mixer] rate=44100
実行方法:
dosbox-x -conf dosbox-x.conf endbot.com
ESC を押すと終了します。
コードは終了時に MIDI リセット (
0xFF) を送信するので、音が残ることはありません。
コードの概要
1 – ファイルヘッダー&初期化
org 100h push 0xa000-20*4 ; VGA フレームバッファ(A000:0000)に若干オフセット pop es ; ES に設定 mov al,0x13 ; モード 13h – 320×200、256 色 int 0x10 mov cl,Nasenatmungsgeraeusch ; 音楽+スプライトブロックの長さ mov di,si ; 音楽ポインタをピクセルポインタに合わせる
initbp は初期 BP 値です;すべてのタイミングはこれに相対します。
2 – メインループ&フレーム毎処理
StartFrame: mov dx,0x330 ; MIDI ポート sub di,si ; ピクセルカウンタを進める jnz StartPixel ; フレームの終わりでない → ピクセル単位作業へ mov ax,bp sub al,initbp&0xFF ; 0 / 256 / 512 / 768 のときにヒット jnz NoSound rep outsb ; CX バイトを MIDI に送信(CX=4 が最初のビート) NoSound: mov al,1193182/256/30 ; PIT 周波数 / 高バイト / FPS out 40h,al ; タイマー設定 (~30 FPS) hlt ; 次の割り込みを待つ inc bp ; 次のタイムステップへ xor byte [si-Nasenatmungsgeraeusch+Colors+1-8],cl ; 怒りフリッカー in al,0x60 ; キーボードスキャンコード取得 sub al,2 ; ESC → 0xFF(キャリー設定) jc Quit ; ESC が押されたら終了
外側のループはピクセル単位で走ります。
di がゼロにラップするとフレーム毎ブロックが実行されます。
3 – ピクセル単位:X/Y デコード & 爆発判定
StartPixel: mov ax,0xcccd ; Rrrola テクニック → DL に X、DH に Y を近似取得 mul di mov ax,bp sub ax,(768+initbp) ; 爆発からの経過時間 mov cx,dx ; スプライト描画に x,y が DX と CX で必要 jc NoExplosion ; まだ爆発していない jz Flash ; 衝突直後 – 一度だけオレンジフラッシュ
0xCCCD × index → 高ワードが (X<<8)/320 + Y を近似。ax のテストで爆発の有無を判断します。
4 – 爆発円、フラッシュ & 終了
sub ch,al ; 衝突後にボットを下へ移動 xchg bx,ax ; 脱落時間を BL に格納 mov al,dh sub al,77 imul al ; Y*Y sub bl,ah mov al,dl add al,128 imul al ; X*X cmp bl,ah ; (time – R²) と比較 Flash: mov al,0x2a ; オレンジ値 jz PlotPixel ; 円周上にある場合 → オレンジで描画 jnl BackGround ; 内部なら背景へ溶け込む js NoExplosion Quit: out dx,al ; 0xFF(無音)または無音後の破棄バイトを送信 ret ; DOS 終了 (int 20h)
拡大円は
X² + Y² = time で定義されます。エッジ上のピクセルはオレンジ、内部は背景へフェードします。
5 – スプライト:登場・アニメーション・ダメージ
NoExplosion: mov ax,bp cmp ax,256+initbp ; 最初の 256 ステップではスプライトなし jl BackGround test al,32 ; ミラーフラグ jnz NoAniFlip not al NoAniFlip: and al,63 add al,148 add cl,al js BackGround sub ch,36+8 js BackGround DrawSprite: mov bx,Sprite ; スプライトデータアドレス mov ax,bp sub ax,(512+initbp) ; ダメージ時間? jc SkipDamage xor al,1010101b btc word [bx],ax SkipDamage: shrd ax,cx,18 ; スケール&ローカル X,Y を転送 test al,16 ; Y 軸ミラー? jz NoFlip not al NoFlip: and ax,00011110b*256 + 00011110b xchg cx,ax add bl,ch mov ax,[bx] shr ax,cl mov bl,Colors-1 and al,3 xlat ; パレット検索 (AL = [BX+AL]) jnz PlotPixel
ロボットスプライトは 16×16 のビットマスクで、各ピクセルに 2 ビット(合計 4 色)を使用します。
512 ステップ以降はランダムなビットが反転 (
btc) され、弾薬の穴が蓄積されます。
6 – 背景:空 & スクロールする地形
BackGround: mov al,0x4e+72 ; 青みがかった色 test dh,dh ; 地平線上か? jns PlotPixel sub dh,-(128+13) js PlotPixel mov ax,bp div dh ; 深度 = BP / Y xchg dx,ax add al,128 imul dl add dx,bp xchg dx,ax xor dh,al imul dh aam 9 add al,212 PlotPixel: stosb ; ピクセルを書き込み ES:[DI] に mov cx,4 ; 次フレームロジック用に CX を復元 jmp StartFrame
dh が正のピクセルは空、地形は視点深度(BP/Y)とスクロールするチェッカー模様で描画されます。aam 9 は不規則な色帯を生成します。
7 – データ:スプライト、MIDI & カラーパレット
Sprite: dw 0000111101110000b ; ピクセルデータ (Steffest/Desire) ... dw 1111111111111100b MusicData: db 0xc9,56 ; ドラムチャンネル SFX db 0x99 ; ドラムで再生 db 70,0x58 ; ヘリコプター中程度 db 81,0x7F ; 最大風速 Colors: db 0x15,0x2C,0x13 ; 明るいグレー、黄色、暗いグレー MusicData2: db 0xc1,91,0x91,37,127 Burst: db 0xb3,0,9,0xc3 Nasenatmungsgeraeusch: db 125,0x93,40,127 Gunsound: db 0x99,70+3,90,0 ExplosionAndTheEnd: db 0xFF,0x90,34,127
スプライトビットマップと MIDI 音楽は連続したメモリブロックを共有します。
行 8 に
と 0xC0
が含まれており、これは有効な MIDI プログラムチェンジ(チャンネル 0、パッチ 127 = 銃声)です。0x7F
サイズ削減テクニック
| テクニック | バイト節約 |
|---|---|
vs. | 4 |
| BP をグローバルクロックとして使用 | なし |
による X/Y 推定(5 バイト)vs. 完全除算 | 3 |
でピクセルを書き込みつつ DI 自動インクリメント | 1 |
でフレーム同期 | 1 |
パレット検索 | 1 |
でスプライトビットを一命令で反転 | 1 |
モジュロ演算 | 2 |
| スプライトが MIDI 初期化データとしても機能 | 0 |
DOS 終了に を使用 | 1 |