Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ Programming ➜ General ➜ SocketMUD Issues

SocketMUD Issues

It is now over 60 days since the last post. This thread is closed.     Refresh page


Pages: 1 2  

Posted by Will Sayin   USA  (17 posts)  Bio
Date Tue 25 May 2010 01:55 AM (UTC)

Amended on Tue 25 May 2010 01:56 AM (UTC) by Will Sayin

Message
I'm not sure if this is the right place for this, but it seems as good a place as any.



My Goal: I'm working on a function that parses a prompt much like SMAUG does, so if a player has a prompt of "[$h/$Hhp]" it will send "[100/100hp]" -- or whatever the player's health and max health are.

My Problem: It appears that sprintf is not working in the function. The function properly detects flags, but it does not add the information I would like.

My Code:

void send_prompt( D_MOBILE *player )
{
	char *buf = (char*) malloc( sizeof( char ) * MAX_BUFFER );
	char *pbuf = player->prompt;
    
	char *start = buf;
	/*
	 *Possible Prompt Flags:
	 *$h - Current Health
	 *$H - Maximum Health
	 *$l - Current Level
	*/

	if( !player->prompt )
	{
		cmd_prompt( player, "default" );
	}
	
	for( ;*pbuf; pbuf++ )
	{
		if( *pbuf != '$' )
		{
			*buf = *pbuf;
			buf++;
		}
		else
		{
            pbuf++;
			switch( *pbuf )
			{
				case 'h':
					sprintf( buf, "%i", player->curHealth );
                    fprintf( stderr, "Current Health Flag\n" );
					break;
				case 'H':
					sprintf( buf, "%i", player->maxHealth );
                    fprintf( stderr, "Maximum Health Flag\n" );
					break;
				case 'l':
					sprintf( buf, "%i", player->level );
                    fprintf( stderr, "Current Level Flag\n" );
					break;
				default:
                    fprintf( stderr, "Default\n" );
					sprintf( buf, "%c", *pbuf );
					break;
			}
		}
    }
	*buf = '\0';
	text_to_mobile( player, start );
	fprintf( stderr, "Prompt set as: %s\nPrompt being displayed: %s\n", player->prompt, start );
	return;
}



As you can see, there is quite a lot of error checking in there. This is what I get as output:

Via telnet:

What is your name? Will

What is your password? 
[LOG: Will has entered the game.]
Welcome to SocketMUD(tm)

We hope your stay here will be a pleasant one,
and are looking forward to serving you a rich
and colorful mud experience.

The staff.
[/hp Level: ]

[/hp Level: ]

[/hp Level: ]


In the terminal:

(06:51 PM Mon May 24)
(w@w.domain1)-(~/dev/C/Projects/SocketMUD/socketmud/src)>./SocketMud
Current Health Flag
Maximum Health Flag
Current Level Flag
Prompt set as: [$h/$Hhp Level: $l]
Prompt being displayed: [/hp Level: ]
Current Health Flag
Maximum Health Flag
Current Level Flag
Prompt set as: [$h/$Hhp Level: $l]
Prompt being displayed: [/hp Level: ]
Current Health Flag
Maximum Health Flag
Current Level Flag
Prompt set as: [$h/$Hhp Level: $l]
Prompt being displayed: [/hp Level: ]
Current Health Flag
Maximum Health Flag
Current Level Flag
Prompt set as: [$h/$Hhp Level: $l]
Prompt being displayed: [/hp Level: ]
(06:52 PM Mon May 24)
(w@w.domain1)-(~/dev/C/Projects/SocketMUD/socketmud/src)>


I don't think I'm doing anything wrong, yet I continue to get the wrong results... so can someone more learned than I tell my where I'm f'ed up?

Thank you,
Will

Will Sayin
Developer, Legends of the Darkstone
www.darkstonemud.com:5432
Top

Posted by Will Sayin   USA  (17 posts)  Bio
Date Reply #1 on Tue 25 May 2010 02:23 AM (UTC)

Amended on Tue 25 May 2010 03:48 AM (UTC) by Will Sayin

Message
Why is it that whenever I post a request for help, I figure it out on my own within a half hour?

Anyways, the problem was that I was overwriting everything. Here is my fixed code with the changes in bold:

void send_prompt( D_MOBILE *player )
{
	char *buf = (char*) malloc( sizeof( char ) * MAX_BUFFER );
	char *pbuf = player->prompt;
    
	char *start = buf;
	/*
	 *Possible Prompt Flags:
	 *$h - Current Health
	 *$H - Maximum Health
	 *$l - Current Level
	*/

	if( !player->prompt )
	{
		cmd_prompt( player, "default" );
	}
	
	for( ;*pbuf; pbuf++ )
	{
		if( *pbuf != '$' )
		{
			*buf = *pbuf;
			buf++;
		}
		else
		{
            pbuf++;
			switch( *pbuf )
			{
				case 'h':
					buf+=sprintf( buf, "%i", player->curHealth );
                    fprintf( stderr, "Current Health Flag\n" );
					break;
				case 'H':
					buf+=sprintf( buf, "%i", player->maxHealth );
                    fprintf( stderr, "Maximum Health Flag\n" );
					break;
				case 'l':
					buf+=sprintf( buf, "%i", player->level );
                    fprintf( stderr, "Current Level Flag\n" );
					break;
				default:
                    fprintf( stderr, "Default\n" );
					buf+=sprintf( buf, "%c", *pbuf );
					break;
			}
		}
    }
	*buf = '\0';
	text_to_mobile( player, start );
	fprintf( stderr, "Prompt set as: %s\nPrompt being displayed: %s\n", player->prompt, start );
        //free( buf ) /*Memory leak!*/ Here I was, thinking I was being clever.... You REALLY don't want to free that variable.
	return;
}

Will Sayin
Developer, Legends of the Darkstone
www.darkstonemud.com:5432
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #2 on Tue 25 May 2010 05:49 PM (UTC)
Message
Quote:
Why is it that whenever I post a request for help, I figure it out on my own within a half hour?

I find that when you take the time to ask a good, detailed question -- as you did -- it helps to organize your own thinking, and make it easier to solve the problem yourself. :-)

Sometimes I even write up questions and explanations of problems without intending to post them, just to force myself to get organized in my head.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Nick Cash   USA  (626 posts)  Bio
Date Reply #3 on Sun 30 May 2010 04:12 AM (UTC)
Message
You were correct that your error was you overwriting buf via sprintf, which you fixed by incrementing your pointer via the return value of sprintf (an interesting solution I might add).

However, it looks to me like you would indeed like to free that variable at the end of the function. Otherwise you are going to use up quite a bit of memory (depending on what your MAX_BUFFER is set to) that you need not use otherwise. As long as you free it after the text_to_mobile call it shouldn't be a problem.

~Nick Cash
http://www.nick-cash.com
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #4 on Sun 30 May 2010 04:57 AM (UTC)
Message
He's right. Either do what is generally done elsewhere:


char buf [MAX_BUFFER];


... in this case buf is statically allocated and you shouldn't free it.


Or, put the free back in, as you will be allocating MAX_BUFFER bytes every time, and will gobble up memory rather quickly.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #5 on Sun 30 May 2010 05:49 AM (UTC)
Message
Good catch, Nick. I should have paid more attention to the code.

Yeah, you don't want to be leaving that pointer dangling. In fact, you probably don't need to allocate 'buf' on the heap at all. Why not do:

char buf[MAX_STING_LENGTH]

or something like that?



EDIT:
wow, hour ninja. That's what I get for leaving a tab open for a while and only replying later :P

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Will Sayin   USA  (17 posts)  Bio
Date Reply #6 on Sun 30 May 2010 11:36 PM (UTC)

Amended on Sun 30 May 2010 11:38 PM (UTC) by Will Sayin

Message
Hey,

The reason I took the free(buf); out was because when I did free it, I got a segmentation fault, and when I took the free(buf); out, it did not crash. I did not really debug it, at the time I wasn't really familiar with gdb, but I should go back through that again because I have since gotten quite familiar with the basics due to a few other problems I've had.

Anyways, I'll see what I can do.

Thanks,
Will

ETA: And yeah, I honestly don't remember why I allocated the memory instead of using buf[MAX_BUFFER], once I get back home I'll look through the code again, I'm using my GF's Macbook ATM and I don't have any programming capabilities on here.

Thanks for all your help!

Will Sayin
Developer, Legends of the Darkstone
www.darkstonemud.com:5432
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #7 on Mon 31 May 2010 12:27 AM (UTC)

Amended on Mon 31 May 2010 12:28 AM (UTC) by Nick Gammon

Message

buf++;


You weren't freeing the original pointer (as you added to it).

You are better off statically defining it. Doing a malloc, then adding to what you got, then freeing it, is definitely a bad idea.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #8 on Mon 31 May 2010 04:05 AM (UTC)
Message
Yup. Since you have char* start = buf at the beginning, you can free 'start' instead of 'buf'. But it's probably easier to allocate statically.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Will Sayin   USA  (17 posts)  Bio
Date Reply #9 on Fri 11 Jun 2010 05:44 AM (UTC)

Amended on Fri 11 Jun 2010 05:45 AM (UTC) by Will Sayin

Message
OK, more issues. Sorry for the long post, but I'm trying to be as detailed as possible. I'm adding in Lua scripting (Seems to be a trend around here) and I'm running into some issues:

I can get one script to work, but I can't get another-- very similar-- script to work.

Right now, all I've got going is scripts on objects. I'll be updating it so that most commands and stuff are done through Lua, but for now I just want to see if I can get some simple scripting to work.

The way I have scripts working on objects, is each object has a linked list of script structures, defined as follows:

struct LuaScript
{
    char *name;
    char *script;
};

The object structure is defined as:

struct dObject
{
   char *name;
   ...
   ...
   LIST luaScripts;
};

The function check_object_script iterates through the list and tries to match a the name of the script to the argument passed by the player:

bool check_object_script( D_OBJECT *obj, char *script )
{
    ITERATOR iter;
    LUASCRIPT *scriptPointer;

    AttachIterator( &iter, obj->luaScripts );
    while( ( scriptPointer = (LUASCRIPT*) NextInList( &iter ) ) != NULL )
    {
        if( !strcasecmp( script, scriptPointer->name ) )
        {
            run_script( scriptPointer );
            return TRUE;
        }
    }
    DetachIterator( &iter );

    return FALSE;
}


If check_object_script is able to find a match for the script name, it calls run_script, which simply loads the script into the Lua state, and calls call_va (from PIL).


void run_script( LUASCRIPT *script )
{
    luaL_loadbuffer( mudL, script->script, strlen( script->script ), script->name );
    lua_pcall( mudL, 0, 0, 0 );
    call_va( mudL, script->name, "" );

    return;
}


All of this compiles fine, but it only works on some scripts, which is why I think it has something to do with some idiosyncrasy with Lua that I don't know about.

If I've got the following object:

##NEW_OBJ## 14
##SNAME## a pair of dice~
##LNAME## A pair of dice sit in the dust~
##WEARPOS## 16
##DESC## A standard pair of dice~
##ISCONT## 0
##LUA##
roll~
function roll()



comm( "mob", "You roll a " .. rand(1,6) .. " and a " .. rand(1,6) .. "." );

comm( "room", "Will rolls a pair of dice" );



end~
##END_OBJ##

You can see how it's loaded, with simple key pairs. ##LUA## marks the beginning of a lua script, "roll" is loaded as the script name (luaScript->name), and "function roll()..." is loaded as the script (luaScript->script).

This works perfectly fine, and outputs what's expected:

The Void
An inky blackness surrounds you, envelopes you, overwhelms your senses.
Nothing can be seen, nothing can be smelled, nothing can be heard. You
are completely and utterly alone, and it is terrifying.
Exits:
  North.
A large oak chest sits in the corner, collecting dust.
[56/100hp Level: 4]eq

You are wearing:
	a sturdy backpack on your shoulders.
	a pair of dice in your left hand.
[56/100hp Level: 4]roll

You roll a 2 and a 1.
[56/100hp Level: 4]roll

You roll a 6 and a 6.
[56/100hp Level: 4]roll

You roll a 4 and a 6.
[56/100hp Level: 4]


But, giving the next object:

##NEW_OBJ## 13
##SNAME## a sturdy backpack~
##LNAME## A sturdy looking backpack sits on the ground~
##WEARPOS## 13
##DESC## Its a sturdy canvas backpack and it looks like it can hold

quite a lot of supplies.~
##ISCONT## 20
##NEW_OBJ##
##SNAME## A tattered bedroll~
##LNAME## A tattered looking bedroll provides a place for one to rest during their travels~
##WEARPOS## 16
##DESC## The bedroll is old and worn, but provides more comfort than the bare ground for the wandering

traveler. The  bedroll consists of a few thick wool blankets and a canvas ground cloth, and keeps who-

ever might use it warm at night.~
##ISCONT## 0
##END_OBJ##
##LUA##
wear~
function wear()

if( ( s = getname() ) == "Will" )

then

	comm( "mob", "Hey, Will!" );

else

	force( "mob", "remove backpack" );

end --endif



end --end func~
##END_OBJ##


When I activate this trigger, I get told:

[56/100hp Level: 4]rem backpack

You remove a sturdy backpack and hold it in your right hand.
[56/100hp Level: 4]wear backpack

[LOG: error running function `wear': attempt to call a nil value]
You wear a sturdy backpack on your shoulders.
[56/100hp Level: 4]


Everything is done exactly the same in between the two scripts, but one work and the other does not. Any ideas?

Will Sayin
Developer, Legends of the Darkstone
www.darkstonemud.com:5432
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #10 on Fri 11 Jun 2010 06:44 AM (UTC)
Message
My first reaction when I saw that was, you will have trouble expressing "not equal" in Lua (ie. if a ~= b) because you are using ~ as the terminator of the script.

Second, I would be reporting the line number in error.

Third, this doesn't even compile under Lua:


function wear()

if( ( s = getname() ) == "Will" )

then

	comm( "mob", "Hey, Will!" );

else

	force( "mob", "remove backpack" );

end --endif



end --end func~


You get the error:


Immediate execution
[string "Immediate"]:3: ')' expected near '='


I'm also a bit doubtful about luaL_loadbuffer every time you want to run a script. That is going through the compile phase every time, and thus will make it hard, or impossible, to keep variables between calls (assuming you want to).

You don't seem to be checking for errors from luaL_loadbuffer, so my guess is, the error is trying to tell you that you got a compile error, and thus there was no function left on the Lua stack for the lua_pcall to call, thus the message about "attempt to call a nil value".

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Will Sayin   USA  (17 posts)  Bio
Date Reply #11 on Fri 11 Jun 2010 07:00 AM (UTC)
Message
Thanks for the reply, Nick! I'm still in the process of learning everything, so I'm not surprised that there's a bunch of mistakes, but that's what this is for. So I guess now I'm going to

1. change the string terminator to something probably in the 0 to 32 ASCII range.

2. I'll be doing more error checking.

3. I'll read, read, read.

And a quick design question, if you don't mind, do you think using key pairs for different scripts is a good idea? And how exactly would you go about storing the compiled script? Would each object needs it's own Lua state?

Thanks again for your help,
--Will

Will Sayin
Developer, Legends of the Darkstone
www.darkstonemud.com:5432
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #12 on Fri 11 Jun 2010 07:02 AM (UTC)
Message
Did you read my post about adding Lua to Smaug?

http://www.gammon.com.au/forum/?id=8000

In my case I loaded the scripts once (from a file at MUD startup time). This saves compiling the snippets of scripts all the time (and catches compile errors at the start, rather than when a particular object is accessed). It also works around the problem of having special characters (like tilde) in the script itself.

Then if you want to call a particular function (eg. "roll") you can let Lua look up the function in its script space for you, you don't have to iterate around through a lot of scripts to find it. Let Lua do the work. :)

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #13 on Fri 11 Jun 2010 07:07 AM (UTC)
Message
Pracllik said:

And how exactly would you go about storing the compiled script? Would each object needs it's own Lua state?


Well that's a lot of script states. I had one per player (and there was some debate about whether that was a good idea). With one per player you can keep track of things the player is doing (eg. killing 5 mobs) since the state could store the number of mobs, and add to it each time one is killed.

However you could conceivably use a single state with a bit more mucking around inside that state to separate out which actions belong to which players (or objects, or mobs).

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #14 on Fri 11 Jun 2010 07:12 AM (UTC)
Message
Also see this: http://www.gammon.com.au/forum/?id=8013

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


52,747 views.

This is page 1, subject is 2 pages long: 1 2  [Next page]

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.