xref: /openbsd/games/hack/hack.vault.c (revision 73471bf0)
1 /*	$OpenBSD: hack.vault.c,v 1.8 2016/01/09 18:33:15 mestre 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 <stdlib.h>
65 
66 #include "hack.h"
67 
68 #ifdef QUEST
69 void
70 setgd(void)
71 {}
72 
73 int
74 gd_move(void)
75 {
76 	return(2);
77 }
78 
79 void
80 gddead(void)
81 {}
82 
83 void
84 replgd(struct monst *mtmp, struct monst *mtmp2)
85 {}
86 
87 void
88 invault(void)
89 {}
90 
91 #else
92 extern struct monst *makemon(struct permonst *, int, int);
93 #define	FCSIZ	(ROWNO+COLNO)
94 struct fakecorridor {
95 	xchar fx,fy,ftyp;
96 };
97 
98 struct egd {
99 	int fcbeg, fcend;	/* fcend: first unused pos */
100 	xchar gdx, gdy;		/* goal of guard's walk */
101 	unsigned gddone:1;
102 	struct fakecorridor fakecorr[FCSIZ];
103 };
104 
105 static struct permonst pm_guard =
106 	{ "guard", '@', 12, 12, -1, 4, 10, sizeof(struct egd) };
107 
108 static struct monst *guard;
109 static int gdlevel;
110 #define	EGD	((struct egd *)(&(guard->mextra[0])))
111 
112 static void restfakecorr(void);
113 static int  goldincorridor(void);
114 
115 
116 static void
117 restfakecorr(void)
118 {
119 	int fcx,fcy,fcbeg;
120 	struct rm *crm;
121 
122 	while((fcbeg = EGD->fcbeg) < EGD->fcend) {
123 		fcx = EGD->fakecorr[fcbeg].fx;
124 		fcy = EGD->fakecorr[fcbeg].fy;
125 		if((u.ux == fcx && u.uy == fcy) || cansee(fcx,fcy) ||
126 		   m_at(fcx,fcy))
127 			return;
128 		crm = &levl[fcx][fcy];
129 		crm->typ = EGD->fakecorr[fcbeg].ftyp;
130 		if(!crm->typ) crm->seen = 0;
131 		newsym(fcx,fcy);
132 		EGD->fcbeg++;
133 	}
134 	/* it seems he left the corridor - let the guard disappear */
135 	mondead(guard);
136 	guard = 0;
137 }
138 
139 static int
140 goldincorridor(void)
141 {
142 	int fci;
143 
144 	for(fci = EGD->fcbeg; fci < EGD->fcend; fci++)
145 		if(g_at(EGD->fakecorr[fci].fx, EGD->fakecorr[fci].fy))
146 			return(1);
147 	return(0);
148 }
149 
150 void
151 setgd(void)
152 {
153 	struct monst *mtmp;
154 
155 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->isgd){
156 		guard = mtmp;
157 		gdlevel = dlevel;
158 		return;
159 	}
160 	guard = 0;
161 }
162 
163 void
164 invault(void)
165 {
166 	int tmp = inroom(u.ux, u.uy);
167 
168     if(tmp < 0 || rooms[tmp].rtype != VAULT) {
169 	u.uinvault = 0;
170 	return;
171     }
172     if(++u.uinvault % 50 == 0 && (!guard || gdlevel != dlevel)) {
173 	char buf[BUFSZ];
174 	int x,y,dd,gx,gy;
175 
176 	/* first find the goal for the guard */
177 	for(dd = 1; (dd < ROWNO || dd < COLNO); dd++) {
178 	  for(y = u.uy-dd; y <= u.uy+dd; y++) {
179 	    if(y < 0 || y > ROWNO-1) continue;
180 	    for(x = u.ux-dd; x <= u.ux+dd; x++) {
181 	      if(y != u.uy-dd && y != u.uy+dd && x != u.ux-dd)
182 		x = u.ux+dd;
183 	      if(x < 0 || x > COLNO-1) continue;
184 	      if(levl[x][y].typ == CORR) goto fnd;
185 	    }
186 	  }
187 	}
188 	impossible("Not a single corridor on this level??");
189 	tele();
190 	return;
191 fnd:
192 	gx = x; gy = y;
193 
194 	/* next find a good place for a door in the wall */
195 	x = u.ux; y = u.uy;
196 	while(levl[x][y].typ == ROOM) {
197 		int dx,dy;
198 
199 		dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
200 		dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
201 		if(abs(gx-x) >= abs(gy-y))
202 			x += dx;
203 		else
204 			y += dy;
205 	}
206 
207 	/* make something interesting happen */
208 	if(!(guard = makemon(&pm_guard,x,y))) return;
209 	guard->isgd = guard->mpeaceful = 1;
210 	EGD->gddone = 0;
211 	gdlevel = dlevel;
212 	if(!cansee(guard->mx, guard->my)) {
213 		mondead(guard);
214 		guard = 0;
215 		return;
216 	}
217 
218 	pline("Suddenly one of the Vault's guards enters!");
219 	pmon(guard);
220 	do {
221 		pline("\"Hello stranger, who are you?\" - ");
222 		getlin(buf);
223 	} while (!letter(buf[0]));
224 
225 	if(!strcmp(buf, "Croesus") || !strcmp(buf, "Kroisos")) {
226 		pline("\"Oh, yes - of course. Sorry to have disturbed you.\"");
227 		mondead(guard);
228 		guard = 0;
229 		return;
230 	}
231 	clrlin();
232 	pline("\"I don't know you.\"");
233 	if(!u.ugold)
234 	    pline("\"Please follow me.\"");
235 	else {
236 	    pline("\"Most likely all that gold was stolen from this vault.\"");
237 	    pline("\"Please drop your gold (say d$ ) and follow me.\"");
238 	}
239 	EGD->gdx = gx;
240 	EGD->gdy = gy;
241 	EGD->fcbeg = 0;
242 	EGD->fakecorr[0].fx = x;
243 	EGD->fakecorr[0].fy = y;
244 	EGD->fakecorr[0].ftyp = levl[x][y].typ;
245 	levl[x][y].typ = DOOR;
246 	EGD->fcend = 1;
247     }
248 }
249 
250 int
251 gd_move(void)
252 {
253 	int x,y,dx,dy,gx,gy,nx,ny,typ;
254 	struct fakecorridor *fcp;
255 	struct rm *crm;
256 
257 	if(!guard || gdlevel != dlevel){
258 		impossible("Where is the guard?");
259 		return(2);	/* died */
260 	}
261 	if(u.ugold || goldincorridor())
262 		return(0);	/* didnt move */
263 	if(dist(guard->mx,guard->my) > 1 || EGD->gddone) {
264 		restfakecorr();
265 		return(0);	/* didnt move */
266 	}
267 	x = guard->mx;
268 	y = guard->my;
269 	/* look around (hor & vert only) for accessible places */
270 	for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) {
271 	    if(nx == x || ny == y) if(nx != x || ny != y)
272 	    if(isok(nx,ny))
273 	    if(!IS_WALL(typ = (crm = &levl[nx][ny])->typ) && typ != POOL) {
274 		int i;
275 		for(i = EGD->fcbeg; i < EGD->fcend; i++)
276 			if(EGD->fakecorr[i].fx == nx &&
277 			   EGD->fakecorr[i].fy == ny)
278 				goto nextnxy;
279 		if((i = inroom(nx,ny)) >= 0 && rooms[i].rtype == VAULT)
280 			goto nextnxy;
281 		/* seems we found a good place to leave him alone */
282 		EGD->gddone = 1;
283 		if(ACCESSIBLE(typ)) goto newpos;
284 		crm->typ = (typ == SCORR) ? CORR : DOOR;
285 		goto proceed;
286 	    }
287     nextnxy:	;
288 	}
289 	nx = x;
290 	ny = y;
291 	gx = EGD->gdx;
292 	gy = EGD->gdy;
293 	dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
294 	dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
295 	if(abs(gx-x) >= abs(gy-y)) nx += dx; else ny += dy;
296 
297 	while((typ = (crm = &levl[nx][ny])->typ) != 0) {
298 	/* in view of the above we must have IS_WALL(typ) or typ == POOL */
299 	/* must be a wall here */
300 		if(isok(nx+nx-x,ny+ny-y) && typ != POOL &&
301 		    ZAP_POS(levl[nx+nx-x][ny+ny-y].typ)){
302 			crm->typ = DOOR;
303 			goto proceed;
304 		}
305 		if(dy && nx != x) {
306 			nx = x; ny = y+dy;
307 			continue;
308 		}
309 		if(dx && ny != y) {
310 			ny = y; nx = x+dx; dy = 0;
311 			continue;
312 		}
313 		/* I don't like this, but ... */
314 		crm->typ = DOOR;
315 		goto proceed;
316 	}
317 	crm->typ = CORR;
318 proceed:
319 	if(cansee(nx,ny)) {
320 		mnewsym(nx,ny);
321 		prl(nx,ny);
322 	}
323 	fcp = &(EGD->fakecorr[EGD->fcend]);
324 	if(EGD->fcend++ == FCSIZ) panic("fakecorr overflow");
325 	fcp->fx = nx;
326 	fcp->fy = ny;
327 	fcp->ftyp = typ;
328 newpos:
329 	if(EGD->gddone) nx = ny = 0;
330 	guard->mx = nx;
331 	guard->my = ny;
332 	pmon(guard);
333 	restfakecorr();
334 	return(1);
335 }
336 
337 void
338 gddead(void)
339 {
340 	guard = 0;
341 }
342 
343 void
344 replgd(struct monst *mtmp, struct monst *mtmp2)
345 {
346 	if(mtmp == guard)
347 		guard = mtmp2;
348 }
349 
350 #endif /* QUEST */
351