Source:NetHack 3.4.0/questpgr.c

Below is the full text to questpgr.c from the source code of NetHack 3.4.0. To link to a particular line, write [[NetHack 3.4.0/questpgr.c#line123 ]], for example.

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