Newbie in need of help!

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
symbolshift
New member
Posts: 5
Joined: Thu Oct 05, 2017 11:36 am

Newbie in need of help!

Post by symbolshift »

Hello everyone,

I'm new to z88dk and wonder if anyone could help me. I'd love to use it for my Spectrum games.

Being a bit confused with the documentation and the several libraries, I?m struggling to do two simple things:

- read the keyboard for games
- print UDGs

I've been reading many posts and code examples but I haven?t managed to make them work. I'd love to get a simple code to achive this two tasks.

Thank you in advance and thanks very much to the developers for the fantastic compiler.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Hi symbolshift,

Yes there are two independent libraries for the zx target called classic and newlib. The classic one has some things not in the newlib yet, mainly to do with b&w graphics (line, circle, etc) and the ansi terminal driver. The newlib has a number of things not in classic, mainly the high-colour sprite engines and proportional fonts. Things that both libraries have in common have occasionally been updated in newlib so there are sometimes some small differences in how common functions operate. There are other differences as well.

For newlib there is a short (and incomplete) introduction written by another user learning to use z88dk that might help:
https://github.com/z88dk/z88dk/blob/mas ... Started.md

and there are examples for newlib here:
(generic) https://github.com/z88dk/z88dk/tree/mas ... T/EXAMPLES
(zx) https://github.com/z88dk/z88dk/tree/mas ... XAMPLES/zx

and examples for classic here:
(general, not necessarily generic) https://github.com/z88dk/z88dk/tree/master/examples
(zx) https://github.com/z88dk/z88dk/tree/mas ... s/spectrum

symbolshift wrote:- read the keyboard for games
The classic lib has a version of the input library for direct access to keyboard, joysticks and mice and it has some other joystick functions with similar functionality.

The newlib standardizes around the input library as it is intended to be cross-platform. Some of the functions have had some changes from classic. I'll described newlib here and the tutorial above has one installment that briefly covers some of the input library.

The newlib headers (both included with input.h)
https://github.com/z88dk/z88dk/blob/mas ... cc/input.h
https://github.com/z88dk/z88dk/blob/mas ... input_zx.h

There are two ways to read the keyboard with in_inkey or with scancodes.

in_inkey() is similar to the basic inkey$ function. It scans the entire keyboard and returns 0 (no keypress) if no key is pressed or if more than one key is simultaneously pressed. It understands CAPS, SYMSHIFT and the two together and will return ascii codes according to the instantaneous state of the keyboard.

A scancode is a single 16-bit number that describes which key to check. It can be used even if multiple keys are pressed at the same time. It's a very fast way to look at keys and is meant to be used in games for directions and fire buttons. You can get a scancode in two ways: you can use a predefined one ( https://github.com/z88dk/z88dk/blob/mas ... t_zx.h#L17 ) or you can look one up at runtime using in_key_scancode(int c). The character passed to in_key_scancode() can be anything and the scancode returned with also indicate if CAPS/SYMSHIFT need to be pressed along with the key. A zero return indicates the ascii code cannot be generated on the keyboard. Scan codes can be passed to in_key_pressed() t find out if the corresponding key is currently pressed.

You can also create a keyboard joystick using scancodes. You fill in a structure with scancodes ( https://github.com/z88dk/z88dk/blob/mas ... nput.h#L25 ) and pass it to in_stick_keyboard() ( https://github.com/z88dk/z88dk/blob/mas ... _zx.h#L102 ) to scan the keys and return a joystick value that is equivalent to the values returned by all joystick functions. The joystick functions are intended to be called through a function pointer so that the user can define a joystick to use in a menu and the program can call any of the joystick functions through that to gather input.

Some miscellaneous functions wait for key presses or test for key presses ( https://github.com/z88dk/z88dk/blob/mas ... t_zx.h#L74 ).

in_inkey() and in_key_scancode (which does a table look up to find a scancode corresponding to an ascii char) are relatively big and slow because they use a key translation table and in in_inkey's case must scan the entire keyboard.

Some examples:

Code: Select all

#include <stdio.h>
#include <input.h>

#pragma printf = "%c"   // limit the size of printf

while (1)
{
   unsigned char c;

   while ((c = in_inkey()) == 0) ;   // loop while no keys detected
   printf("%c", c);
}

Code: Select all

#include <stdio.h>
#include <input.h>

#pragma printf = ""   // limit the size of printf

// wait for keypress

in_wait_nokey();   // wait for no keys
in_wait_key();   // wait for key

// wait at most 5 seconds for keypress

in_wait_nokey();
in_pause(5000);

// check if any keys are pressed

if (in_test_key())
   printf("quit banging on the keys!\n");

Code: Select all

#include <stdio.h>
#include <input.h>

unsigned int sc;

// check predefined scancodes

if (in_key_pressed(IN_KEY_SCANCODE_z))
   printf("You are pressing Z\n");

if (in_key_pressed(IN_KEY_SCANCODE_SPACE | 0x8000))   // space + caps flag 0x8000 ; symshift flag is 0x4000
   printf("BREAK pressed\n");

sc = in_key_scancode('$');   // look up the scancode for $

if (in_key_pressed(sc))
   printf("Pressed $\n");
In a game setting, the keyboard joystick is most appropriate for most controls.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

If you're familiar with machine code, the asm implementation of functions will give some documentation and insight into how things work.

newlib input:
https://github.com/z88dk/z88dk/tree/mas ... put/zx/z80

classic input (slightly different api than previously described):
https://github.com/z88dk/z88dk/tree/mas ... t/spectrum
- print UDGs
You can print UDGs through printf. The classic library makes an exception for codes 144 and above so that UDGs are looked up like basic does when printing. Newlib is completely independent from the basic rom and makes no such treatment, instead a font comes from anywhere (the rom charset or one in ram) and you can define one with UDGs or change the font address to point at UDG characters. (Although see startup=30 which has newlib using the basic rom to print which means chars 144+ are udgs; startups are described in that tutorial previously linked).

However, printing like this is not the fastest way to print graphics to screen. Things have to travel through stdio code before they get printed. Instead, a better way to do things is to have your own print char routine that prints to the screen directly, at least if you need to be as fast as possible (compiled c is quick so maybe printf is good enough depending on what you are doing). You will find that in z88dk the effort is made to try to have speed-critical code written in asm in order to push the c to a higher level - hence the sprite engines are written in asm, just like (ideally) speed critical printchar should be in asm.

There are a bunch of functions in z88dk that will perform various computations on coordinates to find addresses corresponding to characters and pixels in the display file:
(newlib) https://github.com/z88dk/z88dk/blob/mas ... /zx.h#L202
(classic, slightly different) https://github.com/z88dk/z88dk/blob/mas ... rum.h#L325

So a simple example to print a string directly to screen (no bounds checking):

Code: Select all

// zcc +zx -vn -startup=31 -clib=new test.c -o test -create-app
// zcc +zx -vn -startup=31 -clib=sdcc_iy -SO3 --max-allocs-per-node200000 test.c -o test -create-app

#include <arch/zx.h>

unsigned char x, y;
unsigned char *font = (unsigned char *)(15360);   // point font into rom character set (I think that's right)

void zx_print_chr(unsigned char *gr)
{
   unsigned char i;
   unsigned char *p;

   p = zx_cxy2saddr(x,y);   // find screen address for character coord x,y

   for (i = 0; i != 6; ++i)
   {
      *p = *gr++;
      p += 256;
   }

   *p = *gr;
}

void zx_print_str(unsigned char *s)
{
   unsigned char c;

   while (c = *s++)
   {
      zx_print_chr(font + c*8);

      if (++x == 32)
      {
         x = 0;
         y++;
      }
   }
}

void main(void)
{
        zx_print_str("Hello World");
}
and a machine code version from pietro bros:
https://bitbucket.org/CmGonzalez/pietro ... zx.asm-107

A low level frequently used function like this is ideally written in asm although zsdcc especially does a fairly good job with this code (add "--list" to the compile line to see the asm generated).
Timmy
Well known member
Posts: 185
Joined: Sat Mar 10, 2012 4:18 pm

Post by Timmy »

alvin wrote:For newlib there is a short (and incomplete) introduction written by another user learning to use z88dk that might help:
https://github.com/z88dk/z88dk/blob/mas ... Started.md
Wow, this is a nice link! Where did you got that from?

Maybe I can write something similar, too. I'm a bit busy right now, but it looks cool.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Timmy wrote:
alvin wrote:For newlib there is a short (and incomplete) introduction written by another user learning to use z88dk that might help:
https://github.com/z88dk/z88dk/blob/mas ... Started.md
Wow, this is a nice link! Where did you got that from?
It was written by thricenightly at wos. It's really well written and a good start but of course there is still lots to go and he's taken a bit of a break after the bifrost thing which took him a long time to come to grips with, especially sorting out issues of memory map and so on.

A zx next specific one would also be good as it's going to have quite a lot of differences in terms of tooling and libraries.
symbolshift
New member
Posts: 5
Joined: Thu Oct 05, 2017 11:36 am

Post by symbolshift »

Hello!

Thank you very much for your thorough and amazingly prompt reply!

I've been reading the suggested links, all very helpful so far.

Thank you also for adding your own examples, this is very kind.

It seems I was having trouble with choosing the right lib and runtimes. Still I have to make more tests and then I'll post again.
symbolshift
New member
Posts: 5
Joined: Thu Oct 05, 2017 11:36 am

Post by symbolshift »

Hello Alvin!

As promised, I'm posting again: My little (and first ever in C) game is almost completed. Having a loading screen would be nice for me, I've tried the instructions in the Wiki section but haven't been able to make it work.

My program is compiled using:

+zx -vn -startup=1 -clib=sdcc_iy -o2 program.c -o program -create-app

Could you please help me adding a loading screen to the final .tap?


Thank you in advance and thank you again to the z88dk team!
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

My little (and first ever in C) game is almost completed
Nice!
zcc +zx -vn -startup=1 -clib=sdcc_iy -SO3 --max-allocs-per-node200000 program.c -o program -create-app
I added some optimization options to your compile above. You can also add "--opt-code-size" if you want it. This high optimization level will mean a much longer compile time. The defaults are -SO2 and --max-allocs-per-node3000. The -O2 you had is the default, however for zsdcc compiles (as opposed to sccz80), the -O levels are not actually for optimization. Instead they are there to fix certain code generation bugs and to translate the non-standard z80 that zsdcc outputs to more standard form (see https://www.z88dk.org/wiki/doku.php?id=temp:front#sdcc3 )
Could you please help me adding a loading screen to the final .tap?
Sure. The automatic tap generation used when -create-app is present makes a basic loader that loads and runs the compiled code only. But if you want to do something else, like load a screen$, you have to write your own basic loader and construct the tap file manually. This is actually easy to do because tap files can be concatenated together.

So first you make a basic loader, for example:

Code: Select all

10 BORDER 0:INK 0:PAPER 0
20 CLEAR 32767
30 LOAD ""SCREEN$
40 POKE 23739,111
50 LOAD ""CODE
60 RANDOMIZE USR 32768
And then save that as an auto-starting program to a tap file with something like 'SAVE "prog"LINE 1'

Most emulators will allow you to type in a program and create a tap file this way. But there are also tools that will take a text file containing a BASIC program like the above and generate a tap file for it. For example bas2tap ( https://bitbucket.org/CmGonzalez/gandal ... ?at=master ). There's a windows executable there and the source file to compile on other platforms.

bas2tap -sName -a10 loader.bas loader.tap

will create a basic tap "loader.tap" autostarting at line 10 from the text file "loader.bas". "Name" will be the name of the program seen on screen while loading (remember "Program: Name").

If you look at the basic loader, it expects to load a screen$ followed by the compiled program.

So you make make taps out of those. You can use appmake in z88dk to do that.

Suppose your screen$ is a binary file "screen.bin". Appmake can be used to make a tap out of that (appmake +zx will show options):

appmake +zx -b screen.bin -o screen.tap --org 16384 --noloader --blockname art
A tap file "screen.tap" containing "screen.bin" will be created.

Do the same for your output binary.

zcc +zx -vn -startup=1 -clib=sdcc_iy -SO3 --max-allocs-per-node200000 program.c -o program
(note that -create-app has been dropped - the output binary will be "program_CODE.bin")

appmake +zx -b program_CODE.bin -o program.tap --org 32768 --noloader --blockname game
A tap file "program.tap" containing "program_CODE.bin" will be created.

Then put them all together to form the final tap:

(windows)
copy /b loader.tap + screen.tap + program.tap game.tap

(linux)
cat loader.tap screen.tap program.tap > game.tap


In the above I assumed your program org was 32768. If it isn't, you'll have to change the CLEAR address and RAND USR in the basic loader and the --org in the appmake invoke.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

The POKE makes sure there is no "Code: ..." printed over top the screen$ when the next part loads. It may interfere with -startup=30 which uses rst$10 to print but I am not sure about that.
thricenightly
Member
Posts: 28
Joined: Thu Jun 01, 2017 5:46 pm

Post by thricenightly »

alvin wrote:
Timmy wrote:
alvin wrote:For newlib there is a short (and incomplete) introduction written by another user learning to use z88dk that might help:
https://github.com/z88dk/z88dk/blob/mas ... Started.md
Wow, this is a nice link! Where did you got that from?
It was written by thricenightly at wos. It's really well written and a good start but of course there is still lots to go and he's taken a bit of a break after the bifrost thing which took him a long time to come to grips with, especially sorting out issues of memory map and so on.
Not so much a "break" as a "recovery"! I got very sick last summer and the recovery period has run into many months. But I'm getting back to normal and have picked up some Spectrum work again. The problem is, like the OP, I'm learning this as I go, and the more I delve into more complex stuff the longer it all takes. :)

I've had a look at interrupts, and took the chance to fiddle with some z88dk internals. I'll document that next. What I really want to do is investigate the SP1 library, but each time I try to make a start it all looks insurmountable!
symbolshift
New member
Posts: 5
Joined: Thu Oct 05, 2017 11:36 am

Post by symbolshift »

Alvin! Hello!

It works perfectly! Loading screen included in my project, I'm very excited about this and extremely thankful for your help.
User avatar
dom
Well known member
Posts: 1319
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

I honestly don't know how long it's been there, but appmake actually supports inserting a SCREEN$ into the .TAP by itself using the --screen option. So from a zcc command line you just add -Cz--screen=[SCREEN$ file]. This evening I added in the missing poke so the screen isn't corrupted when the program itself is loaded.
stefano
Well known member
Posts: 1637
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

There should be also a screen$ option for the turbotape appmake variant.

That 'turbo' mode is quite special, the data is created directly in wav format (at an average pitch giving good stability also in case of crap audio equipment) with an RLE encoding technique enabled by specific audio gaps. The turbo loader recognizes such "special audio periods" and speeds-up by reading the next bits to repeat a whole byte.

The predictive encoding was not possible at those times but the loader will work perfectly on any original Spectrum with a simple tape recorder.

Two more curiosities:
- the existing software copiers won't work on this audio steam ;)
- the wav files created by appmake can be compressed *very* efficiently, please try ;)
symbolshift
New member
Posts: 5
Joined: Thu Oct 05, 2017 11:36 am

Post by symbolshift »

dom wrote:I honestly don't know how long it's been there, but appmake actually supports inserting a SCREEN$ into the .TAP by itself using the --screen option. So from a zcc command line you just add -Cz--screen=[SCREEN$ file]. This evening I added in the missing poke so the screen isn't corrupted when the program itself is loaded.
Thank you Dom!

I will try your suggestion also.
RobertK
Well known member
Posts: 218
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

I will use this existing thread to ask a few very simple beginner's questions.

First: how do I print the ZX81's graphic characters using printf()?

I know that using capital letters in the printf() parameter string will output the respective inverse characters. But what about the rest of the character set?

The solution is probably to use the \x statement (followed by the characters's hex code) within the string parameter.

After some experimenting I found out that this will print the "A" character:

Code: Select all

printf("character 97 (hex 61) is \x61.\n");
But looking at the ZX81 character set table I have no idea why 0x61 is the hex code of the A character. Can anyone please tell me how to determine the \x hex code of the desired character?
User avatar
dom
Well known member
Posts: 1319
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

For the ZX81, ZX80, Lambda there's some translation going on from ASCII to their character sets. The conversion tables (for symbols outside of [A-Za-z0-9] are defined here: https://github.com/z88dk/z88dk/blob/mas ... cnvtab.asm

Looking at them it looks like graphics can't be printed using the standard printf routines at the moment. I'm guessing that code 128-148 would probably be a good space to slot them in.
RobertK
Well known member
Posts: 218
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

Thanks, so printf() currently won't help much. I have found out it can print a few characters (but not all), these are:

Code: Select all

printf("-------------\n");
printf("\x23 \x27 \x40 \x5b \x5d \x5f \x60");
Image

BTW, is there a platform-independent way to output text to a specific screen location?

For the ZX81 I have so far been using this method taken from the z8048 game source code:

Code: Select all

#include <stdio.h>                // required for zxTextOut()

char *display;
extern int d_file @16396;

void zxTextOut(int x, int y, const char* text)        // taken from z8048.c written by sirmorris
{
        // writes a text to the specified x,y screen position
        char* dm = display + x + (33 * y);
        while (*text)
        {
                *dm = ascii_zx(*text);
                
                ++text;
                ++dm;
        }
}
And how could I output graphic characterss by specifying their character codes, either using a modified version of this function or a platform-independent one?
RobertK
Well known member
Posts: 218
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

RobertK wrote:I have found out it can print a few characters (but not all), these are:

Code: Select all

printf("-------------\n");
printf("\x23 \x27 \x40 \x5b \x5d \x5f \x60");
Here is the screenshot, the previous upload did not work:

Image
User avatar
dom
Well known member
Posts: 1319
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

BTW, is there a platform-independent way to output text to a specific screen location?
Short answer is no. But conio.h is fairly close - this uses the ANSI display printer if it's available on a platform (and it is for ZX80, ZX81, Jupiter Ace)

If you're looking to do cross platform then I can recommend taking a look at Fabrizio's cross-chase: https://github.com/Fabrizio-Caruso/CROSS-CHASE
And how could I output graphic characterss by specifying their character codes, either using a modified version of this function or a platform-independent one?
I think if you change *dm = ascii_zx(*text); to *dm = *text; you should be able to print using ZX81 codes. I suspect the characters you've found that work have been mapped through from standard ASCII symbols because "they look like the character they're trying to represent but isn't actually available on the ZX81"
RobertK
Well known member
Posts: 218
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

When I check like this what system my program is running on (i.e. what system it has been compiled for)...

Code: Select all

#if defined(__ZX81__) || defined(__ZX80__) || defined(__ACE__) || defined(__GAL__)
        ...
#endif
...the constant's name seems to be identical to the target system name that you specify in the zcc command line (e.g. zcc +zx81 ...).

This works correctly at least for these constants:

__ZX81__
__ZX80__
__ACE__
__GAL__
__AQUARIUS__
__TRS80__
__Z1013__

But for the following systems it does not work:

__VG5K__
__VZ__
__MZ__

Do I have to use other constants for these three systems (Philips VG5000, V-Tech VZ200, Sharp MZ)?

And one more question: how can I identify the sub-type "EG2000"? This is a sub-type of the TRS-80 system, so here __TRS80__ is defined, but I would like to differentiate between TRS-80 and EG2000.
User avatar
dom
Well known member
Posts: 1319
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

The config files in lib/config/ reveal the answers:

VG5k: -DVG5000 -D__VG5000__
VZ: -DVZ200 -D__VZ200__
MZ: -DSHARPMZ -D__SHARPMZ__

There's nothing for the EG2000 at moment, we can add one in pretty easily.
RobertK
Well known member
Posts: 218
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

dom wrote:The config files in lib/config/ reveal the answers:
Ah, there it is, thanks!
dom wrote:There's nothing for the EG2000 at moment, we can add one in pretty easily.
Please do so, because the EG2000 has a different lo-res screen resolution than the TRS-80, so we need to know what system our program is running on.
stefano
Well known member
Posts: 1637
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

> I have found out it can print a few characters (but not all), these are:
> (...)

My memory is very bad in this period, but I think it is possible to disable the conversion function by calling zx_asciimode():

; Activates /deactivates the ZX81<->ASCII converter
; mode=0 ..disable
; other values ..enable

I also introduced a VT-ANSI character output variant recently, which should give some different collision between printable characters and control codes.
RobertK
Well known member
Posts: 218
Joined: Mon Feb 26, 2018 12:58 pm

Post by RobertK »

dom wrote:
BTW, is there a platform-independent way to output text to a specific screen location?
Short answer is no. But conio.h is fairly close - this uses the ANSI display printer if it's available on a platform (and it is for ZX80, ZX81, Jupiter Ace)

If you're looking to do cross platform then I can recommend taking a look at Fabrizio's cross-chase: https://github.com/Fabrizio-Caruso/CROSS-CHASE
Thanks for the conio.h hint, I tried it for the Jupiter Ace and it works great. I will first concentrate on targets that support low-res plotting *and* VT100 Console I/O.

How it can be done for other targets can be seen in the Cross Chase source file z88dk_conio_implementation.h. There Fabrizio redefines the gotoxy() command for various platforms:

Code: Select all

        #if defined(__SPECTRUM__)
                #if defined(SPECTRUM_NATIVE_DIRECTIVES)
                        #define gotoxy(x,y) printf("\x16%c%c",y+32,x+32);
                #else
                        #define gotoxy(x,y) printf("\x16%c%c",x+1,y+1); 
                #endif
        #elif defined(__ZX81__)        || defined(__ZX80__) || defined(__LAMBDA__)
                #undef gotoxy
                #define gotoxy(x,y) zx_setcursorpos(y,x)
        #elif defined(__ENTERPRISE__) || defined(__MTX__)
                #define gotoxy(x,y) printf("\x16%c%c",x+1,y+1); 
        #elif defined(__SVI__) || defined(__MSX__)
                #define gotoxy(a,b)     printf("\033Y%c%c",b+31+1,a+31)
                #define clrscr() printf("\033E")
                #define cprintf printf
                #define _cprintf printf
                #define cputs puts_cons
                #define _cputs puts_cons
                #define cgets gets
                #define _cgets gets        
        #else
        #endif
And finally I have found out that a zx_setcursorpos() function exists for the ZX81/ZX80, so I don't need that zxTextOut() function at all. The sample program I was looking at was probably from a time before that function was introduced.

stefano wrote:My memory is very bad in this period, but I think it is possible to disable the conversion function by calling zx_asciimode():
Exactly, that's the trick! The German-language ZX81 forum team have made a z88dk C tutorial (English translation is here but misses some pictures), and chapter 13 and chapter 17 describe how to disable and enable the character code conversion.

Here is a sample program I have written:

Code: Select all

// zcc +zx81 -startup=2 -o printtest4 -create-app printtest4.c

#include <stdio.h>                        // required for zxTextOut()

void main(void) {
        char textP1[25];
        char textP2[25];

        printf("%c",12);                                         // clear the screen          
        
        // Graphic characters test
        zx_asciimode(1);        // activate the ZX81 <-> ASCII converter (not necessary here as it is on by default)
        printf("\nprintf...\n");
        zx_asciimode(0);        // deactivate the ZX81 <-> ASCII converter
        printf("%c%c%c%c%c%c%c%c%c%c\n", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // for some reason characters 8, 9, and 10 do not appear
        printf("%c%c%c%c%c%c%c%c%c%c%c\n\n", 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138);

    zx_asciimode(1);        // activate the ZX81 <-> ASCII converter        
        printf("\nsprintf and printf...\n");
    zx_asciimode(0);        // deactivate the ZX81 <-> ASCII converter
        sprintf(textP1,"%c%c%c%c%c%c%c%c%c%c\n", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // for some reason characters 8, 9, and 10 do not appear
        sprintf(textP2,"%c%c%c%c%c%c%c%c%c%c%c\n\n", 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138);
        
        printf(textP1);
        printf("\n");
        printf("%s\n",textP2);        // this method works as well

    zx_asciimode(1);        // activate the ZX81 <-> ASCII converter
        printf("\nzx-setcursorpos and printf...\n");
        zx_asciimode(0);        // deactivate the ZX81 <-> ASCII converter
        zx_setcursorpos(17,3);
        printf(textP1);
        zx_setcursorpos(18,3);
        printf(textP2);
        zx_asciimode(1);        // activate the ZX81 <-> ASCII converter
        
        fgetc_cons(); // wait for keypress
    return;
}
With that I can now print all characters I need at any screen position, thanks.
But is there a reason why the characters number 8, 9 and 10 do not appear on the screen?
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

> But is there a reason why the characters number 8, 9 and 10 do not appear on the screen?

8 is usually backspace and 10 is \r on machines that swap \r and \n (like the zx81 I think). That could be the reason but I am not too familiar with the zx81 codebase.
Post Reply