Blindfold removal fix
[slashemextended.git] / src / rumors.c
blob5a79192c3b4aac02c45bff102968d208c9c7def1
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. */
5 #include "hack.h"
6 #include "lev.h"
7 #include "dlb.h"
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
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().
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'.
31 STATIC_DCL void init_rumors(dlb *);
32 STATIC_DCL void init_oracles(dlb *);
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;
40 STATIC_OVL void
41 init_rumors(fp)
42 dlb *fp;
44 char line[BUFSZ];
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 */
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.
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;
72 dlb *rumors;
73 long tidbit, beginning;
74 char *endp, line[BUFSZ], xbuf[BUFSZ];
76 rumor_buf[0] = '\0';
77 if (true_rumor_size < 0L) /* we couldn't open NH_RUMORFILE */
78 return rumor_buf;
80 rumors = dlb_fopen_area(NH_RUMORAREA, NH_RUMORFILE, "r");
82 if (rumors) {
83 int count = 0;
84 int adjtruth;
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 NH_RUMORFILE);
93 return rumor_buf;
97 * input: 1 0 -1
98 * rn2 \ +1 2=T 1=T 0=F
99 * adj./ +0 1=T 0=F -1=F
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, "Uh-oh...");
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);
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 */
134 return rumor_buf;
137 void
138 outrumor(truth, mechanism, unchangeable)
139 int truth; /* 1=true, -1=false, 0=either */
140 int mechanism;
141 boolean unchangeable; /* if true, no random chance of getting different messages */
143 static const char fortune_msg[] =
144 "This cookie has a scrap of paper inside.";
145 const char *line;
146 char buf[BUFSZ];
147 boolean reading = (mechanism == BY_COOKIE ||
148 mechanism == BY_PAPER);
150 if (reading) {
151 /* deal with various things that prevent reading */
152 if (is_fainted() && mechanism == BY_COOKIE)
153 return;
154 else if (Blind) {
155 if (mechanism == BY_COOKIE)
156 pline(fortune_msg);
157 pline("What a pity that you cannot read it!");
158 return;
161 line = ((rn2(20) || unchangeable) ? getrumor(truth, buf, reading ? FALSE : TRUE) : random_mesgX() ) ;
162 if (!*line)
163 line = "NetHack rumors file closed for renovation.";
164 switch (mechanism) {
165 case BY_ORACLE:
166 /* Oracle delivers the rumor */
167 pline("True to her word, the Oracle %ssays: ",
168 (!rn2(4) ? "offhandedly " : (!rn2(3) ? "casually " :
169 (rn2(2) ? "nonchalantly " : ""))));
170 verbalize("%s", line);
171 exercise(A_WIS, TRUE);
172 return;
173 case BY_COOKIE:
174 pline(fortune_msg);
175 /* FALLTHRU */
176 case BY_PAPER:
177 pline("It reads:");
178 break;
180 pline("%s", line);
183 STATIC_OVL void
184 init_oracles(fp)
185 dlb *fp;
187 register int i;
188 char line[BUFSZ];
189 int cnt = 0;
191 /* this assumes we're only called once */
192 (void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment*/
193 (void) dlb_fgets(line, sizeof line, fp);
194 if (sscanf(line, "%5d\n", &cnt) == 1 && cnt > 0) {
195 oracle_cnt = (unsigned) cnt;
196 oracle_loc = (long *) alloc((unsigned)cnt * sizeof (long));
197 for (i = 0; i < cnt; i++) {
198 (void) dlb_fgets(line, sizeof line, fp);
199 (void) sscanf(line, "%5lx\n", &oracle_loc[i]);
202 return;
205 void
206 save_oracles(fd, mode)
207 int fd, mode;
209 if (perform_bwrite(mode)) {
210 bwrite(fd, (void *) &oracle_cnt, sizeof oracle_cnt);
211 if (oracle_cnt)
212 bwrite(fd, (void *)oracle_loc, oracle_cnt*sizeof (long));
214 if (release_data(mode)) {
215 if (oracle_cnt) {
216 free((void *)oracle_loc);
217 oracle_loc = 0, oracle_cnt = 0, oracle_flg = 0;
222 void
223 restore_oracles(fd)
224 int fd;
226 mread(fd, (void *) &oracle_cnt, sizeof oracle_cnt);
227 if (oracle_cnt) {
228 oracle_loc = (long *) alloc(oracle_cnt * sizeof (long));
229 mread(fd, (void *) oracle_loc, oracle_cnt * sizeof (long));
230 oracle_flg = 1; /* no need to call init_oracles() */
234 void
235 outoracle(special, delphi)
236 boolean special;
237 boolean delphi;
239 char line[COLNO];
240 char *endp;
241 dlb *oracles;
242 int oracle_idx;
243 char xbuf[BUFSZ];
245 if(oracle_flg < 0 || /* couldn't open NH_ORACLEFILE */
246 (oracle_flg > 0 && oracle_cnt == 0)) /* oracles already exhausted */
247 return;
249 oracles = dlb_fopen_area(NH_ORACLEAREA, NH_ORACLEFILE, "r");
251 if (oracles) {
252 winid tmpwin;
253 if (oracle_flg == 0) { /* if this is the first outoracle() */
254 init_oracles(oracles);
255 oracle_flg = 1;
256 if (oracle_cnt == 0) return;
258 /* oracle_loc[0] is the special oracle; */
259 /* oracle_loc[1..oracle_cnt-1] are normal ones */
260 if (oracle_cnt <= 1 && !special) return; /*(shouldn't happen)*/
261 oracle_idx = special ? 0 : rnd((int) oracle_cnt - 1);
262 (void) dlb_fseek(oracles, oracle_loc[oracle_idx], SEEK_SET);
263 if (!special) oracle_loc[oracle_idx] = oracle_loc[--oracle_cnt];
265 tmpwin = create_nhwindow(NHW_TEXT);
266 if (delphi)
267 putstr(tmpwin, 0, special ?
268 "The Oracle scornfully takes all your money and says:" :
269 "The Oracle meditates for a moment and then intones:");
270 else
271 putstr(tmpwin, 0, "The message reads:");
272 putstr(tmpwin, 0, "");
274 while(dlb_fgets(line, COLNO, oracles) && strcmp(line,"---\n")) {
275 if ((endp = index(line, '\n')) != 0) *endp = 0;
276 putstr(tmpwin, 0, xcrypt(line, xbuf));
278 display_nhwindow(tmpwin, TRUE);
279 destroy_nhwindow(tmpwin);
280 (void) dlb_fclose(oracles);
281 } else {
282 pline("Can't open oracles file!");
283 oracle_flg = -1; /* don't try to open it again */
288 doconsult(oracl)
289 register struct monst *oracl;
291 #ifdef GOLDOBJ
292 long umoney = money_cnt(invent);
293 #endif
294 int u_pay, minor_cost = 50, major_cost = 500 + 50 * u.ulevel;
295 int add_xpts;
296 char qbuf[QBUFSZ];
298 multi = 0;
300 if (!oracl) {
301 There("is no one here to consult.");
302 return 0;
303 } else if (!oracl->mpeaceful) {
304 pline("%s is in no mood for consultations.", Monnam(oracl));
305 return 0;
306 #ifndef GOLDOBJ
307 } else if (!u.ugold) {
308 #else
309 } else if (!umoney) {
310 #endif
311 You("have no money.");
312 return 0;
315 sprintf(qbuf,
316 "\"Wilt thou settle for a minor consultation?\" (%d %s)",
317 minor_cost, currency((long)minor_cost));
318 switch (ynq(qbuf)) {
319 default:
320 case 'q':
321 return 0;
322 case 'y':
323 #ifndef GOLDOBJ
324 if (u.ugold < (long)minor_cost) {
325 #else
326 if (umoney < (long)minor_cost) {
327 #endif
328 You("don't even have enough money for that!");
329 return 0;
331 u_pay = minor_cost;
332 break;
333 case 'n':
334 #ifndef GOLDOBJ
335 if (u.ugold <= (long)minor_cost || /* don't even ask */
336 #else
337 if (umoney <= (long)minor_cost || /* don't even ask */
338 #endif
339 (oracle_cnt == 1 || oracle_flg < 0)) return 0;
340 sprintf(qbuf,
341 "\"Then dost thou desire a major one?\" (%d %s)",
342 major_cost, currency((long)major_cost));
343 if (yn(qbuf) != 'y') return 0;
344 #ifndef GOLDOBJ
345 u_pay = (u.ugold < (long)major_cost ? (int)u.ugold
346 : major_cost);
347 #else
348 u_pay = (umoney < (long)major_cost ? (int)umoney
349 : major_cost);
350 #endif
351 break;
353 #ifndef GOLDOBJ
354 u.ugold -= (long)u_pay;
355 if (rn2(2)) oracl->mgold += (long)u_pay; /* prevent player from getting everything back --Amy */
356 #else
357 money2mon(oracl, (long)u_pay);
358 #endif
359 flags.botl = 1;
360 add_xpts = 0; /* first oracle of each type gives experience points */
361 if (u_pay == minor_cost) {
362 outrumor(1, BY_ORACLE, TRUE);
363 if (!u.uevent.minor_oracle)
364 add_xpts = u_pay / (u.uevent.major_oracle ? 2 : 10);
365 /* 5 pts if very 1st, or 2 pts if major already done */
366 u.uevent.minor_oracle = TRUE;
367 } else {
368 boolean cheapskate = u_pay < major_cost;
369 outoracle(cheapskate, TRUE);
370 if (!cheapskate && !u.uevent.major_oracle) {
371 add_xpts = u_pay / (u.uevent.minor_oracle ? 2 : 10);
373 u.uevent.major_oracle = TRUE; /* so you can't hangup cheat */
374 You_feel("very enlightened!"); /* idea by hothraxxa: +1 INT; I (Amy) decided to give +1 WIS too */
375 (void) adjattrib(A_INT, 1, FALSE, TRUE);
376 (void) adjattrib(A_WIS, 1, FALSE, TRUE);
377 /* what if your sustainer started with 3 wisdom? let's give you an extra point if you are one --Amy */
378 if (Race_if(PM_SUSTAINER) && ABASE(A_WIS) < 25) {
379 ABASE(A_WIS) += 1;
380 AMAX(A_WIS) += 1;
381 flags.botl = 1;
383 /* ~100 pts if very 1st, ~40 pts if minor already done */
385 u.uevent.major_oracle = TRUE;
386 exercise(A_WIS, !cheapskate);
388 if (add_xpts) {
389 more_experienced(add_xpts, u_pay/50);
390 newexplevel();
392 return 1;
395 /*rumors.c*/