1 | /* SCCS Id: @(#)quest.c 3.3 2000/05/05 */
2 | /* Copyright 1991, M. Stephenson */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | #include "hack.h"
6 |
7 | /* quest dungeon branch routines. */
8 |
9 | #include "quest.h"
10 | #include "qtext.h"
11 |
12 | #define Not_firsttime (on_level(&u.uz0, &u.uz))
13 | #define Qstat(x) (quest_status.x)
14 |
15 | STATIC_DCL void NDECL(on_start);
16 | STATIC_DCL void NDECL(on_locate);
17 | STATIC_DCL void NDECL(on_goal);
18 | STATIC_DCL boolean NDECL(not_capable);
19 | STATIC_DCL boolean FDECL(is_pure, (BOOLEAN_P));
20 | STATIC_DCL void FDECL(expulsion, (BOOLEAN_P));
21 | STATIC_DCL void NDECL(chat_with_leader);
22 | STATIC_DCL void NDECL(chat_with_nemesis);
23 | STATIC_DCL void NDECL(chat_with_guardian);
24 | STATIC_DCL void FDECL(prisoner_speaks, (struct monst *));
25 |
26 |
27 | STATIC_OVL void
28 | on_start()
29 | {
30 | if(!Qstat(first_start)) {
31 | qt_pager(QT_FIRSTTIME);
32 | Qstat(first_start) = TRUE;
33 | } else if((u.uz0.dnum != u.uz.dnum) || (u.uz0.dlevel < u.uz.dlevel)) {
34 | if(Qstat(not_ready) <= 2) qt_pager(QT_NEXTTIME);
35 | else qt_pager(QT_OTHERTIME);
36 | }
37 | }
38 |
39 | STATIC_OVL void
40 | on_locate()
41 | {
42 | if(!Qstat(first_locate)) {
43 | qt_pager(QT_FIRSTLOCATE);
44 | Qstat(first_locate) = TRUE;
45 | } else if(u.uz0.dlevel < u.uz.dlevel && !Qstat(killed_nemesis))
46 | qt_pager(QT_NEXTLOCATE);
47 | }
48 |
49 | STATIC_OVL void
50 | on_goal()
51 | {
52 | if (Qstat(killed_nemesis)) {
53 | return;
54 | } else if (!Qstat(made_goal)) {
55 | qt_pager(QT_FIRSTGOAL);
56 | Qstat(made_goal) = 1;
57 | } else {
58 | qt_pager(QT_NEXTGOAL);
59 | if(Qstat(made_goal) < 7) Qstat(made_goal)++;
60 | }
61 | }
62 |
63 | void
64 | onquest()
65 | {
66 | if(u.uevent.qcompleted || Not_firsttime) return;
67 | if(!Is_special(&u.uz)) return;
68 |
69 | if(Is_qstart(&u.uz)) on_start();
70 | else if(Is_qlocate(&u.uz) && u.uz.dlevel > u.uz0.dlevel) on_locate();
71 | else if(Is_nemesis(&u.uz)) on_goal();
72 | return;
73 | }
74 |
75 | void
76 | nemdead()
77 | {
78 | if(!Qstat(killed_nemesis)) {
79 | Qstat(killed_nemesis) = TRUE;
80 | qt_pager(QT_KILLEDNEM);
81 | }
82 | }
83 |
84 | void
85 | artitouch()
86 | {
87 | if(!Qstat(touched_artifact)) {
88 | Qstat(touched_artifact) = TRUE;
89 | qt_pager(QT_GOTIT);
90 | exercise(A_WIS, TRUE);
91 | }
92 | }
93 |
94 | /* external hook for do.c (level change check) */
95 | boolean
96 | ok_to_quest()
97 | {
98 | return((boolean)((Qstat(got_quest) || Qstat(got_thanks)))
99 | && is_pure(FALSE));
100 | }
101 |
102 | STATIC_OVL boolean
103 | not_capable()
104 | {
105 | return((boolean)(u.ulevel < MIN_QUEST_LEVEL));
106 | }
107 |
108 | STATIC_OVL boolean
109 | is_pure(talk)
110 | boolean talk;
111 | {
112 | aligntyp original_alignment = u.ualignbase[A_ORIGINAL];
113 |
114 | #ifdef WIZARD
115 | if (wizard && talk) {
116 | if (u.ualign.type != original_alignment) {
117 | You("are currently %s instead of %s.",
118 | align_str(u.ualign.type), align_str(original_alignment));
119 | } else if (u.ualignbase[A_CURRENT] != original_alignment) {
120 | You("have converted.");
121 | } else if (u.ualign.record < MIN_QUEST_ALIGN) {
122 | You("are currently %d and require %d.",
123 | u.ualign.record, MIN_QUEST_ALIGN);
124 | if (yn_function("adjust?", (char *)0, 'y') == 'y')
125 | u.ualign.record = MIN_QUEST_ALIGN;
126 | }
127 | }
128 | #endif
129 | return (boolean)(u.ualign.record >= MIN_QUEST_ALIGN &&
130 | u.ualign.type == original_alignment &&
131 | u.ualignbase[A_CURRENT] == original_alignment);
132 | }
133 |
134 | /*
135 | * Expell the player to the stairs on the parent of the quest dungeon.
136 | *
137 | * This assumes that the hero is currently _in_ the quest dungeon and that
138 | * there is a single branch to and from it.
139 | */
140 | STATIC_OVL void
141 | expulsion(seal)
142 | boolean seal;
143 | {
144 | branch *br;
145 | d_level *dest;
146 | struct trap *t;
147 | int portal_flag;
148 |
149 | br = dungeon_branch("The Quest");
150 | dest = (br->end1.dnum == u.uz.dnum) ? &br->end2 : &br->end1;
151 | portal_flag = u.uevent.qexpelled ? 0 : /* returned via artifact? */
152 | !seal ? 1 : -1;
153 | schedule_goto(dest, FALSE, FALSE, portal_flag, (char *)0, (char *)0);
154 | if (seal) { /* remove the portal to the quest - sealing it off */
155 | u.uevent.qexpelled = 1;
156 | /* Delete the near portal now; the far (main dungeon side)
157 | portal will be deleted as part of arrival on that level.
158 | If monster movement is in progress, any who haven't moved
159 | yet will now miss out on a chance to wander through it... */
160 | for (t = ftrap; t; t = t->ntrap)
161 | if (t->ttyp == MAGIC_PORTAL) break;
162 | if (t) deltrap(t); /* (display might be briefly out of sync) */
163 | else impossible("quest portal already gone?");
164 | }
165 | }
166 |
167 | /* Either you've returned to quest leader while carrying the quest
168 | artifact or you've just thrown it to/at him or her. If quest
169 | completion text hasn't been given yet, give it now. Otherwise
170 | give another message about the character keeping the artifact
171 | and using the magic portal to return to the dungeon. */
172 | void
173 | finish_quest(obj)
174 | struct obj *obj; /* quest artifact; possibly null if carrying Amulet */
175 | {
176 | struct obj *otmp;
177 |
178 | if (u.uhave.amulet) { /* unlikely but not impossible */
179 | qt_pager(QT_HASAMULET);
180 | /* leader IDs the real amulet but ignores any fakes */
181 | if ((otmp = carrying(AMULET_OF_YENDOR)) != 0)
182 | fully_identify_obj(otmp);
183 | } else {
184 | qt_pager(!Qstat(got_thanks) ? QT_OFFEREDIT : QT_OFFEREDIT2);
185 | /* should have obtained bell during quest;
186 | if not, suggest returning for it now */
187 | if ((otmp = carrying(BELL_OF_OPENING)) == 0)
188 | com_pager(5);
189 | }
190 | Qstat(got_thanks) = TRUE;
191 |
192 | if (obj) {
193 | u.uevent.qcompleted = 1; /* you did it! */
194 | /* behave as if leader imparts sufficient info about the
195 | quest artifact */
196 | fully_identify_obj(obj);
197 | }
198 | }
199 |
200 | STATIC_OVL void
201 | chat_with_leader()
202 | {
203 | /* Rule 0: Cheater checks. */
204 | if(u.uhave.questart && !Qstat(met_nemesis))
205 | Qstat(cheater) = TRUE;
206 |
207 | /* It is possible for you to get the amulet without completing
208 | * the quest. If so, try to induce the player to quest.
209 | */
210 | if(Qstat(got_thanks)) {
211 | /* Rule 1: You've gone back with/without the amulet. */
212 | if(u.uhave.amulet) finish_quest((struct obj *)0);
213 |
214 | /* Rule 2: You've gone back before going for the amulet. */
215 | else qt_pager(QT_POSTHANKS);
216 | }
217 |
218 | /* Rule 3: You've got the artifact and are back to return it. */
219 | else if(u.uhave.questart) {
220 | struct obj *otmp;
221 |
222 | for (otmp = invent; otmp; otmp = otmp->nobj)
223 | if (is_quest_artifact(otmp)) break;
224 |
225 | finish_quest(otmp);
226 |
227 | /* Rule 4: You haven't got the artifact yet. */
228 | } else if(Qstat(got_quest)) {
229 | qt_pager(rn1(10, QT_ENCOURAGE));
230 |
231 | /* Rule 5: You aren't yet acceptable - or are you? */
232 | } else {
233 | if(!Qstat(met_leader)) {
234 | qt_pager(QT_FIRSTLEADER);
235 | Qstat(met_leader) = TRUE;
236 | Qstat(not_ready) = 0;
237 | } else qt_pager(QT_NEXTLEADER);
238 | /* the quest leader might have passed through the portal into
239 | the regular dungeon; none of the remaining make sense there */
240 | if (!on_level(&u.uz, &qstart_level)) return;
241 |
242 | if(not_capable()) {
243 | qt_pager(QT_BADLEVEL);
244 | exercise(A_WIS, TRUE);
245 | expulsion(FALSE);
246 | } else if(!is_pure(TRUE)) {
247 | qt_pager(QT_BADALIGN);
248 | if(Qstat(not_ready) == MAX_QUEST_TRIES) {
249 | qt_pager(QT_LASTLEADER);
250 | expulsion(TRUE);
251 | } else {
252 | Qstat(not_ready)++;
253 | exercise(A_WIS, TRUE);
254 | expulsion(FALSE);
255 | }
256 | } else { /* You are worthy! */
257 | qt_pager(QT_ASSIGNQUEST);
258 | exercise(A_WIS, TRUE);
259 | Qstat(got_quest) = TRUE;
260 | }
261 | }
262 | }
263 |
264 | void
265 | leader_speaks(mtmp)
266 | register struct monst *mtmp;
267 | {
268 | /* maybe you attacked leader? */
269 | if(!mtmp->mpeaceful) {
270 | Qstat(pissed_off) = TRUE;
271 | mtmp->mstrategy &= ~STRAT_WAITMASK; /* end the inaction */
272 | }
273 | /* the quest leader might have passed through the portal into the
274 | regular dungeon; if so, mustn't perform "backwards expulsion" */
275 | if (!on_level(&u.uz, &qstart_level)) return;
276 |
277 | if(Qstat(pissed_off)) {
278 | qt_pager(QT_LASTLEADER);
279 | expulsion(TRUE);
280 | } else chat_with_leader();
281 | }
282 |
283 | STATIC_OVL void
284 | chat_with_nemesis()
285 | {
286 | /* The nemesis will do most of the talking, but... */
287 | qt_pager(rn1(10, QT_DISCOURAGE));
288 | if(!Qstat(met_nemesis)) Qstat(met_nemesis++);
289 | }
290 |
291 | void
292 | nemesis_speaks()
293 | {
294 | if(!Qstat(in_battle)) {
295 | if(u.uhave.questart) qt_pager(QT_NEMWANTSIT);
296 | else if(Qstat(made_goal) == 1) qt_pager(QT_FIRSTNEMESIS);
297 | else if(Qstat(made_goal) < 4) qt_pager(QT_NEXTNEMESIS);
298 | else if(Qstat(made_goal) < 7) qt_pager(QT_OTHERNEMESIS);
299 | else if(!rn2(5)) qt_pager(rn1(10, QT_DISCOURAGE));
300 | if(Qstat(made_goal) < 7) Qstat(made_goal)++;
301 | Qstat(met_nemesis) = TRUE;
302 | } else /* he will spit out random maledictions */
303 | if(!rn2(5)) qt_pager(rn1(10, QT_DISCOURAGE));
304 | }
305 |
306 | STATIC_OVL void
307 | chat_with_guardian()
308 | {
309 | /* These guys/gals really don't have much to say... */
310 | qt_pager(rn1(5, QT_GUARDTALK));
311 | }
312 |
313 | STATIC_OVL void
314 | prisoner_speaks (mtmp)
315 | register struct monst *mtmp;
316 | {
317 | if (mtmp->data == &mons[PM_PRISONER] &&
318 | (mtmp->mstrategy & STRAT_WAITMASK)) {
319 | /* Awaken the prisoner */
320 | if (canseemon(mtmp))
321 | pline("%s speaks:", Monnam(mtmp));
322 | verbalize("I'm finally free!");
323 | mtmp->mstrategy &= ~STRAT_WAITMASK;
324 | mtmp->mpeaceful = 1;
325 |
326 | /* Your god is happy... */
327 | adjalign(3);
328 |
329 | /* ...But the guards are not */
330 | (void) angry_guards(FALSE);
331 | }
332 | return;
333 | }
334 |
335 | void
336 | quest_chat(mtmp)
337 | register struct monst *mtmp;
338 | {
339 | switch(mtmp->data->msound) {
340 | case MS_LEADER: chat_with_leader(); break;
341 | case MS_NEMESIS: chat_with_nemesis(); break;
342 | case MS_GUARDIAN: chat_with_guardian(); break;
343 | default: impossible("quest_chat: Unknown quest character %s.",
344 | mon_nam(mtmp));
345 | }
346 | }
347 |
348 | void
349 | quest_talk(mtmp)
350 | register struct monst *mtmp;
351 | {
352 | switch(mtmp->data->msound) {
353 | case MS_LEADER: leader_speaks(mtmp); break;
354 | case MS_NEMESIS: nemesis_speaks(); break;
355 | case MS_DJINNI: prisoner_speaks(mtmp); break;
356 | default: break;
357 | }
358 | }
359 |
360 | void
361 | quest_stat_check(mtmp)
362 | struct monst *mtmp;
363 | {
364 | if(mtmp->data->msound == MS_NEMESIS)
365 | Qstat(in_battle) = (mtmp->mcanmove && !mtmp->msleeping &&
366 | monnear(mtmp, u.ux, u.uy));
367 | }
368 |
369 | /*quest.c*/