Browsing through the dead listings, you will see a lot of POKEs and PEEKs in the code. If the addresses are between 23552 and 23733, then these are known as System Variables.
The following are some of the more common ones you will come across when looking through a dead and/or extracted BASIC listing.
Switching the speed at which a key press repeats
ROM Address: 23561 (REPDEL)
This is the amount of time (in 50ths of a second / in 60ths of a second in N. America) that a key must be held down before it repeats.
This has shown up in some text adventures and strategy games and the coders usually turn it off to prevent auto-repeat. The default value is 35, but POKEing 0 at this address would turn off the auto-repeat.
POKE 23561,0
If your tweaked or original code is going to quit back to the BASIC editor, I would include the POKE to turn it back to the normal value of 35 into your exit routine.
Switching the speed at which a key press repeats
ROM Address: 23562 (REPPER)
This will alter the delay (in 50ths of a second / in 60ths of a second in N. America) between successive repeats of a key held down: initially 5.
Change the Font
ROM Addresses: 23606, 23607 (CHARS)
This is only applicable if the game you’re snooping through uses a different font. Examining the .TAP file for a binary file of (usually) 768 bytes long. This is usually loaded after the main BASIC code, but in some cases might be embedded in the first REM line.
Check the listing and see if the addresses 23606 and 23607 are being manipulated and this gives it away that a new font is in town. Normally these values are set to point to the system font in memory. To find out where the new font is being stored (if you can’t find an obvious LOAD “” CODE command), then break into the program whilst it is running and type the following from the prompt.
PRINT 256*PEEK 23607 + PEEK 23606
Calculating the address yourself
The 16-bit font address is stored in memory as two 8-bit bytes, at 23606 and 23607.
Here’s how to work it out:
- Take your font address and subtract 256 from it (*)
- Divide this value by 256, and POKE the whole number in 23607
- Whatever is left you POKE into 23606
(*) This is because your first printable character is ASCII 32 (a space), so you need 23606/7 to point to 256 bytes below where your font actually is. It’s 256 because each character is 8 bytes, so it’s 32 characters x 8 bytes.
| Address Examples | 16K Spectrum | 48K Spectrum |
| Font is loaded at: | 31232 | 64000 |
| CHARS are POKEd with these values: | 23606: 0 23607: 121 | 23606: 0 23607: 249 |
| Calculation: | 31232-256 = 30976, then divide by 256 = 121. No bytes are left over, so 23606 gets 0 placed in it. | 64000-256 = 63744, then divide by 256 = 249 No bytes are left over, so 23606 gets 0 placed in it. |
Example code to load in a new font (48K Spectrum)
This code will load a new font file (768 bytes long) into address 64000. Then alter the CHARS system variable to point to the new address.
10 CLEAR 63999
20 LOAD ""CODE 64000
30 POKE 23607,249
Altering the length of the buzz sound effect on keypresses
ROM Address: 23608 (RASP)
Altering this byte will change the length of warning buzz noise that is played … (need examples)
Change length of keyboard beep noise
ROM Address: 23609 (PIP)
The value range is the length of the beep (try various values between 0 and 255). When it is 0, the beep is so short that it sounds like a soft click.
POKE 23609, 0 - shortest beep
POKE 23609,255 - longest beep
Change length of keyboard beep noise
ROM Address: 23617 (MODE)
The value range is the length of the beep (try various values between 0 and 255). When it is 0, the beep is so short that it sounds like a soft click.
Official parameters from System Variables section of manual
Specifies which cursor to display in an INPUT command.
POKE 23617, x - where x can be:
0=Alpha (C/L),
1=Extended (E)
2=Graphics (G)
4=Keyword (K).
Alternate examples found in commercial titles
Ghost Town (Virgin Games) - POKE 23617, 164 - Flashing / alternating half horizontal bar
The Island (Virgin Games) - POKE 23617,158 - Gives a blank flashing square
Boxing Manager (?) - POKE 23617, 252 - Flashing < character
Border and Ink colours
ROM Addresses: 23624 (BORDCR) & 23693 (ATTR P)
BORDER 0: POKE 23624,0 : POKE 23693,0: CLEAR xxxxx will set everything to a black and blank screen. It uses the BORDCR and ATTRP system variables.
For example, a simple SCREEN$ and BYTES loader program could look like this:
10 BORDER 0: PAPER 0: POKE 23624,0: POKE 23639,0: CLEAR xxxxx-1: POKE 23739,111
20 LOAD "" SCREEN$
30 LOAD "" CODE
40 POKE 23739,244
50 RANDOMIZE USR xxxxx
The filename prevention and colour modifications were taken from a post in Basic on the ZX Spectrum Facebook group.
Thanks to Johnny McGibbits and Chris Flynn :)
Caps Lock for input on / off
ROM Address: 23658 (CAPS)
If you want to force caps lock on or off, then use one of the POKEs below:
POKE 23658,0 - turns off CAPS LOCK
POKE 23658,1 - turns it on.
Prevent text causing screen scrolling message
ROM Address: 23659 (DF_SZ)
This system variable contains the number of lines in the lower section of the screen, normally used for INPUTs, error reports and so on.
POKEing 255 into 23659 would prevent the “Scroll? y/n” message from appearing at the bottom of the screen.
This was also used as a simple form of protection in BASIC games, as it prevented you from using BREAK to get back in and look around. Although MERGE”” got past that ‘protection’ back in the day.
Timer
ROM Addresses: 23672, 23673 & 23674 (FRAMES)
LET tmr = 65636*PEEK 23674 + 256*PEEK 23673 + PEEK 23672
LET tmr=tmr/50
tmr now has the number of seconds elapsed so far. Divide this again by 60 to get the number of minutes.
As a working example, Everest Ascent by Richard Shepherd Software would not let you save the game’s progress unless you had played it for 30 minutes or more! (1800 = 30 minutes in seconds)
9950 IF (65536*PEEK 23674+256*PEEK 23673+PEEK 23672)/50<1800 THEN GO TO 584
(Line 584 being the routine that prevented you from saving the game yet)
Preventing Filenames appearing during loading
ROM Address: 23739
When loading SCREEN$, we might use POKE 23739,111 to hide the “Bytes: xyz” text. Then remember to POKE 23739,244 to restore printing, prior to any RANDOMIZE USR command.
More to add to this page – taken from System Variables in the manual. I will add examples taken from existing programs, to make it easier to understand how they’re used in ZX BASIC:
23627 VARS – Address of variables. (2 bytes)
23635 PROG – Address of BASIC program. (2 bytes)
23660 S TOP – The number of the top program line in automatic listings. (2 bytes)
23670 SEED – The seed for RND. This is the variable that is set by RANDOMIZE. (2 bytes)
23675 UDG – Address of 1st user defined graphic You can change this for instance to save space by having fewer user defined graphics. (2 bytes)
23692 SCR CT – Counts scrolls: it is always 1 more than the number of scrolls that will be done before stopping with scroll? If you keep poking this with a number bigger than 1 (say 255), the screen will scroll on and on without asking you. (1 byte)
23693 ATTR P – Permanent current colours, etc (as set up by colour statements). (1 byte)
23694 MASK P – Used for transparent colours, etc. Any bit that is 1 shows that the corresponding attribute bit is taken not from ATTR P, but from what is already on the screen. (1 byte)
23695 ATTR T – Temporary current colours, etc (as set up by colour items). (1 byte)
23730 RAMTOP – Address of last byte of BASIC system area. (2 bytes)
23732 P RAMT – Address of last byte of physical RAM. (2 bytes)