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, confirm your email, resolve issues, 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.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ SMAUG ➜ SMAUG coding ➜ Any good tutorials or help files on outputting text in Smaug or C?

Any good tutorials or help files on outputting text in Smaug or C?

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


Pages: 1 2  

Posted by Gadush   (92 posts)  Bio
Date Fri 23 Jun 2006 05:30 PM (UTC)
Message
Hi all,

I am trying to output a very basic display of a room, using variables I have assigned to each room file. The variables needed are x and y, and I know how to access them now, thanks to help here. I need to figure out how to make the do_display command I am working on decide how many symbols to print out based on the integer in x and y variables. Does anyone know of a good reference showing ways to output ascii characters using Smaug? Or any other sources of help on learning how to display things like this? I took a look at mapout, but wow. It looks very complex.
Thanks for any info or nods in the right direction.
Gadush
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #1 on Fri 23 Jun 2006 06:01 PM (UTC)
Message
I am not sure I understand your question:
Quote:
I am working on decide how many symbols to print out based on the integer in x and y variables
Could you rephrase that or explain what you mean? What's unclear to me is what you mean by "symbols", and what you would do in the various cases.

Are you trying to just print out the numbers? If so, you can do this: printf("%d %d", x, y); -- that will print out "12 53" if x=12 and y=53. Not sure if that's what you wanted.

You would of course have to print not to standard output, but to the player's connection. You can either use a buffer with sprintf (for string-printf) or ch_printf(ch, "%d ...) if that function is defined in your codebase.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

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

Posted by Gadush   (92 posts)  Bio
Date Reply #2 on Fri 23 Jun 2006 06:21 PM (UTC)

Amended on Fri 23 Jun 2006 06:29 PM (UTC) by Gadush

Message
Sorry about that. Upon reading what I posted its a wonder anyone could understand what I was asking. Heh.

The way it would work is that for example, x is set to 5 and y is set to 5. When I print the display map, I want to know how to use those numbers. I think I need a loop maybe? So, x would print out '--' (without the single quoutes), and it would print it 5 times. ' ---------- '
And then y would print out '|', plus ((x*2) - 2)spaces, plus '|', plus \n\r. 5 times. This would effectively build a box where each symbol, both -- and |<spaces>|, would be printed the correct number of times based on the integers in x and y variables.
Whew, sounds ridiculously confused.
I am trying to draw out this:

room size set to 5 x 5
		+----------+
		|          |
		|	   |
		|	   |
		| 	   |
		|	   |
		+----------+

Corner = 	'+'
Top/Bottom =	'--'
Sides =		'|'

Those are for each Unit.  Each Unit = 5'.
So the above map is 25' x 25'.


Geeze, I don't know it that is any clearer. Sorry...
Gadush
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #3 on Fri 23 Jun 2006 06:31 PM (UTC)
Message
OK, I see what you want now. One of your problems is that although you know what you want, you have not formulated it precisely. Once you have a precise formulation, the code follows almost naturally.

In your case, you have to distinguish between a number of things:


  1. You have to draw a header line. This consists of one '+', followed by 2*x '-', and one '+'.
  2. Now you want to print the y rows. So, y times, you want to print out: one '|', followed by 2*x ' ', and one '|'.
  3. Finally, you draw the footer line. This is the same as the header.


Once you have a more precise formulation like this, all you need to do is write some simple for loops. It would look like this, in pseudo-code:

// Print the header
Output: "+"
For i = 0 to x-1
  Output: "--"
Output: "+\n"

// Print each row
For i = 0 to y-1
  Output: "|"
  For j = 0 to x-1
    Output: "  "
  Output: "|\n"

// Print the footer
Output: "+"
For i = 0 to x-1
  Output: "--"
Output: "+\n"


That's not so bad, is it? I'll leave the actual C code to you: it should be fairly easy to translate.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

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

Posted by Gadush   (92 posts)  Bio
Date Reply #4 on Sat 24 Jun 2006 06:01 AM (UTC)

Amended on Sat 24 Jun 2006 06:07 AM (UTC) by Gadush

Message
Thanks so much, Ksiylan. That was very helpful indeed. Here is the code I came up with. I modified it slightly, experimenting with the best characters to use to print out the rooms, and finding the right equation to make each one work out.

void do_display ( CHAR_DATA *ch, char *argument  )
{
	// need to declare int i, x, y, j
	int x, i, y, j;
	ROOM_INDEX_DATA *location = ch->in_room;
        x = location->x;
	y = location->y;
        send_to_char( "+", ch); /* sends corner */
  for(i = 0; i < x; i++)  /* does it x number of loops */
      {
        send_to_char( "-", ch); /* sends top dashes
      }
  send_to_char( "+\n", ch); /* sends corner */

  for(i =0; i < (y / 2)+1; i++)  /* loops until it has drawn number of rows */
      {
        send_to_char( "|", ch);
          for(j = 0; j < x; j++) /* loops until drawn number of spaces */
             {
               send_to_char( " ", ch);  
             }
        send_to_char( "|\n", ch); /* sends ending pipe */
       }

send_to_char( "+", ch); /* sends corner */
 for(i = 0; i < x; i++)  /* does it x number of loops */
      {
        send_to_char( "-", ch); /* sends top dashes*/
      }
send_to_char( "+\n", ch); /* sends corner */

}


Now, after a bit of a break, I will try to figure out how to loop through all objects that are in the room, get the first letter of their name, get their coordinate positions, and then fix my loop to include that letter in the correct spot on the display. (Eeek that sounds hard!)
Thanks again for all the help.
Gadush
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #5 on Sat 24 Jun 2006 07:21 AM (UTC)
Message
Glad to be of help. :-)

Assuming all your objects already have coordinates stored, this won't be that hard. What you'll do is modify the row printing part of the function. If there is something there, you print whatever its letter is. If it's empty, you just print a blank.

I suggest that you try to get it working before you try to be clever. For example, you can scan all objects once, creating a nice little table of their positions, so that you don't have to keep looking at all the room's contents. But while that would indeed be the thing to do in an ideal world, it is much better if you start simpler to learn things. So, you can do something like this:
// For each row:
for i = 0 to y-1
  print |
  for j = 0 to x-1
    obj = obj_at_position(x,y,room)
    mob = mob_at_position(x,y,room)
    if obj != null
      print obj->letter
    else if mob != null
      print mob->letter
    else
      print " "
    endif
  endfor
  print |\n
endfor


The functions obj_at_position and mob_at_position are helper functions you would write that take a room and see if its content lists contain something at position x,y, and if they do, return it. That would involve iterating over the whole list, and checking if each object's coordinates were equal to the one you're looking for.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

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

Posted by Gadush   (92 posts)  Bio
Date Reply #6 on Mon 26 Jun 2006 06:25 PM (UTC)

Amended on Mon 26 Jun 2006 06:32 PM (UTC) by Gadush

Message
Well, I took a couple of days away, to let it all gel in my mind. Fascinating stuff, this coding. But it can drive a person crazy trying to figure it out. =)
I looked in act_info, at the do_look function, because I thought there must be a method in that function that shows a player any objects that are in the room. (and not in another container, or being carried, etc.)

I found this line:
show_list_to_char( ch->in_room->first_content, ch, FALSE, FALSE, eItemGet );
But I am not certain it is even close to what I am looking for here.
I need, as you indicated, to check the coordinates of each object that is in the room where the look is taking place. Coordinates are already on the object (and mobs, but I am only trying it with objects first, to try to learn how). Then, I can decide how to display that using part of the do_display function, like you showed above. But where is this list of objects in a room? It seems like it would be referenced in do_look, but . . . well, I am still struggling. I keep refering to my books on C, but books, as good as they are, cannot compare to a person.
Anyway, any thoughts on where/how to access the list of objects in a room?
Thanks!
Gadush

Edit: I checked for show_list_to_char in mud.h and found the function:

void	show_list_to_char	args( ( OBJ_DATA *list, CHAR_DATA *ch,
				    bool fShort, bool fShowNothing, const int iDefaultAction  ) );


I am trying to understand this . . .
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #7 on Mon 26 Jun 2006 06:36 PM (UTC)
Message
You actually found the right line. Contents of a room are implemented as a linked list in SMAUG. So, ch->in_room is a pointer to the room ch is in. And in turn, in_room->first_content is a pointer to the first object in the room.

To loop over all objects, you do something like this:

OBJ_DATA * obj;
for ( obj = in_room->first_content; obj != NULL; obj = obj->next )
{
  /* do something with obj */
  printf("Obj's name: %s\n", obj->name);
}


If you have books on C, I would suggest reading up on linked lists; they're not too hard (compared to, say, hash tables) but they can be tricky getting your head around them, especially around how to maintain them.

Don't underestimate the importance of books, by the way. They provide a fundamental theoretical underpinning that you might not get from a person. Books are infinitely patient, whereas most people won't take the trouble to explain theoretical points to you and instead will just give the answer. I try to avoid just giving the answer because of the "don't give a fish, teach to fish" philosophy.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

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

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #8 on Mon 26 Jun 2006 06:37 PM (UTC)
Message
Looks like you edited your post while I was replying. Which part of the line you pasted isn't clear? Or were you referring to how the function fits in with the bigger picture?

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

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

Posted by Gadush   (92 posts)  Bio
Date Reply #9 on Mon 26 Jun 2006 06:55 PM (UTC)
Message
Actually, I meant more the overall smaug coding was tough to understand. I am trying to learn not only C, but the intricacies of a huge pile of coding that is Smaug.
As for the line, I think it works like this?
The function show_list_to_char takes as arguments the following:
a pointer named *list that points to ROOM_DATA,
a pointer named *ch that points to CHAR_DATA,
bool fShort which is the short description of an obj,
bool fShowNothing which . . . shows nothing? =P,
a constant that is an integer, checked to give a default message to *ch?

By the way, even though I want the pre-made answer like any human, I can't stress enough how much I appreciate your method of pushing and pointing in the right direction. I admit to feeling a much greater thrill at doing it myself (even with all the tremendous help!) however easy the parts left for me are. Like formating the room display checks. You could've just churned it out for me, but I am glad you didn't. I know you showed me pretty much exactly how, but it still felt good to have to write them out myself.
Anyhow . . . thanks.
Gadush
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #10 on Mon 26 Jun 2006 07:43 PM (UTC)
Message
Learning to code on SMAUG is definitely not the easiest way to learn, because as you have discovered SMAUG is a pretty big piece of code (even though it is relatively simple not in size but in architecture). But, you've already come a fair way, so you might as well persevere!

You are correct about the first two arguments, but a 'bool' is a true/false variable. It's commonly called a 'flag' (in fact, the little 'f' in front of the name most likely stands for 'flag'). 'bool' stands for 'boolean', which comes from George Boole, who is largely credited with the invention of boolean algebra. (i.e. how to combine trues, falses, ands, ors, etc.)

So, in this case, fShort and fShowNothing aren't really data, they're more like ways to fine-tune the behavior of the function. This is a very important part of code re-use. Imagine you want to do many different things, but they're all really quite similar. What you can do is make one function to handle all of it, but depending on which arguments you give it (i.e. the boolean variables), it can do slightly different things.

In this example, I'm not sure what fShowNothing is for, but I'm willing to bet that if fShort is true, it only displays short descriptions, and if it's false, it displays long descriptions.

Quote:
I know you showed me pretty much exactly how,
Actually, I didn't, not really. What I did is try to provide a precise formulation of what you were trying to do; you wrote all the C code yourself. My goal is to show you that you have to think clearly in English first. Once you've done that, you've done the hardest part of the work. It's kind of like writing an essay. You can be a master of English, but if you have no idea what to say or how to write an essay, it won't make any sense at all and will be a disconnected, bad essay. Programming is even less forgiving than an essay, as you've probably noticed: "spelling" and "grammar" mistakes either make your program blow up, or worse yet, make it do something similar but subtly different that will cause problems later on.

As you get better, again, much like essays, the "English thinking" phase will become somewhat natural and you will be able to reason about high-level concepts fairly easily and quickly. The part that most people find so frustrating as they're learning, and rightly so, is that they have enough trouble thinking about the high level concepts, that thinking about code is overwhelming, and the end result is a big mish-mash of code and concepts. Trust me -- I've been there too. :P

The mistake generally made is to reason directly in terms of for loops, if statements, function calls etc. and forget the bigger picture. It's important to back off from the code a bit and think (in natural language, not programming terms) about what you're trying to do.

OK, I'll get off my soapbox now. :P

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

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

Posted by Gadush   (92 posts)  Bio
Date Reply #11 on Tue 27 Jun 2006 04:03 AM (UTC)

Amended on Tue 27 Jun 2006 04:07 AM (UTC) by Gadush

Message
Hrmmm . . . I am really trying to put this in plain english pseudocode, as you suggest, but it keeps eluding me.
What I have printing out now, basically goes row by row, so if I use a loop to check all the objects, it checks all the objects each time it prints a row. As it checks the object, it gets its x and y coordinates. Then, what? It needs a whole bunch of if checks, for each space in the current row?
So:

if(location x == 0 && location y == 0)
	{
		print <letter>
	}
		else
		{
			print " "
		}
else if(location x == 1 && location y == 0)
	{
		print<letter>
	}
		else
		{
			print " "
		}

etc. . .

I guess that would work? But it seems like an awful lot of if checks! Maybe this is too much for me, but man I can taste it, it seems so close. heh

I am still puzzling on those helper functions, trying to understand how they would work.

Did I mention my brain hurts? =P
Thanks,
Gadush
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #12 on Tue 27 Jun 2006 05:07 AM (UTC)
Message
OK, first thing, as you noticed, yes, that's an awful lot of if checks! It's good that you're starting to get a "feeling" for when there is a lot of redundancy. Because that's what's going on here: you're doing something over and over again, when it really can be considered as just one process.

More precisely, you can think about it in terms of a question:

For every row R,
  for every column C,
    is there something in location R/C?
      --> Yes: print its letter
      --> No: print space


Often what I do when I code, especially things like this that can be decomposed naturally, is what's called top-down coding. I'll write out the functions that have sub-functions, and I'll only worry about the sub-functions once I'm done with the upper level of functions. Not only does this help write clean code, but it also helps me think about the problem precisely. Too often if I just jump right in, I end up with something albeit more-or-less working but usually messy.


Your case is a very good example. As you said, you could do it by simply cascading a whole bunch of if checks. But that's really not the most elegant way of doing it. As I said above, a function can be thought of as a question, of sorts. Worry about getting the top-level logic figured out. Then you can worry about implementing the sub-functions (what I called the helper functions).

You might notice, if you think ahead a bit, that having functions to tell you what is at location x/y will be really, really, really useful later on, for instance when you want to start playing around with moving things from square to square (and checking if the square is occupied already). This is a big benefit of decomposing your functions: chances are, you will be able to use the exact same function later on, thus avoiding the writing of a whole new function!

I think you pretty much understand the general idea of the top-level logic. What you need to get your head around now is how to loop through the lists of objects and see if one of them has coordinates "x"/"y". To do so, you will need to understand (at least the basics of) linked-list theory. Your books will provide a more in-depth explanation than I can do here, but basically here is how they work:


Node1 --(next)--> Node2 --(next)--> Node3 --(next)--> null
|-data            |-data            |-data

The idea is that every node contains a 'next' pointer and some data. The next pointer indicates what the next element of the list is. When you reach a next pointer that is null, you know that you have reached the end of the list. (That is what the code I showed you was doing.) The data contained in the node represents whatever you have a linked list of (in this case, objects and characters).


Side note: SMAUG doesn't implement linked-lists according to theory, because it puts next and data in the same level. This leads to problems because an object must have multiple list pointers: next_content, next_carried, etc. It is cleaner to have objects called something like "linked list node" that have a next pointer and a data pointer, where next points to another node and data points to the actual OBJ_DATA structure. End side note.


In any case, you are indeed very close -- keep it up! Give a think over what I've written and let me know if it makes sense. For now I'm going to get some sleep. :-)

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

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

Posted by Gadush   (92 posts)  Bio
Date Reply #13 on Wed 28 Jun 2006 06:22 PM (UTC)
Message
I may have been overlooking a key concept here . . .

as we loop through each 'row', we print first | then we start with another loop that checks each space for an object or an 'empty' space. If it is empty, it prints " ".
If it is not empty, it prints the letter of the object.
My mind keeps boggling as I try to see how the loop knows which 'location' it is at, in order to check if something is there. The if checks I put in the last post wouldn't really work, would they? Or . . . wait a sec. I guess it would, because it would only loop x number of times, either with a space of a letter, before moving to the next row. But wouldn't each row just repeat? I mean, the loop wouldn't know what row along the y axis it was on?

I have been looking into 2d arrays . . . whew. An array, sized according to my room sizes, would contain a 'grid', with each memory location being one space in my room. Perhaps it would be easier to check an array element somehow? I don't know, I feel close, but maybe this is just too much at my level of skill.

Sorry for rambling here, but I started to post, and figured I would leave my thoughts, in case you noticed me wandering either closer or farther from a solution. Heh

Meanwhile, I continue working through the C books.
Thanks for everything,
Gadush
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #14 on Wed 28 Jun 2006 07:02 PM (UTC)
Message
Quote:
as we loop through each 'row', we print first | then we start with another loop that checks each space for an object or an 'empty' space. If it is empty, it prints " ".
If it is not empty, it prints the letter of the object.
My mind keeps boggling as I try to see how the loop knows which 'location' it is at, in order to check if something is there.


Well, you are looping over the rows, so you already have the row number from your for loop variable. And, you are looping over the columns, so you have that number too. Presto: you have the coordinates.

Consider this code:

int i, j;
for ( i = 0; i < 5; i++ ) {
  for ( j = 0; j < 5; j++ ) {
    printf("%d %d\n", i, j);
  }
}


This will print out:

0 0
0 1
0 2
0 3
0 4
1 0
1 1
...


Do you see how this works? Basically, you already have the variables there, so you can use them directly.

Quote:
I have been looking into 2d arrays . . . whew. An array, sized according to my room sizes, would contain a 'grid', with each memory location being one space in my room. Perhaps it would be easier to check an array element somehow?


You are quite correct. If the room had a 2d array, it would be quite easy to find out what was in there. For example, room->grid[x][y] would give you the contents of x/y. But... (see below)

Quote:
I don't know, I feel close, but maybe this is just too much at my level of skill.


You are very, very close. The difficulty is that you have to ingurgitate 50 concepts at once, and the problem you're trying to solve (a coordinate system) is non-trivial enough as it is.

What you can try is to create a whole new project somewhere and just play around with much, much smaller files than all of SMAUG. SMAUG is, you'll admit, really a lot of code to navigate when you're still learning how to code! :-)

Have you seen example "Hello, world!" programs? Those might look stupid but you shouldn't underestimate them. You can get one of those, and play with it, adding 2d arrays, and for-loops, and all the stuff you're trying to learn. The advantage is that you will see exactly what is going on in a very manageable scope, as opposed to having to deal with the whole of SMAUG code on the side. Basically: learn to write small sentences before writing paragraphs; learn to write paragraphs before writing chapters; learn to write chapters before writing books; and so forth. If you start in chapters without knowing sentences, you'll be in trouble. :)

Good luck, and let me know if you have questions.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
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,495 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.