..

How to Compile Envy MUD

I have always been fascinated with MUDs, also known as Multi-User Dungeons. They are the World of Warcraft before there was a world to craft war in. It's an interesting mesh between computers and Dungeons and Dragons. Imagination is an important factor, and from my experience, they are a great place for beginning programmers to learn how to code. I first learned how to code in C by programming for a few MUDs.

Compiling your first MUD can be a scary experience, though. Many of the codebases are pre-y2k, thus making some of the processes obsolete. For this demonstration, I will be using the EnvyMUD source code. It is widely used enough that many people can relate to it, and being directly related to DIKUMUD, the processes will be very similar for other DIKU related subservers. The first step will be to download the MUD source code. You can get it from the MUDBytes codebase repository here. The version of Envy I will be using is Envy 2.0 on a current Ubuntu server.

After downloading the Envy source code, you will need to un-tar and un-gzip it:

tar -xvzf envy-20.tar.gz

Next, navigate to the src directory:

cd ./Envy20/src/

Now the fun starts. Run the make command and see what happens:

$ make
gcc -c -O -Wall -g act_comm.c
gcc -c -O -Wall -g act_info.c
gcc -c -O -Wall -g act_move.c
act_move.c: In function 'move_char':
act_move.c:230: warning: suggest explicit braces to avoid ambiguous 'else'
gcc -c -O -Wall -g act_obj.c
gcc -c -O -Wall -g act_wiz.c
act_wiz.c: In function 'do_sset':
act_wiz.c:2296: warning: suggest explicit braces to avoid ambiguous 'else'
gcc -c -O -Wall -g comm.c
comm.c:162: error: conflicting types for 'accept'
/usr/include/sys/socket.h:214: note: previous declaration of 'accept' was here
comm.c:163: error: conflicting types for 'bind'
/usr/include/sys/socket.h:115: note: previous declaration of 'bind' was here
comm.c:165: error: conflicting types for 'getpeername'
/usr/include/sys/socket.h:133: note: previous declaration of 'getpeername' was here
comm.c:166: error: conflicting types for 'getsockname'
/usr/include/sys/socket.h:119: note: previous declaration of 'getsockname' was here
comm.c:169: error: conflicting types for 'read'
/usr/include/bits/unistd.h:35: note: previous definition of 'read' was here
comm.c:173: error: conflicting types for 'write'
/usr/include/unistd.h:363: note: previous declaration of 'write' was here
comm.c: In function 'init_socket':
comm.c:440: warning: ignoring return value of 'system', declared with attribute warn_unused_result
comm.c:490: warning: ignoring return value of 'system', declared with attribute warn_unused_result
comm.c: In function 'nanny':
comm.c:1829: warning: comparison with string literal results in unspecified behavior
make: *** [comm.o] Error 1

Fixing Prototypes

These errors are caused by prototype functions that are no longer needed. To fix this, open up comm.c in your favorite text editor and navigate to line 161. There, you will comment out the following lines:

$ #if	defined( linux )
// int	accept		args( ( int s, struct sockaddr *addr, int *addrlen ) );
// int	bind		args( ( int s, struct sockaddr *name, int namelen ) );
int	close		args( ( int fd ) );
// int	getpeername	args( ( int s, struct sockaddr *name, int *namelen ) );
// int	getsockname	args( ( int s, struct sockaddr *name, int *namelen ) );
// int	gettimeofday	args( ( struct timeval *tp, struct timezone *tzp ) );
int	listen		args( ( int s, int backlog ) );
int	read		args( ( int fd, char *buf, int nbyte ) );
int	select		args( ( int width, fd_set *readfds, fd_set *writefds,
			    fd_set *exceptfds, struct timeval *timeout ) );
int	socket		args( ( int domain, int type, int protocol ) );
int	write		args( ( int fd, char *buf, int nbyte ) );
#endif

Get Crypty With It

Now, you could re-run the make command, but there's a good chance it will still error out because the crypt library hasn't been properly setup or linked. I won't walk you through how to install libcrypt in your operating system of choice (probably something like apt install libcrypt-dev, but YMMV), but when it is installed, you have to pull in the headers and make sure it is linked in the compiler.

The first thing we need to do is open up both act_info.c and comm.c and add the following line at the top of the file, just before the #include "merc.h" directive:

#include <crypt.h>

Next, we need to add the -lcrypt flag to the envy target in the Makefile, like so:

envy: $(O_FILES)
	rm -f envy
	$(CC) $(L_FLAGS) -o envy $(O_FILES) -lcrypt

Bring It All Together

If we did everything above right, then run make again and you should get a successful build:

$ make
gcc -c -O -Wall -g comm.c
comm.c: In function 'init_socket':
comm.c:440: warning: ignoring return value of 'system', declared with attribute warn_unused_result
comm.c:490: warning: ignoring return value of 'system', declared with attribute warn_unused_result
comm.c: In function 'new_descriptor':
comm.c:870: warning: pointer targets in passing argument 3 of 'getsockname' differ in signedness
/usr/include/sys/socket.h:119: note: expected 'socklen_t * __restrict__' but argument is of type 'int *'
comm.c:871: warning: pointer targets in passing argument 3 of 'accept' differ in signedness
/usr/include/sys/socket.h:214: note: expected 'socklen_t * __restrict__' but argument is of type 'int *'
comm.c:914: warning: pointer targets in passing argument 3 of 'getpeername' differ in signedness
/usr/include/sys/socket.h:133: note: expected 'socklen_t * __restrict__' but argument is of type 'int *'
comm.c: In function 'nanny':
comm.c:1829: warning: comparison with string literal results in unspecified behavior
gcc -c -O -Wall -g const.c
gcc -c -O -Wall -g db.c
gcc -c -O -Wall -g fight.c
gcc -c -O -Wall -g handler.c
gcc -c -O -Wall -g interp.c
interp.c:436:50: warning: trigraph ??' ignored, use -trigraphs to enable
interp.c:437:50: warning: trigraph ??' ignored, use -trigraphs to enable
interp.c:438:55: warning: trigraph ??' ignored, use -trigraphs to enable
interp.c:439:56: warning: trigraph ??' ignored, use -trigraphs to enable
interp.c:440:56: warning: trigraph ??' ignored, use -trigraphs to enable
gcc -c -O -Wall -g magic.c
gcc -c -O -Wall -g save.c
save.c: In function 'load_char_obj':
save.c:406: warning: ignoring return value of 'system', declared with attribute warn_unused_result
gcc -c -O -Wall -g special.c
gcc -c -O -Wall -g update.c
rm -f envy
gcc -O -lcrypt -o envy act_comm.o act_info.o act_move.o act_obj.o act_wiz.o comm.o const.o db.o fight.o handler.o interp.o magic.o save.o special.o update.o

Now, we need to start the game up. If you are on a modern Ubuntu version like I am, run the following:

nohup ./startupSH &

That's it! You have just started your first MUD on port 4000! To log into your game from the localhost, just type the following:

telnet localhost 4000

Congratulations! You are officially an implementor!