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. */
8 /* quest-specific pager routines. */
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
;
31 /* used by ldrname() and neminame(), then copied into cvt_buf */
32 static char nambuf
[sizeof cvt_buf
];
35 static void dump_qtlist(void);
38 dump_qtlist() /* dump the character msg list to check appearance */
43 for (msg
= qt_list
.chrole
; msg
->msgnum
> 0; msg
++) {
44 pline("msgnum %d: delivery %c",
45 msg
->msgnum
, msg
->delivery
);
47 (void) dlb_fseek(msg_file
, msg
->offset
, SEEK_SET
);
48 deliver_by_window(msg
, NHW_TEXT
);
54 Fread(ptr
, size
, nitems
, stream
)
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
)
72 struct qtmsg
*msg_list
;
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
));
83 Fread((void *)msg_list
, n_msgs
*sizeof(struct qtmsg
), 1, msg_file
);
85 msg_list
[n_msgs
].msgnum
= -1;
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
);
99 panic("CANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE
);
102 * Read in the number of classes, then the ID's & offsets for
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
]);
128 if (!qt_list
.common
|| !qt_list
.chrole
)
129 impossible("load_qtlist: cannot load quest text.");
133 return; /* no ***DON'T*** close the msg_file */
136 /* called at program exit */
141 (void) dlb_fclose(msg_file
), msg_file
= 0;
143 free((void *) qt_list
.common
), qt_list
.common
= 0;
145 free((void *) qt_list
.chrole
), qt_list
.chrole
= 0;
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
);
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 ",
174 STATIC_OVL
const char *
175 intermed() /* return your intermediate target string */
177 return (urole
.intermed
);
181 is_quest_artifact(otmp
)
184 return((boolean
)( (unsigned int) otmp
->oartifact
== (unsigned int) urole
.questarti
));
188 neminame() /* return your role nemesis' name */
190 int i
= urole
.neminum
;
192 sprintf(nambuf
, "%s%s",
193 type_is_pname(&mons
[i
]) ? "" : "the ",
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
;
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);
229 register const char *str
;
233 case 'p': str
= playeraliasname
;
235 case 'c': str
= (flags
.female
&& urole
.name
.f
) ?
236 urole
.name
.f
: urole
.name
.m
;
238 case 'r': str
= rank_of(u
.ulevel
, Role_switch
, flags
.female
);
240 case 'R': str
= rank_of(MIN_QUEST_LEVEL
, Role_switch
,
243 case 's': str
= (flags
.female
) ? "sister" : "brother";
245 case 'S': str
= (flags
.female
) ? "daughter" : "son";
247 case 'l': str
= ldrname();
249 case 'i': str
= intermed();
251 case 'o': str
= the(artiname(urole
.questarti
));
253 case 'n': str
= neminame();
255 case 'g': str
= guardname();
257 case 'G': str
= align_gtitle(u
.ualignbase
[A_ORIGINAL
]);
259 case 'H': str
= homebase();
261 case 'a': str
= align_str(u
.ualignbase
[A_ORIGINAL
]);
263 case 'A': str
= align_str(u
.ualign
.type
);
265 case 'd': str
= align_gname(u
.ualignbase
[A_ORIGINAL
]);
267 case 'D': str
= align_gname(A_LAWFUL
);
269 case 'C': str
= "chaotic";
271 case 'N': str
= "neutral";
273 case 'L': str
= "lawful";
275 case 'x': str
= Blind
? "sense" : "see";
277 case 'Z': str
= dungeons
[0].dname
;
284 strcpy(cvt_buf
, str
);
294 for (c
= xcrypt(in_line
, xbuf
); *c
; c
++) {
309 /* insert "a"/"an" prefix */
310 case 'A': strcat(cc
, An(cvt_buf
));
313 case 'a': strcat(cc
, an(cvt_buf
));
318 case 'C': cvt_buf
[0] = highc(cvt_buf
[0]);
322 case 'P': cvt_buf
[0] = highc(cvt_buf
[0]);
323 case 'p': strcpy(cvt_buf
, makeplural(cvt_buf
));
326 /* append possessive suffix */
327 case 'S': cvt_buf
[0] = highc(cvt_buf
[0]);
328 case 's': strcpy(cvt_buf
, s_suffix(cvt_buf
));
331 /* strip any "the" prefix */
332 case 't': if (!strncmpi(cvt_buf
, "the ", 4)) {
333 strcat(cc
, &cvt_buf
[4]);
339 default: --c
; /* undo switch increment */
343 cc
+= strlen(cvt_buf
);
345 } /* else fall through */
352 if (cc
>= out_line
+ sizeof out_line
)
353 panic("convert_line: overflow");
359 deliver_by_pline(qt_msg
)
360 struct qtmsg
*qt_msg
;
364 for (size
= 0; size
< qt_msg
->size
; size
+= (long)strlen(in_line
)) {
365 (void) dlb_fgets(in_line
, 80, msg_file
);
367 pline("%s", out_line
);
373 deliver_by_window(qt_msg
, how
)
374 struct qtmsg
*qt_msg
;
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
);
383 putstr(datawin
, 0, out_line
);
385 display_nhwindow(datawin
, TRUE
);
386 destroy_nhwindow(datawin
);
393 struct qtmsg
*qt_msg
;
395 if (!(qt_msg
= msg_in(qt_list
.common
, msgnum
))) {
396 impossible("com_pager: message %d not found.", msgnum
);
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
);
411 struct qtmsg
*qt_msg
;
413 if (!(qt_msg
= msg_in(qt_list
.chrole
, msgnum
))) {
414 impossible("qt_pager: message %d not found.", msgnum
);
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
;
448 qpm
= urole
.enemy1num
;
449 if (qpm
!= NON_PM
&& rn2(5) && !(mvitals
[qpm
].mvflags
& G_GENOD
))
451 return (mkclass(urole
.enemy1sym
, 0));
453 qpm
= urole
.enemy2num
;
454 if (qpm
!= NON_PM
&& rn2(5) && !(mvitals
[qpm
].mvflags
& G_GENOD
))
456 return (mkclass(urole
.enemy2sym
, 0));
465 qpm
= u
.rivalenemy1num
;
466 if (qpm
!= NON_PM
&& rn2(5) && !(mvitals
[qpm
].mvflags
& G_GENOD
))
468 return (mkclass(u
.rivalenemy1sym
, 0));
470 qpm
= u
.rivalenemy2num
;
471 if (qpm
!= NON_PM
&& rn2(5) && !(mvitals
[qpm
].mvflags
& G_GENOD
))
473 return (mkclass(u
.rivalenemy2sym
, 0));