Source:SLASH'EM 0.0.7E7F2/questpgr.c

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

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

1.   /*	SCCS Id: @(#)questpgr.c	3.4	2000/05/05	*/ 2.   /*	Copyright 1991, M. Stephenson		  */ 3.   /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6.    #include "dlb.h"  7. 8.   /*  quest-specific pager routines. */ 9.     10.   #include "qtext.h"  11. 12.  #define QTEXT_AREA      FILE_AREA_SHARE 13.  #define QTEXT_FILE	"quest.dat" 14.   15.   /* #define DEBUG */	/* uncomment for debugging */ 16.   17.   static void FDECL(Fread, (genericptr_t,int,int,dlb *)); 18.  STATIC_DCL struct qtmsg * FDECL(construct_qtlist, (long)); 19.  STATIC_DCL const char * NDECL(intermed); 20.  STATIC_DCL const char * NDECL(neminame); 21.  STATIC_DCL const char * NDECL(guardname); 22.  STATIC_DCL const char * NDECL(homebase); 23.  STATIC_DCL struct qtmsg * FDECL(msg_in, (struct qtmsg *,int)); 24.  STATIC_DCL void FDECL(convert_arg, (CHAR_P)); 25.  STATIC_DCL void NDECL(convert_line); 26.  STATIC_DCL void FDECL(deliver_by_pline, (struct qtmsg *)); 27.  STATIC_DCL void FDECL(deliver_by_window, (struct qtmsg *,int)); 28.   29.   static char	in_line[80], cvt_buf[64], out_line[128]; 30.  static struct	qtlists	qt_list; 31.  static dlb	*msg_file; 32.  /* used by ldrname and neminame, then copied into cvt_buf */ 33.  static char	nambuf[sizeof cvt_buf]; 34.   35.   #ifdef DEBUG 36.  static void NDECL(dump_qtlist); 37.   38.   static void 39.  dump_qtlist	/* dump the character msg list to check appearance */ 40.  {  41.   	struct	qtmsg	*msg; 42.  	long	size; 43.   44.   	for (msg = qt_list.chrole; msg->msgnum > 0; msg++) { 45.  		pline("msgnum %d: delivery %c",  46.   			msg->msgnum, msg->delivery); 47.  		more; 48.  		(void) dlb_fseek(msg_file, msg->offset, SEEK_SET); 49.  		deliver_by_window(msg, NHW_TEXT); 50.  	}  51.   }  52.   #endif /* DEBUG */ 53.   54.   static void 55.  Fread(ptr, size, nitems, stream) 56.  genericptr_t	ptr; 57.  int	size, nitems; 58.  dlb	*stream; 59.  {  60.   	int cnt; 61.   62.   	if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) { 63.   64.   	    panic("PREMATURE EOF ON QUEST TEXT FILE! Expected %d bytes, got %d",  65.   		    (size * nitems), (size * cnt)); 66.  	}  67.   }  68.    69.   STATIC_OVL struct qtmsg * 70.  construct_qtlist(hdr_offset) 71.  long	hdr_offset; 72.  {  73.   	struct qtmsg *msg_list; 74.  	int	n_msgs; 75.   76.   	(void) dlb_fseek(msg_file, hdr_offset, SEEK_SET); 77.  	Fread(&n_msgs, sizeof(int), 1, msg_file); 78.  	msg_list = (struct qtmsg *) 79.  		alloc((unsigned)(n_msgs+1)*sizeof(struct qtmsg)); 80.   81.   	/*  82.   	 * Load up the list. 83.  	 */  84.   	Fread((genericptr_t)msg_list, n_msgs*sizeof(struct qtmsg), 1, msg_file); 85.   86.   	msg_list[n_msgs].msgnum = -1; 87.  	return(msg_list); 88.  }  89.    90.   void 91.  load_qtlist 92.  {  93.    94.   	int	n_classes, i;  95. char	qt_classes[N_HDR][LEN_HDR]; 96.  	long	qt_offsets[N_HDR]; 97.   98.   	msg_file = dlb_fopen_area(QTEXT_AREA, QTEXT_FILE, RDBMODE); 99.  	if (!msg_file) 100. 	    panic("CANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE); 101.  102.  	/*  103.  	 * Read in the number of classes, then the ID's & offsets for 104. 	 * each header. 105. 	 */  106.   107.  	Fread(&n_classes, sizeof(int), 1, msg_file); 108. 	Fread(&qt_classes[0][0], sizeof(char)*LEN_HDR, n_classes, msg_file); 109. 	Fread(qt_offsets, sizeof(long), n_classes, msg_file); 110.  111.  	/*  112.  	 * Now construct the message lists for quick reference later 113. 	 * on when we are actually paging the messages out. 114. 	 */  115.   116.  	qt_list.common = qt_list.chrole = (struct qtmsg *)0; 117.  118.  	for (i = 0; i < n_classes; i++) { 119. 	    if (!strncmp(COMMON_ID, qt_classes[i], LEN_HDR)) 120. 	    	qt_list.common = construct_qtlist(qt_offsets[i]); 121. 	    else if (!strncmp(urole.filecode, qt_classes[i], LEN_HDR)) 122. 	    	qt_list.chrole = construct_qtlist(qt_offsets[i]); 123. #if 0	/* UNUSED but available */ 124. 	    else if (!strncmp(urace.filecode, qt_classes[i], LEN_HDR)) 125. 	    	qt_list.chrace = construct_qtlist(qt_offsets[i]); 126. #endif 127. 	}  128.   129.  	if (!qt_list.common || !qt_list.chrole) 130. 	    impossible("load_qtlist: cannot load quest text."); 131. #ifdef DEBUG 132. 	dump_qtlist; 133. #endif 134. 	return;	/* no ***DON'T*** close the msg_file */ 135. }  136.   137.  /* called at program exit */ 138. void 139. unload_qtlist 140. {  141.  	if (msg_file) 142. 	    (void) dlb_fclose(msg_file),  msg_file = 0; 143. 	if (qt_list.common) 144. 	    free((genericptr_t) qt_list.common),  qt_list.common = 0; 145. 	if (qt_list.chrole) 146. 	    free((genericptr_t) qt_list.chrole),  qt_list.chrole = 0; 147. 	return; 148. }  149.   150.  short 151. quest_info(typ) 152. int typ; 153. {  154.  	switch (typ) { 155. 	    case 0:		return (urole.questarti); 156. 	    case MS_LEADER:	return (urole.ldrnum); 157. 	    case MS_NEMESIS:	return (urole.neminum); 158. 	    case MS_GUARDIAN:	return (urole.guardnum); 159. 	    default:		impossible("quest_info(%d)", typ); 160. 	}  161.  	return 0; 162. }  163.   164.  const char * 165. ldrname	/* return your role leader's name */ 166. {  167.  	int i = urole.ldrnum; 168.  169.  	Sprintf(nambuf, "%s%s",  170.  		type_is_pname(&mons[i]) ? "" : "the ",  171.  		mons[i].mname); 172. 	return nambuf; 173. }  174.   175.  STATIC_OVL const char * 176. intermed	/* return your intermediate target string */ 177. {  178.  	return (urole.intermed); 179. }  180.   181.  boolean 182. is_quest_artifact(otmp) 183. struct obj *otmp; 184. {  185.  	return((boolean)(otmp->oartifact == urole.questarti)); 186. }  187.   188.  STATIC_OVL const char * 189. neminame	/* return your role nemesis' name */ 190. {  191.  	int i = urole.neminum; 192.  193.  	Sprintf(nambuf, "%s%s",  194.  		type_is_pname(&mons[i]) ? "" : "the ",  195.  		mons[i].mname); 196. 	return nambuf; 197. }  198.   199.  STATIC_OVL const char * 200. guardname	/* return your role leader's guard monster name */ 201. {  202.  	int i = urole.guardnum; 203.  204.  	return(mons[i].mname); 205. }  206.   207.  STATIC_OVL const char * 208. homebase	/* return your role leader's location */ 209. {  210.  	return(urole.homebase); 211. }  212.   213.  STATIC_OVL struct qtmsg * 214. msg_in(qtm_list, msgnum) 215. struct qtmsg *qtm_list; 216. int	msgnum; 217. {  218.  	struct qtmsg *qt_msg; 219.  220.  	for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++) 221. 	    if (qt_msg->msgnum == msgnum) return(qt_msg); 222.  223.  	return((struct qtmsg *)0); 224. }  225.   226.  STATIC_OVL void 227. convert_arg(c) 228. char c;  229. { 230.  	register const char *str; 231.  232.  	switch (c) { 233.  234.  	    case 'p':	str = plname; 235. 			break; 236. 	    case 'c':	str = (flags.female && urole.name.f) ? 237. 	    			urole.name.f : urole.name.m;  238. break; 239. 	    case 'r':	str = rank_of(u.ulevel, Role_switch, flags.female); 240. 			break; 241. 	    case 'R':	str = rank_of(MIN_QUEST_LEVEL, Role_switch,  242.  	    			flags.female); 243. 			break; 244. 	    case 's':	str = (flags.female) ? "sister" : "brother"; 245. 			break; 246. 	    case 'S':	str = (flags.female) ? "daughter" : "son"; 247. 			break; 248. 	    case 'l':	str = ldrname; 249. 			break; 250. 	    case 'i':	str = intermed; 251. 			break; 252. 	    case 'o':	str = the(artiname(urole.questarti)); 253. 			break; 254. 	    case 'n':	str = neminame; 255. 			break; 256. 	    case 'g':	str = guardname; 257. 			break; 258. 	    case 'G':	str = align_gtitle(u.ualignbase[A_ORIGINAL]); 259. 			break; 260. 	    case 'H':	str = homebase; 261. 			break; 262. 	    case 'a':	str = align_str(u.ualignbase[A_ORIGINAL]); 263. 			break; 264. 	    case 'A':	str = align_str(u.ualign.type); 265. 			break; 266. 	    case 'd':	str = align_gname(u.ualignbase[A_ORIGINAL]); 267. 			break; 268. 	    case 'D':	str = align_gname(A_LAWFUL); 269. 			break; 270. 	    case 'C':	str = "chaotic"; 271. 			break; 272. 	    case 'N':	str = "neutral"; 273. 			break; 274. 	    case 'L':	str = "lawful"; 275. 			break; 276. 	    case 'x':	str = Blind ? "sense" : "see"; 277. 			break; 278. 	    case 'Z':	str = dungeons[0].dname; 279. 			break; 280. 	    case '%':	str = "%"; 281. 			break; 282. 	     default:	str = ""; 283. 			break; 284. 	}  285.  	Strcpy(cvt_buf, str); 286. }  287.   288.  STATIC_OVL void 289. convert_line 290. {  291.  	char *c, *cc; 292. 	char xbuf[BUFSZ]; 293.  294.  	cc = out_line; 295. 	for (c = xcrypt(in_line, xbuf); *c; c++) { 296.  297.  	    *cc = 0; 298. 	    switch(*c) { 299.  300.  		case '\r': 301. 		case '\n': 302. 			*(++cc) = 0; 303. 			return; 304.  305.  		case '%': 306. 			if (*(c+1)) { 307. 			    convert_arg(*(++c)); 308. 			    switch (*(++c)) { 309.  310.  					/* insert "a"/"an" prefix */ 311. 				case 'A': Strcat(cc, An(cvt_buf)); 312. 				    cc += strlen(cc); 313. 				    continue; /* for */ 314. 				case 'a': Strcat(cc, an(cvt_buf)); 315. 				    cc += strlen(cc); 316. 				    continue; /* for */ 317.  318.  					/* capitalize */ 319. 				case 'C': cvt_buf[0] = highc(cvt_buf[0]); 320. 				    break; 321.  322.  					/* pluralize */ 323. 				case 'P': cvt_buf[0] = highc(cvt_buf[0]); 324. 				case 'p': Strcpy(cvt_buf, makeplural(cvt_buf)); 325. 				    break; 326.  327.  					/* append possessive suffix */ 328. 				case 'S': cvt_buf[0] = highc(cvt_buf[0]); 329. 				case 's': Strcpy(cvt_buf, s_suffix(cvt_buf)); 330. 				    break; 331.  332.  					/* strip any "the" prefix */ 333. 				case 't': if (!strncmpi(cvt_buf, "the ", 4)) { 334. 					Strcat(cc, &cvt_buf[4]); 335. 					cc += strlen(cc); 336. 					continue; /* for */ 337. 				    }  338.  				    break; 339.  340.  				default: --c;	/* undo switch increment */ 341. 				    break; 342. 			    }  343.  			    Strcat(cc, cvt_buf); 344. 			    cc += strlen(cvt_buf); 345. 			    break; 346. 			}	/* else fall through */ 347.  348.  		default: 349. 			*cc++ = *c; 350. 			break; 351. 	    }  352.  	}  353.  	if (cc >= out_line + sizeof out_line) 354. 	    panic("convert_line: overflow"); 355. 	*cc = 0; 356. 	return; 357. }  358.   359.  STATIC_OVL void 360. deliver_by_pline(qt_msg) 361. struct qtmsg *qt_msg; 362. {  363.  	long	size; 364.  365.  	for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) { 366. 	    (void) dlb_fgets(in_line, 80, msg_file); 367. 	    convert_line; 368. 	    pline(out_line); 369. 	}  370.   371.  }  372.   373.  STATIC_OVL void 374. deliver_by_window(qt_msg, how) 375. struct qtmsg *qt_msg; 376. int how; 377. {  378.  	long	size; 379. 	winid datawin = create_nhwindow(how); 380.  381.  	for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) { 382. 	    (void) dlb_fgets(in_line, 80, msg_file); 383. 	    convert_line; 384. 	    putstr(datawin, 0, out_line); 385. 	}  386.  	display_nhwindow(datawin, TRUE); 387. 	destroy_nhwindow(datawin); 388. }  389.   390.  void 391. com_pager(msgnum) 392. int	msgnum; 393. {  394.  	struct qtmsg *qt_msg; 395.  396.  	if (!(qt_msg = msg_in(qt_list.common, msgnum))) { 397. 		impossible("com_pager: message %d not found.", msgnum); 398. 		return; 399. 	}  400.   401.  	(void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET); 402. 	if (qt_msg->delivery == 'p') deliver_by_pline(qt_msg); 403. 	else if (msgnum == 1) deliver_by_window(qt_msg, NHW_MENU); 404. 	else		     deliver_by_window(qt_msg, NHW_TEXT); 405. 	return; 406. }  407.   408.  void 409. qt_pager(msgnum) 410. int	msgnum; 411. {  412.  	struct qtmsg *qt_msg; 413.  414.  	if (!(qt_msg = msg_in(qt_list.chrole, msgnum))) { 415. 		impossible("qt_pager: message %d not found.", msgnum); 416. 		return; 417. 	}  418.   419.  	(void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET); 420. 	if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11")) 421. 		deliver_by_pline(qt_msg); 422. 	else	deliver_by_window(qt_msg, NHW_TEXT); 423. 	return; 424. }  425.   426.  struct permonst * 427. qt_montype 428. {  429.  	int qpm; 430.  431.  	if (rn2(5)) { 432. 	    qpm = urole.enemy1num; 433. 	    if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD)) 434. 	    	return (&mons[qpm]); 435. 	    return (mkclass(urole.enemy1sym, 0)); 436. 	}  437.  	qpm = urole.enemy2num; 438. 	if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD)) 439. 	    return (&mons[qpm]); 440. 	return (mkclass(urole.enemy2sym, 0)); 441. }  442.   443.  /*questpgr.c*/