Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

MUD programming in C

Status
Not open for further replies.

dakuneko

Programmer
Nov 17, 2000
19
SG
I am interested in creating MUD but I do not know where to start. My problems include: (I would use Unix C++)


1. How does the communication between the MUD server and the TELNET client work?

2. What C/C++ functions should I use to be able to establish client-server communications in MUD?

I hope someone out there can help about this. Thanks in advance!
 
Check out it's an open source RPG taht is going to be graphical and online. I don't know about mud programming, but if you want to contribute, this is a great looking project. I may not have spelled the url right, but if you go to google and search for arianne rpg you'll get it.
 
Thanks for the info mbaranski. Is this similar to Ultima Online and EverQuest? I am also interested in those but programming those kind of games are too advanced which is why I chose to start from MUD programming and maybe go into graphical later.

 
Kind of similar to both, but if you read their description of what they're going to do, it's pretty awsome. As far as how the communication and stuff works, I can't do a whole lot there.

If you're running your MUD over telnet, you only need a program running on the server, then, your users telnet into the server, and run the MUD located on the server. You can use STDIN to get commands, because as long as they don't run your program in the background, telnet will pass the commands to the running program. I hope that makes sense.

That will eliminate your client-server problems, people can just telnet in to run it and then let telnet worry about passing commands and output back and forth.

If you want to do all of it yourself, your best bet is probably to set up a "socket" on another port, other than one that's used already, and write the commands to connect through that. If I were you, I'd use telnet. But, if you do decide to do all of the communications yourself, I'd go to google and do a search on sockets in c++ and see what you can find there. I'm not going to be able to help with that...

Good Luck!
Mike B.
 
Somebody told me to start with a single player first. So now, that's what I am doing. I encountered a problem. The problem is the time information. You see, I plan to have my own time frame. Can anybody help me on how to set up the time. Should it be in a different thread then let another thread access the time information?
 
Why not use the time() function. Look at time.h, and you should be able to do it with that. You can set up a thread to listen to time, so when it's time to switch from day to night or whatever, you just let that thread notify the thread that sets up the environment. Something like that should do fine.

Mike B.
 
I used the time function and i have the code below (I got it from CircleMUD but i revised a little):
Code:
#define SEC_PER_MUD_MIN		3
#define SEC_PER_MUD_HOUR	(60*SEC_PER_MUD_MIN)	/*     180 */
#define SEC_PER_MUD_DAY		(24*SEC_PER_MUD_HOUR)	/*    4320 */
#define SEC_PER_MUD_MONTH	(32*SEC_PER_MUD_DAY)	/*  138240 */
#define SEC_PER_MUD_YEAR	(20*SEC_PER_MUD_MONTH)	/* 2764800 */

// decade name 
const char *decade_name[] = {
						/*  1 */	"the Rebirth"	,
						/*  2 */	"the Twin Towers"	,
						/*  3 */	"Asheron's Call"	,
						/*  4 */	"the Black Rain"	,
						/*  5 */	"the Blinding"	,
						/*  6 */	"the First Sight"	,
						/*  7 */	"the Moon Rivers"	,
						/*  8 */	"the Sky Fall"	,
						/*  9 */	"the Shields of Fate"	,
						/* 10 */	"the Fates"	,
						/* 11 */	"the Great Battles"	,
						/* 12 */	"the Revolt"	,
						/* 13 */	"the Rebellion"	,
						/* 14 */	"Mica's Regret"	,
						/* 15 */	"the Fierce Winds"	} ;

const char *month_name[] = {
						/*  1 */	"Month of Terebrinth"	,
						/*  2 */	"Month of Czuven Lith"	,
						/*  3 */	"Month of Cian"	,
						/*  4 */	"Month of Diere"	,
						/*  5 */	"Month of Garai"	,
						/*  6 */	"Month of Shevatt"	,
						/*  7 */	"Month of Juno"	,
						/*  8 */	"Month of Micah"	,
						/*  9 */	"Month of Ezra"	,
						/* 10 */	"Month of Durai"	,
						/* 11 */	"Month of Poshu"	,
						/* 12 */	"Month of Quezacotl"	,
						/* 13 */	"Month of Armagged"	,
						/* 14 */	"Month of Osiris"	,
						/* 15 */	"Month of Iris"	,
						/* 16 */	"Month of Ar"	,
						/* 17 */	"Month of MonThaire"	,
						/* 18 */	"Month of Iezapeth"	,
						/* 19 */	"Month of Ttannia"	,
						/* 20 */	"Month of Zerynth"	,
} ;

// day of the week 
const char *day_of_week[] = {
								/* Holy     */	"the Day of Sunnan"		,
								/* Wind     */	"the Day of Celes"		,
								/* Fire     */	"the Day of Helios"		,
								/* Earth    */	"the Day of Zovogath"	,
								/* Water    */	"the Day of Leviath"	,
								/* Thunder  */	"the Day of Innothor"	,
								/* Dark	    */	"the Day of Anak-zuul"	,
								/* Strength */	"the Day of Runaeis"		} ;


// time information container
typedef struct 
{
	unsigned int	year	:	32 ;
	unsigned int	months	:	8 ;		// 20 months in a year
	unsigned int	days	:	8 ;		// 32 days in a month
	unsigned int	hours	:	8;		// 24 hours a day
	unsigned int	minutes :	8;		// 60 minutes an hour
} M_TIME_DATA;



// gets the current MUD time based on the beginning of time
M_TIME_DATA get_current_mud_time(time_t epoch, time_t current_time)
{
	M_TIME_DATA		now ;
	unsigned long	seconds_passed ;

	seconds_passed = (unsigned long) (current_time - epoch) ;
	memset(&now, 0x00, sizeof(M_TIME_DATA)) ;
	now.minutes = (seconds_passed/SEC_PER_MUD_MIN) % 60;	// 0..59
	seconds_passed -= SEC_PER_MUD_MIN * now.minutes;

	now.hours = (seconds_passed/SEC_PER_MUD_HOUR) % 24;		// 0..23
	seconds_passed -= SEC_PER_MUD_HOUR * now.hours;

	now.days = (seconds_passed/SEC_PER_MUD_DAY) % 32 ;		// 0..31
	seconds_passed -= SEC_PER_MUD_DAY * now.days;

	now.months = (seconds_passed/SEC_PER_MUD_MONTH) % 20;	// 0..19
	seconds_passed -= SEC_PER_MUD_MONTH * now.months;

	now.year = (seconds_passed/SEC_PER_MUD_YEAR);			// 0..1553 years

	return now ;
}

// make the time readable to players
void say_time(M_TIME_DATA time_info)
{
	char			am_pm[14] ;
	char			*suf ;
	char			minutes[3] ;
	char			minute_buff[3] ;
	unsigned long	hours ;
	unsigned int	day ;
	unsigned int	decade = 0;

	memset(&am_pm, 0x00, (sizeof(char)*14)) ;
	memset(&minutes, 0x00, (sizeof(char)*3)) ;
	memset(&minute_buff, 0x00, (sizeof(char)*3)) ;

	// determine if AM or PM 
	((time_info.hours < 12) && (time_info.minutes <= 59)) ? strncpy(am_pm, &quot;Ante Meridian&quot;, 14)
		: strncpy(am_pm, &quot;Post Meridian&quot;, 14) ;
	hours = ((time_info.hours % 12) == 0) ? 12 : (time_info.hours % 12) ; // change 0 to 12

	// padd additional '0' to minutes if less than 10
	itoa(time_info.minutes, minute_buff, 10);
	if (time_info.minutes < 10) {
		minutes[0] = '0' ;
		strncat(minutes, minute_buff, 1) ;
	} else {
		strncpy(minutes, minute_buff, 2) ;
	}

	day = time_info.days + 1 ; /* 1..32 */
	// add the suffixes
	if (day == 1)
		suf = &quot;st&quot;;
	else if (day == 2)
		suf = &quot;nd&quot;;
	else if (day == 3)
		suf = &quot;rd&quot;;
	else if (day < 20)
		suf = &quot;th&quot;;
	else if ((day % 10) == 1)
		suf = &quot;st&quot;;
	else if ((day % 10) == 2)
		suf = &quot;nd&quot;;
	else if ((day % 10) == 3)
		suf = &quot;rd&quot;;
	else
		suf = &quot;th&quot;;
	
	printf(&quot;The current time is %d:%s %s.\n&quot;, hours, minutes, am_pm) ;
	printf(&quot;This is %s, %d%s of the %s, the year %d of %s.\n&quot;, 
		day_of_week[(time_info.days%8)], day, suf, month_name[(time_info.months%20)], 
		time_info.year, decade_name[decade]) ;
	
}

int main(void)
{
	unsigned long		beginning_of_time	= 0 ;
	unsigned long		test_time			= 2764800 ;
	M_TIME_DATA	time_info ;

	for(;;) {
		test_time += SEC_PER_MUD_YEAR ;
		time_info = get_current_mud_time(beginning_of_time, test_time);	
		printf(&quot;test_time value:%l [%X]\n&quot;, test_time, test_time) ;
		say_time(time_info) ;
	}
	return 0;
}

There seems to be a problem when I reach the max value an
Code:
unsigned long
can have. It becomes negative. I had an overflow because the value of
Code:
test_time
was greater than the maximum of unsigned long.

It happened this way when my
Code:
test_time
value of 2145484800 was added to 2764800 aka SEC_PER_MUD_YEAR.Because of this the largest year I can have is only at year 777.

Can somebody help me out so that I can go upto the year 9999 without having any overflows?
 
One way to do it that I would recommend is to have a class

class hugeLong{

unsigned long first, second, third ...as many as it takes
}

Then, overload the = + and copy operators. I would keep adding to first until it reaches it's max value, with second, thrid, initilized to zero. Then, when first becomes full, start adding to second and so forth. Then, when you need to compare this to another value, subtract each (first, second, etc) from the value, and if you end up with 0, you know that the hugeLong and the comparison are equal.

I hope this makes sense, if not, let me know and I&quot;ll give more detail.

Mike B.
 
Yes please, kindly explain it further and I would really appreciate an example. Thanks!
 
OK, here goes, this is dirty and untested and off teh top of my head, but it should give you an idea of what I&quot;m trying to do, hoepfully someone will see a better way to do it and let you know... You may be able to find a library to do this for you.

//This is a global var
static unsigned long maximum_long_value = xxxxxxxxx;

class hugeLong{
/* Any # of Longs will allow you to have an arbitrarly large number, equal to
(maximum_long_value * (number_of_longs-1) + current_long)

Basically, you fill up the current_long_value until it is equal to maximum_long_value, and then, when it is exactly full, increment number of longs and set current_long equal to zero.
*/

private:
unsigned long current_long;
unsigned int number_of_longs;

public:
/*This will set the initial value, and zero lol[1..9] */
hugeLong(long);

/* This will zero lol[0..9] */
hugeLong();

/* This will add a value to your long */
void add(hugeLong, long);

/* return 0 for eq, -1 for lt, and 1 for gt */
int cmp(hugeLong, hugeLong);

/* Add a sub function if you need it */
};

hugeLong::hugeLong(long initial_value){
current_long = initial_value;
number_of_longs = 1;
}
}

hugeLong::hugeLong(){
current_long = 0;
number_of_longs = 1;
}
}

void hugeLong::add(hugeLong leftop, long rightop){
/* add as much of rightop to leftop.current_long as you can, and if leftop reaches maximum_long_value, increment number_of_longs and set current_long to what is left of rightop
*/
}

int hugeLong::cmp(hugeLong leftop, hugeLong rightop){
/* Here you can compare number_of_longs, and if they are not equal, you know which is larger, or if they are equal, compare leftop.current_long and rightop.current_long to find which is larger.
*/
}


This will allow you to have very large numbers, if you need to you can have number_of_longs also be an unsigned long, which would allow you and even larger number, and so on. I hope this makes sense, I don't relly have time to write the whole thing and test it, because I'm inschool and finals are about to start. If you need further help, I can maybe do it this weekend. I hope that this is helpful.

Mike B.
 
Im currently working on a MUD bot for unix/linux. It's working in Win2k.

It's quite easy to send a command to the mud,
open a streaming socket and send the string over the socket, just terminate the string with a \n so the MUD knows where the command
ends. MUD is using the standart Telnet protocole, to learn about it, search for telnet RFC. I've not implemented the telnet special functions but it still works, no color tho.

I've written the bot in Windows c++, so I'm about to port it to linux.

Sockets is one thing I need to change.

Drop me a mail or something and I can send you some code with a easy to use socket lib
(win2k) and some code how to send stuff to the mud.

//KingHippo d99pth@du.se
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top