Source:Rumors.c

Below is the full text to src/rumors.c from NetHack 3.4.3. To link to a particular line, write [[rumors.c#line123 ]], for example. 1.   /*	SCCS Id: @(#)rumors.c	3.4	1996/04/20	*/ 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.

5.   #include "hack.h"  6.    #include "lev.h"  7.    #include "dlb.h"  8. 9.   /*	[note: this comment is fairly old, but still accurate for 3.1] 10.   * Rumors have been entirely rewritten to speed up the access. This is 11. * essential when working from floppies. Using fseek the way that's done 12.   * here means rumors following longer rumors are output more often than those 13.   * following shorter rumors. Also, you may see the same rumor more than once 14.   * in a particular game (although the odds are highly against it), but 15.   * this also happens with real fortune cookies. -dgk 16.   */  17.    18.   /*	3.1  19.    * The rumors file consists of a "do not edit" line, a hexadecimal number 20.   * giving the number of bytes of useful/true rumors, followed by those 21.   * true rumors (one per line), followed by the useless/false/misleading/cute 22.   * rumors (also one per line). Number of bytes of untrue rumors is derived 23.   * via fseek(EOF)+ftell. 24.   *  25.    * The oracles file consists of a "do not edit" comment, a decimal count N  26. * and set of N+1 hexadecimal fseek offsets, followed by N multiple-line 27.   * records, separated by "---" lines. The first oracle is a special case, 28.   * and placed there by 'makedefs'. 29.   */  30.    31.   STATIC_DCL void FDECL(init_rumors, (dlb *)); 32.  STATIC_DCL void FDECL(init_oracles, (dlb *)); 33.   34.   static long true_rumor_start,  true_rumor_size,  true_rumor_end, 35.  	    false_rumor_start, false_rumor_size, false_rumor_end; 36.  static int oracle_flg = 0;  /* -1=>don't use, 0=>need init, 1=>init done */ 37.  static unsigned oracle_cnt = 0; 38.  static long *oracle_loc = 0; 39.   40.   STATIC_OVL void 41.  init_rumors(fp) 42.  dlb *fp; 43.  {  44.   	char line[BUFSZ]; 45.   46.   	(void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment */ 47.  	(void) dlb_fgets(line, sizeof line, fp); 48.  	if (sscanf(line, "%6lx\n", &true_rumor_size) == 1 &&  49.   	    true_rumor_size > 0L) { 50.  	    (void) dlb_fseek(fp, 0L, SEEK_CUR); 51.  	    true_rumor_start  = dlb_ftell(fp); 52.  	    true_rumor_end    = true_rumor_start + true_rumor_size; 53.  	    (void) dlb_fseek(fp, 0L, SEEK_END); 54.  	    false_rumor_end   = dlb_ftell(fp); 55.  	    false_rumor_start = true_rumor_end;	/* ok, so it's redundant... */ 56.   	    false_rumor_size  = false_rumor_end - false_rumor_start; 57.  	} else 58.  	    true_rumor_size = -1L;	/* init failed */ 59.  }  60.    61.   /* exclude_cookie is a hack used because we sometimes want to get rumors in a  62. * context where messages such as "You swallowed the fortune!" that refer to 63. * cookies should not appear. This has no effect for true rumors since none 64.   * of them contain such references anyway. 65.   */  66.   char * 67.  getrumor(truth, rumor_buf, exclude_cookie) 68.  int truth; /* 1=true, -1=false, 0=either */ 69.  char *rumor_buf; 70.  boolean exclude_cookie; 71.  {  72.   	dlb	*rumors; 73.  	long tidbit, beginning; 74.  	char	*endp, line[BUFSZ], xbuf[BUFSZ]; 75.   76.   	rumor_buf[0] = '\0'; 77.  	if (true_rumor_size < 0L)	/* we couldn't open RUMORFILE */ 78.  		return rumor_buf; 79.   80.   	rumors = dlb_fopen(RUMORFILE, "r"); 81.   82.   	if (rumors) { 83.  	    int count = 0; 84.  	    int adjtruth; 85.   86.   	    do { 87.  		rumor_buf[0] = '\0'; 88.  		if (true_rumor_size == 0L) {	/* if this is 1st outrumor */ 89.  		    init_rumors(rumors); 90.  		    if (true_rumor_size < 0L) {	/* init failed */ 91.  			Sprintf(rumor_buf, "Error reading \"%.80s\".",  92.   				RUMORFILE); 93.  			return rumor_buf; 94.  		    }  95.   		}  96.   		/*  97.   		 *	input:      1    0   -1 98.  		 *	 rn2 \ +1  2=T  1=T  0=F 99.  		 *	 adj./ +0  1=T  0=F -1=F 100. 		 */  101.  		switch (adjtruth = truth + rn2(2)) { 102. 		  case  2:	/*(might let a bogus input arg sneak thru)*/ 103. 		  case  1:  beginning = true_rumor_start; 104. 			    tidbit = Rand % true_rumor_size; 105. 			break; 106. 		  case  0:	/* once here, 0 => false rather than "either"*/ 107. 		  case -1:  beginning = false_rumor_start; 108. 			    tidbit = Rand % false_rumor_size; 109. 			break; 110. 		  default: 111. 			    impossible("strange truth value for rumor"); 112. 			return strcpy(rumor_buf, "Oops..."); 113. 		}  114.  		(void) dlb_fseek(rumors, beginning + tidbit, SEEK_SET); 115. 		(void) dlb_fgets(line, sizeof line, rumors); 116. 		if (!dlb_fgets(line, sizeof line, rumors) ||  117.  		    (adjtruth > 0 && dlb_ftell(rumors) > true_rumor_end)) { 118. 			/* reached end of rumors -- go back to beginning */ 119. 			(void) dlb_fseek(rumors, beginning, SEEK_SET); 120. 			(void) dlb_fgets(line, sizeof line, rumors); 121. 		}  122.  		if ((endp = index(line, '\n')) != 0) *endp = 0; 123. 		Strcat(rumor_buf, xcrypt(line, xbuf)); 124. 	    } while(count++ < 50 && exclude_cookie && (strstri(rumor_buf, "fortune") || strstri(rumor_buf, "pity"))); 125. 	    (void) dlb_fclose(rumors); 126. 	    if (count >= 50) 127. 		impossible("Can't find non-cookie rumor?"); 128. 	    else 129. 		exercise(A_WIS, (adjtruth > 0)); 130. 	} else { 131. 		pline("Can't open rumors file!"); 132. 		true_rumor_size = -1;	/* don't try to open it again */ 133. 	}  134.  	return rumor_buf; 135. }  136.   137.  void 138. outrumor(truth, mechanism) 139. int truth; /* 1=true, -1=false, 0=either */ 140. int mechanism; 141. {  142.  	static const char fortune_msg[] = 143. 		"This cookie has a scrap of paper inside."; 144. 	const char *line; 145. 	char buf[BUFSZ]; 146. 	boolean reading = (mechanism == BY_COOKIE ||  147.  			   mechanism == BY_PAPER); 148.  149.  	if (reading) { 150. 	    /* deal with various things that prevent reading */ 151. 	    if (is_fainted && mechanism == BY_COOKIE) 152. 	    	return; 153. 	    else if (Blind) { 154. 		if (mechanism == BY_COOKIE) 155. 			pline(fortune_msg); 156. 		pline("What a pity that you cannot read it!"); 157. 	    	return; 158. 	    }  159.  	}  160.  	line = getrumor(truth, buf, reading ? FALSE : TRUE); 161. 	if (!*line) 162. 		line = "NetHack rumors file closed for renovation."; 163. 	switch (mechanism) { 164. 	    case BY_ORACLE: 165. 	 	/* Oracle delivers the rumor */ 166. 		pline("True to her word, the Oracle %ssays: ",  167.  		  (!rn2(4) ? "offhandedly " : (!rn2(3) ? "casually " : 168.  		  (rn2(2) ? "nonchalantly " : "")))); 169. 		verbalize("%s", line); 170. 		exercise(A_WIS, TRUE); 171. 		return; 172. 	    case BY_COOKIE: 173. 		pline(fortune_msg); 174. 		/* FALLTHRU */ 175. 	    case BY_PAPER: 176. 		pline("It reads:"); 177. 		break; 178. 	}  179.  	pline("%s", line); 180. }  181.   182.  STATIC_OVL void 183. init_oracles(fp) 184. dlb *fp; 185. {  186.  	register int i;  187. char line[BUFSZ]; 188. 	int cnt = 0; 189.  190.  	/* this assumes we're only called once */ 191. 	(void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment*/ 192. 	(void) dlb_fgets(line, sizeof line, fp); 193. 	if (sscanf(line, "%5d\n", &cnt) == 1 && cnt > 0) { 194. 	    oracle_cnt = (unsigned) cnt; 195. 	    oracle_loc = (long *) alloc((unsigned)cnt * sizeof (long)); 196. 	    for (i = 0; i < cnt; i++) { 197. 		(void) dlb_fgets(line, sizeof line, fp); 198. 		(void) sscanf(line, "%5lx\n", &oracle_loc[i]); 199. 	    }  200.  	}  201.  	return; 202. }  203.   204.  void 205. save_oracles(fd, mode) 206. int fd, mode; 207. {  208.  	if (perform_bwrite(mode)) { 209. 	    bwrite(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt); 210. 	    if (oracle_cnt) 211. 		bwrite(fd, (genericptr_t)oracle_loc, oracle_cnt*sizeof (long)); 212. 	}  213.  	if (release_data(mode)) { 214. 	    if (oracle_cnt) { 215. 		free((genericptr_t)oracle_loc); 216. 		oracle_loc = 0,  oracle_cnt = 0,  oracle_flg = 0; 217. 	    }  218.  	}  219.  }  220.   221.  void 222. restore_oracles(fd) 223. int fd; 224. {  225.  	mread(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt); 226. 	if (oracle_cnt) { 227. 	    oracle_loc = (long *) alloc(oracle_cnt * sizeof (long)); 228. 	    mread(fd, (genericptr_t) oracle_loc, oracle_cnt * sizeof (long)); 229. 	    oracle_flg = 1;	/* no need to call init_oracles */ 230. 	}  231.  }  232.   233.  void 234. outoracle(special, delphi) 235. boolean special; 236. boolean delphi; 237. {  238.  	char	line[COLNO]; 239. 	char	*endp; 240. 	dlb	*oracles; 241. 	int oracle_idx; 242. 	char xbuf[BUFSZ]; 243.  244.  	if(oracle_flg < 0 ||			/* couldn't open ORACLEFILE */  245.  	   (oracle_flg > 0 && oracle_cnt == 0))	/* oracles already exhausted */ 246. 		return; 247.  248.  	oracles = dlb_fopen(ORACLEFILE, "r"); 249.  250.  	if (oracles) { 251. 		winid tmpwin; 252. 		if (oracle_flg == 0) {	/* if this is the first outoracle */ 253. 			init_oracles(oracles); 254. 			oracle_flg = 1; 255. 			if (oracle_cnt == 0) return; 256. 		}  257.  		/* oracle_loc[0] is the special oracle;		*/ 258. 		/* oracle_loc[1..oracle_cnt-1] are normal ones	*/ 259. 		if (oracle_cnt <= 1 && !special) return;  /*(shouldn't happen)*/ 260. 		oracle_idx = special ? 0 : rnd((int) oracle_cnt - 1); 261. 		(void) dlb_fseek(oracles, oracle_loc[oracle_idx], SEEK_SET); 262. 		if (!special) oracle_loc[oracle_idx] = oracle_loc[--oracle_cnt]; 263.  264.  		tmpwin = create_nhwindow(NHW_TEXT); 265. 		if (delphi) 266. 		    putstr(tmpwin, 0, special ?  267.  		          "The Oracle scornfully takes all your money and says:" :  268.  		          "The Oracle meditates for a moment and then intones:"); 269. 		else 270. 		    putstr(tmpwin, 0, "The message reads:"); 271. 		putstr(tmpwin, 0, ""); 272.  273.  		while(dlb_fgets(line, COLNO, oracles) && strcmp(line,"---\n")) { 274. 			if ((endp = index(line, '\n')) != 0) *endp = 0; 275. 			putstr(tmpwin, 0, xcrypt(line, xbuf)); 276. 		}  277.  		display_nhwindow(tmpwin, TRUE); 278. 		destroy_nhwindow(tmpwin); 279. 		(void) dlb_fclose(oracles); 280. 	} else { 281. 		pline("Can't open oracles file!"); 282. 		oracle_flg = -1;	/* don't try to open it again */ 283. 	}  284.  }  285.   286.  int 287. doconsult(oracl) 288. register struct monst *oracl; 289. {  290.  #ifdef GOLDOBJ 291.         long umoney = money_cnt(invent); 292. #endif 293. 	int u_pay, minor_cost = 50, major_cost = 500 + 50 * u.ulevel; 294. 	int add_xpts; 295. 	char qbuf[QBUFSZ]; 296.  297.  	multi = 0; 298.  299.  	if (!oracl) { 300. 		There("is no one here to consult."); 301. 		return 0; 302. 	} else if (!oracl->mpeaceful) { 303. 		pline("%s is in no mood for consultations.", Monnam(oracl)); 304. 		return 0; 305. #ifndef GOLDOBJ 306. 	} else if (!u.ugold) { 307. #else 308. 	} else if (!umoney) { 309. #endif 310. 		You("have no money."); 311. 		return 0; 312. 	}  313.   314.  	Sprintf(qbuf,  315.  		"\"Wilt thou settle for a minor consultation?\" (%d %s)",  316.  		minor_cost, currency((long)minor_cost)); 317. 	switch (ynq(qbuf)) { 318. 	    default: 319. 	    case 'q': 320. 		return 0; 321. 	    case 'y': 322. #ifndef GOLDOBJ 323. 		if (u.ugold < (long)minor_cost) { 324. #else 325. 		if (umoney < (long)minor_cost) { 326. #endif 327. 		    You("don't even have enough money for that!"); 328. 		    return 0; 329. 		}  330.  		u_pay = minor_cost; 331. 		break; 332. 	    case 'n': 333. #ifndef GOLDOBJ 334. 		if (u.ugold <= (long)minor_cost ||	/* don't even ask */  335.  #else  336.  		if (umoney <= (long)minor_cost ||	/* don't even ask */ 337. #endif 338. 		    (oracle_cnt == 1 || oracle_flg < 0)) return 0;  339.  		Sprintf(qbuf, 340. 			"\"Then dost thou desire a major one?\" (%d %s)", 341. 			major_cost, currency((long)major_cost));  342.  		if (yn(qbuf) != 'y') return 0;  343.  #ifndef GOLDOBJ  344.  		u_pay = (u.ugold < (long)major_cost ? (int)u.ugold 345. 						    : major_cost);  346.  #else  347.  		u_pay = (umoney < (long)major_cost ? (int)umoney 348. 						    : major_cost);  349.  #endif  350.  		break;  351.  	}  352.  #ifndef GOLDOBJ  353.  	u.ugold -= (long)u_pay;  354.  	oracl->mgold += (long)u_pay;  355.  #else  356.          money2mon(oracl, (long)u_pay);  357.  #endif  358.  	flags.botl = 1;  359.  	add_xpts = 0;	/* first oracle of each type gives experience points */  360.  	if (u_pay == minor_cost) {  361.  		outrumor(1, BY_ORACLE);  362.  		if (!u.uevent.minor_oracle)  363.  		    add_xpts = u_pay / (u.uevent.major_oracle ? 25 : 10); 364.  		    /* 5 pts if very 1st, or 2 pts if major already done */  365.  		u.uevent.minor_oracle = TRUE;  366.  	} else {  367.  		boolean cheapskate = u_pay < major_cost;  368.  		outoracle(cheapskate, TRUE);  369.  		if (!cheapskate && !u.uevent.major_oracle)  370.  		    add_xpts = u_pay / (u.uevent.minor_oracle ? 25 : 10); 371.  		    /* ~100 pts if very 1st, ~40 pts if minor already done */  372.  		u.uevent.major_oracle = TRUE;  373.  		exercise(A_WIS, !cheapskate);  374.  	}  375.  	if (add_xpts) {  376.  		more_experienced(add_xpts, u_pay/50);  377.  		newexplevel;  378.  	}  379.  	return 1;  380.  }  381.   382.  /*rumors.c*/