--- title: "Christmas Card" id: 71953 type: "computer_media" slug: "christmas-card" url: "http://localhost/computer_media/christmas-card/" markdown_url: "http://localhost/computer_media/christmas-card.md" published_at: "2026-10-20T14:55:41+00:00" modified_at: "2026-10-20T14:55:42+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2022/04/20230809-041332.jpg" excerpt: "Christmas scene with a decorated tree, a large star and snowy ground, plus a double-height scrolling message and carols played note by note." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Floyd Chrysler" slug: "floyd-chrysler" taxonomy: "indiv" url: "http://localhost/indiv/floyd-chrysler/" - name: "Tony Samuels" slug: "tony-samuels" taxonomy: "indiv" url: "http://localhost/indiv/tony-samuels/" genre: - name: "Holiday" slug: "holiday" taxonomy: "genre" url: "http://localhost/type/holiday/" media_contents: - id: 71965 title: "Long Island Sinclair Timex (LIST) User Group Library Tape #3.5" type: "computer_media" url: "http://localhost/computer_media/long-island-sinclair-timex-list-user-group-library-tape-3-5/" media_type: "Program" programmers: - name: "Tony Samuels" slug: "tony-samuels" taxonomy: "indiv" url: "http://localhost/indiv/tony-samuels/" - name: "Floyd Chrysler" slug: "floyd-chrysler" taxonomy: "indiv" url: "http://localhost/indiv/floyd-chrysler/" tsrun_member: "LIST LIB 3.5 (198x)(Long Island Sinclair Timex User Group)(TS2068)(US)(Cassette)/List_Lib_3.5A(Unk)(Unk)(TS2068)(Cassette)/8_Xmas.tap" mediadate: "198x" media_type_tags: "Holiday" --- # Christmas Card Draws a night scene with snowy ground, a green tree hung with coloured UDG baubles and topped with a star, a large yellow star in the sky and scattered small stars, then scrolls a double-height greeting along a white band near the bottom of the screen while playing carols with BEEP. A routine at line 9000 lets the user type a new message and prints (and LPRINTs) a replacement DATA line for it. A REM credits the program to Tony Samuels, from Your Spectrum Dec/Jan 85, entered by Floyd Chrysler. The tape holds two saves: “Xmas” with a long message, and “xlist”, the same program with a shorter message in line 570. ## Program Analysis ### Program Structure Lines 10–340 draw the scene with `PLOT`/`DRAW` loops and UDGs `a` (small star), `b` (bauble) and `t` (tree-top star). Line 360 POKEs a 72-byte routine to 65400. Lines 400–410 decode the message, and 420–470 print one character at a time, call the routine and play the next note from the DATA at 500–540. ### Scrolling Message Each character is printed invisibly (black on black) at the top-left of the screen. The machine code at 65400 shifts rows 19 and 20 of the display file left by one cell with `LDIR`, then copies the eight pixel bytes of the top-left cell into the vacated right-hand cells, writing each byte twice so the character appears at double height. ### Notable Techniques - The message in line 570 is stored obfuscated: each character is recovered as `CHR$ (255-(m-PEEK f))`, using ROM bytes as the key. - The ground line is built with a random walk, `LET a=a+INT (RND*3)-1`, clamped between 32 and 60 pixels. - The small stars are placed only on empty cells by testing `ATTR (y,x)<>0`. ### Potential Issues - Because the message key is read from the ROM, DATA produced on one machine decodes correctly only on a machine with the same ROM bytes. ## Source Code ``` 1 REM christmas card From Your Spectrum Dec/Jan 85 By Tony Samuels entered by Floyd Chrysler 10 CLEAR 65399: BORDER 0: PAPER 0: INK 0: CLS : INK 7 20 DATA 0,8,8,62,8,8,8,8: RESTORE : FOR f=0 TO 7: READ z: POKE USR "t"+f,z: NEXT f 30 DATA 0,0,0,0,1,0,0,0,0,2,64,0,0,0,16,0: FOR f=0 TO 15: READ a: POKE USR "a"+f,a: NEXT f 40 LET a=50 50 FOR f=0 TO 255 60 PLOT f,0: DRAW 0,a 70 LET a=a+INT (RND*3)-1 80 IF a<32 THEN LET a=32 90 IF a>60 THEN LET a=60 100 NEXT f 110 FOR f=17 TO 14 STEP -1: PRINT AT f,23; PAPER 1;" ": NEXT f 120 LET a=10: FOR f=180 TO 200: PLOT f,30: DRAW 0,a: LET a=a+INT (RND*3)-1: NEXT f 130 INK 4: LET a=30: FOR f=64 TO 160: PLOT 188,f 140 DRAW -a,0: DRAW a*2,0 150 LET a=a-.3 170 NEXT f 180 DATA 4,23,6,23,7,22,7,24,8,23,9,22,10,24,11,21,11,25,12,23,13,22,13,25 190 FOR f=0 TO 11: READ x,y: PRINT AT x,y; INK RND*6+1; PAPER 4;"b": NEXT f 200 INK 6 210 LET a=0: FOR f=175 TO 165 STEP -1: PLOT 30,f: DRAW -a,0: DRAW a*2,0: LET a=a+.25: NEXT f: FOR f=164 TO 146 STEP -1: PLOT 30,f: DRAW -a,0: DRAW 2*a,0: LET a=a-.16: NEXT f 220 LET a=2.5: FOR f=1 TO 10: PLOT 30-f,165: DRAW 0,a: DRAW 0,-a*2: PLOT 30+f,165: DRAW 0,a: DRAW 0,-a*2: LET a=a-.25: NEXT f 230 PLOT 26,170: DRAW -5,5: PLOT 34,170: DRAW 5,5: PLOT 25,160: DRAW -7,-13: PLOT 36,160: DRAW 7,-13 240 PRINT AT 1,23;"t" 300 FOR f=0 TO 30 310 LET x=INT (RND*32): LET y=INT (RND*12) 320 IF ATTR (y,x)<>0 THEN GO TO 310 330 PRINT AT y,x; INK 7;"a" 340 NEXT f 350 PRINT AT 19,0; INK 2; PAPER 7;" " 360 RESTORE 550: FOR f=65400 TO 65471: READ p: POKE f,p: NEXT f 400 RESTORE 570: LET m$="": FOR f=1 TO 1000: READ m: IF m=999 THEN GO TO 410 405 LET m$=m$+CHR$ (255-(m-PEEK (f))): NEXT f 410 RESTORE 500: LET m$=m$+" ": LET f=f+4 420 LET c=1 430 LET c$=m$(c): PRINT AT 0,0; INK 0; PAPER 0;c$: LET c=c+1 440 IF c=f THEN GO TO 420 450 READ b1,b2: IF b1=999 THEN RESTORE 500: GO TO 450 460 LET l=USR 65400: BEEP b1/4,b2 470 GO TO 430 500 DATA 1,7,1,7,1,7,1,9,1,7,1,7,2,2,1,4,1,2,1,4,1,6,2,7,2,7,1,7,1,7,1,7,1,9,1,7,1,7,2,2,1,4,1,2,1,4,1,6,2,7,2,7,1,14,1,12,1,11,1,9,1,11,1,9,2,7,1,4,1,2,1,4,1,6,2,7,2,7,1,2,1,2,1,4,1,6,1,7,1,7,2,9,1,14,1,12,1,11,1,9,2,7,2,12,4,7 510 DATA 1,11,.5,9,1,7,.5,4,.5,6,.5,7,.5,6,1.5,4,1,11,.5,9,1,7,.5,4,.5,6,.5,7,.5,6,1.5,4,1,7,.5,7,1,9,.5,9,1,11,.5,11,.5,14,.5,12,.5,11,.5,9,.5,11,.5,9,1,7,.5,6,3,4,1,6,.5,9,1,7,.5,7,1,7,.5,2,1,7,.5,4,1.5,7,1,7,.5,7,1,7,.5,2,1,7,.5,4,1.5,7,1,7,.5,7,1,9,.5,11,1,12,.5,11,1,9,.5,11,1,7,.5,7,1,7,.5,2,1,7,.5,4,3,7 520 DATA 1,7,1,12,.5,12,.5,14,.5,12,.5,11,1,9,1,5,1,9,1,14,.5,14,.5,16,.5,14,.5,12,1,11,1,7,1,11,1,16,.5,16,.5,17,.5,16,.5,14,1,12,1,9,.5,7,.5,7,1,9,1,14,1,11,2,12 530 DATA 1,7,1,12,1,12,1,12,2,11,1,11,1,12,1,11,1,9,2,7,1,14,1,16,.5,12,.5,14,.5,16,.5,17,1,19,1,7,.5,7,.5,7,1,9,1,14,1,11,2,12 540 DATA 999,999 550 DATA 6,8,33,97,80,229,209,27,197,1,31,0,237,176,1,225,0,9,193,16,240,6,8,33,129,80,229,209,27,197,1,31,0,237,176,1,225,0,9,193,16,240 560 DATA 33,0,64,17,127,80,6,4,126,18,20,18,20,36,16,248,235,1,224,7,237,66,235,123,254,159,40,234,201,0 570 DATA 358,175,398,398,329,272,180,188,251,232,257,248,233,168,213,418,415,165,407,466,478,426,405,187,251,303,349,380,279,139,362,416,339,183,182,380,409,402,466,418,198,194,409,392,409,466,478,372,196,238,233,363,418,203,164,400,452,223,270,239,182,257,330,315,314,328,179,226,392,203,218,420,365,363,370,154,432,351,364,464,417,345,363,251,476,289,143,391,279,200,233,333,230,241,478,464,464,464,478,999 8999 STOP 9000 PAPER 7: INK 0: BORDER 1 9001 REM To create your own message enter go to 9000. You will be asked for your message and then given the data statement you can use to replace line 570 above. 9010 INPUT "TYPE IN MESSAGE ............"; LINE m$ 9015 DIM m(LEN m$) 9020 FOR f=1 TO LEN m$ 9030 LET c=CODE m$(f): LET m(f)=255-c+PEEK f 9040 NEXT f 9090 CLS : PRINT " DATA "; 9091 LPRINT " DATA "; 9100 FOR f=1 TO LEN m$ 9110 PRINT m(f);","; 9120 LPRINT m(f);","; 9130 NEXT f 9140 PRINT "999": LPRINT "999" 9150 STOP ```