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. */
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
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;
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
;
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.
67 getrumor(truth
, rumor_buf
, exclude_cookie
)
68 int truth
; /* 1=true, -1=false, 0=either */
70 boolean exclude_cookie
;
73 long tidbit
, beginning
;
74 char *endp
, line
[BUFSZ
], xbuf
[BUFSZ
];
77 if (true_rumor_size
< 0L) /* we couldn't open NH_RUMORFILE */
80 rumors
= dlb_fopen_area(NH_RUMORAREA
, NH_RUMORFILE
, "r");
88 if (true_rumor_size
== 0L) { /* if this is 1st outrumor() */
90 if (true_rumor_size
< 0L) { /* init failed */
91 sprintf(rumor_buf
, "Error reading \"%.80s\".",
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
;
106 case 0: /* once here, 0 => false rather than "either"*/
107 case -1: beginning
= false_rumor_start
;
108 tidbit
= Rand() % false_rumor_size
;
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
);
127 impossible("Can't find non-cookie rumor?");
129 exercise(A_WIS
, (adjtruth
> 0));
131 pline("Can't open rumors file!");
132 true_rumor_size
= -1; /* don't try to open it again */
138 outrumor(truth
, mechanism
, unchangeable
)
139 int truth
; /* 1=true, -1=false, 0=either */
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.";
147 boolean reading
= (mechanism
== BY_COOKIE
||
148 mechanism
== BY_PAPER
);
151 /* deal with various things that prevent reading */
152 if (is_fainted() && mechanism
== BY_COOKIE
)
155 if (mechanism
== BY_COOKIE
)
157 pline("What a pity that you cannot read it!");
161 line
= ((rn2(20) || unchangeable
) ? getrumor(truth
, buf
, reading
? FALSE
: TRUE
) : random_mesgX() ) ;
163 line
= "NetHack rumors file closed for renovation.";
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
);
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
]);
206 save_oracles(fd
, mode
)
209 if (perform_bwrite(mode
)) {
210 bwrite(fd
, (void *) &oracle_cnt
, sizeof oracle_cnt
);
212 bwrite(fd
, (void *)oracle_loc
, oracle_cnt
*sizeof (long));
214 if (release_data(mode
)) {
216 free((void *)oracle_loc
);
217 oracle_loc
= 0, oracle_cnt
= 0, oracle_flg
= 0;
226 mread(fd
, (void *) &oracle_cnt
, sizeof 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() */
235 outoracle(special
, delphi
)
245 if(oracle_flg
< 0 || /* couldn't open NH_ORACLEFILE */
246 (oracle_flg
> 0 && oracle_cnt
== 0)) /* oracles already exhausted */
249 oracles
= dlb_fopen_area(NH_ORACLEAREA
, NH_ORACLEFILE
, "r");
253 if (oracle_flg
== 0) { /* if this is the first outoracle() */
254 init_oracles(oracles
);
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
);
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:");
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
);
282 pline("Can't open oracles file!");
283 oracle_flg
= -1; /* don't try to open it again */
289 register struct monst
*oracl
;
292 long umoney
= money_cnt(invent
);
294 int u_pay
, minor_cost
= 50, major_cost
= 500 + 50 * u
.ulevel
;
301 There("is no one here to consult.");
303 } else if (!oracl
->mpeaceful
) {
304 pline("%s is in no mood for consultations.", Monnam(oracl
));
307 } else if (!u
.ugold
) {
309 } else if (!umoney
) {
311 You("have no money.");
316 "\"Wilt thou settle for a minor consultation?\" (%d %s)",
317 minor_cost
, currency((long)minor_cost
));
324 if (u
.ugold
< (long)minor_cost
) {
326 if (umoney
< (long)minor_cost
) {
328 You("don't even have enough money for that!");
335 if (u
.ugold
<= (long)minor_cost
|| /* don't even ask */
337 if (umoney
<= (long)minor_cost
|| /* don't even ask */
339 (oracle_cnt
== 1 || oracle_flg
< 0)) return 0;
341 "\"Then dost thou desire a major one?\" (%d %s)",
342 major_cost
, currency((long)major_cost
));
343 if (yn(qbuf
) != 'y') return 0;
345 u_pay
= (u
.ugold
< (long)major_cost
? (int)u
.ugold
348 u_pay
= (umoney
< (long)major_cost
? (int)umoney
354 u
.ugold
-= (long)u_pay
;
355 if (rn2(2)) oracl
->mgold
+= (long)u_pay
; /* prevent player from getting everything back --Amy */
357 money2mon(oracl
, (long)u_pay
);
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
;
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) {
383 /* ~100 pts if very 1st, ~40 pts if minor already done */
385 u
.uevent
.major_oracle
= TRUE
;
386 exercise(A_WIS
, !cheapskate
);
389 more_experienced(add_xpts
, u_pay
/50);