First thing I noticed when I assembled your game is that it's 3814 bytes. That means that it won't quite fit in the low 4kb of RAM. (remember: the first 512 bytes are reserved, and CHIP-8 programs always begin assembling at 0x200.) If you pop a compile-time assertion like the following:
:assert "overflowed code RAM" { HERE < 4096 }
Somwhere in your "game over" routine, you'll see that the assertion fails, which confirms the theory.
Instructions like "jump" (which is emitted as part of an "if...begin" or a "loop...again") take a 12-bit address, so they can only point somewhere in the low 4kb of memory. We need to make your program shorter, or at least ensure that the code fits in a smaller space. Fortunately, I see some easy opportunities to make this happen!
The simplest option might be to move some or all of your graphics data to the end of the program. This may require you to use "i := long NNNN" instead of "i := NNN" in some cases, since that data will now be located somewhere that needs a 16-bit address to access; Octo's assembler will complain when this is necessary.
Another option to explore is reworking that "text" macro. As written, it emits 3 CHIP-8 instructions (6 bytes) for every character printed. That adds up quickly! Even just special-casing spaces like this should save you a couple dozen bytes:
:stringmode text "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,!?/" {
:calc addr { font + VALUE * 4 }
i := addr
sprite vx vy 4
vx += 4
}
:stringmode text " " { vx += 4 }
Does that make sense?