mail.html 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <html>
  2. <head>
  3. <link href="../tutorial.css" rel="stylesheet" type="text/css">
  4. </head>
  5. <body>
  6. <div class="header">
  7. The NakedMud Tutorial :: Mail Module
  8. </div>
  9. <!-- content starts here -->
  10. <div class="content-wrap"><div class="content-body-wrap"><div class="content">
  11. <div class="head">The Mail Module</div>
  12. <div class="info">
  13. This basic incarnation of the mail module will allow players to send written
  14. messages to one another. Send mail will not be persistent (it will not save
  15. over reboots or crashes). That feature will be postponed until the section on
  16. Storage Sets.
  17. <p></p>
  18. To start, create a new structure to represent a piece of sent mail. Add this to
  19. <i>mail.c</i>:
  20. <pre class="code">
  21. typedef struct {
  22. char *sender; // name of the char who sent this mail
  23. char *time; // the time it was sent at
  24. BUFFER *mssg; // the accompanying message
  25. } MAIL_DATA;
  26. </pre>
  27. Now, write some functions for a couple procedures that will be needed down
  28. the road -- the creation and deletion of mail:
  29. <pre class="code">
  30. // create a new piece of mail.
  31. MAIL_DATA *newMail(CHAR_DATA *sender, const char *mssg) {
  32. MAIL_DATA *mail = malloc(sizeof(MAIL_DATA));
  33. mail->sender = strdup(charGetName(sender));
  34. mail->time = strdup(get_time());
  35. mail->mssg = newBuffer(strlen(mssg));
  36. bufferCat(mail->mssg, mssg);
  37. return mail;
  38. }
  39. // free all of the memory that was allocated to make this piece of mail
  40. void deleteMail(MAIL_DATA *mail) {
  41. if(mail->sender) free(mail->sender);
  42. if(mail->time) free(mail->time);
  43. if(mail->mssg) deleteBuffer(mail->mssg);
  44. free(mail);
  45. }
  46. </pre>
  47. Now that the basic steps for creating and deleting mail are complete, we
  48. can set up some commands to allow players to send mail:
  49. <pre class="code">
  50. // mails a message to the specified person. This command must take the
  51. // following form:
  52. // mail <person>
  53. //
  54. // The contents of the character's notepad will be used as the body of the
  55. // message. The character's notepad must not be empty.
  56. COMMAND(cmd_mail) {
  57. // make sure the character exists
  58. if(!player_exists(arg))
  59. send_to_char(ch, "Noone named %s is registered on %s.\r\n",
  60. arg, "<insert mud name here>");
  61. // make sure we have a socket - we'll need access to its notepad
  62. else if(!charGetSocket(ch))
  63. send_to_char(ch, "Only characters with sockets can send mail!\r\n");
  64. // make sure our notepad is not empty
  65. else if(!*bufferString(socketGetNotepad(charGetSocket(ch))))
  66. send_to_char(ch, "Your notepad is empty. "
  67. "First, try writing something with {cwrite{n.\r\n");
  68. // the character exists. Let's parse the items and send the mail
  69. else {
  70. MAIL_DATA *mail = newMail(ch, bufferString(socketGetNotepad(charGetSocket(ch))));
  71. // if we had some way of storing mail, we'd now do that. But since we
  72. // don't, let's just delete the mail.
  73. //***********
  74. // FINISH ME
  75. //***********
  76. deleteMail(mail);
  77. // let the character know we've sent the mail
  78. send_to_char(ch, "You send a message to %s.\r\n", arg);
  79. }
  80. }
  81. </pre>
  82. We will also want to add this new command to the main command table. To do that,
  83. make a call to add_cmd in init_mail:
  84. <pre class="code">
  85. // boot up the mail module
  86. void init_mail(void) {
  87. // add all of the commands that come with this module
  88. add_cmd("mail", NULL, cmd_mail, "player", FALSE);
  89. }
  90. </pre>
  91. The first incarnation of the mail module is just about complete. The only thing
  92. needed now is a way to store mail that has been sent. To do this, there needs
  93. to be some way of mapping characters to their received mail, and a command for
  94. them to access that mail. Let us create a hashtable to map character names to
  95. their mail. Do this at the top of mail.c, just before the MAIL_DATA structure
  96. is defined:
  97. <pre class="code">
  98. // maps charName to a list of mail they have received
  99. HASHTABLE *mail_table = NULL;
  100. </pre>
  101. The hashtable will also need to be initialized. This can be done in the
  102. init_mail function:
  103. <pre class="code">
  104. // boot up the mail module
  105. void init_mail(void) {
  106. // initialize the mail table
  107. mail_table = newHashtable();
  108. // add all of the commands that come with this module
  109. add_cmd("mail", NULL, cmd_mail, "player", FALSE);
  110. }
  111. </pre>
  112. Earlier, the mail command was left unfinished because there was no way to store
  113. mail. Now that there is a hashtable for serving this function, go back to
  114. cmd_mail and fill in the unfinishedp art:
  115. <pre class="code">
  116. // the character exists. Let's parse the items and send the mail
  117. else {
  118. MAIL_DATA *mail = newMail(ch, bufferString(socketGetNotepad(charGetSocket(ch))));
  119. // see if the receiver already has a mail list
  120. LIST *mssgs = hashGet(mail_table, arg);
  121. // if he doesn't, create one and add it to the hashtable
  122. if(mssgs == NULL) {
  123. mssgs = newList();
  124. hashPut(mail_table, arg, mssgs);
  125. }
  126. // add the new mail to our mail list
  127. listPut(mssgs, mail);
  128. // let the character know we've sent the mail
  129. send_to_char(ch, "You send a message to %s.\r\n", arg);
  130. }
  131. </pre>
  132. It's all well and good being able to send mail, but what about receiving mail?
  133. Here is a way to write a command for performing that function:
  134. <pre class="code">
  135. // checks to see if the character has any mail. If he does, convert each piece
  136. // of mail into an object, and transfer them all into the character's inventory.
  137. COMMAND(cmd_receive) {
  138. // Remove the character's mail list from our mail table
  139. LIST *mail_list = hashRemove(mail_table, charGetName(ch));
  140. // make sure the list exists
  141. if(mail_list == NULL || listSize(mail_list) == 0)
  142. send_to_char(ch, "You have no new mail.\r\n");
  143. // hand over all of the mail
  144. else {
  145. // go through each piece of mail, make an object for it,
  146. // and transfer the new object to us
  147. LIST_ITERATOR *mail_i = newListIterator(mail_list);
  148. MAIL_DATA *mail = NULL;
  149. ITERATE_LIST(mail, mail_i) {
  150. OBJ_DATA *obj = newObj();
  151. objSetName (obj, "a letter");
  152. objSetKeywords (obj, "letter, mail");
  153. objSetRdesc (obj, "A letter is here.");
  154. objSetMultiName (obj, "A stack of %d letters");
  155. objSetMultiRdesc(obj, "A stack of %d letters are here.");
  156. bprintf(objGetDescBuffer(obj),
  157. "Sender : %s\r\n"
  158. "Date sent: %s\r\n"
  159. "%s", mail->sender, mail->time, bufferString(mail->mssg));
  160. // give the object to the character
  161. obj_to_game(obj);
  162. obj_to_char(obj, ch);
  163. } deleteListIterator(mail_i);
  164. // let the character know how much mail he received
  165. send_to_char(ch, "You receive %d letter%s.\r\n",
  166. listSize(mail_list), (listSize(mail_list) == 1 ? "" : "s"));
  167. }
  168. // delete the mail list, and all of its contents
  169. if(mail_list != NULL) deleteListWith(mail_list, deleteMail);
  170. }
  171. </pre>
  172. Like with cmd_mail, add the receive command to the global command table. You
  173. can copy and paste from what already exists. Once that is done, you have the
  174. first pass at a mail module. You could probably add lots to this module, like
  175. parcels of items, fees for sending mail, checks to make sure mail is only sent
  176. at mailboxes, etc... but for our purposes of demonstrating how modules work,
  177. this will suffice. The rest of the features will be left to you as an exercise.
  178. </div>
  179. <!-- content ends here-->
  180. </div></div></div>
  181. <!-- navigation starts here -->
  182. <div class="nav-wrap"><div class="nav">
  183. <iframe src="nav.html" height="100%" width="100%" scrolling=no frameborder=0>
  184. </iframe>
  185. <!-- navigation ends here -->
  186. </div></div>
  187. <!--div class="footer">Edit Date: Nov 15, 2008. By Geoff Hollis</div-->
  188. </body>
  189. </html>