From 94fe41a745e002c3a7ee40973c6b8157b114a681 Mon Sep 17 00:00:00 2001 From: pkali Date: Thu, 18 Dec 2025 14:56:11 -0500 Subject: [PATCH] 5 bits workinggit status! --- Atari/textproc.asm | 78 ++++++++++++++ C64/textproc.asm | 78 ++++++++++++++ artwork/pack_talk5.py | 224 ++++++++++++++++++++++++++++++++++++++++ artwork/talk.asm | 8 +- artwork/talk_packed.asm | 174 +++++++++++++++++++++++++++++++ grafproc.asm | 146 +++++++++++++++++++++++--- scorch.asm | 2 +- scorch5bit.xex | Bin 0 -> 32375 bytes scorchC64.asm | 2 +- weapons.asm | 18 ++-- 10 files changed, 701 insertions(+), 29 deletions(-) create mode 100644 artwork/pack_talk5.py create mode 100644 artwork/talk_packed.asm create mode 100644 scorch5bit.xex diff --git a/Atari/textproc.asm b/Atari/textproc.asm index ab9fea8..dbf074d 100644 --- a/Atari/textproc.asm +++ b/Atari/textproc.asm @@ -2157,5 +2157,83 @@ zeroth_talk ldy #0 rts .endp + +;------------------------------------------------- +.proc _calc_packed_display +; Find Nth packed string inside a [len][packed-bytes] stream. +; +; in: +; TextNumberOff = index (0..) +; LineAddress4x4 = base address of the packed stream (points to first len byte) +; out: +; LineAddress4x4 = address of selected record (points to its len byte) +; trashes: A, X, Y, temp, temp2 +; +; Record size in bytes = 1 + ceil(len*5/8) +; where `len` is the 1-byte character count (max 63). +;------------------------------------------------- +@idx = temp+1 + lda TextNumberOff + sta @idx + beq done + +next_record + ldy #0 + lda (LineAddress4x4),y + sta temp ; len (low byte) + + ; advance past len byte + inw LineAddress4x4 + + ; temp2 = len*5 + 7 + lda temp + sta temp2 + lda #0 + sta temp2+1 + + ; temp2 = len*4 + asl temp2 + rol temp2+1 + asl temp2 + rol temp2+1 + ; temp2 = len*5 + clc + lda temp2 + adc temp + sta temp2 + lda temp2+1 + adc #0 + sta temp2+1 + ; +7 for ceil + clc + lda temp2 + adc #7 + sta temp2 + bcc @+ + inc temp2+1 +@ + ; >>3 (divide by 8) + lsr temp2+1 + ror temp2 + lsr temp2+1 + ror temp2 + lsr temp2+1 + ror temp2 + + ; LineAddress4x4 += temp2 + clc + lda LineAddress4x4 + adc temp2 + sta LineAddress4x4 + lda LineAddress4x4+1 + adc temp2+1 + sta LineAddress4x4+1 + + dec @idx + bne next_record + +done + rts +.endp .endif \ No newline at end of file diff --git a/C64/textproc.asm b/C64/textproc.asm index 7621f96..2942b04 100644 --- a/C64/textproc.asm +++ b/C64/textproc.asm @@ -376,6 +376,84 @@ DisplayAngle zeroth_talk rts .endp + +;------------------------------------------------- +.proc _calc_packed_display +; Find Nth packed string inside a [len][packed-bytes] stream. +; +; in: +; TextNumberOff = index (0..) +; LineAddress4x4 = base address of the packed stream (points to first len byte) +; out: +; LineAddress4x4 = address of selected record (points to its len byte) +; trashes: A, X, Y, temp, temp2 +; +; Record size in bytes = 1 + ceil(len*5/8) +; where `len` is the 1-byte character count (max 63). +;------------------------------------------------- +@idx = temp+1 + lda TextNumberOff + sta @idx + beq done + +next_record + ldy #0 + lda (LineAddress4x4),y + sta temp ; len (low byte) + + ; advance past len byte + inw LineAddress4x4 + + ; temp2 = len*5 + 7 + lda temp + sta temp2 + lda #0 + sta temp2+1 + + ; temp2 = len*4 + asl temp2 + rol temp2+1 + asl temp2 + rol temp2+1 + ; temp2 = len*5 + clc + lda temp2 + adc temp + sta temp2 + lda temp2+1 + adc #0 + sta temp2+1 + ; +7 for ceil + clc + lda temp2 + adc #7 + sta temp2 + bcc @+ + inc temp2+1 +@ + ; >>3 (divide by 8) + lsr temp2+1 + ror temp2 + lsr temp2+1 + ror temp2 + lsr temp2+1 + ror temp2 + + ; LineAddress4x4 += temp2 + clc + lda LineAddress4x4 + adc temp2 + sta LineAddress4x4 + lda LineAddress4x4+1 + adc temp2+1 + sta LineAddress4x4+1 + + dec @idx + bne next_record + +done + rts +.endp ;------------------------------------------------- diff --git a/artwork/pack_talk5.py b/artwork/pack_talk5.py new file mode 100644 index 0000000..ef2c115 --- /dev/null +++ b/artwork/pack_talk5.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 +"""Pack Scorch talk texts into 5-bit stream. + +Reads artwork/talk.asm and generates artwork/talk_packed.asm. + +Design goals: +- Keep the original artwork/talk.asm as editable source of strings. +- Generate a MADS-friendly .asm include with: + - .proc talk (namespace-compatible) + - talk5_alphabet (32 chars) + - talk5_data: records of [len][packed bytes...] + - constants (NumberOfOffensiveTexts, etc.) copied verbatim + - hoverFull/hoverEmpty blocks copied verbatim (uncompressed) + +Bit packing: +- 5-bit codes are packed LSB-first. +- For each string record: + - 1 byte length (0..63) + - packed bytes little-endian (first char in bits 0..4) + +The decoder in 6502 should read 5-bit codes from the low bits. +""" + +from __future__ import annotations + +import argparse +import re +from pathlib import Path +from typing import Iterable, List, Tuple + + +# 32-symbol alphabet. +# Note: We intentionally omit 'X' to make room for punctuation. +# Order must match the decoder table. +ALPHABET = " ABCDEFGHIJKLMNOPQRSTUVWYZ'!,-.?" # length must be 32 + + +_DTA_STR_RE = re.compile(r"^\s*dta\s+d\"(.*?)\"\^\s*(?:;.*)?$") + + +def _iter_lines(path: Path) -> List[str]: + return path.read_text(encoding="utf-8", errors="replace").splitlines() + + +def _find_section(lines: List[str], start_pat: re.Pattern[str], end_pat: re.Pattern[str]) -> Tuple[int, int]: + start_idx = None + for i, line in enumerate(lines): + if start_pat.search(line): + start_idx = i + break + if start_idx is None: + raise ValueError(f"Start pattern not found: {start_pat.pattern}") + + for j in range(start_idx + 1, len(lines)): + if end_pat.search(lines[j]): + return start_idx, j + raise ValueError(f"End pattern not found: {end_pat.pattern}") + + +def extract_talk_strings(lines: List[str]) -> List[str]: + # Only pack strings inside `.proc talk` up to the `LEND` marker. + proc_start, _ = _find_section(lines, re.compile(r"^\s*\.proc\s+talk\b"), re.compile(r"^\s*\.endp\b")) + + lend_idx = None + for i in range(proc_start, len(lines)): + if re.match(r"^\s*LEND\b", lines[i]): + lend_idx = i + break + if lend_idx is None: + raise ValueError("LEND marker not found inside .proc talk") + + strings: List[str] = [] + for line in lines[proc_start:lend_idx]: + m = _DTA_STR_RE.match(line) + if m: + strings.append(m.group(1)) + + if not strings: + raise ValueError("No talk strings found to pack") + + return strings + + +def extract_constants_block(lines: List[str]) -> List[str]: + # Copy constant definitions from after LEND up to `.endp` (inclusive of constants, exclusive of .endp). + proc_start, proc_end = _find_section(lines, re.compile(r"^\s*\.proc\s+talk\b"), re.compile(r"^\s*\.endp\b")) + + lend_idx = None + for i in range(proc_start, proc_end + 1): + if re.match(r"^\s*LEND\b", lines[i]): + lend_idx = i + break + if lend_idx is None: + raise ValueError("LEND marker not found inside .proc talk") + + # Keep from LEND line through the line before `.endp`. + return lines[lend_idx:proc_end] + + +def extract_tail_after_talk_proc(lines: List[str]) -> List[str]: + # Copy everything after `.endp` for talk proc. This includes hoverFull/hoverEmpty. + _, proc_end = _find_section(lines, re.compile(r"^\s*\.proc\s+talk\b"), re.compile(r"^\s*\.endp\b")) + return lines[proc_end + 1 :] + + +def validate_alphabet() -> None: + if len(ALPHABET) != 32: + raise ValueError(f"ALPHABET must be 32 chars, got {len(ALPHABET)}") + if len(set(ALPHABET)) != len(ALPHABET): + raise ValueError("ALPHABET has duplicate characters") + + +def pack_string_5bit(s: str, mapping: dict[str, int]) -> bytes: + if len(s) > 63: + raise ValueError(f"String too long ({len(s)}): {s!r}") + + out = bytearray() + out.append(len(s) & 0xFF) + + bitbuf = 0 + bitcount = 0 + + for ch in s: + try: + code = mapping[ch] + except KeyError as e: + raise ValueError(f"Character {ch!r} not in alphabet") from e + + bitbuf |= (code & 0x1F) << bitcount + bitcount += 5 + + while bitcount >= 8: + out.append(bitbuf & 0xFF) + bitbuf >>= 8 + bitcount -= 8 + + if bitcount: + out.append(bitbuf & 0xFF) + + return bytes(out) + + +def format_dta_bytes(data: bytes, indent: str = " ", per_line: int = 16) -> List[str]: + lines: List[str] = [] + for i in range(0, len(data), per_line): + chunk = data[i : i + per_line] + nums = ",".join(f"${b:02x}" for b in chunk) + lines.append(f"{indent}dta b({nums})") + return lines + + +def generate_output( + source_path: Path, + strings: List[str], + constants_block: List[str], + tail_lines: List[str], +) -> str: + mapping = {ch: i for i, ch in enumerate(ALPHABET)} + + packed_records: List[bytes] = [pack_string_5bit(s, mapping) for s in strings] + + out_lines: List[str] = [] + out_lines.append("; AUTO-GENERATED FILE - DO NOT EDIT") + out_lines.append(f"; Generated by {source_path.name} -> pack_talk5.py") + out_lines.append("; Source: artwork/talk.asm") + out_lines.append("") + + out_lines.append(".proc talk") + out_lines.append("; 5-bit packed talk strings (len + packed bytes)") + out_lines.append(f"talk5_alphabet dta d\"{ALPHABET}\"") + out_lines.append("talk5_data") + + for rec in packed_records: + out_lines.extend(format_dta_bytes(rec)) + + out_lines.append(";") + out_lines.append("; Constants copied from source") + out_lines.extend(constants_block) + out_lines.append(".endp") + + if tail_lines: + out_lines.append("") + out_lines.append("; Tail copied from source (uncompressed)") + out_lines.extend(tail_lines) + + out_lines.append("") + return "\n".join(out_lines) + + +def main(argv: List[str] | None = None) -> int: + parser = argparse.ArgumentParser(description="Pack artwork/talk.asm into a 5-bit blob for MADS.") + parser.add_argument( + "--src", + default="artwork/talk.asm", + help="Path to source talk.asm (default: artwork/talk.asm)", + ) + parser.add_argument( + "--out", + default="artwork/talk_packed.asm", + help="Path to output .asm include (default: artwork/talk_packed.asm)", + ) + + args = parser.parse_args(argv) + + validate_alphabet() + + src_path = Path(args.src) + out_path = Path(args.out) + + lines = _iter_lines(src_path) + strings = extract_talk_strings(lines) + constants_block = extract_constants_block(lines) + tail_lines = extract_tail_after_talk_proc(lines) + + content = generate_output(src_path, strings, constants_block, tail_lines) + + out_path.write_text(content, encoding="utf-8") + print(f"Wrote {out_path} ({len(content.encode('utf-8'))} bytes text)") + print(f"Packed {len(strings)} strings") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/artwork/talk.asm b/artwork/talk.asm index e620fb6..28989d1 100644 --- a/artwork/talk.asm +++ b/artwork/talk.asm @@ -101,23 +101,23 @@ dta d"I LET YOU HIT ME!"^ dta d"SUCKER SHOT!"^ dta d"I DIDN'T WANT TO LIVE ANYWAY."^ - dta d"--"^ + dta d".-SOB-."^ dta d"WAS THAT AS CLOSE AS I THINK IT WAS?"^ dta d"JOIN THE ARMY, SEE THE WORLD THEY SAID."^ dta d"IT WASN'T JUST A JOB, IT WAS AN ADVENTURE!"^ dta d"I DIDN'T LIKE VIOLENCE ANYWAY!"^ dta d"I THOUGHT YOU LIKED ME?"^ - dta d"CTO XYEB"^ + dta d"RUSH B!"^ dta d"I THINK THIS GUY'S A LITTLE CRAZY."^ dta d"SOMEHOW I DON'T FEEL LIKE KILLING ANYMORE."^ dta d"HEY! KILLIN' AIN'T COOL."^ dta d"GEE... THANKS."^ dta d"I'VE FALLEN AND I CAN'T GET UP!"^ - dta d"911?"^ + dta d"NINE ONE ONE?"^ dta d"OH NO! HERE I BLOW AGAIN!"^ dta d"I'LL BE BACK..."^ dta d"I'VE GOT LAWYERS!"^ - dta d"CALL 1-900-SUE-TANK."^ + dta d"CALL MY LAWYERS!"^ dta d"YOU BIG DUMMY!"^ ;(sanford and son) LEND NumberOfOffensiveTexts=55 diff --git a/artwork/talk_packed.asm b/artwork/talk_packed.asm new file mode 100644 index 0000000..1810ab3 --- /dev/null +++ b/artwork/talk_packed.asm @@ -0,0 +1,174 @@ +; AUTO-GENERATED FILE - DO NOT EDIT +; Generated by talk.asm -> pack_talk5.py +; Source: artwork/talk.asm + +.proc talk +; 5-bit packed talk strings (len + packed bytes) +talk5_alphabet dta d" ABCDEFGHIJKLMNOPQRSTUVWYZ'!,-.?" +talk5_data + dta b($04,$24,$95,$0d) + dta b($10,$a6,$4a,$40,$4a,$a5,$73,$20,$16,$1c,$d9) + dta b($11,$f8,$55,$2d,$0b,$20,$25,$10,$d0,$4a,$a0,$1e) + dta b($0f,$24,$15,$30,$5e,$6b,$a9,$00,$98,$ce,$06) + dta b($08,$36,$0d,$fa,$24,$de) + dta b($11,$24,$15,$0e,$02,$4b,$c5,$81,$79,$93,$2b,$1b) + dta b($08,$e1,$ca,$ba,$f6,$de) + dta b($09,$03,$af,$00,$04,$0b,$14) + dta b($0a,$34,$ac,$02,$28,$4a,$73,$03) + dta b($0e,$25,$50,$d0,$30,$98,$e8,$49,$3a,$37) + dta b($0d,$f8,$55,$2d,$0b,$a0,$2f,$4c,$ba,$01) + dta b($07,$22,$b8,$1c,$d2,$06) + dta b($0a,$0f,$16,$07,$6e,$22,$65,$03) + dta b($09,$28,$00,$14,$00,$0a,$1e) + dta b($07,$03,$05,$79,$ca,$06) + dta b($07,$81,$d2,$30,$d6,$06) + dta b($0f,$24,$15,$0e,$68,$70,$ab,$cf,$51,$db,$06) + dta b($0d,$c9,$01,$fc,$aa,$04,$26,$8c,$b2,$01) + dta b($0c,$34,$ac,$02,$02,$40,$69,$95,$0d) + dta b($0c,$2d,$ac,$02,$1a,$06,$24,$60,$0f) + dta b($0d,$cb,$bd,$b1,$38,$58,$ee,$8d,$e5,$01) + dta b($23,$46,$be,$06,$50,$61,$4c,$4f,$80,$4a,$90,$14,$24,$30,$69,$10) + dta b($20,$50,$40,$51,$29,$de,$7b) + dta b($18,$e4,$01,$fc,$2a,$30,$a5,$30,$c0,$ea,$58,$98,$03,$1a,$dc,$fa) + dta b($12,$f8,$55,$2d,$0b,$78,$95,$d2,$00,$50,$91,$c5,$03) + dta b($11,$37,$50,$3a,$03,$68,$81,$d2,$00,$f0,$ab,$1f) + dta b($16,$46,$96,$92,$0b,$07,$4f,$82,$a4,$19,$03,$13,$bd,$47,$37) + dta b($21,$b7,$80,$f1,$5a,$01,$c9,$01,$58,$c2,$28,$a0,$83,$89,$de,$a3) + dta b($80,$3e,$b0,$12,$63,$1b) + dta b($2a,$09,$b0,$67,$0b,$a0,$a8,$80,$d9,$0a,$63,$e0,$19,$e0,$02,$0c) + dta b($ac,$81,$e4,$00,$45,$05,$b4,$27,$5d,$72,$c7,$03) + dta b($12,$13,$bd,$0b,$e6,$6b,$05,$c8,$32,$61,$19,$d4,$03) + dta b($1e,$aa,$4e,$0a,$2e,$7a,$80,$3c,$80,$5f,$05,$14,$25,$b7,$00,$7e) + dta b($15,$04,$59,$3e) + dta b($0f,$ec,$bd,$05,$5e,$a5,$40,$14,$f6,$ee,$06) + dta b($10,$ec,$bd,$05,$9e,$2d,$12,$50,$54,$64,$f1) + dta b($1f,$a7,$96,$39,$c1,$45,$81,$ea,$09,$c6,$6b,$c9,$1d,$60,$9e,$04) + dta b($24,$39,$57,$e4,$07) + dta b($10,$ad,$48,$89,$c1,$40,$32,$4d,$da,$c2,$f4) + dta b($14,$a8,$c8,$02,$ce,$2b,$13,$b8,$47,$51,$72,$c7,$7b,$0f) + dta b($23,$e4,$39,$4d,$c1,$7d,$52,$62,$0e,$12,$05,$69,$3a,$4d,$41,$00) + dta b($2c,$d9,$02,$e4,$ab,$8e,$78) + dta b($16,$82,$bd,$47,$38,$80,$21,$39,$0e,$6c,$7a,$ac,$b8,$51,$36) + dta b($11,$34,$ac,$02,$28,$4a,$93,$83,$99,$e6,$c4,$1b) + dta b($14,$09,$4c,$14,$18,$03,$86,$05,$4a,$8b,$03,$f8,$d5,$0d) + dta b($1d,$09,$4c,$14,$18,$03,$b3,$85,$89,$00,$7e,$55,$82,$7a,$18,$06) + dta b($34,$b8,$b5,$01) + dta b($1f,$09,$dc,$e7,$48,$91,$e0,$a2,$40,$01,$45,$69,$02,$51,$29,$7d) + dta b($0e,$90,$57,$e6,$07) + dta b($1b,$e4,$39,$4d,$01,$0d,$ab,$00,$8a,$d2,$04,$b0,$c8,$f9,$5c,$60) + dta b($0c,$7b) + dta b($18,$f7,$55,$46,$00,$45,$69,$82,$16,$56,$01,$f8,$55,$d0,$02,$f9) + dta b($24,$09,$d0,$c7,$08,$c0,$af,$02,$fa,$00,$2b,$c1,$16,$d0,$30,$98) + dta b($69,$d2,$22,$41,$60,$cf,$95,$0d) + dta b($1b,$09,$8c,$57,$19,$01,$13,$06,$59,$00,$7e,$95,$03,$51,$29,$b8) + dta b($08,$7f) + dta b($1d,$0d,$03,$f1,$9a,$00,$69,$02,$91,$ce,$29,$12,$50,$14,$1c,$c0) + dta b($af,$ca,$e9,$01) + dta b($16,$e4,$39,$4d,$81,$79,$f2,$14,$0a,$82,$78,$95,$82,$56,$36) + dta b($15,$28,$4c,$1a,$00,$0b,$c0,$a6,$49,$03,$07,$22,$08,$bc,$01) + dta b($1d,$14,$a5,$09,$d2,$04,$f8,$55,$09,$84,$0c,$c9,$81,$e7,$c0,$1c) + dta b($4f,$0e,$e4,$01) + dta b($24,$14,$a5,$09,$e6,$90,$a5,$38,$10,$92,$d3,$14,$88,$74,$40,$71) + dta b($af,$1e,$04,$cc,$93,$a0,$4e,$0f) + dta b($26,$09,$4c,$14,$18,$03,$2f,$31,$d0,$30,$a0,$55,$ca,$42,$c1,$4d) + dta b($14,$01,$fc,$aa,$04,$82,$bd,$47,$3c) + dta b($1a,$49,$37,$70,$9e,$73,$01,$08,$59,$c2,$02,$f8,$55,$09,$4c,$18) + dta b($65,$03) + dta b($18,$2d,$b4,$00,$66,$48,$04,$2c,$f7,$c6,$02,$f8,$55,$f0,$2a,$dd) + dta b($16,$09,$a0,$07,$0b,$c0,$af,$82,$e2,$d4,$c3,$00,$86,$e4,$36) + dta b($24,$e8,$5d,$4d,$00,$7e,$15,$b0,$b4,$0a,$78,$ae,$80,$30,$e4,$9b) + dta b($13,$e0,$57,$25,$60,$09,$ce,$0f) + dta b($24,$30,$48,$9a,$dc,$01,$69,$82,$59,$07,$02,$f3,$96,$42,$c1,$7c) + dta b($52,$be,$eb,$bd,$07,$ee,$d1,$0d) + dta b($04,$f5,$a0,$0d) + dta b($06,$21,$c8,$83,$36) + dta b($09,$21,$84,$73,$10,$42,$1b) + dta b($0c,$49,$37,$d0,$0a,$a3,$c9,$9d,$0d) + dta b($05,$ef,$19,$ef,$01) + dta b($03,$0f,$6d) + dta b($05,$a5,$94,$b5,$01) + dta b($06,$21,$8c,$81,$36) + dta b($1c,$09,$a0,$40,$0b,$48,$14,$5c,$54,$1c,$a0,$28,$50,$80,$02,$84) + dta b($c5,$4d,$0f) + dta b($20,$cf,$15,$80,$12,$05,$23,$38,$20,$6b,$72,$00,$bf,$2a,$c1,$45) + dta b($8f,$15,$40,$02,$f6) + dta b($06,$0f,$01,$f7,$36) + dta b($07,$ee,$51,$d0,$ca,$06) + dta b($05,$af,$0e,$e4,$01) + dta b($11,$0f,$01,$f7,$38,$70,$8f,$82,$70,$42,$72,$1e) + dta b($1b,$c1,$3d,$8a,$8a,$04,$cf,$15,$20,$12,$2d,$13,$50,$54,$00,$a9) + dta b($93,$7a) + dta b($08,$e7,$3d,$22,$70,$f1) + dta b($08,$a8,$30,$08,$5a,$d9) + dta b($16,$26,$c8,$72,$0b,$63,$1c,$0c,$59,$0b,$03,$f7,$49,$46,$3c) + dta b($13,$b2,$b4,$d2,$44,$91,$80,$a2,$02,$02,$0b,$ed,$6d) + dta b($07,$0f,$81,$16,$dc,$06) + dta b($07,$e4,$bd,$7a,$d0,$06) + dta b($12,$ae,$5c,$40,$02,$e6,$c0,$95,$0b,$c4,$6b,$c2,$03) + dta b($20,$14,$a5,$09,$d2,$04,$14,$15,$50,$1c,$e1,$a0,$61,$f0,$1c,$c3) + dta b($c0,$c8,$54,$1c,$f1) + dta b($0b,$b6,$48,$0c,$4c,$75,$0e,$7b) + dta b($12,$14,$15,$60,$02,$05,$2c,$10,$0c,$66,$70,$c7,$03) + dta b($16,$17,$61,$40,$5e,$99,$00,$05,$08,$8b,$03,$f4,$81,$56,$3e) + dta b($0f,$49,$37,$70,$5e,$72,$07,$90,$77,$9d,$07) + dta b($17,$49,$db,$02,$ce,$a3,$20,$00,$11,$08,$30,$a5,$b0,$e4,$8e,$07) + dta b($08,$43,$06,$f8,$58,$f0) + dta b($04,$f0,$dd,$0d) + dta b($04,$22,$99,$0d) + dta b($04,$22,$b4,$0d) + dta b($05,$f9,$b9,$b5,$01) + dta b($1f,$09,$4c,$f4,$2a,$23,$da,$16,$c0,$d2,$a4,$c5,$15,$02,$e8,$03) + dta b($0d,$83,$f6,$9a,$07) + dta b($2a,$09,$dc,$c0,$16,$a0,$48,$be,$7a,$10,$a0,$a8,$00,$1b,$18,$2b) + dta b($18,$3c,$03,$28,$2a,$60,$a2,$40,$de,$f5,$de,$03) + dta b($14,$17,$05,$0a,$6e,$98,$80,$a2,$40,$81,$7b,$69,$96,$0f) + dta b($24,$2d,$b4,$00,$66,$48,$04,$50,$54,$64,$d1,$04,$88,$02,$48,$c0) + dta b($13,$b0,$b4,$0a,$a0,$28,$4d,$0f) + dta b($1e,$89,$ea,$09,$54,$9d,$14,$3c,$57,$c0,$33,$80,$a2,$37,$0b,$20) + dta b($01,$4f,$ef,$3d) + dta b($17,$09,$cc,$52,$40,$00,$42,$a6,$83,$28,$60,$e9,$20,$ea,$bd,$07) + dta b($13,$ed,$b5,$86,$3f,$48,$13,$50,$14,$28,$c0,$af,$7e) + dta b($11,$09,$b0,$42,$01,$7e,$15,$a0,$44,$41,$2b,$1b) + dta b($0c,$b3,$8e,$55,$24,$98,$e8,$d1,$0d) + dta b($1d,$09,$90,$44,$9c,$a6,$e0,$06,$47,$01,$7d,$80,$25,$5b,$40,$70) + dta b($f8,$06,$ec,$01) + dta b($07,$be,$cf,$27,$ba,$07) + dta b($24,$37,$4c,$40,$51,$a0,$20,$4c,$30,$d8,$9b,$05,$84,$09,$12,$a0) + dta b($28,$b9,$05,$12,$05,$37,$cc,$0f) + dta b($27,$ea,$25,$07,$28,$2a,$20,$c8,$86,$39,$98,$a5,$00,$8a,$0a,$b8) + dta b($4f,$32,$02,$28,$2a,$18,$cc,$90,$88,$07) + dta b($2a,$89,$82,$1b,$a6,$d3,$14,$a8,$3a,$29,$08,$40,$3d,$c1,$41,$a2) + dta b($e0,$86,$09,$82,$03,$81,$d8,$e2,$68,$95,$65,$03) + dta b($1e,$09,$90,$44,$9c,$a6,$80,$a5,$55,$80,$4d,$8f,$15,$37,$0a,$08) + dta b($0e,$df,$80,$37) + dta b($17,$09,$50,$f4,$ea,$41,$14,$e0,$57,$01,$4b,$ab,$10,$d0,$ca,$07) + dta b($07,$b2,$4e,$04,$c4,$06) + dta b($22,$09,$50,$94,$dc,$02,$14,$a5,$09,$4e,$c5,$7a,$82,$00,$58,$a2) + dta b($94,$15,$30,$64,$c8,$d8,$03) + dta b($2a,$f3,$b5,$82,$de,$05,$09,$90,$e7,$34,$05,$a6,$14,$06,$58,$5a) + dta b($05,$ac,$c4,$58,$72,$07,$04,$87,$db,$93,$c5,$03) + dta b($18,$a8,$e0,$0d,$56,$62,$2c,$39,$0d,$42,$72,$9a,$82,$f1,$1e,$f3) + dta b($0e,$a7,$14,$ef,$3d,$a0,$28,$b8,$35,$3d) + dta b($1f,$49,$db,$02,$4c,$60,$ac,$38,$10,$1c,$01,$09,$8c,$e0,$34,$05) + dta b($a7,$50,$50,$e1,$06) + dta b($0d,$2e,$b9,$02,$9e,$2b,$e0,$b9,$f2,$01) + dta b($19,$0f,$01,$f7,$36,$40,$45,$16,$90,$80,$60,$ef,$82,$70,$42,$72) + dta b($1b) + dta b($0f,$49,$33,$06,$44,$01,$22,$8c,$e5,$bd,$07) + dta b($11,$49,$db,$02,$ce,$a3,$80,$85,$8b,$8b,$9c,$1b) + dta b($10,$23,$30,$06,$1a,$06,$2c,$5c,$5c,$e4,$dc) + dta b($0e,$f8,$55,$20,$d2,$01,$a4,$b6,$86,$37) +; +; Constants copied from source +LEND +NumberOfOffensiveTexts=55 +NumberOfDeffensiveTexts=62 +NumberOfPropagandaTexts=21 +VeryFunnyText=79 +.endp + +; Tail copied from source (uncompressed) +hoverFull dta d"MY HOVERCRAFT IS FULL OF EELS!"^ +hoverFullEnd +hoverEmpty dta d"RUNNING OUT OF EELS"^ +hoverEmptyEnd diff --git a/grafproc.asm b/grafproc.asm index 3a48a61..6cdfeb7 100644 --- a/grafproc.asm +++ b/grafproc.asm @@ -1422,22 +1422,35 @@ notZero sta plot4x4color tya tax ; save Y - mwa #talk LineAddress4x4 - jsr _calc_inverse_display - - ; now find length of the text -@ iny - lda (LineAddress4x4),y - bpl @- - iny - sty fx + mwa #talk.talk5_data LineAddress4x4 + jsr _calc_packed_display + + ; record starts with length byte + ldy #0 + lda (LineAddress4x4),y + sta fx + inw LineAddress4x4 ; point to packed payload txa ; load Y tay + jmp Display4x4AboveTankPacked +.endp + +;-------------------------------------------------------- +.proc Display4x4AboveTankPacked ; + ; Displays packed texts using PutChar4x4 above tank and mountains. + ;parameters are: + ;Y - number of tank above which text is displayed + ;fx - length of text + ;LineAddress4x4 - address of packed payload + + lda xtankstableL,y + sta temp + lda xtankstableH,y + sta temp+1 + jsr Calculate4x4TextPosition + jmp TypeLine4x4Packed.noLengthNoColor - ;jsr Display4x4AboveTank - ;rts - ; POZOR !!! .endp ;-------------------------------------------------------- @@ -1627,6 +1640,115 @@ EndOfTypeLine4x4 rts .endp +;------------------------------- +.proc TypeLine4x4Packed ; +;------------------------------- + ;this routine prints packed line of length `fx` + ;packed payload address in LineAddress4x4 + ;starting from LineXdraw, LineYdraw + + lda #14 ; default length of 4x4 texts + sta fx + +variableLength + lda #$ff ; $ff - visible characters, $00 - clearing + +staplot4x4color + sta plot4x4color +noLengthNoColor + + ; init packed bitstream + ; Reuse ZP vars: + ; - LineAddress4x4 is the packed byte pointer (advanced during decoding) + ; - Multiplier/Multiplier_ are used as bit buffer/state + lda #0 + sta Multiplier + sta Multiplier+1 + sta Multiplier_ + + ldy #0 + sty LineCharNr + +TypeLine4x4PackedLoop + ldy LineCharNr + + jsr _packed_get5bits + tay + lda talk.talk5_alphabet,y + sta CharCode4x4 + mwa LineXdraw dx + mva LineYdraw dy + mva #0 dy+1 ; dy is 2 bytes value + jsr PutChar4x4 ;type empty pixels as well! + adw LineXdraw #4 + inc:lda LineCharNr + cmp fx + bne TypeLine4x4PackedLoop + + rts +.endp + +;-------------------------------- +; Packed 5-bit bitstream decoder +; +; Uses a 16-bit shift register where the lowest bits are the next bits to read. +; Bytes are appended little-endian (LSB-first) at bit position PackedBitCount4x4. +;-------------------------------- +.proc _packed_get5bits + ; ensure at least 5 bits available + lda Multiplier_ + cmp #5 + bcs have_bits + + ; read next byte and append at current bit count + ldy #0 + lda (LineAddress4x4),y + sta temp2 ; new byte + lda #0 + sta temp2+1 + inw LineAddress4x4 + + ldx Multiplier_ + beq append_ready +append_shift + asl temp2 + rol temp2+1 + dex + bne append_shift +append_ready + lda Multiplier + ora temp2 + sta Multiplier + lda Multiplier+1 + ora temp2+1 + sta Multiplier+1 + + lda Multiplier_ + clc + adc #8 + sta Multiplier_ + +have_bits + lda Multiplier + and #$1f + sta temp2 + + ; shift register right by 5 + ldx #5 +@ lsr Multiplier+1 + ror Multiplier + dex + bne @- + + lda Multiplier_ + sec + sbc #5 + sta Multiplier_ + + lda temp2 + rts +.endp + ;-------------------------------- .proc AreYouSure diff --git a/scorch.asm b/scorch.asm index 03a418a..add9950 100644 --- a/scorch.asm +++ b/scorch.asm @@ -535,7 +535,7 @@ noingame ;---------------------------------------------- icl 'ai.asm' ;---------------------------------------------- - icl 'artwork/talk.asm' + icl 'artwork/talk_packed.asm' ;---------------------------------------------- TankFont ins 'artwork/tanksv4.fnt',+0,384 ; 48 characters only diff --git a/scorch5bit.xex b/scorch5bit.xex new file mode 100644 index 0000000000000000000000000000000000000000..d82406795b285e5522a0d705a07a5e1df5b8f8cb GIT binary patch literal 32375 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 literal 0 HcmV?d00001 diff --git a/scorchC64.asm b/scorchC64.asm index b42f537..65e599d 100644 --- a/scorchC64.asm +++ b/scorchC64.asm @@ -315,7 +315,7 @@ noShellDelay ;---------------------------------------------- icl 'ai.asm' ;---------------------------------------------- - icl 'artwork/talk.asm' + icl 'artwork/talk_packed.asm' ;---------------------------------------------- TankFont ins 'artwork/tanksv4.fnt',+0,384 ; 48 characters only diff --git a/weapons.asm b/weapons.asm index ecfe047..80ee12f 100644 --- a/weapons.asm +++ b/weapons.asm @@ -399,19 +399,15 @@ nexttext bcs @- sta TextNumberOff - ; all text start from `talk` and end with an inverse. - ; we go through the `talk`, count number of inverses. - ; if equal to TextNumberOff, it is our text, printit lda #$ff sta plot4x4color - mwa #talk LineAddress4x4 - jsr _calc_inverse_display - ; now find length of the text -@ iny + mwa #talk.talk5_data LineAddress4x4 + jsr _calc_packed_display + ; record starts with length byte + ldy #0 lda (LineAddress4x4),y - bpl @- - iny - sty fx + sta fx + inw LineAddress4x4 ; point to packed payload mwa tempXROLLER temp ; X coordinate of hitpoint ; calculate position of message jsr Calculate4x4TextPosition @@ -436,7 +432,7 @@ nexttext dec LineXdraw+1 DisplayMessage ; display propaganda message - jsr TypeLine4x4.noLengthNoColor + jsr TypeLine4x4Packed.noLengthNoColor ldy #7 jsr PauseYFrames