Blindfold removal fix
[slashemextended.git] / src / questpgr.c
blob88afe014a4b28301292610867cfb794163bd5e55
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. */
5 #include "hack.h"
6 #include "dlb.h"
8 /* quest-specific pager routines. */
10 #include "qtext.h"
12 #define QTEXT_AREA FILE_AREA_SHARE
13 #define QTEXT_FILE "quest.dat"
15 /* #define DEBUG */ /* uncomment for debugging */
17 static void Fread(void *,int,int,dlb *);
18 STATIC_DCL struct qtmsg * construct_qtlist(long);
19 STATIC_DCL const char * intermed(void);
20 STATIC_DCL const char * guardname(void);
21 STATIC_DCL const char * homebase(void);
22 STATIC_DCL struct qtmsg * msg_in(struct qtmsg *,int);
23 STATIC_DCL void convert_arg(CHAR_P);
24 STATIC_DCL void convert_line(void);
25 STATIC_DCL void deliver_by_pline(struct qtmsg *);
26 STATIC_DCL void deliver_by_window(struct qtmsg *,int);
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];
34 #ifdef DEBUG
35 static void dump_qtlist(void);
37 static void
38 dump_qtlist() /* dump the character msg list to check appearance */
40 struct qtmsg *msg;
41 long size;
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);
51 #endif /* DEBUG */
53 static void
54 Fread(ptr, size, nitems, stream)
55 void * ptr;
56 int size, nitems;
57 dlb *stream;
59 int cnt;
61 if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
63 panic("PREMATURE EOF ON QUEST TEXT FILE! Expected %d bytes, got %d",
64 (size * nitems), (size * cnt));
68 STATIC_OVL struct qtmsg *
69 construct_qtlist(hdr_offset)
70 long hdr_offset;
72 struct qtmsg *msg_list;
73 int n_msgs;
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));
81 * Load up the list.
83 Fread((void *)msg_list, n_msgs*sizeof(struct qtmsg), 1, msg_file);
85 msg_list[n_msgs].msgnum = -1;
86 return(msg_list);
89 void
90 load_qtlist()
93 int n_classes, i;
94 char qt_classes[N_HDR][LEN_HDR];
95 long qt_offsets[N_HDR];
97 msg_file = dlb_fopen_area(QTEXT_AREA, QTEXT_FILE, RDBMODE);
98 if (!msg_file)
99 panic("CANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE);
102 * Read in the number of classes, then the ID's & offsets for
103 * each header.
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);
111 * Now construct the message lists for quick reference later
112 * on when we are actually paging the messages out.
115 qt_list.common = qt_list.chrole = (struct qtmsg *)0;
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
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 */
136 /* called at program exit */
137 void
138 unload_qtlist()
140 if (msg_file)
141 (void) dlb_fclose(msg_file), msg_file = 0;
142 if (qt_list.common)
143 free((void *) qt_list.common), qt_list.common = 0;
144 if (qt_list.chrole)
145 free((void *) qt_list.chrole), qt_list.chrole = 0;
146 return;
150 quest_info(typ)
151 int typ;
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);
160 return 0;
163 const char *
164 ldrname() /* return your role leader's name */
166 int i = urole.ldrnum;
168 sprintf(nambuf, "%s%s",
169 type_is_pname(&mons[i]) ? "" : "the ",
170 mons[i].mname);
171 return nambuf;
174 STATIC_OVL const char *
175 intermed() /* return your intermediate target string */
177 return (urole.intermed);
180 boolean
181 is_quest_artifact(otmp)
182 struct obj *otmp;
184 return((boolean)( (unsigned int) otmp->oartifact == (unsigned int) urole.questarti));
187 const char *
188 neminame() /* return your role nemesis' name */
190 int i = urole.neminum;
192 sprintf(nambuf, "%s%s",
193 type_is_pname(&mons[i]) ? "" : "the ",
194 mons[i].mname);
195 return nambuf;
198 STATIC_OVL const char *
199 guardname() /* return your role leader's guard monster name */
201 int i = urole.guardnum;
203 return(mons[i].mname);
206 STATIC_OVL const char *
207 homebase() /* return your role leader's location */
209 return(urole.homebase);
212 STATIC_OVL struct qtmsg *
213 msg_in(qtm_list, msgnum)
214 struct qtmsg *qtm_list;
215 int msgnum;
217 struct qtmsg *qt_msg;
219 for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++)
220 if (qt_msg->msgnum == msgnum) return(qt_msg);
222 return((struct qtmsg *)0);
225 STATIC_OVL void
226 convert_arg(c)
227 char c;
229 register const char *str;
231 switch (c) {
233 case 'p': str = playeraliasname;
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;
284 strcpy(cvt_buf, str);
287 STATIC_OVL void
288 convert_line()
290 char *c, *cc;
291 char xbuf[BUFSZ];
293 cc = out_line;
294 for (c = xcrypt(in_line, xbuf); *c; c++) {
296 *cc = 0;
297 switch(*c) {
299 case '\r':
300 case '\n':
301 *(++cc) = 0;
302 return;
304 case '%':
305 if (*(c+1)) {
306 convert_arg(*(++c));
307 switch (*(++c)) {
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 */
317 /* capitalize */
318 case 'C': cvt_buf[0] = highc(cvt_buf[0]);
319 break;
321 /* pluralize */
322 case 'P': cvt_buf[0] = highc(cvt_buf[0]);
323 case 'p': strcpy(cvt_buf, makeplural(cvt_buf));
324 break;
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;
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 */
337 break;
339 default: --c; /* undo switch increment */
340 break;
342 strcat(cc, cvt_buf);
343 cc += strlen(cvt_buf);
344 break;
345 } /* else fall through */
347 default:
348 *cc++ = *c;
349 break;
352 if (cc >= out_line + sizeof out_line)
353 panic("convert_line: overflow");
354 *cc = 0;
355 return;
358 STATIC_OVL void
359 deliver_by_pline(qt_msg)
360 struct qtmsg *qt_msg;
362 long size;
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("%s", out_line);
372 STATIC_OVL void
373 deliver_by_window(qt_msg, how)
374 struct qtmsg *qt_msg;
375 int how;
377 long size;
378 winid datawin = create_nhwindow(how);
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);
385 display_nhwindow(datawin, TRUE);
386 destroy_nhwindow(datawin);
389 void
390 com_pager(msgnum)
391 int msgnum;
393 struct qtmsg *qt_msg;
395 if (!(qt_msg = msg_in(qt_list.common, msgnum))) {
396 impossible("com_pager: message %d not found.", msgnum);
397 return;
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;
407 void
408 qt_pager(msgnum)
409 int msgnum;
411 struct qtmsg *qt_msg;
413 if (!(qt_msg = msg_in(qt_list.chrole, msgnum))) {
414 impossible("qt_pager: message %d not found.", msgnum);
415 return;
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);
423 if (practicantterror && msgnum == QT_FIRSTNEMESIS && !u.pract_trespassing) {
424 fineforpracticant(2000, 0, 0);
425 u.pract_trespassing = TRUE;
427 if (practicantterror && msgnum == QT_NEXTNEMESIS && !u.pract_trespassing2) {
428 fineforpracticant(4000, 0, 0);
429 u.pract_trespassing2 = TRUE;
431 if (practicantterror && msgnum == QT_OTHERNEMESIS) { /* can be repeated an arbitrary amount of times */
432 fineforpracticant(5000, 0, 0);
434 if (practicantterror && msgnum == QT_NEMWANTSIT && !u.pract_artitheft) {
435 fineforpracticant(50000, 0, 0);
436 u.pract_artitheft = TRUE;
439 return;
442 struct permonst *
443 qt_montype()
445 int qpm;
447 if (rn2(5)) {
448 qpm = urole.enemy1num;
449 if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
450 return (&mons[qpm]);
451 return (mkclass(urole.enemy1sym, 0));
453 qpm = urole.enemy2num;
454 if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
455 return (&mons[qpm]);
456 return (mkclass(urole.enemy2sym, 0));
459 struct permonst *
460 qt_rival_montype()
462 int qpm;
464 if (rn2(5)) {
465 qpm = u.rivalenemy1num;
466 if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
467 return (&mons[qpm]);
468 return (mkclass(u.rivalenemy1sym, 0));
470 qpm = u.rivalenemy2num;
471 if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
472 return (&mons[qpm]);
473 return (mkclass(u.rivalenemy2sym, 0));
476 /*questpgr.c*/