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