OSDN Git Service

rearrange main dungeon
[nethackexpress/trunk.git] / src / rumors.c
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*/