ZX Spectrum Multi User Dungeon (MUD)
ZX Spectrum Multi User Dungeon (MUD)
Many years ago, I was fortunate to be at a school with multiple networked BBC Masters. The machines were networked using Econet, there was also a file server connected to a Winchester HDD (30MB if my memory serves me well). This allowed us to play a game called 'The Cave'. The game was a multi user dungeon, a text adventure with multiple users. Some hours were spent mucking about roaming the cave, bashing teachers/1st years/noobs. Much fun was had. This was in fact my very first experience of online gaming.
Fast forward to around 1998 when I finally had a modem and access to the internet. By this time MUD's had come a long way. Class based adventuring with huge worlds to explore and puzzles to solve. Shops, traders and currency were all now part of adventure systems. Many hours were lost leveling characters and diving deep into player generated lore.
MUD's are very different to usual text adventures. Politics and social structures play a huge part in the game, which can bring extra enjoyment to text adventuring but can also bring drama and upset. So MUD's may not be for all text adventure fans, some preferring the solo questing found on traditional text adventures.
I am tinkering with the idea of making a ZX Spectrum MUD client. MUD's are a server/client system. All of the game data and processing is done server side. The client is a simple Telnet client, a dumb terminal. On the PC many customised telnet clients have been made that give you many MUD related functions. I intend to code a telnet client that is totally geared toward MUD's.
My progress so far is purely server side. I have managed to compile a build of CircleMUD (based on DikuMUD) and have had it up and running, tested with a Linux telnet client. CircleMUD has some great resources for editing the files that create the world. It is a full feature server that has shops, mobile non-player characters, objects, combat and much more. It also has a way of editing the world from inside the game, which allows people to easily collaborate with the building of the world. So, I think I have the server side sorted, although I have plenty to learn about the admin. I have compiled the code on a RaspberryPi 2 I had spare. I can keep the server on 24/7 at little cost to me. I am a little worried about the security risk as I will have to give out my home IP and forward a port to the Pi, so maybe I could get some advice on this. I may need a VPN or some such. For now I would be fine to give my IP in DM to interested parties. Currently the server is loaded with the default world, which works just fine. I intend to alter this soon, the start location will be the Baron of Beef pub, maybe have a Sir Clive and Chris Curry mobile.
The client side will be written for Spectranet. I do not have hardware sadly, my two real speccies are not in good working order so I think spending out for a Spectranet card would be unwise at this time (this may change soon). FUSE does have excellent Spectranet support though, and I can develop with this. If interest is there I would like to make a SpecNEXT version and also a version for Russian clones and other Spectrum networking interfaces. I would need help for those.
I am posting this to create a thread to gauge interest and to ramble about the client code.
Links for more info:
CircleMUD documentation : https://www.circlemud.org/cdp/
MUD Wikipedia page : https://en.wikipedia.org/wiki/MUD
MUD's can be also used as a chatroom, similar to IRC. More fun than IRC because the emotes are more complex and object based, and you can bash each other with a wide array of blunt and sharpened instruments.
Please reply if this idea interests you, or if you have any ideas of the direction of the project.
Fast forward to around 1998 when I finally had a modem and access to the internet. By this time MUD's had come a long way. Class based adventuring with huge worlds to explore and puzzles to solve. Shops, traders and currency were all now part of adventure systems. Many hours were lost leveling characters and diving deep into player generated lore.
MUD's are very different to usual text adventures. Politics and social structures play a huge part in the game, which can bring extra enjoyment to text adventuring but can also bring drama and upset. So MUD's may not be for all text adventure fans, some preferring the solo questing found on traditional text adventures.
I am tinkering with the idea of making a ZX Spectrum MUD client. MUD's are a server/client system. All of the game data and processing is done server side. The client is a simple Telnet client, a dumb terminal. On the PC many customised telnet clients have been made that give you many MUD related functions. I intend to code a telnet client that is totally geared toward MUD's.
My progress so far is purely server side. I have managed to compile a build of CircleMUD (based on DikuMUD) and have had it up and running, tested with a Linux telnet client. CircleMUD has some great resources for editing the files that create the world. It is a full feature server that has shops, mobile non-player characters, objects, combat and much more. It also has a way of editing the world from inside the game, which allows people to easily collaborate with the building of the world. So, I think I have the server side sorted, although I have plenty to learn about the admin. I have compiled the code on a RaspberryPi 2 I had spare. I can keep the server on 24/7 at little cost to me. I am a little worried about the security risk as I will have to give out my home IP and forward a port to the Pi, so maybe I could get some advice on this. I may need a VPN or some such. For now I would be fine to give my IP in DM to interested parties. Currently the server is loaded with the default world, which works just fine. I intend to alter this soon, the start location will be the Baron of Beef pub, maybe have a Sir Clive and Chris Curry mobile.
The client side will be written for Spectranet. I do not have hardware sadly, my two real speccies are not in good working order so I think spending out for a Spectranet card would be unwise at this time (this may change soon). FUSE does have excellent Spectranet support though, and I can develop with this. If interest is there I would like to make a SpecNEXT version and also a version for Russian clones and other Spectrum networking interfaces. I would need help for those.
I am posting this to create a thread to gauge interest and to ramble about the client code.
Links for more info:
CircleMUD documentation : https://www.circlemud.org/cdp/
MUD Wikipedia page : https://en.wikipedia.org/wiki/MUD
MUD's can be also used as a chatroom, similar to IRC. More fun than IRC because the emotes are more complex and object based, and you can bash each other with a wide array of blunt and sharpened instruments.
Please reply if this idea interests you, or if you have any ideas of the direction of the project.
Re: ZX Spectrum Multi User Dungeon (MUD)
Sounds like a perfect use for Spectranet. My Speccy and Spectranet have been packed away in the loft for a few years - but I would be keen to try this out if it, and my Speccy, see the light of day.
Re: ZX Spectrum Multi User Dungeon (MUD)
[mention]p13z[/mention] Thanks for the feed back. It will take me some time to code the client, but once I get something useful to test it would be great if you can help with a proper hardware test.
Re: ZX Spectrum Multi User Dungeon (MUD)
Update:
Baby steps have been taken with the coding of the client. I have successfully got the Spectrum communicating with the server. At this point the client only receives the greeting message from the MUD after sending a handshake. Not much, but I am am pretty chuffed.
I have decided to use the 42 column print routine that is built into the Spectranet ROM. I was going to use a proportional spaced text, but a fixed column print mode is better for formatting text and for ASCII art. CircleMUD is geared for an 80 column terminal so I will have to make code which neatly wraps the text into a 42 column client. Some texts will have to be altered in the MUD to accommodate the 42 columns.
To Do's:
Code a scroll routine to scroll the output text.
Code the keyboard input and send text routine.
Code a socket polling routine that checks the socket for incoming text.
Decisions to be made:
How will I handle the text? Do I store a buffer of text that can be rolled back, it would be useful to be able to do this as text comes at you fast in a busy MUD? Do I simply have a 'more..' message when the incoming text goes over the 28 lines of the client screen, wait for the user to hit a key to continue and discard the text which leaves the screen?
At this point I would really like to say a huge thanks to Winston (Dylan Smith), [mention]Guesser[/mention] and all the other people involved in making the Spectranet and the excellent documentation. Also a big thanks to the authors/maintainers of the FUSE project.
Code:
labels.asm contains declarations of all the entry points and constants used by the Spectranet. It is an abridged version of spectranet.inc.
Client code. Basically the code from Tutorial 3 on the wiki with minor tweaks, with an additional custom CLEAR42 to place a title bar and use colours other than white on blue provided by the ROM. I am using a local IP at this point.
Baby steps have been taken with the coding of the client. I have successfully got the Spectrum communicating with the server. At this point the client only receives the greeting message from the MUD after sending a handshake. Not much, but I am am pretty chuffed.
I have decided to use the 42 column print routine that is built into the Spectranet ROM. I was going to use a proportional spaced text, but a fixed column print mode is better for formatting text and for ASCII art. CircleMUD is geared for an 80 column terminal so I will have to make code which neatly wraps the text into a 42 column client. Some texts will have to be altered in the MUD to accommodate the 42 columns.
To Do's:
Code a scroll routine to scroll the output text.
Code the keyboard input and send text routine.
Code a socket polling routine that checks the socket for incoming text.
Decisions to be made:
How will I handle the text? Do I store a buffer of text that can be rolled back, it would be useful to be able to do this as text comes at you fast in a busy MUD? Do I simply have a 'more..' message when the incoming text goes over the 28 lines of the client screen, wait for the user to hit a key to continue and discard the text which leaves the screen?
At this point I would really like to say a huge thanks to Winston (Dylan Smith), [mention]Guesser[/mention] and all the other people involved in making the Spectranet and the excellent documentation. Also a big thanks to the authors/maintainers of the FUSE project.
Code:
Spoiler
labels.asm contains declarations of all the entry points and constants used by the Spectranet. It is an abridged version of spectranet.inc.
Code: Select all
;;; Defined Labels
; Hardware page-in entry points
PAGEIN equ 0x3FF9
PAGEOUT equ 0x007C
HLCALL equ 0x3FFA
IXCALL equ 0x3FFD
; Jump table entry points
SOCKET equ 0x3E00 ; Allocate a socket
CLOSE equ 0x3E03 ; Close a socket
LISTEN equ 0x3E06 ; Listen for incoming connections
ACCEPT equ 0x3E09 ; Accept an incoming connection
BIND equ 0x3E0C ; Bind a local address to a socket
CONNECT equ 0x3E0F ; Connect to a remote host
SEND equ 0x3E12 ; Send data
RECV equ 0x3E15 ; Receive data
POLL equ 0x3E1E ; Poll a list of sockets
POLLALL equ 0x3E21 ; Poll all open sockets
POLLFD equ 0x3E24 ; Poll a single socket
GETHOSTBYNAME equ 0x3E27 ; Look up a hostname
PUTCHAR42 equ 0x3E2A ; 42 column print write a character
PRINT42 equ 0x3E2D ; 42 column print a null terminated string
CLEAR42 equ 0x3E30 ; Clear the screen and reset 42-col print
LONG2IPSTRING equ 0x3E39 ; Convert a 4 byte big endian long to an IP
IPSTRING2LONG equ 0x3E3C ; Convert an IP to a 4 byte big endian long
ITOA8 equ 0x3E3F ; Convert a byte to ascii
RAND16 equ 0x3E42 ; 16 bit PRNG
GETKEY equ 0x3E66 ; Get a key from the keyboard, and put it in A
KEYUP equ 0x3E69 ; Wait for key release
INPUTSTRING equ 0x3E6C ; Read a string into buffer at DE
; POLL status bits
BIT_RECV equ 2
BIT_DISCON equ 1
BIT_CONN equ 0
;;; Socket Types (added by me from socket.h)
AF_INET equ 0
SOCK_STREAM equ 1
SOCK_DGRAM equ 2
SOCK_RAW equ 3
;;; System Variables (only available while paged in)
v_column equ 0x3F00
v_row equ 0x3F01
v_rowcount equ 0x3F03
Code: Select all
; A simple TCP client - this goes along with the following:
; http://spectrum.alioth.net/doc/index.php/Spectranet:_Tutorial_3
include "labels.asm"
org 33000 ; Start with RAND USR 33000
call CLS42 ; clear the screen and set cursor
; Open the socket - this simply allocates the resources we
; need, and gives us an identifier (file descriptor) for the socket.
ld c, SOCK_STREAM ; We want a stream - i.e. TCP socket.
ld hl, SOCKET ; Routine to call in ROM - SOCKET.
call HLCALL
jp c, ERROR ; Exit on error.
ld (v_sockfd), a ; Save the socket.
; Connect to the remote host. First print a message saying
; that this is what we're trying.
ld ix, PRINT42
ld hl, STR_connect
call IXCALL
; ...now connect
ld a, (v_sockfd) ; Get the socket file descriptor
ld de, ip_buffer ; DE = the address of the IP address in memory
ld bc, 4000 ; we want to connect to port 4000
ld hl, CONNECT ; call the CONNECT routine
call HLCALL
jp c, ERROR ; carry is set on error.
; Now send some data - 'ping' which will elicit a response.
ld a, (v_sockfd) ; Get the socket file descriptor
ld de, STR_send ; String to send
ld bc, 4 ; which is 18 bytes long
ld hl, SEND ; to be passed to the ROM SEND routine
call HLCALL
jr c, ERROR
; Get the response and print it to the screen. Display a message
; saying we're waiting.
ld ix, PRINT42
ld hl, STR_receiving
call IXCALL
ld a, (v_sockfd)
ld de, resp_buffer ; the buffer we want to fill.
ld bc, 1024 ; up to 1K at a time
ld hl, RECV ; and use the ROM's RECV routine
call HLCALL
jr c, ERROR
; Make sure the returned buffer has a null on the end for
; when we go to print it.
ld hl, resp_buffer
add hl, bc ; BC contains the number of bytes received.
ld (hl), 0 ; put a NULL on the end
ld ix, PRINT42
ld hl, resp_buffer ; and print the data we received
call IXCALL
ld a, (v_sockfd) ; Get the socket fd
ld hl, CLOSE ; and close it.
call HLCALL
ld ix, PRINT42
ld hl, STR_done ; Print 'Done'
call IXCALL
ret
; The next two routines are support routines - exit on error, and print
; a string.
ERROR
ld ix, PRINT42
ld hl, STR_error ; Error string
call IXCALL ; print it
ld a, (v_sockfd)
and a ; is the socket set?
ret z ; no.. but if it is
ld hl, CLOSE ; clean up the socket
call HLCALL
ret
;; Clear the screen, set PRINT42 cursor and set the title bar.
CLS42
ld a, 7
out (254), a ; white border
ld hl, 16384
ld de, 16385
ld bc, 6144
ld (hl), l
ldir
ld (hl), 71 ; bright 1/black paper/white ink
ld bc, 32
ldir
ld (hl), 56 ; white paper/black ink
ld bc, 735
ldir
call PAGEIN
ld a,9
ld (v_column), a
xor a
ld (v_rowcount), a
ld hl, 16384
ld (v_row), hl
ld hl, STR_titlebar ; Title bar string
call PRINT42 ; print it
call PAGEOUT
ld hl, 16385
ld de, stripes
ld b,8
loop1
push bc
push hl
ld a,(de)
ld b,5
loop2
ld (hl),a
inc hl
djnz loop2
inc de
pop hl
call Pixel_Address_Down
pop bc
djnz loop1
ld hl,22529
ld a,66
ld (hl),a
inc hl
ld a,86
ld (hl),a
inc hl
ld a,116
ld (hl),a
inc hl
ld a,101
ld (hl),a
inc hl
ld a,104
ld (hl),a
ret
stripes
defb %00000001
defb %00000011
defb %00000111
defb %00001111
defb %00011111
defb %00111111
defb %01111111
defb %11111111
;; Move HL down one pixel line
Pixel_Address_Down
INC H ; Go down onto the next pixel line
LD A,H ; Check if we have gone onto next character boundary
AND 7
RET NZ ; No, so skip the next bit
LD A,L ; Go onto the next character line
ADD A,32
LD L,A
RET C ; Check if we have gone onto next third of screen
LD A,H ; Yes, so go onto next third
SUB 8
LD H,A
RET
;; Message Strings. Note that the strings are C strings - they are all null terminated.
STR_send defb "ping",0
STR_titlebar defb "SpectraMUD v1.0",10,0
STR_looking defb "Looking up remote host...\r",0
STR_connect defb "Connected...",10,0
STR_receiving defb "Receiving data...",10,0
STR_error defb "Failed!\r",0
STR_done defb "Done.\r",0
;; Variables
v_sockfd defb 0 ; storage for socket file descriptor
ip_buffer defb 192,168,0,43 ; IP address
resp_buffer ; put the response after everything else
Re: ZX Spectrum Multi User Dungeon (MUD)
I'm just an enthusiastic user and advocate (well I've committed a few minor patches).
Re: ZX Spectrum Multi User Dungeon (MUD)
Another update on progress.
Big breakthroughs with client-server communications. I have coded a keyboard entry routine. I have coded a main client loop which polls the socket for incoming data, prints data when it arrives, reads keyboard into a buffer and sends the buffer when enter is hit. So basically a fully working (crude) telnet/MUD client.
https://youtu.be/b7J4Kc_96Aw
Apologies for the odd flashes, my desktop grabber is a bit iffy. I also forgot to move my mouse pointer aside.
ToDo's are :
A text scrolling routine. I am currently using the PRINT42 routine from the SpectraNet ROM. This is great for testing but scrolls the screen in 1/3rds, I want to scroll at least an 8 pixel row at a time. I can put back my title banner once I have a scroll routine working. I also need to add a delete key to the keyboard input.
Text filtering. I need to filter some codes such as the upside-down question mark. I need to add carriage returns to stop words being cut in half due to the 80 column formatting of CircleMUD.
Better error handling. The error routine is vague. I can use the SpectraNet flags to determine what error occurred and print an appropriate message.
Tidy up the MUD files. Some of the MUD file texts can be re formatted to fit a 42 column display more elegantly.
Future Possibilities :
A 10kb text buffer which can be scrolled back with the up cursor key.
Coupling the MUD server with a TNFS file server and have location images. Use a control code in the MUD descriptions that can point to files on the file system. Scroll the images in with the text.
Customized GUI for shops, combat etc.
The Code :
Big breakthroughs with client-server communications. I have coded a keyboard entry routine. I have coded a main client loop which polls the socket for incoming data, prints data when it arrives, reads keyboard into a buffer and sends the buffer when enter is hit. So basically a fully working (crude) telnet/MUD client.
https://youtu.be/b7J4Kc_96Aw
Apologies for the odd flashes, my desktop grabber is a bit iffy. I also forgot to move my mouse pointer aside.
ToDo's are :
A text scrolling routine. I am currently using the PRINT42 routine from the SpectraNet ROM. This is great for testing but scrolls the screen in 1/3rds, I want to scroll at least an 8 pixel row at a time. I can put back my title banner once I have a scroll routine working. I also need to add a delete key to the keyboard input.
Text filtering. I need to filter some codes such as the upside-down question mark. I need to add carriage returns to stop words being cut in half due to the 80 column formatting of CircleMUD.
Better error handling. The error routine is vague. I can use the SpectraNet flags to determine what error occurred and print an appropriate message.
Tidy up the MUD files. Some of the MUD file texts can be re formatted to fit a 42 column display more elegantly.
Future Possibilities :
A 10kb text buffer which can be scrolled back with the up cursor key.
Coupling the MUD server with a TNFS file server and have location images. Use a control code in the MUD descriptions that can point to files on the file system. Scroll the images in with the text.
Customized GUI for shops, combat etc.
The Code :
Spoiler
labels. asm
main code.
Code: Select all
;;; Defined Labels
; Hardware page-in entry points
PAGEIN equ 0x3FF9
PAGEOUT equ 0x007C
HLCALL equ 0x3FFA
IXCALL equ 0x3FFD
; Jump table entry points
SOCKET equ 0x3E00 ; Allocate a socket
CLOSE equ 0x3E03 ; Close a socket
LISTEN equ 0x3E06 ; Listen for incoming connections
ACCEPT equ 0x3E09 ; Accept an incoming connection
BIND equ 0x3E0C ; Bind a local address to a socket
CONNECT equ 0x3E0F ; Connect to a remote host
SEND equ 0x3E12 ; Send data
RECV equ 0x3E15 ; Receive data
POLL equ 0x3E1E ; Poll a list of sockets
POLLALL equ 0x3E21 ; Poll all open sockets
POLLFD equ 0x3E24 ; Poll a single socket
GETHOSTBYNAME equ 0x3E27 ; Look up a hostname
PUTCHAR42 equ 0x3E2A ; 42 column print write a character
PRINT42 equ 0x3E2D ; 42 column print a null terminated string
CLEAR42 equ 0x3E30 ; Clear the screen and reset 42-col print
LONG2IPSTRING equ 0x3E39 ; Convert a 4 byte big endian long to an IP
IPSTRING2LONG equ 0x3E3C ; Convert an IP to a 4 byte big endian long
ITOA8 equ 0x3E3F ; Convert a byte to ascii
RAND16 equ 0x3E42 ; 16 bit PRNG
GETKEY equ 0x3E66 ; Get a key from the keyboard, and put it in A
KEYUP equ 0x3E69 ; Wait for key release
INPUTSTRING equ 0x3E6C ; Read a string into buffer at DE
; POLL status bits
BIT_RECV equ 2
BIT_DISCON equ 1
BIT_CONN equ 0
; POLL events/revents bit field
POLLCON equ 1 ; Host has connected to listening socket (not used in spectraMUD)
POLLHUP equ 2 ; The remote host closed the connection
POLLIN equ 4 ; Data is ready to be received
POLLNVAL equ 128 ; An error occurred during polling
;;; Socket Types (added by me from socket.h)
AF_INET equ 0
SOCK_STREAM equ 1
SOCK_DGRAM equ 2
SOCK_RAW equ 3
;;; System Variables (only available while paged in)
v_column equ 0x3F00
v_row equ 0x3F01
v_rowcount equ 0x3F03
Code: Select all
; A simple TCP client - this goes along with the following:
; http://spectrum.alioth.net/doc/index.php/Spectranet:_Tutorial_3
include "labels.asm"
org 33000 ; Start with RAND USR 33000
call CLS_42 ; clear the screen and set cursor
; Open the socket - this simply allocates the resources we
; need, and gives us an identifier (file descriptor) for the socket.
ld c, SOCK_STREAM ; We want a stream - i.e. TCP socket.
ld hl, SOCKET ; Routine to call in ROM - SOCKET.
call HLCALL
jp c, Error ; Exit on error.
ld (v_sockfd), a ; Save the socket.
; Connect to the remote host. First print a message saying
; that this is what we're trying.
ld ix, PRINT42
ld hl, STR_connect
call IXCALL
; ...now connect
ld a, (v_sockfd) ; Get the socket file descriptor
ld de, ip_buffer ; DE = the address of the IP address in memory
ld bc, 4000 ; we want to connect to port 4000
ld hl, CONNECT ; call the CONNECT routine
call HLCALL
jp c, Error ; carry is set on error.
;; Send a handshake ' ', print a message notifying user of this.
ld ix, PRINT42
ld hl, STR_handshake
call IXCALL
;; Now send some data - ' ' which will elicit a response.
;; not sure why, but you must do this to get the MUD to send the motd/login page.
ld a, (v_sockfd) ; Get the socket file descriptor
ld de, STR_send ; String to send
ld bc, 1 ; which is 1 bytes long
ld hl, SEND ; to be passed to the ROM SEND routine
call HLCALL
jp c, Error
ld b,0 ; use B to count a short delay between socket polls
ld hl,23560 ; LAST K system variable.
ld (hl),b ; put null value there.
;;; And so begins an endless loop
Client_Loop
;; check poll delay
ld a,b
cp 0
jp nz, Skip_Poll
ld b,255 ; reset the delay counter
push bc ; preserve B for delay counter
;; Poll the socket for ready data
ld a, (v_sockfd) ; socket file descriptor
ld hl, POLLFD
call HLCALL ; zero flag is set if sockfd is not ready. Flags returned in C
jp z, Skip_Print ; skip printing if sockfd is not ready
ld a, c ; load the events flags into A
cp POLLIN ; check if data is ready to be recieved
jp nz, Poll_Error ; no data, most likely the host has closed the connection.
call Print_Text ; print incoming text
Skip_Print
pop bc
Skip_Poll
push bc ; preserve B for delay counter
;; Read the keyboard
ld hl,23560 ; LAST K system variable.
ld a,(hl)
cp 0 ; check for null
jr z, non_printable ; no key has been pressed, loop back
ld b,0
ld (hl),b ; put null value there.
cp 13
jp z, return ; check if ENTER has been pressed
cp 32
jp c, non_printable ; check if input char is out of ASCII range (will be a cursor,inverse video or delete)
cp 123
jp nc, non_printable ; check if input char is out of ASCII range (not sure if this is possible)
ld b,a ; put input char into B for safekeeping
ld a,(kb_size)
cp 86
jp z,non_printable ; check if the key buffer is full
inc a
ld (kb_size),a ; increase the buffer size variable by one byte
ld a,b ; retrieve the input char
ld hl,(kb_pointer) ; load HL with the key buffer pointer address
ld (hl),a ; store the char in the buffer
inc hl ; increment the buffer pointer
ld (kb_pointer),hl ; store the buffer pointer
ld hl,PUTCHAR42
call HLCALL
non_printable
pop bc ; retrieve B for delay counter
dec b ; decriment the delay counter
jp Client_Loop
;; We have an ENTER, send the command to the MUD!!
return
ld de,(kb_pointer) ; load DE with the key buffer pointer address
ld hl,STR_terminator ; load HL with the CR+LF string address
ld bc, 2
ldir ; store the chars in the buffer
ld a, (kb_size)
ld c,a
ld b,0 ; load BC with the byte length of the buffer
ld a, (v_sockfd) ; load A with the socket file descriptor
ld de, kb_buffer ; load DE with the address of the keyboard buffer
ld hl, SEND ; to be passed to the ROM SEND routine
call HLCALL
jp c, Error
;; reset the keyboard buffer
xor a ; Load A with zero
ld hl,kb_buffer
ld b,86 ; fill the buffer with zeros
reset_loop
ld (hl),a ; store a zero into buffer
inc hl
djnz reset_loop
ld bc,kb_buffer
ld (kb_pointer),bc ; reset the key buffer pointer
ld a,8
ld (kb_size),a ; reset the key buffer size
pop bc ; retrieve B for delay counter
ld b,0 ; reset the delay counter
;; print a carriage return
ld a,10
ld hl,PUTCHAR42
call HLCALL
jp Client_Loop
;; Exit cleanly to BASIC from main loop
exit
call Close_Socket
ld ix, PRINT42
ld hl, STR_done ; Print 'Done'
call IXCALL
pop bc ; empty the stack for a clean return to BASIC
ret
Print_Text
ld a, (v_sockfd)
ld de, resp_buffer ; the buffer we want to fill.
ld bc, 1024 ; up to 1K at a time
ld hl, RECV ; and use the ROM's RECV routine
call HLCALL
; Make sure the returned buffer has a null on the end for
; when we go to print it.
ld hl, resp_buffer
add hl, bc ; BC contains the number of bytes received.
ld (hl), 0 ; put a NULL on the end
ld ix, PRINT42
ld hl, resp_buffer ; and print the data we received
call IXCALL
ld ix, PRINT42
ld hl, kb_buffer ; print the text input buffer
call IXCALL
ret
;; Error while polling, if the host closed the connection message the user
Poll_Error
cp POLLHUP ; check if host has closed the connection
jp nz,Error ; it must be an error during polling
ld ix, PRINT42
ld hl, STR_host_closed ; Host has closed the connection string
call IXCALL ; print it
pop bc ; empty the stack for a clean return to BASIC
jp Close_Socket
;; Exit on error, and print a vague string.
Error
ld ix, PRINT42
ld hl, STR_error ; Error string
call IXCALL ; print it
;; Close the socket and exit
Close_Socket
ld a, (v_sockfd)
and a ; is the socket set?
ret z ; no.. but if it is
ld hl, CLOSE ; clean up the socket
call HLCALL
ret
;; Clear the screen, set PRINT42 cursor and set the title bar.
CLS_42
ld a, 7
out (254), a ; white border
ld hl, 16384
ld de, 16385
ld bc, 6144
ld (hl), l
ldir
ld (hl), 56 ; bright 1/black paper/white ink (71 for banner)
ld bc, 32
ldir
ld (hl), 56 ; white paper/black ink
ld bc, 735
ldir
call PAGEIN
ld a,0 ; 9 for banner
ld (v_column), a
xor a
ld (v_rowcount), a
ld hl, 16384
ld (v_row), hl
jp skip_banner ; skipping banner for now
ld hl, STR_titlebar ; Title bar string
call PRINT42 ; print it
call PAGEOUT
ld hl, 16385
ld de, stripes
ld b,8
loop1
push bc
push hl
ld a,(de)
ld b,5
loop2
ld (hl),a
inc hl
djnz loop2
inc de
pop hl
call Pixel_Address_Down
pop bc
djnz loop1
ld hl,22529
ld a,66
ld (hl),a
inc hl
ld a,86
ld (hl),a
inc hl
ld a,116
ld (hl),a
inc hl
ld a,101
ld (hl),a
inc hl
ld a,104
ld (hl),a
skip_banner
ret
stripes
defb %00000001
defb %00000011
defb %00000111
defb %00001111
defb %00011111
defb %00111111
defb %01111111
defb %11111111
;; Move HL down one pixel line
Pixel_Address_Down
INC H ; Go down onto the next pixel line
LD A,H ; Check if we have gone onto next character boundary
AND 7
RET NZ ; No, so skip the next bit
LD A,L ; Go onto the next character line
ADD A,32
LD L,A
RET C ; Check if we have gone onto next third of screen
LD A,H ; Yes, so go onto next third
SUB 8
LD H,A
RET
;; Message Strings. Note that the strings are C strings - they are all null terminated.
STR_send defb 32,"ping",13,10,0
STR_titlebar defb "SpectraMUD v1.0",10,0
STR_cursor defb 10,">",0
STR_looking defb "Looking up remote host...",10,0
STR_connect defb "Connecting to MUD...",10,0
STR_handshake defb "Sending handshake...",10,0
STR_host_closed defb 10,"The host has closed the connection!",0
STR_error defb 10,"An error has occured!",0
STR_done defb 10,"Done.",0
STR_not_null defb "nn",0
STR_terminator defb 13,10 ; CR+LF
;; Keyboard buffer and variables (reserve 84 bytes, two lines of text)
kb_buffer
defb 0,0,0,0,0,0,0,0,0,0
defb 0,0,0,0,0,0,0,0,0,0
defb 0,0,0,0,0,0,0,0,0,0
defb 0,0,0,0,0,0,0,0,0,0
defb 0,0,0,0,0,0,0,0,0,0
defb 0,0,0,0,0,0,0,0,0,0
defb 0,0,0,0,0,0,0,0,0,0
defb 0,0,0,0,0,0,0,0,0,0
defb 0,0,0,0
defb 0,0 ; extra 2 bytes for CR+LF termination
kb_pointer
defw kb_buffer
kb_size
defb 2
;; Variables
v_sockfd defb 0 ; storage for socket file descriptor
ip_buffer defb 192,168,0,43 ; IP address
resp_buffer ; put the response after everything else
- Einar Saukas
- Bugaboo
- Posts: 3167
- Joined: Wed Nov 15, 2017 2:48 pm
Re: ZX Spectrum Multi User Dungeon (MUD)
This is looking great!
It has the characteristics of a project that may continue to evolve over time. For this reason, I suggest you move this project to Github and post a link here, instead of posting copies of your code directly.
This will have many advantages. People will be able to easily find the latest version (instead of searching through many posts), it will take a single click to download and try it, it will give your project more visibility, you will have a good place to add an intro page explaining it later, we will be able to add it to ZXDB later with a direct link to it, and so on.
It has the characteristics of a project that may continue to evolve over time. For this reason, I suggest you move this project to Github and post a link here, instead of posting copies of your code directly.
This will have many advantages. People will be able to easily find the latest version (instead of searching through many posts), it will take a single click to download and try it, it will give your project more visibility, you will have a good place to add an intro page explaining it later, we will be able to add it to ZXDB later with a direct link to it, and so on.
Re: ZX Spectrum Multi User Dungeon (MUD)
This sounds very interesting, I'll have to keep an eye on it! (I was playing/coding on a MUD way, way back in 1992 or so, seriously addictive stuff!). While I don't have a Spectranet for my ZX Spectrums I do have the Next dev board and could also help with adapting the client for the SAM Coupé as I gave that an ethernet connection with my Trinity interface.
Quazar - Developing for the SAM Coupé for 30+ Years!
Hardware, Software, 'SAM Revival' magazine -> www.samcoupe.com
Plus hardware for the ZX Spectrum, RC2014 and other general retro peripherals.
Hardware, Software, 'SAM Revival' magazine -> www.samcoupe.com
Plus hardware for the ZX Spectrum, RC2014 and other general retro peripherals.
Re: ZX Spectrum Multi User Dungeon (MUD)
I will look into this. I am not a trained programmer so I am never confident my code is acceptable. I strive to get a piece of code to work, and gain satisfaction when it does what I want it to do. I am never certain I took the best approach. Github does look like a great way to organize and present a project, so I will set one up soon. Thanks for the advice.Einar Saukas wrote: ↑Mon Jul 06, 2020 2:06 pm For this reason, I suggest you move this project to Github and post a link here, instead of posting copies of your code directly.
The MUD server side of things is pretty overwhelming to be honest. There is so much to learn just to get something basic working. I will try to get some Spectrum themed areas working but most likely I will run a slightly altered default CircleMUD (Midgaard, New Thalos etc.) server for any testing. The base world on CircleMUD is pretty huge and fun to explore if you have never played in it. I have never played a stock DikuMUD so it is new content to me. Ultimately I want to have an area aimed at Spectrum users, with a portal into the circleMUD content. I may ask for advice when I get to that stage. I am totally new to the server side of MUD's. I only played in heavily populated MUD's and never got high enough in a guild to get close to editing the content. Wrote a bunch of client side scripts and macro's though. Aye, can be quite addictive.
An eventual NEXT and SAM client would be cool I really wanted a SAM back in the day. By the time I had the income to buy one, the ship had sailed and I went the Amiga route.
Re: ZX Spectrum Multi User Dungeon (MUD)
you don't have to publish some "perfect" code. you don't have to be a "trained professional". that's the whole idea of FOSS -- start something you want to do, and other people will join and help you if they'll like it.MonkZy wrote: ↑Tue Jul 07, 2020 1:16 amI will look into this. I am not a trained programmer so I am never confident my code is acceptable.Einar Saukas wrote: ↑Mon Jul 06, 2020 2:06 pm For this reason, I suggest you move this project to Github and post a link here, instead of posting copies of your code directly.
look at a source code repository as if it is just a backup archive. that archive doesn't have to be in a "perfect" state. and there is no authority to "accept" your code (besides Z80, of course ;-). you just copying your working files to a remove server (with some comments). most people will never expect your commits to be always perfect.
sorry for this long text. i just wanted to encourage you a little. ;-)
Re: ZX Spectrum Multi User Dungeon (MUD)
Not familiar with CircleMUD, admittedly though it's been nearly 3 decades since I was spending hours a day on one. It was a lpMUD I was programming for.
I was late to the SAM scene, didn't get my first until Spring 1993!
Quazar - Developing for the SAM Coupé for 30+ Years!
Hardware, Software, 'SAM Revival' magazine -> www.samcoupe.com
Plus hardware for the ZX Spectrum, RC2014 and other general retro peripherals.
Hardware, Software, 'SAM Revival' magazine -> www.samcoupe.com
Plus hardware for the ZX Spectrum, RC2014 and other general retro peripherals.
Re: ZX Spectrum Multi User Dungeon (MUD)
Update....
Progress has slowed due to work and other distractions but some advances have been made. I have written my own text scrolling routine which is a vast improvement on the scroll used by the spectraNet ROM. I will post the scroll code below. I am very open to suggestions for this routine. The routine + lookup table costs 404 bytes. I am sure there are ways to reduce the size without reducing the speed. I have also added some text formatting to stop words being cut in half. Things look OK, but the MUD data has a carriage return at the end of each 80 character line so some lines leave excess white space at the ends. Really to improve the text formatting, the MUD data would have to be changed. Editing the default circleMUD world would take many hours. I have spent a few hours learning how to structure the MUD files and have added a few new locations and a portal system to gain access to the default circleMUD world. The new locations are more friendly to the 42 char client.
https://www.youtube.com/watch?v=mMpVs27dS00
The assembly for my 52 byte scroll routine.
The routine uses a 352 byte lookup table :
I have also set up a TNFS server on the Pi alongside the MUD server. I will be adding in-line images very soon.
Imminent ToDo's
- Delete key. Still not got one.
- 10kb text buffer, allowing the user to scroll back text to re-read it.
- A 'More..' prompt when the incoming data goes over 21 lines. Client will wait for a space bar before continuing.
I am pretty much ready to put this thing online for testing. My only reservation at this point is security. How much of a risk is forwarding a couple of ports (TCP for the MUD, UDP for the TNFS server) to a Pi running on a standard broadband router?
I could afford to rent some server space and host the two servers on that which would remove the need to publish my home IP, but if it is relatively safe to run TNFS/MUD from home I would do it that way and forgo the cost.
I have set up the TNFS server to deliver the latest version of the SpectraMUD client, so you can set it up as a default filesystem and boot straight into the latest version.
Progress has slowed due to work and other distractions but some advances have been made. I have written my own text scrolling routine which is a vast improvement on the scroll used by the spectraNet ROM. I will post the scroll code below. I am very open to suggestions for this routine. The routine + lookup table costs 404 bytes. I am sure there are ways to reduce the size without reducing the speed. I have also added some text formatting to stop words being cut in half. Things look OK, but the MUD data has a carriage return at the end of each 80 character line so some lines leave excess white space at the ends. Really to improve the text formatting, the MUD data would have to be changed. Editing the default circleMUD world would take many hours. I have spent a few hours learning how to structure the MUD files and have added a few new locations and a portal system to gain access to the default circleMUD world. The new locations are more friendly to the 42 char client.
https://www.youtube.com/watch?v=mMpVs27dS00
The assembly for my 52 byte scroll routine.
Code: Select all
;;; scroll the text window up one row
;;; B = number of rows to scroll up
Scroll_Up
push bc
halt
ld b,168 ; we will loop for 168 lines of screen memory
scroll_loop
push bc
;; source and destination are referenced from a lookup table (screen-lookup.asm)
source
ld hl,(screen_lookup+16) ; source is 8 lines below destination (each line is a 2 byte address)
destination
ld de,(screen_lookup)
ld bc,32 ; copy 32 bytes, the length of one line
ldir ; perform copy
;; increment the source and destination lookup pointers
ld hl,(destination+2) ; ld de,(NN) uses ED prefix hence +2
inc hl
inc hl
ld (destination+2),hl
ld hl,(source+1)
inc hl
inc hl
ld (source+1),hl
pop bc
djnz scroll_loop
;; reset the source and destination pointers
ld hl,screen_lookup+16
ld (source+1),hl
ld hl,screen_lookup
ld (destination+2),hl
pop bc
djnz Scroll_Up
Spoiler
Code: Select all
;;; Lookup table of the address of the first byte of each pixel line
;;; Row 00
;defw 16384 ; 000
;defw 16640 ; 001
;defw 16896 ; 002
;defw 17152 ; 003
;defw 17408 ; 004
;defw 17664 ; 005
;defw 17920 ; 006
;defw 18176 ; 007
;;; Row 01
screen_lookup ;this label marks the top of the scroll window
defw 16416 ; 008
defw 16672 ; 009
defw 16928 ; 010
defw 17184 ; 011
defw 17440 ; 012
defw 17696 ; 013
defw 17952 ; 014
defw 18208 ; 015
;;; Row 02
defw 16448 ; 016
defw 16704 ; 017
defw 16960 ; 018
defw 17216 ; 019
defw 17472 ; 020
defw 17728 ; 021
defw 17984 ; 022
defw 18240 ; 023
;;; Row 03
defw 16480 ; 024
defw 16736 ; 025
defw 16992 ; 026
defw 17248 ; 027
defw 17504 ; 028
defw 17760 ; 029
defw 18016 ; 030
defw 18272 ; 031
;;; Row 04
defw 16512 ; 032
defw 16768 ; 033
defw 17024 ; 034
defw 17280 ; 035
defw 17536 ; 036
defw 17792 ; 037
defw 18048 ; 038
defw 18304 ; 039
;;; Row 05
defw 16544 ; 040
defw 16800 ; 041
defw 17056 ; 042
defw 17312 ; 043
defw 17568 ; 044
defw 17824 ; 045
defw 18080 ; 046
defw 18336 ; 047
;;; Row 06
defw 16576 ; 048
defw 16832 ; 049
defw 17088 ; 050
defw 17344 ; 051
defw 17600 ; 052
defw 17856 ; 053
defw 18112 ; 054
defw 18368 ; 055
;;; Row 07
defw 16608 ; 056
defw 16864 ; 057
defw 17120 ; 058
defw 17376 ; 059
defw 17632 ; 060
defw 17888 ; 061
defw 18144 ; 062
defw 18400 ; 063
;;; Row 08
defw 18432 ; 064
defw 18688 ; 065
defw 18944 ; 066
defw 19200 ; 067
defw 19456 ; 068
defw 19712 ; 069
defw 19968 ; 070
defw 20224 ; 071
;;; Row 09
defw 18464 ; 072
defw 18720 ; 073
defw 18976 ; 074
defw 19232 ; 075
defw 19488 ; 076
defw 19744 ; 077
defw 20000 ; 078
defw 20256 ; 079
;;; Row 10
defw 18496 ; 080
defw 18752 ; 081
defw 19008 ; 082
defw 19264 ; 083
defw 19520 ; 084
defw 19776 ; 085
defw 20032 ; 086
defw 20288 ; 087
;;; Row 11
defw 18528 ; 088
defw 18784 ; 089
defw 19040 ; 090
defw 19296 ; 091
defw 19552 ; 092
defw 19808 ; 093
defw 20064 ; 094
defw 20320 ; 095
;;; Row 12
defw 18560 ; 096
defw 18816 ; 097
defw 19072 ; 098
defw 19328 ; 099
defw 19584 ; 100
defw 19840 ; 101
defw 20096 ; 102
defw 20352 ; 103
;;; Row 13
defw 18592 ; 104
defw 18848 ; 105
defw 19104 ; 106
defw 19360 ; 107
defw 19616 ; 108
defw 19872 ; 109
defw 20128 ; 110
defw 20384 ; 111
;;; Row 14
defw 18624 ; 112
defw 18880 ; 113
defw 19136 ; 114
defw 19392 ; 115
defw 19648 ; 116
defw 19904 ; 117
defw 20160 ; 118
defw 20416 ; 119
;;; Row 15
defw 18656 ; 120
defw 18912 ; 121
defw 19168 ; 122
defw 19424 ; 123
defw 19680 ; 124
defw 19936 ; 125
defw 20192 ; 126
defw 20448 ; 127
;;; Row 16
defw 20480 ; 128
defw 20736 ; 129
defw 20992 ; 130
defw 21248 ; 131
defw 21504 ; 132
defw 21760 ; 133
defw 22016 ; 134
defw 22272 ; 135
;;; Row 17
defw 20512 ; 136
defw 20768 ; 137
defw 21024 ; 138
defw 21280 ; 139
defw 21536 ; 140
defw 21792 ; 141
defw 22048 ; 142
defw 22304 ; 143
;;; Row 18
defw 20544 ; 144
defw 20800 ; 145
defw 21056 ; 146
defw 21312 ; 147
defw 21568 ; 148
defw 21824 ; 149
defw 22080 ; 150
defw 22336 ; 151
;;; Row 19
defw 20576 ; 152
defw 20832 ; 153
defw 21088 ; 154
defw 21344 ; 155
defw 21600 ; 156
defw 21856 ; 157
defw 22112 ; 158
defw 22368 ; 159
;;; Row 20
defw 20608 ; 160
defw 20864 ; 161
defw 21120 ; 162
defw 21376 ; 163
defw 21632 ; 164
defw 21888 ; 165
defw 22144 ; 166
defw 22400 ; 167
;;; Row 21
output_line
defw 20640 ; 168
defw 20896 ; 169
defw 21152 ; 170
defw 21408 ; 171
defw 21664 ; 172
defw 21920 ; 173
defw 22176 ; 174
defw 22432 ; 175
;;; Row 22
defw 20672 ; 176
defw 20928 ; 177
defw 21184 ; 178
defw 21440 ; 179
defw 21696 ; 180
defw 21952 ; 181
defw 22208 ; 182
defw 22464 ; 183
;;; Row 23
status_line
defw 20704 ; 184
;defw 20960 ; 185
;defw 21216 ; 186
;defw 21472 ; 187
;defw 21728 ; 188
;defw 21984 ; 189
;defw 22240 ; 190
;defw 22496 ; 191
Imminent ToDo's
- Delete key. Still not got one.
- 10kb text buffer, allowing the user to scroll back text to re-read it.
- A 'More..' prompt when the incoming data goes over 21 lines. Client will wait for a space bar before continuing.
I am pretty much ready to put this thing online for testing. My only reservation at this point is security. How much of a risk is forwarding a couple of ports (TCP for the MUD, UDP for the TNFS server) to a Pi running on a standard broadband router?
I could afford to rent some server space and host the two servers on that which would remove the need to publish my home IP, but if it is relatively safe to run TNFS/MUD from home I would do it that way and forgo the cost.
I have set up the TNFS server to deliver the latest version of the SpectraMUD client, so you can set it up as a default filesystem and boot straight into the latest version.
Re: ZX Spectrum Multi User Dungeon (MUD)
Definitely set up your file permissions to make the tnfs root read only to the daemon if it's a public server. You can run tnfsd 'chroot' too.
I love the smooth scrolling.
I love the smooth scrolling.
Re: ZX Spectrum Multi User Dungeon (MUD)
Interesting stuff. I spent a good year or so, solidly playing MUDs and MUSHes when I was at Uni in 93/94. Too long probably. As a text adventure fan it was a natural first step in online gaming. Was a regular on Uglymug and EleMUD... It's quite cool to see that they're still around... I even logged in to my old Uglymug account a few years ago and wandered around the rooms I created... Sadly my EleMUD account was long gone and the landscape was almost completely different to what I remembered.
Certainly a fun project. I've seen similar things done on other platforms too. On the BBC they''ve recreated some of the old MUDs in an offline single-player form which is also an interesting way of capturing some elements of the experience.
Certainly a fun project. I've seen similar things done on other platforms too. On the BBC they''ve recreated some of the old MUDs in an offline single-player form which is also an interesting way of capturing some elements of the experience.