Source:NetHack 3.1.0/questpgr.c

Below is the full text to questpgr.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.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.1	93/01/20	*/ 2.   /*	Copyright 1991, M. Stephenson		  */ 3.   /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6. 7.   #ifdef MULDGN 8.   /*  quest-specific pager routines. */ 9.     10.   #include "qtext.h"  11. 12.  #define QTEXT_FILE	"quest.dat" 13.  #if defined(MICRO) && !defined(AMIGA) 14.  # define RDMODE "rb" 15.  #else 16.  # define RDMODE "r" 17.  #endif 18.   19.   #ifndef SEEK_SET 20.  # define SEEK_SET 0 21.  #endif 22.   23.   /* #define DEBUG	/* uncomment for debugging */ 24.   25.   static void FDECL(Fread, (genericptr_t,int,int,FILE	*)); 26.  static struct qtmsg * FDECL(construct_qtlist, (long)); 27.  static unsigned NDECL(class_index); 28.  static const char * NDECL(intermed); 29.  static const char * NDECL(neminame); 30.  static const char * NDECL(guardname); 31.  static const char * NDECL(homebase); 32.  static struct qtmsg * FDECL(msg_in, (struct qtmsg *,int)); 33.  static void FDECL(convert_arg, (CHAR_P)); 34.  static void NDECL(convert_line); 35.  static void FDECL(deliver_by_pline, (struct qtmsg *)); 36.  static void FDECL(deliver_by_window, (struct qtmsg *)); 37.   38.   static char	in_line[80], cvt_buf[64], out_line[128]; 39.  static struct	qtlists	qt_list; 40.  static	FILE	*msg_file; 41.   42.   #ifdef DEBUG 43.  static void NDECL(dump_qtlist); 44.   45.   static void 46.  dump_qtlist	/* dump the character msg list to check appearance */ 47.  {  48.   	struct	qtmsg	*msg; 49.  	long	size; 50.   51.   	for (msg = qt_list.chclass; msg->msgnum > 0; msg++) { 52.  		pline("msgnum %d: delivery %c",  53.   			msg->msgnum, msg->delivery); 54.  		more; 55.  		(void) fseek(msg_file, msg->offset, SEEK_SET); 56.  		deliver_by_window(msg); 57.  	}  58.   }  59.   #endif /* DEBUG */ 60.   61.   static void 62.  Fread(ptr, size, nitems, stream) 63.  genericptr_t	ptr; 64.  int	size, nitems; 65.  FILE	*stream; 66.  {  67.   	int cnt; 68.   69.   	if ((cnt = fread(ptr, size, nitems, stream)) != nitems) { 70.   71.   	    panic("PREMATURE EOF ON QUEST TEXT FILE!\nExpected %d bytes - got %d\n",  72.   		    (size * nitems), (size * cnt)); 73.  	}  74.   }  75.    76.   static struct qtmsg * 77.  construct_qtlist(hdr_offset) 78.  long	hdr_offset; 79.  {  80.   	struct qtmsg *msg_list; 81.  	int	n_msgs; 82.   83.   	(void) fseek(msg_file, hdr_offset, SEEK_SET); 84.  	Fread(&n_msgs, sizeof(int), 1, msg_file); 85.  	msg_list = (struct qtmsg *) alloc((n_msgs+1)*sizeof(struct qtmsg)); 86.   87.   	/*  88.   	 * Load up the list. 89.  	 */  90.   	Fread((genericptr_t)msg_list, n_msgs*sizeof(struct qtmsg), 1, msg_file); 91.   92.   	msg_list[n_msgs].msgnum = -1; 93.  	return(msg_list); 94.  }  95.    96.   void 97.  load_qtlist 98.  {  99.    100.  	int	n_classes, i;  101. char	qt_classes[N_HDR]; 102. 	long	qt_offsets[N_HDR]; 103.  104.  	msg_file = fopen_datafile(QTEXT_FILE, RDMODE); 105. 	if (!msg_file) 106. 	    panic("\rCANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE); 107.  108.  	/*  109.  	 * Read in the number of classes, then the ID's & offsets for 110. 	 * each header. 111. 	 */  112.   113.  	Fread(&n_classes, sizeof(int), 1, msg_file); 114. 	Fread(qt_classes, sizeof(char), n_classes, msg_file); 115. 	Fread(qt_offsets, sizeof(long), n_classes, msg_file); 116.  117.  	/*  118.  	 * Now construct the message lists for quick reference later 119. 	 * on when we are actually paging the messages out. 120. 	 */  121.   122.  	qt_list.common = qt_list.chclass = (struct qtmsg *)0; 123.  124.  	for (i = 0; i < n_classes; i++) { 125. 	    if (qt_classes[i] == COMMON_ID) 126. 		qt_list.common = construct_qtlist(qt_offsets[i]); 127. 	    else if (qt_classes[i] == pl_character[0]) 128. 		qt_list.chclass = construct_qtlist(qt_offsets[i]); 129. 	}  130.   131.  	if (!qt_list.common || !qt_list.chclass) 132. 	    impossible("load_qtlist: cannot load quest text."); 133. #ifdef DEBUG 134. 	dump_qtlist; 135. #endif 136. 	return;	/* no ***DON'T*** close the msg_file */ 137. }  138.   139.  static struct qt_matrix { 140.  141.  	const char *intermed;	/* intermediate goal text */ 142. 	const char *homebase;	/* leader's "location" */ 143.  144.  	short	ldrnum,		/* mons[] indicies */ 145. 		neminum, 146. 		guardnum; 147.  148.  	short	mtyp1, mtyp2;	/* monster types for enemies 0 == random */ 149. 	char	msym1, msym2;	/* monster classes for enemies */ 150.  151.  	short	artinum;	/* index of quest artifact */ 152.  153.  } qt_matrix[] = { 154.  155.  /* A */ { "the tomb of the Toltec Kings", 156. 	  "the College of Archeology", 157. 	  PM_LORD_CARNARVON, PM_MINION_OF_HUHETOL, PM_STUDENT, 158. 	  0, PM_HUMAN_MUMMY, S_SNAKE, S_MUMMY, 159. 	  ART_ORB_OF_DETECTION }, 160.  161.  /* B */ { "the Duali Oasis", 162. 	  "the Camp of the Duali Tribe", 163. 	  PM_PELIAS, PM_THOTH_AMON, PM_CHIEFTAIN, 164. 	  PM_OGRE, PM_TROLL, S_OGRE, S_TROLL, 165. 	  ART_HEART_OF_AHRIMAN }, 166.  167.  /* C */ { "the Dragon's Lair", 168. 	  "the Caves of the Ancestors", 169. 	  PM_SHAMAN_KARNOV, PM_CHROMATIC_DRAGON, PM_NEANDERTHAL, 170. 	  PM_BUGBEAR, PM_HILL_GIANT, S_HUMANOID, S_GIANT, 171. 	  ART_SCEPTRE_OF_MIGHT }, 172.  173.  /* E */ { "the Goblins' Cave", 174. 	  "the great Circle of Earendil", 175. 	  PM_EARENDIL, PM_GOBLIN_KING, PM_HIGH_ELF, 176. 	  PM_URUK_HAI, PM_OGRE, S_ORC, S_OGRE, 177. 	  ART_PALANTIR_OF_WESTERNESSE }, 178.  179.  /* E */ { "the Goblins' Cave", 180. 	  "the great Circle of Elwing", 181. 	  PM_ELWING, PM_GOBLIN_KING, PM_HIGH_ELF, 182. 	  PM_URUK_HAI, PM_OGRE, S_ORC, S_OGRE, 183. 	  ART_PALANTIR_OF_WESTERNESSE }, 184.  185.  /* H */ { "the Temple of Coeus", 186. 	  "the Isle of the Healers", 187. 	  PM_HIPPOCRATES, PM_CYCLOPS, PM_NURSE, 188. 	  PM_GIANT_RAT, PM_APE, S_RODENT, S_YETI, 189. 	  ART_STAFF_OF_AESCULAPIUS }, 190.  191.  /* K */ { "the Isle of Glass", 192. 	  "Camelot Castle", 193. 	  PM_KING_ARTHUR, PM_IXOTH, PM_PAGE, 194. 	  PM_QUASIT, PM_OCHRE_JELLY, S_IMP, S_JELLY, 195. 	  ART_MAGIC_MIRROR_OF_MERLIN }, 196.  197.  /* P */ { "the Temple of Nalzok", 198. 	  "the Great Temple", 199. 	  PM_ARCH_PRIEST, PM_NALZOK, PM_ACOLYTE, 200. 	  PM_HUMAN_ZOMBIE, PM_WRAITH, S_ZOMBIE, S_WRAITH, 201. 	  ART_MITRE_OF_HOLINESS }, 202.  203.  /* R */ { "the Asassins' Guild Hall", 204. 	  "the Thieves' Guild Hall", 205. 	  PM_MASTER_OF_THIEVES, PM_MASTER_ASSASSIN, PM_THUG, 206. 	  PM_LEPRECHAUN, PM_GUARDIAN_NAGA, S_NYMPH, S_NAGA, 207. 	  ART_MASTER_KEY_OF_THIEVERY }, 208.  209.  /* S */ { "the Shogun's Castle", 210. 	  "the castle of the Taro Clan", 211. 	  PM_LORD_SATO, PM_ASHIKAGA_TAKAUJI, PM_NINJA, 212. 	  PM_WOLF, PM_STALKER, S_DOG, S_STALKER, 213. 	  ART_TSURUGI_OF_MURAMASA }, 214.  215.  #ifdef TOURIST 216. /* T */ { "the Thieves' Guild Hall", 217. 	  "the Traveller's Aid Office", 218. 	  PM_TWOFLOWER, PM_MASTER_OF_THIEVES, PM_GUIDE, 219. 	  PM_GIANT_SPIDER, PM_FOREST_CENTAUR, S_SPIDER, S_CENTAUR, 220. 	  ART_YENDORIAN_EXPRESS_CARD }, 221. #endif 222.  223.  /* V */ { "the cave of Surtur", 224. 	  "the Shrine of Destiny", 225. 	  PM_NORN, PM_LORD_SURTUR, PM_WARRIOR, 226. 	  PM_FIRE_ANT, PM_FIRE_GIANT, S_ANT, S_GIANT, 227. 	  ART_ORB_OF_FATE }, 228.  229.  /* W */ { "the Tower of Darkness", 230. 	  "the Tower of the Balance", 231. 	  PM_WIZARD_OF_BALANCE, PM_DARK_ONE, PM_APPRENTICE, 232. 	  PM_VAMPIRE_BAT, PM_XORN, S_BAT, S_WRAITH, 233. 	  ART_EYE_OF_THE_AETHIOPICA }, 234.  235.  /* - */ { "", "", 0, 0, 0, 0, 0, 0, 0, 0 }  236.  };  237.   238.  static unsigned 239. class_index 240. {  241.  	switch (pl_character[0]) { 242.  243.  	    case 'A':	return(0); 244. 	    case 'B':	return(1); 245. 	    case 'C':	return(2); 246. 	    case 'E':	return(3+flags.female); 247. 	    case 'H':	return(5); 248. 	    case 'K':	return(6); 249. 	    case 'P':	return(7); 250. 	    case 'R':	return(8); 251. 	    case 'S':	return(9); 252. #ifdef TOURIST 253. 	    case 'T':	return(10); 254. 	    case 'V':	return(11); 255. 	    case 'W':	return(12); 256. 	    default:	return(13); 257. #else 258. 	    case 'V':	return(10); 259. 	    case 'W':	return(11); 260. 	    default:	return(12); 261. #endif 262. 	}  263.  }  264.   265.  const char * 266. ldrname	/* return your class leader's name */ 267. {  268.  	int i = qt_matrix[class_index].ldrnum; 269. /*	return(mons[qt_matrix[class_index].ldrnum].mname); */ 270. 	return(mons[i].mname); 271. }  272.   273.  static const char * 274. intermed	/* return your intermediate target string */ 275. {  276.  	return(qt_matrix[class_index].intermed); 277. }  278.   279.  boolean 280. is_quest_artifact(otmp) 281. struct obj *otmp; 282. {  283.  	return(otmp->oartifact == qt_matrix[class_index].artinum); 284. }  285.   286.  static const char * 287. neminame	/* return your class nemesis' name */ 288. {  289.  	return(mons[qt_matrix[class_index].neminum].mname); 290. }  291.   292.  static const char * 293. guardname	/* return your class leader's guard monster name */ 294. {  295.  	return(mons[qt_matrix[class_index].guardnum].mname); 296. }  297.   298.  static const char * 299. homebase	/* return your class leader's location */ 300. {  301.  	return(qt_matrix[class_index].homebase); 302. }  303.   304.  boolean 305. leaderless	/* return true iff leader is dead */ 306. {  307.  	int i = qt_matrix[class_index].ldrnum; 308. 	return (u.nr_killed[i] > 0); 309. }  310.   311.  static struct qtmsg * 312. msg_in(qtm_list, msgnum) 313. struct qtmsg *qtm_list; 314. int	msgnum; 315. {  316.  	struct qtmsg *qt_msg; 317.  318.  	for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++) 319. 	    if (qt_msg->msgnum == msgnum) return(qt_msg); 320.  321.  	return((struct qtmsg *)0); 322. }  323.   324.  static void 325. convert_arg(c) 326. char c;  327. { 328.  	register const char *str; 329.  330.  	switch (c) { 331.  332.  	    case 'p':	str = plname; 333. 			break; 334. 	    case 'c':	str = pl_character; 335. 			break; 336. 	    case 'r':	str = rank_of(u.ulevel, pl_character[0], flags.female); 337. 			break; 338. 	    case 'R':	str = rank_of(MIN_QUEST_LEVEL, pl_character[0],  339.  							  flags.female); 340. 			break; 341. 	    case 's':	str = (flags.female) ? "sister" : "brother"; 342. 			break; 343. 	    case 'S':	str = (flags.female) ? "daughter" : "son"; 344. 			break; 345. 	    case 'l':	str = ldrname; 346. 			break; 347. 	    case 'i':	str = intermed; 348. 			break; 349. 	    case 'o':	str = artiname(qt_matrix[class_index].artinum); 350. 			break; 351. 	    case 'n':	str = neminame; 352. 			break; 353. 	    case 'g':	str = guardname; 354. 			break; 355. 	    case 'H':	str = homebase; 356. 			break; 357. 	    case 'a':	str = align_str(u.ualignbase[0]); 358. 			break; 359. 	    case 'A':	str = align_str(u.ualign.type); 360. 			break; 361. 	    case 'd':	str = u_gname; 362. 			break; 363. 	    case 'D':	str = align_gname(A_LAWFUL); 364. 			break; 365. 	    case 'C':	str = "chaotic"; 366. 			break; 367. 	    case 'N':	str = "neutral"; 368. 			break; 369. 	    case 'L':	str = "lawful"; 370. 			break; 371. 	    case 'x':	str = Blind ? "sense" : "see"; 372. 			break; 373. 	    case '%':	str = "%"; 374. 			break; 375. 	     default:	str = ""; 376. 			break; 377. 	}  378.  	Strcpy(cvt_buf, str); 379. }  380.   381.  static void 382. convert_line 383. {  384.  	char *c, *cc; 385.  386.  	cc = out_line; 387. 	for (c = xcrypt(in_line); *c; c++) { 388.  389.  	    *cc = 0; 390. 	    switch(*c) { 391.  392.  		case '\r': 393. 		case '\n': 394. 			*(++cc) = 0; 395. 			return; 396.  397.  		case '%': 398. 			if (*(c+1)) { 399. 			    convert_arg(*(++c)); 400. 			    switch (*(c+1)) { 401.  402.  				case 'P': cvt_buf[0] = highc(cvt_buf[0]); 403. 				case 'p': Strcpy(cvt_buf, makeplural(cvt_buf)); 404. 					    c++; break; 405.  406.  				default: break; 407. 			    }  408.  			    Strcat(cc, cvt_buf); 409. 			    cc += strlen(cvt_buf); 410. 			    break; 411. 			}	/* else fall through */ 412.  413.  		default: 414. 			*cc++ = *c; 415. 			break; 416. 	    }  417.  	}  418.  	*cc = 0; 419. 	return; 420. }  421.   422.  static void 423. deliver_by_pline(qt_msg) 424. struct qtmsg *qt_msg; 425. {  426.  	long	size; 427.  428.  	for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) { 429. 	    (void) fgets(in_line, 80, msg_file); 430. 	    convert_line; 431. 	    pline(out_line); 432. 	}  433.   434.  }  435.   436.  static void 437. deliver_by_window(qt_msg) 438. struct qtmsg *qt_msg; 439. {  440.  	long	size; 441. 	winid datawin = create_nhwindow(NHW_TEXT); 442.  443.  	for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) { 444. 	    (void) fgets(in_line, 80, msg_file); 445. 	    convert_line; 446. 	    putstr(datawin, 0, out_line); 447. 	}  448.  	display_nhwindow(datawin, TRUE); 449. 	destroy_nhwindow(datawin); 450. }  451.   452.  void 453. com_pager(msgnum) 454. int	msgnum; 455. {  456.  	struct qtmsg *qt_msg; 457.  458.  	if (!(qt_msg = msg_in(qt_list.common, msgnum))) { 459. 		impossible("com_pager: message %d not found.", msgnum); 460. 		return; 461. 	}  462.   463.  	(void) fseek(msg_file, qt_msg->offset, SEEK_SET); 464. 	if (qt_msg->delivery == 'p') deliver_by_pline(qt_msg); 465. 	else		     deliver_by_window(qt_msg); 466. 	return; 467. }  468.   469.  void 470. qt_pager(msgnum) 471. int	msgnum; 472. {  473.  	struct qtmsg *qt_msg; 474.  475.  	if (!(qt_msg = msg_in(qt_list.chclass, msgnum))) { 476. 		impossible("qt_pager: message %d not found.", msgnum); 477. 		return; 478. 	}  479.   480.  	(void) fseek(msg_file, qt_msg->offset, SEEK_SET); 481. 	if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11")) 482. 		deliver_by_pline(qt_msg); 483. 	else	deliver_by_window(qt_msg); 484. 	return; 485. }  486.   487.  struct permonst * 488. qt_montype 489. {  490.  	int class = class_index; 491.  492.  	if (rn2(5)) { 493. 		if (qt_matrix[class].mtyp1 && rn2(5) &&  494.  			 !(mons[qt_matrix[class].mtyp1].geno & G_GENOD)) 495. 				return(&mons[qt_matrix[class].mtyp1]); 496. 		return(mkclass(qt_matrix[class].msym1,0)); 497. 	}  498.  	if (qt_matrix[class].mtyp2 && rn2(5) &&  499.  		 !(mons[qt_matrix[class].mtyp1].geno & G_GENOD)) 500. 			return(&mons[qt_matrix[class].mtyp2]); 501. 	return(mkclass(qt_matrix[class].msym2,0)); 502. }  503.  #endif /* MULDGN */ 504.  505.  /*questpgr.c*/