OSDN Git Service

rearrange main dungeon
[nethackexpress/trunk.git] / src / questpgr.c
1 /*      SCCS Id: @(#)questpgr.c 3.4     2000/05/05      */
2 /*      Copyright 1991, M. Stephenson             */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6 #include "dlb.h"
7
8 /*  quest-specific pager routines. */
9
10 #include "qtext.h"
11
12 #define QTEXT_FILE      "quest.dat"
13
14 /* #define DEBUG */     /* uncomment for debugging */
15
16 static void FDECL(Fread, (genericptr_t,int,int,dlb *));
17 STATIC_DCL struct qtmsg * FDECL(construct_qtlist, (long));
18 STATIC_DCL const char * NDECL(intermed);
19 STATIC_DCL const char * NDECL(neminame);
20 STATIC_DCL const char * NDECL(guardname);
21 STATIC_DCL const char * NDECL(homebase);
22 STATIC_DCL struct qtmsg * FDECL(msg_in, (struct qtmsg *,int));
23 STATIC_DCL void FDECL(convert_arg, (CHAR_P));
24 STATIC_DCL void NDECL(convert_line);
25 STATIC_DCL void FDECL(deliver_by_pline, (struct qtmsg *));
26 STATIC_DCL void FDECL(deliver_by_window, (struct qtmsg *,int));
27
28 static char     in_line[80], cvt_buf[64], out_line[128];
29 static struct   qtlists qt_list;
30 static dlb      *msg_file;
31 /* used by ldrname() and neminame(), then copied into cvt_buf */
32 static char     nambuf[sizeof cvt_buf];
33
34 #ifdef DEBUG
35 static void NDECL(dump_qtlist);
36
37 static void
38 dump_qtlist()   /* dump the character msg list to check appearance */
39 {
40         struct  qtmsg   *msg;
41         long    size;
42
43         for (msg = qt_list.chrole; msg->msgnum > 0; msg++) {
44                 pline("msgnum %d: delivery %c",
45                         msg->msgnum, msg->delivery);
46                 more();
47                 (void) dlb_fseek(msg_file, msg->offset, SEEK_SET);
48                 deliver_by_window(msg, NHW_TEXT);
49         }
50 }
51 #endif /* DEBUG */
52
53 static void
54 Fread(ptr, size, nitems, stream)
55 genericptr_t    ptr;
56 int     size, nitems;
57 dlb     *stream;
58 {
59         int cnt;
60
61         if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
62
63             panic("PREMATURE EOF ON QUEST TEXT FILE! Expected %d bytes, got %d",
64                     (size * nitems), (size * cnt));
65         }
66 }
67
68 STATIC_OVL struct qtmsg *
69 construct_qtlist(hdr_offset)
70 long    hdr_offset;
71 {
72         struct qtmsg *msg_list;
73         int     n_msgs;
74
75         (void) dlb_fseek(msg_file, hdr_offset, SEEK_SET);
76         Fread(&n_msgs, sizeof(int), 1, msg_file);
77         msg_list = (struct qtmsg *)
78                 alloc((unsigned)(n_msgs+1)*sizeof(struct qtmsg));
79
80         /*
81          * Load up the list.
82          */
83         Fread((genericptr_t)msg_list, n_msgs*sizeof(struct qtmsg), 1, msg_file);
84
85         msg_list[n_msgs].msgnum = -1;
86         return(msg_list);
87 }
88
89 void
90 load_qtlist()
91 {
92
93         int     n_classes, i;
94         char    qt_classes[N_HDR][LEN_HDR];
95         long    qt_offsets[N_HDR];
96
97         msg_file = dlb_fopen(QTEXT_FILE, RDBMODE);
98         if (!msg_file)
99             panic("CANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE);
100
101         /*
102          * Read in the number of classes, then the ID's & offsets for
103          * each header.
104          */
105
106         Fread(&n_classes, sizeof(int), 1, msg_file);
107         Fread(&qt_classes[0][0], sizeof(char)*LEN_HDR, n_classes, msg_file);
108         Fread(qt_offsets, sizeof(long), n_classes, msg_file);
109
110         /*
111          * Now construct the message lists for quick reference later
112          * on when we are actually paging the messages out.
113          */
114
115         qt_list.common = qt_list.chrole = (struct qtmsg *)0;
116
117         for (i = 0; i < n_classes; i++) {
118             if (!strncmp(COMMON_ID, qt_classes[i], LEN_HDR))
119                 qt_list.common = construct_qtlist(qt_offsets[i]);
120             else if (!strncmp(urole.filecode, qt_classes[i], LEN_HDR))
121                 qt_list.chrole = construct_qtlist(qt_offsets[i]);
122 #if 0   /* UNUSED but available */
123             else if (!strncmp(urace.filecode, qt_classes[i], LEN_HDR))
124                 qt_list.chrace = construct_qtlist(qt_offsets[i]);
125 #endif
126         }
127
128         if (!qt_list.common || !qt_list.chrole)
129             impossible("load_qtlist: cannot load quest text.");
130 #ifdef DEBUG
131         dump_qtlist();
132 #endif
133         return; /* no ***DON'T*** close the msg_file */
134 }
135
136 /* called at program exit */
137 void
138 unload_qtlist()
139 {
140         if (msg_file)
141             (void) dlb_fclose(msg_file),  msg_file = 0;
142         if (qt_list.common)
143             free((genericptr_t) qt_list.common),  qt_list.common = 0;
144         if (qt_list.chrole)
145             free((genericptr_t) qt_list.chrole),  qt_list.chrole = 0;
146         return;
147 }
148
149 short
150 quest_info(typ)
151 int typ;
152 {
153         switch (typ) {
154             case 0:             return (urole.questarti);
155             case MS_LEADER:     return (urole.ldrnum);
156             case MS_NEMESIS:    return (urole.neminum);
157             case MS_GUARDIAN:   return (urole.guardnum);
158             default:            impossible("quest_info(%d)", typ);
159         }
160         return 0;
161 }
162
163 const char *
164 ldrname()       /* return your role leader's name */
165 {
166         int i = urole.ldrnum;
167
168         Sprintf(nambuf, "%s%s",
169                 type_is_pname(&mons[i]) ? "" : "the ",
170                 mons[i].mname);
171         return nambuf;
172 }
173
174 STATIC_OVL const char *
175 intermed()      /* return your intermediate target string */
176 {
177         return (urole.intermed);
178 }
179
180 boolean
181 is_quest_artifact(otmp)
182 struct obj *otmp;
183 {
184         return((boolean)(otmp->oartifact == urole.questarti));
185 }
186
187 STATIC_OVL const char *
188 neminame()      /* return your role nemesis' name */
189 {
190         int i = urole.neminum;
191
192         Sprintf(nambuf, "%s%s",
193                 type_is_pname(&mons[i]) ? "" : "the ",
194                 mons[i].mname);
195         return nambuf;
196 }
197
198 STATIC_OVL const char *
199 guardname()     /* return your role leader's guard monster name */
200 {
201         int i = urole.guardnum;
202
203         return(mons[i].mname);
204 }
205
206 STATIC_OVL const char *
207 homebase()      /* return your role leader's location */
208 {
209         return(urole.homebase);
210 }
211
212 STATIC_OVL struct qtmsg *
213 msg_in(qtm_list, msgnum)
214 struct qtmsg *qtm_list;
215 int     msgnum;
216 {
217         struct qtmsg *qt_msg;
218
219         for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++)
220             if (qt_msg->msgnum == msgnum) return(qt_msg);
221
222         return((struct qtmsg *)0);
223 }
224
225 STATIC_OVL void
226 convert_arg(c)
227 char c;
228 {
229         register const char *str;
230
231         switch (c) {
232
233             case 'p':   str = plname;
234                         break;
235             case 'c':   str = (flags.female && urole.name.f) ?
236                                 urole.name.f : urole.name.m;
237                         break;
238             case 'r':   str = rank_of(u.ulevel, Role_switch, flags.female);
239                         break;
240             case 'R':   str = rank_of(MIN_QUEST_LEVEL, Role_switch,
241                                 flags.female);
242                         break;
243             case 's':   str = (flags.female) ? "sister" : "brother";
244                         break;
245             case 'S':   str = (flags.female) ? "daughter" : "son";
246                         break;
247             case 'l':   str = ldrname();
248                         break;
249             case 'i':   str = intermed();
250                         break;
251             case 'o':   str = the(artiname(urole.questarti));
252                         break;
253             case 'n':   str = neminame();
254                         break;
255             case 'g':   str = guardname();
256                         break;
257             case 'G':   str = align_gtitle(u.ualignbase[A_ORIGINAL]);
258                         break;
259             case 'H':   str = homebase();
260                         break;
261             case 'a':   str = align_str(u.ualignbase[A_ORIGINAL]);
262                         break;
263             case 'A':   str = align_str(u.ualign.type);
264                         break;
265             case 'd':   str = align_gname(u.ualignbase[A_ORIGINAL]);
266                         break;
267             case 'D':   str = align_gname(A_LAWFUL);
268                         break;
269             case 'C':   str = "chaotic";
270                         break;
271             case 'N':   str = "neutral";
272                         break;
273             case 'L':   str = "lawful";
274                         break;
275             case 'x':   str = Blind ? "sense" : "see";
276                         break;
277             case 'Z':   str = dungeons[0].dname;
278                         break;
279             case '%':   str = "%";
280                         break;
281              default:   str = "";
282                         break;
283         }
284         Strcpy(cvt_buf, str);
285 }
286
287 STATIC_OVL void
288 convert_line()
289 {
290         char *c, *cc;
291         char xbuf[BUFSZ];
292
293         cc = out_line;
294         for (c = xcrypt(in_line, xbuf); *c; c++) {
295
296             *cc = 0;
297             switch(*c) {
298
299                 case '\r':
300                 case '\n':
301                         *(++cc) = 0;
302                         return;
303
304                 case '%':
305                         if (*(c+1)) {
306                             convert_arg(*(++c));
307                             switch (*(++c)) {
308
309                                         /* insert "a"/"an" prefix */
310                                 case 'A': Strcat(cc, An(cvt_buf));
311                                     cc += strlen(cc);
312                                     continue; /* for */
313                                 case 'a': Strcat(cc, an(cvt_buf));
314                                     cc += strlen(cc);
315                                     continue; /* for */
316
317                                         /* capitalize */
318                                 case 'C': cvt_buf[0] = highc(cvt_buf[0]);
319                                     break;
320
321                                         /* pluralize */
322                                 case 'P': cvt_buf[0] = highc(cvt_buf[0]);
323                                 case 'p': Strcpy(cvt_buf, makeplural(cvt_buf));
324                                     break;
325
326                                         /* append possessive suffix */
327                                 case 'S': cvt_buf[0] = highc(cvt_buf[0]);
328                                 case 's': Strcpy(cvt_buf, s_suffix(cvt_buf));
329                                     break;
330
331                                         /* strip any "the" prefix */
332                                 case 't': if (!strncmpi(cvt_buf, "the ", 4)) {
333                                         Strcat(cc, &cvt_buf[4]);
334                                         cc += strlen(cc);
335                                         continue; /* for */
336                                     }
337                                     break;
338
339                                 default: --c;   /* undo switch increment */
340                                     break;
341                             }
342                             Strcat(cc, cvt_buf);
343                             cc += strlen(cvt_buf);
344                             break;
345                         }       /* else fall through */
346
347                 default:
348                         *cc++ = *c;
349                         break;
350             }
351         }
352         if (cc >= out_line + sizeof out_line)
353             panic("convert_line: overflow");
354         *cc = 0;
355         return;
356 }
357
358 STATIC_OVL void
359 deliver_by_pline(qt_msg)
360 struct qtmsg *qt_msg;
361 {
362         long    size;
363
364         for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) {
365             (void) dlb_fgets(in_line, 80, msg_file);
366             convert_line();
367             pline(out_line);
368         }
369
370 }
371
372 STATIC_OVL void
373 deliver_by_window(qt_msg, how)
374 struct qtmsg *qt_msg;
375 int how;
376 {
377         long    size;
378         winid datawin = create_nhwindow(how);
379
380         for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) {
381             (void) dlb_fgets(in_line, 80, msg_file);
382             convert_line();
383             putstr(datawin, 0, out_line);
384         }
385         display_nhwindow(datawin, TRUE);
386         destroy_nhwindow(datawin);
387 }
388
389 void
390 com_pager(msgnum)
391 int     msgnum;
392 {
393         struct qtmsg *qt_msg;
394
395         if (!(qt_msg = msg_in(qt_list.common, msgnum))) {
396                 impossible("com_pager: message %d not found.", msgnum);
397                 return;
398         }
399
400         (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET);
401         if (qt_msg->delivery == 'p') deliver_by_pline(qt_msg);
402         else if (msgnum == 1) deliver_by_window(qt_msg, NHW_MENU);
403         else                 deliver_by_window(qt_msg, NHW_TEXT);
404         return;
405 }
406
407 void
408 qt_pager(msgnum)
409 int     msgnum;
410 {
411         struct qtmsg *qt_msg;
412
413         if (!(qt_msg = msg_in(qt_list.chrole, msgnum))) {
414                 impossible("qt_pager: message %d not found.", msgnum);
415                 return;
416         }
417
418         (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET);
419         if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11"))
420                 deliver_by_pline(qt_msg);
421         else    deliver_by_window(qt_msg, NHW_TEXT);
422         return;
423 }
424
425 struct permonst *
426 qt_montype()
427 {
428         int qpm;
429
430         if (rn2(5)) {
431             qpm = urole.enemy1num;
432             if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
433                 return (&mons[qpm]);
434             return (mkclass(urole.enemy1sym, 0));
435         }
436         qpm = urole.enemy2num;
437         if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
438             return (&mons[qpm]);
439         return (mkclass(urole.enemy2sym, 0));
440 }
441
442 /*questpgr.c*/