Wikia

Wikihack

Source:SLASH'EM 0.0.7E7F2/mail.c

2,032pages on
this wiki
Talk0

Below is the full text to mail.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/mail.c#line123]], for example.

The latest source code for vanilla NetHack is at Source code.


The NetHack General Public License applies to screenshots, source code and other content from NetHack.
1.    /*	SCCS Id: @(#)mail.c	3.4	2002/01/13	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #include "hack.h"
6.    
7.    #ifdef MAIL
8.    #include "mail.h"
9.    
10.   /*
11.    * Notify user when new mail has arrived.  Idea by Merlyn Leroy.
12.    *
13.    * The mail daemon can move with less than usual restraint.  It can:
14.    *	- move diagonally from a door
15.    *	- use secret and closed doors
16.    *	- run through a monster ("Gangway!", etc.)
17.    *	- run over pools & traps
18.    *
19.    * Possible extensions:
20.    *	- Open the file MAIL and do fstat instead of stat for efficiency.
21.    *	  (But sh uses stat, so this cannot be too bad.)
22.    *	- Examine the mail and produce a scroll of mail named "From somebody".
23.    *	- Invoke MAILREADER in such a way that only this single letter is read.
24.    *	- Do something to the text when the scroll is enchanted or cancelled.
25.    *	- Make the daemon always appear at a stairwell, and have it find a
26.    *	  path to the hero.
27.    *
28.    * Note by Olaf Seibert: On the Amiga, we usually don't get mail.  So we go
29.    *			 through most of the effects at 'random' moments.
30.    * Note by Paul Winner:  The MSDOS port also 'fakes' the mail daemon at
31.    *			 random intervals.
32.    */
33.   
34.   STATIC_DCL boolean FDECL(md_start,(coord *));
35.   STATIC_DCL boolean FDECL(md_stop,(coord *, coord *));
36.   STATIC_DCL boolean FDECL(md_rush,(struct monst *,int,int));
37.   STATIC_DCL void FDECL(newmail, (struct mail_info *));
38.   
39.   extern char *viz_rmin, *viz_rmax;	/* line-of-sight limits (vision.c) */
40.   
41.   #ifdef OVL0
42.   
43.   # if !defined(UNIX) && !defined(VMS) && !defined(LAN_MAIL)
44.   int mustgetmail = -1;
45.   # endif
46.   
47.   #endif /* OVL0 */
48.   #ifdef OVLB
49.   
50.   # ifdef UNIX
51.   #include <sys/stat.h>
52.   #include <pwd.h>
53.   /* DON'T trust all Unices to declare getpwuid() in <pwd.h> */
54.   #  if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX)
55.   #   if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__))
56.   #    if !defined(LINUX)
57.   /* DO trust all SVR4 to typedef uid_t in <sys/types.h> (probably to a long) */
58.   #    if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX)
59.   extern struct passwd *FDECL(getpwuid,(uid_t));
60.   #    else
61.   extern struct passwd *FDECL(getpwuid,(int));
62.   #    endif
63.   #   endif
64.   #  endif
65.   #  endif
66.   static struct stat omstat,nmstat;
67.   static char *mailbox = (char *)0;
68.   static long laststattime;
69.   
70.   # if !defined(MAILPATH) && defined(AMS)	/* Just a placeholder for AMS */
71.   #  define MAILPATH "/dev/null"
72.   # endif
73.   # if !defined(MAILPATH) && (defined(LINUX) || defined(__osf__))
74.   #  define MAILPATH "/var/spool/mail/"
75.   # endif
76.   # if !defined(MAILPATH) && defined(__FreeBSD__)
77.   #  define MAILPATH "/var/mail/"
78.   # endif
79.   # if !defined(MAILPATH) && (defined(BSD) || defined(ULTRIX))
80.   #  define MAILPATH "/usr/spool/mail/"
81.   # endif
82.   # if !defined(MAILPATH) && (defined(SYSV) || defined(HPUX))
83.   #  define MAILPATH "/usr/mail/"
84.   # endif
85.   
86.   void
87.   getmailstatus()
88.   {
89.   	if(!mailbox && !(mailbox = nh_getenv("MAIL"))) {
90.   #  ifdef MAILPATH
91.   #   ifdef AMS
92.   	        struct passwd ppasswd;
93.   
94.   		(void) memcpy(&ppasswd, getpwuid(getuid()), sizeof(struct passwd));
95.   		if (ppasswd.pw_dir) {
96.   		     mailbox = (char *) alloc((unsigned) strlen(ppasswd.pw_dir)+sizeof(AMS_MAILBOX));
97.   		     Strcpy(mailbox, ppasswd.pw_dir);
98.   		     Strcat(mailbox, AMS_MAILBOX);
99.   		} else
100.  		  return;
101.  #   else
102.  		const char *pw_name = getpwuid(getuid())->pw_name;
103.  		mailbox = (char *) alloc(sizeof(MAILPATH)+strlen(pw_name));
104.  		Strcpy(mailbox, MAILPATH);
105.  		Strcat(mailbox, pw_name);
106.  #  endif /* AMS */
107.  #  else
108.  		return;
109.  #  endif
110.  	}
111.  	if(stat(mailbox, &omstat)){
112.  #  ifdef PERMANENT_MAILBOX
113.  		pline("Cannot get status of MAIL=\"%s\".", mailbox);
114.  		mailbox = 0;
115.  #  else
116.  		omstat.st_mtime = 0;
117.  #  endif
118.  	}
119.  }
120.  # endif /* UNIX */
121.  
122.  #endif /* OVLB */
123.  #ifdef OVL0
124.  
125.  /*
126.   * Pick coordinates for a starting position for the mail daemon.  Called
127.   * from newmail() and newphone().
128.   */
129.  STATIC_OVL boolean
130.  md_start(startp)
131.      coord *startp;
132.  {
133.      coord testcc;	/* scratch coordinates */
134.      int row;		/* current row we are checking */
135.      int lax;		/* if TRUE, pick a position in sight. */
136.      int dd;		/* distance to current point */
137.      int max_distance;	/* max distance found so far */
138.  
139.      /*
140.       * If blind and not telepathic, then it doesn't matter what we pick ---
141.       * the hero is not going to see it anyway.  So pick a nearby position.
142.       */
143.      if (Blind && !Blind_telepat) {
144.  	if (!enexto(startp, u.ux, u.uy, (struct permonst *) 0))
145.  	    return FALSE;	/* no good posiitons */
146.  	return TRUE;
147.      }
148.  
149.      /*
150.       * Arrive at an up or down stairwell if it is in line of sight from the
151.       * hero.
152.       */
153.      if (couldsee(upstair.sx, upstair.sy)) {
154.  	startp->x = upstair.sx;
155.  	startp->y = upstair.sy;
156.  	return TRUE;
157.      }
158.      if (couldsee(dnstair.sx, dnstair.sy)) {
159.  	startp->x = dnstair.sx;
160.  	startp->y = dnstair.sy;
161.  	return TRUE;
162.      }
163.  
164.      /*
165.       * Try to pick a location out of sight next to the farthest position away
166.       * from the hero.  If this fails, try again, just picking the farthest
167.       * position that could be seen.  What we really ought to be doing is
168.       * finding a path from a stairwell...
169.       *
170.       * The arrays viz_rmin[] and viz_rmax[] are set even when blind.  These
171.       * are the LOS limits for each row.
172.       */
173.      lax = 0;	/* be picky */
174.      max_distance = -1;
175.  retry:
176.      for (row = 0; row < ROWNO; row++) {
177.  	if (viz_rmin[row] < viz_rmax[row]) {
178.  	    /* There are valid positions on this row. */
179.  	    dd = distu(viz_rmin[row],row);
180.  	    if (dd > max_distance) {
181.  		if (lax) {
182.  		    max_distance = dd;
183.  		    startp->y = row;
184.  		    startp->x = viz_rmin[row];
185.  		
186.  		} else if (enexto(&testcc, (xchar)viz_rmin[row], row,
187.  						(struct permonst *) 0) &&
188.  			   !cansee(testcc.x, testcc.y) &&
189.  			   couldsee(testcc.x, testcc.y)) {
190.  		    max_distance = dd;
191.  		    *startp = testcc;
192.  		}
193.  	    }
194.  	    dd = distu(viz_rmax[row],row);
195.  	    if (dd > max_distance) {
196.  		if (lax) {
197.  		    max_distance = dd;
198.  		    startp->y = row;
199.  		    startp->x = viz_rmax[row];
200.  		
201.  		} else if (enexto(&testcc, (xchar)viz_rmax[row], row,
202.  						(struct permonst *) 0) &&
203.  			   !cansee(testcc.x,testcc.y) &&
204.  			   couldsee(testcc.x, testcc.y)) {
205.  
206.  		    max_distance = dd;
207.  		    *startp = testcc;
208.  		}
209.  	    }
210.  	}
211.      }
212.  
213.      if (max_distance < 0) {
214.  	if (!lax) {
215.  	    lax = 1;		/* just find a position */
216.  	    goto retry;
217.  	}
218.  	return FALSE;
219.      }
220.  
221.      return TRUE;
222.  }
223.  
224.  /*
225.   * Try to choose a stopping point as near as possible to the starting
226.   * position while still adjacent to the hero.  If all else fails, try
227.   * enexto().  Use enexto() as a last resort because enexto() chooses
228.   * its point randomly, which is not what we want.
229.   */
230.  STATIC_OVL boolean
231.  md_stop(stopp, startp)
232.      coord *stopp;	/* stopping position (we fill it in) */
233.      coord *startp;	/* starting positon (read only) */
234.  {
235.      int x, y, distance, min_distance = -1;
236.  
237.      for (x = u.ux-1; x <= u.ux+1; x++)
238.  	for (y = u.uy-1; y <= u.uy+1; y++) {
239.  	    if (!isok(x, y) || (x == u.ux && y == u.uy)) continue;
240.  
241.  	    if (ACCESSIBLE(levl[x][y].typ) && !MON_AT(x,y)) {
242.  		distance = dist2(x,y,startp->x,startp->y);
243.  		if (min_distance < 0 || distance < min_distance ||
244.  			(distance == min_distance && rn2(2))) {
245.  		    stopp->x = x;
246.  		    stopp->y = y;
247.  		    min_distance = distance;
248.  		}
249.  	    }
250.  	}
251.  
252.      /* If we didn't find a good spot, try enexto(). */
253.      if (min_distance < 0 &&
254.  		!enexto(stopp, u.ux, u.uy, &mons[PM_MAIL_DAEMON]))
255.  	return FALSE;
256.  
257.      return TRUE;
258.  }
259.  
260.  /* Let the mail daemon have a larger vocabulary. */
261.  static NEARDATA const char *mail_text[] = {
262.      "Gangway!",
263.      "Look out!",
264.      "Pardon me!"
265.  };
266.  #define md_exclamations()	(mail_text[rn2(3)])
267.  
268.  /*
269.   * Make the mail daemon run through the dungeon.  The daemon will run over
270.   * any monsters that are in its path, but will replace them later.  Return
271.   * FALSE if the md gets stuck in a position where there is a monster.  Return
272.   * TRUE otherwise.
273.   */
274.  STATIC_OVL boolean
275.  md_rush(md,tx,ty)
276.      struct monst *md;
277.      register int tx, ty;		/* destination of mail daemon */
278.  {
279.      struct monst *mon;			/* displaced monster */
280.      register int dx, dy;		/* direction counters */
281.      int fx = md->mx, fy = md->my;	/* current location */
282.      int nfx = fx, nfy = fy,		/* new location */
283.  	d1, d2;				/* shortest distances */
284.  
285.      /*
286.       * It is possible that the monster at (fx,fy) is not the md when:
287.       * the md rushed the hero and failed, and is now starting back.
288.       */
289.      if (m_at(fx, fy) == md) {
290.  	remove_monster(fx, fy);		/* pick up from orig position */
291.  	newsym(fx, fy);
292.      }
293.  
294.      /*
295.       * At the beginning and exit of this loop, md is not placed in the
296.       * dungeon.
297.       */
298.      while (1) {
299.  	/* Find a good location next to (fx,fy) closest to (tx,ty). */
300.  	d1 = dist2(fx,fy,tx,ty);
301.  	for (dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
302.  	    if ((dx || dy) && isok(fx+dx,fy+dy) &&
303.  				       !IS_STWALL(levl[fx+dx][fy+dy].typ)) {
304.  		d2 = dist2(fx+dx,fy+dy,tx,ty);
305.  		if (d2 < d1) {
306.  		    d1 = d2;
307.  		    nfx = fx+dx;
308.  		    nfy = fy+dy;
309.  		}
310.  	    }
311.  
312.  	/* Break if the md couldn't find a new position. */
313.  	if (nfx == fx && nfy == fy) break;
314.  
315.  	fx = nfx;			/* this is our new position */
316.  	fy = nfy;
317.  
318.  	/* Break if the md reaches its destination. */
319.  	if (fx == tx && fy == ty) break;
320.  
321.  	if ((mon = m_at(fx,fy)) != 0)	/* save monster at this position */
322.  	    verbalize(md_exclamations());
323.  	else if (fx == u.ux && fy == u.uy)
324.  	    verbalize("Excuse me.");
325.  
326.  	place_monster(md,fx,fy);	/* put md down */
327.  	newsym(fx,fy);			/* see it */
328.  	flush_screen(0);		/* make sure md shows up */
329.  	delay_output();			/* wait a little bit */
330.  
331.  	/* Remove md from the dungeon.  Restore original mon, if necessary. */
332.  	if (mon) {
333.  	    if ((mon->mx != fx) || (mon->my != fy))
334.  		place_worm_seg(mon, fx, fy);
335.  	    else
336.  		place_monster(mon, fx, fy);
337.  	} else
338.  	    remove_monster(fx, fy);
339.  	newsym(fx,fy);
340.      }
341.  
342.      /*
343.       * Check for a monster at our stopping position (this is possible, but
344.       * very unlikely).  If one exists, then have the md leave in disgust.
345.       */
346.      if ((mon = m_at(fx, fy)) != 0) {
347.  	place_monster(md, fx, fy);	/* display md with text below */
348.  	newsym(fx, fy);
349.  	verbalize("This place's too crowded.  I'm outta here.");
350.  
351.  	if ((mon->mx != fx) || (mon->my != fy))	/* put mon back */
352.  	    place_worm_seg(mon, fx, fy);
353.  	else
354.  	    place_monster(mon, fx, fy);
355.  
356.  	newsym(fx, fy);
357.  	return FALSE;
358.      }
359.  
360.      place_monster(md, fx, fy);	/* place at final spot */
361.      newsym(fx, fy);
362.      flush_screen(0);
363.      delay_output();			/* wait a little bit */
364.  
365.      return TRUE;
366.  }
367.  
368.  /* Deliver a scroll of mail. */
369.  /*ARGSUSED*/
370.  STATIC_OVL void
371.  newmail(info)
372.  struct mail_info *info;
373.  {
374.      struct monst *md;
375.      coord start, stop;
376.      boolean message_seen = FALSE;
377.  
378.      /* Try to find good starting and stopping places. */
379.      if (!md_start(&start) || !md_stop(&stop,&start)) goto give_up;
380.  
381.      /* Make the daemon.  Have it rush towards the hero. */
382.      if (!(md = makemon(&mons[PM_MAIL_DAEMON], start.x, start.y, NO_MM_FLAGS)))
383.  	 goto give_up;
384.      if (!md_rush(md, stop.x, stop.y)) goto go_back;
385.  
386.      message_seen = TRUE;
387.      verbalize("%s, %s!  %s.", Hello(md), plname, info->display_txt);
388.  
389.      if (info->message_typ) {
390.  	struct obj *obj = mksobj(SCR_MAIL, FALSE, FALSE);
391.  	if (distu(md->mx,md->my) > 2)
392.  	    verbalize("Catch!");
393.  	display_nhwindow(WIN_MESSAGE, FALSE);
394.  	if (info->object_nam) {
395.  	    obj = oname(obj, info->object_nam);
396.  	    if (info->response_cmd) {	/*(hide extension of the obj name)*/
397.  		int namelth = info->response_cmd - info->object_nam - 1;
398.  		if ( namelth <= 0 || namelth >= (int) obj->onamelth )
399.  		    impossible("mail delivery screwed up");
400.  		else
401.  		    *(ONAME(obj) + namelth) = '\0';
402.  		/* Note: renaming object will discard the hidden command. */
403.  	    }
404.  	}
405.  	obj = hold_another_object(obj, "Oops!",
406.  				  (const char *)0, (const char *)0);
407.      }
408.  
409.      /* zip back to starting location */
410.  go_back:
411.      (void) md_rush(md, start.x, start.y);
412.      mongone(md);
413.      /* deliver some classes of messages even if no daemon ever shows up */
414.  give_up:
415.      if (!message_seen && info->message_typ == MSG_OTHER)
416.  	pline("Hark!  \"%s.\"", info->display_txt);
417.  }
418.  
419.  # if !defined(UNIX) && !defined(VMS) && !defined(LAN_MAIL)
420.  
421.  void
422.  ckmailstatus()
423.  {
424.  	if (u.uswallow || !flags.biff) return;
425.  	if (mustgetmail < 0) {
426.  #if defined(AMIGA) || defined(MSDOS) || defined(TOS) || defined(OS2)
427.  	    mustgetmail=(moves<2000)?(100+rn2(2000)):(2000+rn2(3000));
428.  #endif
429.  	    return;
430.  	}
431.  	if (--mustgetmail <= 0) {
432.  		static struct mail_info
433.  			deliver = {MSG_MAIL,"I have some mail for you",0,0};
434.  		newmail(&deliver);
435.  		mustgetmail = -1;
436.  	}
437.  }
438.  
439.  /*ARGSUSED*/
440.  void
441.  readmail(otmp)
442.  struct obj *otmp;
443.  {
444.      const char *line;
445.      char buf[BUFSZ];
446.      line = getrumor(bcsign(otmp), buf, TRUE);
447.      if (!*line)
448.  	   line = "NetHack rumors file closed for renovation.";
449.      if (Blind) {
450.  	pline("Unfortunately you cannot see what it says.");
451.      } else
452.  	pline("It reads:  \"%s\"", line);
453.  
454.  }
455.  
456.  # endif /* !UNIX && !VMS */
457.  
458.  # ifdef UNIX
459.  
460.  void
461.  ckmailstatus()
462.  {
463.  	if(!mailbox || u.uswallow || !flags.biff
464.  #  ifdef MAILCKFREQ
465.  		    || moves < laststattime + MAILCKFREQ
466.  #  endif
467.  							)
468.  		return;
469.  
470.  	laststattime = moves;
471.  	if(stat(mailbox, &nmstat)){
472.  #  ifdef PERMANENT_MAILBOX
473.  		pline("Cannot get status of MAIL=\"%s\" anymore.", mailbox);
474.  		mailbox = 0;
475.  #  else
476.  		nmstat.st_mtime = 0;
477.  #  endif
478.  	} else if(nmstat.st_mtime > omstat.st_mtime) {
479.  		if (nmstat.st_size) {
480.  		    static struct mail_info deliver = {
481.  #  ifndef NO_MAILREADER
482.  			MSG_MAIL, "I have some mail for you",
483.  #  else
484.  			/* suppress creation and delivery of scroll of mail */
485.  			MSG_OTHER, "You have some mail in the outside world",
486.  #  endif
487.  			0, 0
488.  		    };
489.  		    newmail(&deliver);
490.  		}
491.  		getmailstatus();	/* might be too late ... */
492.  	}
493.  }
494.  
495.  /*ARGSUSED*/
496.  void
497.  readmail(otmp)
498.  struct obj *otmp;
499.  {
500.  #  ifdef DEF_MAILREADER			/* This implies that UNIX is defined */
501.  	register const char *mr = 0;
502.  
503.  	display_nhwindow(WIN_MESSAGE, FALSE);
504.  	if(!(mr = nh_getenv("MAILREADER")))
505.  		mr = DEF_MAILREADER;
506.  
507.  	if(child(1)){
508.  		(void) execl(mr, mr, (char *)0);
509.  		terminate(EXIT_FAILURE);
510.  	}
511.  #  else
512.  #   ifndef AMS				/* AMS mailboxes are directories */
513.  	display_file_area(NULL, mailbox, TRUE);
514.  #   endif /* AMS */
515.  #  endif /* DEF_MAILREADER */
516.  
517.  	/* get new stat; not entirely correct: there is a small time
518.  	   window where we do not see new mail */
519.  	getmailstatus();
520.  }
521.  
522.  # endif /* UNIX */
523.  
524.  # ifdef VMS
525.  
526.  extern NDECL(struct mail_info *parse_next_broadcast);
527.  
528.  volatile int broadcasts = 0;
529.  
530.  void
531.  ckmailstatus()
532.  {
533.      struct mail_info *brdcst;
534.  
535.      if(u.uswallow || !flags.biff) return;
536.  
537.      while (broadcasts > 0) {	/* process all trapped broadcasts [until] */
538.  	broadcasts--;
539.  	if ((brdcst = parse_next_broadcast()) != 0) {
540.  	    newmail(brdcst);
541.  	    break;		/* only handle one real message at a time */
542.  	}
543.      }
544.  }
545.  
546.  void
547.  readmail(otmp)
548.  struct obj *otmp;
549.  {
550.  #  ifdef SHELL	/* can't access mail reader without spawning subprocess */
551.      const char *txt, *cmd;
552.      char *p, buf[BUFSZ], qbuf[BUFSZ];
553.      int len;
554.  
555.      /* there should be a command hidden beyond the object name */
556.      txt = otmp->onamelth ? ONAME(otmp) : "";
557.      len = strlen(txt);
558.      cmd = (len + 1 < otmp->onamelth) ? txt + len + 1 : (char *) 0;
559.      if (!cmd || !*cmd) cmd = "SPAWN";
560.  
561.      Sprintf(qbuf, "System command (%s)", cmd);
562.      getlin(qbuf, buf);
563.      if (*buf != '\033') {
564.  	for (p = eos(buf); p > buf; *p = '\0')
565.  	    if (*--p != ' ') break;	/* strip trailing spaces */
566.  	if (*buf) cmd = buf;		/* use user entered command */
567.  	if (!strcmpi(cmd, "SPAWN") || !strcmp(cmd, "!"))
568.  	    cmd = (char *) 0;		/* interactive escape */
569.  
570.  	vms_doshell(cmd, TRUE);
571.  	(void) sleep(1);
572.      }
573.  #  endif /* SHELL */
574.  }
575.  
576.  # endif /* VMS */
577.  
578.  # ifdef LAN_MAIL
579.  
580.  void
581.  ckmailstatus()
582.  {
583.  	static int laststattime = 0;
584.  	
585.  	if(u.uswallow || !flags.biff
586.  #  ifdef MAILCKFREQ
587.  		    || moves < laststattime + MAILCKFREQ
588.  #  endif
589.  							)
590.  		return;
591.  
592.  	laststattime = moves;
593.  	if (lan_mail_check()) {
594.  		    static struct mail_info deliver = {
595.  #  ifndef NO_MAILREADER
596.  			MSG_MAIL, "I have some mail for you",
597.  #  else
598.  			/* suppress creation and delivery of scroll of mail */
599.  			MSG_OTHER, "You have some mail in the outside world",
600.  #  endif
601.  			0, 0
602.  		    };
603.  		    newmail(&deliver);
604.  	}
605.  }
606.  
607.  /*ARGSUSED*/
608.  void
609.  readmail(otmp)
610.  struct obj *otmp;
611.  {
612.  	lan_mail_read(otmp);
613.  }
614.  
615.  # endif /* LAN_MAIL */
616.  
617.  #endif /* OVL0 */
618.  
619.  #endif /* MAIL */
620.  
621.  /*mail.c*/

Around Wikia's network

Random Wiki