xref: /netbsd-src/games/hack/hack.vault.c (revision 72db7ca91297c7ce829030479befd7248c559e0c)
1 /*	$NetBSD: hack.vault.c,v 1.9 2011/08/16 09:26:22 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5  * Amsterdam
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * - Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * - Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * - Neither the name of the Stichting Centrum voor Wiskunde en
20  * Informatica, nor the names of its contributors may be used to endorse or
21  * promote products derived from this software without specific prior
22  * written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.vault.c,v 1.9 2011/08/16 09:26:22 christos Exp $");
67 #endif				/* not lint */
68 
69 #include "hack.h"
70 #include "extern.h"
71 #ifdef QUEST
72 void
setgd(void)73 setgd(void)
74 {
75 }
76 
77 int
gd_move(void)78 gd_move(void)
79 {
80 	return (2);
81 }
82 
83 void
gddead(void)84 gddead(void)
85 {
86 }
87 
88 void
replgd(struct monst * mtmp __unused,struct monst * mtmp2 __unused)89 replgd(struct monst *mtmp __unused, struct monst *mtmp2 __unused)
90 {
91 }
92 
93 void
invault(void)94 invault(void)
95 {
96 }
97 
98 #else
99 
100 
101 #include "def.mkroom.h"
102 #define	FCSIZ	(ROWNO+COLNO)
103 struct fakecorridor {
104 	xchar           fx, fy, ftyp;
105 };
106 
107 struct egd {
108 	int             fcbeg, fcend;	/* fcend: first unused pos */
109 	xchar           gdx, gdy;	/* goal of guard's walk */
110 	unsigned        gddone:1;
111 	struct fakecorridor fakecorr[FCSIZ];
112 };
113 
114 static const struct permonst pm_guard =
115 {"guard", '@', 12, 12, -1, 4, 10, sizeof(struct egd)};
116 
117 static struct monst *guard;
118 static int      gdlevel;
119 
120 static void restfakecorr(void);
121 static int goldincorridor(void);
122 
123 static void
restfakecorr(void)124 restfakecorr(void)
125 {
126 	int		fcx, fcy, fcbeg;
127 	struct rm      *crm;
128 	struct egd	*egd = monster_private(guard);
129 
130 	while ((fcbeg = egd->fcbeg) < egd->fcend) {
131 		fcx = egd->fakecorr[fcbeg].fx;
132 		fcy = egd->fakecorr[fcbeg].fy;
133 		if ((u.ux == fcx && u.uy == fcy) || cansee(fcx, fcy) ||
134 		    m_at(fcx, fcy))
135 			return;
136 		crm = &levl[fcx][fcy];
137 		crm->typ = egd->fakecorr[fcbeg].ftyp;
138 		if (!crm->typ)
139 			crm->seen = 0;
140 		newsym(fcx, fcy);
141 		egd->fcbeg++;
142 	}
143 	/* it seems he left the corridor - let the guard disappear */
144 	mondead(guard);
145 	guard = 0;
146 }
147 
148 static int
goldincorridor(void)149 goldincorridor(void)
150 {
151 	int             fci;
152 	struct egd	*egd = monster_private(guard);
153 
154 	for (fci = egd->fcbeg; fci < egd->fcend; fci++)
155 		if (g_at(egd->fakecorr[fci].fx, egd->fakecorr[fci].fy))
156 			return (1);
157 	return (0);
158 }
159 
160 void
setgd(void)161 setgd(void)
162 {
163 	struct monst   *mtmp;
164 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
165 		if (mtmp->isgd) {
166 			guard = mtmp;
167 			gdlevel = dlevel;
168 			return;
169 		}
170 	guard = 0;
171 }
172 
173 void
invault(void)174 invault(void)
175 {
176 	int tmp = inroom(u.ux, u.uy);
177 	struct egd	*egd;
178 	if (tmp < 0 || rooms[tmp].rtype != VAULT) {
179 		u.uinvault = 0;
180 		return;
181 	}
182 	if (++u.uinvault % 50 == 0 && (!guard || gdlevel != dlevel)) {
183 		char            buf[BUFSZ];
184 		int		x, y, dd, gx, gy;
185 
186 		/* first find the goal for the guard */
187 		for (dd = 1; (dd < ROWNO || dd < COLNO); dd++) {
188 			for (y = u.uy - dd; y <= u.uy + dd; y++) {
189 				if (y < 0 || y > ROWNO - 1)
190 					continue;
191 				for (x = u.ux - dd; x <= u.ux + dd; x++) {
192 					if (y != u.uy - dd && y != u.uy + dd && x != u.ux - dd)
193 						x = u.ux + dd;
194 					if (x < 0 || x > COLNO - 1)
195 						continue;
196 					if (levl[x][y].typ == CORR)
197 						goto fnd;
198 				}
199 			}
200 		}
201 		impossible("Not a single corridor on this level??");
202 		tele();
203 		return;
204 fnd:
205 		gx = x;
206 		gy = y;
207 
208 		/* next find a good place for a door in the wall */
209 		x = u.ux;
210 		y = u.uy;
211 		while (levl[x][y].typ == ROOM) {
212 			int             dx, dy;
213 
214 			dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
215 			dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
216 			if (abs(gx - x) >= abs(gy - y))
217 				x += dx;
218 			else
219 				y += dy;
220 		}
221 
222 		/* make something interesting happen */
223 		if (!(guard = makemon(&pm_guard, x, y)))
224 			return;
225 		guard->isgd = guard->mpeaceful = 1;
226 		egd = monster_private(guard);
227 		egd->gddone = 0;
228 		gdlevel = dlevel;
229 		if (!cansee(guard->mx, guard->my)) {
230 			mondead(guard);
231 			guard = 0;
232 			return;
233 		}
234 		pline("Suddenly one of the Vault's guards enters!");
235 		pmon(guard);
236 		do {
237 			pline("\"Hello stranger, who are you?\" - ");
238 			getlin(buf);
239 		} while (!letter(buf[0]));
240 
241 		if (!strcmp(buf, "Croesus") || !strcmp(buf, "Kroisos")) {
242 			pline("\"Oh, yes - of course. Sorry to have disturbed you.\"");
243 			mondead(guard);
244 			guard = 0;
245 			return;
246 		}
247 		clrlin();
248 		pline("\"I don't know you.\"");
249 		if (!u.ugold)
250 			pline("\"Please follow me.\"");
251 		else {
252 			pline("\"Most likely all that gold was stolen from this vault.\"");
253 			pline("\"Please drop your gold (say d$ ) and follow me.\"");
254 		}
255 		egd->gdx = gx;
256 		egd->gdy = gy;
257 		egd->fcbeg = 0;
258 		egd->fakecorr[0].fx = x;
259 		egd->fakecorr[0].fy = y;
260 		egd->fakecorr[0].ftyp = levl[x][y].typ;
261 		levl[x][y].typ = DOOR;
262 		egd->fcend = 1;
263 	}
264 }
265 
266 int
gd_move(void)267 gd_move(void)
268 {
269 	int             x, y, dx, dy, gx, gy, nx, ny, typ;
270 	struct fakecorridor *fcp;
271 	struct rm      *crm;
272 	struct egd	*egd = monster_private(guard);
273 	if (!guard || gdlevel != dlevel) {
274 		impossible("Where is the guard?");
275 		return (2);	/* died */
276 	}
277 	if (u.ugold || goldincorridor())
278 		return (0);	/* didnt move */
279 	if (dist(guard->mx, guard->my) > 1 || egd->gddone) {
280 		restfakecorr();
281 		return (0);	/* didnt move */
282 	}
283 	x = guard->mx;
284 	y = guard->my;
285 	/* look around (hor & vert only) for accessible places */
286 	for (nx = x - 1; nx <= x + 1; nx++)
287 		for (ny = y - 1; ny <= y + 1; ny++) {
288 			if (nx == x || ny == y)
289 				if (nx != x || ny != y)
290 					if (isok(nx, ny))
291 						if (!IS_WALL(typ = (crm = &levl[nx][ny])->typ) && typ != POOL) {
292 							int             i;
293 							for (i = egd->fcbeg; i < egd->fcend; i++)
294 								if (egd->fakecorr[i].fx == nx &&
295 								    egd->fakecorr[i].fy == ny)
296 									goto nextnxy;
297 							if ((i = inroom(nx, ny)) >= 0 && rooms[i].rtype == VAULT)
298 								goto nextnxy;
299 							/*
300 							 * seems we found a
301 							 * good place to
302 							 * leave him alone
303 							 */
304 							egd->gddone = 1;
305 							if (ACCESSIBLE(typ))
306 								goto newpos;
307 							crm->typ = (typ == SCORR) ? CORR : DOOR;
308 							goto proceed;
309 						}
310 	nextnxy:	;
311 		}
312 	nx = x;
313 	ny = y;
314 	gx = egd->gdx;
315 	gy = egd->gdy;
316 	dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
317 	dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
318 	if (abs(gx - x) >= abs(gy - y))
319 		nx += dx;
320 	else
321 		ny += dy;
322 
323 	while ((typ = (crm = &levl[nx][ny])->typ) != 0) {
324 		/*
325 		 * in view of the above we must have IS_WALL(typ) or typ ==
326 		 * POOL
327 		 */
328 		/* must be a wall here */
329 		if (isok(nx + nx - x, ny + ny - y) && typ != POOL &&
330 		    ZAP_POS(levl[nx + nx - x][ny + ny - y].typ)) {
331 			crm->typ = DOOR;
332 			goto proceed;
333 		}
334 		if (dy && nx != x) {
335 			nx = x;
336 			ny = y + dy;
337 			continue;
338 		}
339 		if (dx && ny != y) {
340 			ny = y;
341 			nx = x + dx;
342 			dy = 0;
343 			continue;
344 		}
345 		/* I don't like this, but ... */
346 		crm->typ = DOOR;
347 		goto proceed;
348 	}
349 	crm->typ = CORR;
350 proceed:
351 	if (cansee(nx, ny)) {
352 		mnewsym(nx, ny);
353 		prl(nx, ny);
354 	}
355 	fcp = &(egd->fakecorr[egd->fcend]);
356 	if (egd->fcend++ == FCSIZ)
357 		panic("fakecorr overflow");
358 	fcp->fx = nx;
359 	fcp->fy = ny;
360 	fcp->ftyp = typ;
361 newpos:
362 	if (egd->gddone)
363 		nx = ny = 0;
364 	guard->mx = nx;
365 	guard->my = ny;
366 	pmon(guard);
367 	restfakecorr();
368 	return (1);
369 }
370 
371 void
gddead(void)372 gddead(void)
373 {
374 	guard = 0;
375 }
376 
377 void
replgd(struct monst * mtmp,struct monst * mtmp2)378 replgd(struct monst *mtmp, struct monst *mtmp2)
379 {
380 	if (mtmp == guard)
381 		guard = mtmp2;
382 }
383 
384 #endif	/* QUEST */
385