xref: /netbsd/games/hack/hack.engrave.c (revision 6550d01e)
1 /*	$NetBSD: hack.engrave.c,v 1.9 2009/08/12 07:28:40 dholland 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.engrave.c,v 1.9 2009/08/12 07:28:40 dholland Exp $");
67 #endif				/* not lint */
68 
69 #include <stdlib.h>
70 #include "hack.h"
71 #include "extern.h"
72 
73 struct engr {
74 	struct engr    *nxt_engr;
75 	char           *engr_txt;
76 	xchar           engr_x, engr_y;
77 	unsigned        engr_lth;	/* for save & restore; not length of
78 					 * text */
79 	long            engr_time;	/* moment engraving was (will be)
80 					 * finished */
81 	xchar           engr_type;
82 #define	DUST	1
83 #define	ENGRAVE	2
84 #define	BURN	3
85 };
86 
87 static struct engr *head_engr;
88 
89 static void del_engr(struct engr *);
90 
91 static struct engr *
92 engr_at(xchar x, xchar y)
93 {
94 	struct engr    *ep = head_engr;
95 	while (ep) {
96 		if (x == ep->engr_x && y == ep->engr_y)
97 			return (ep);
98 		ep = ep->nxt_engr;
99 	}
100 	return ((struct engr *) 0);
101 }
102 
103 int
104 sengr_at(const char *s, xchar x, xchar y)
105 {
106 	struct engr    *ep = engr_at(x, y);
107 	char           *t;
108 	int             n;
109 	if (ep && ep->engr_time <= moves) {
110 		t = ep->engr_txt;
111 		/*
112 				if(!strcmp(s,t)) return(1);
113 		*/
114 		n = strlen(s);
115 		while (*t) {
116 			if (!strncmp(s, t, n))
117 				return (1);
118 			t++;
119 		}
120 	}
121 	return (0);
122 }
123 
124 void
125 u_wipe_engr(int cnt)
126 {
127 	if (!u.uswallow && !Levitation)
128 		wipe_engr_at(u.ux, u.uy, cnt);
129 }
130 
131 void
132 wipe_engr_at(xchar x, xchar y, xchar cnt)
133 {
134 	struct engr    *ep = engr_at(x, y);
135 	int             lth, pos;
136 	char            ch;
137 	if (ep) {
138 		if ((ep->engr_type != DUST) || Levitation) {
139 			cnt = rn2(1 + 50 / (cnt + 1)) ? 0 : 1;
140 		}
141 		lth = strlen(ep->engr_txt);
142 		if (lth && cnt > 0) {
143 			while (cnt--) {
144 				pos = rn2(lth);
145 				if ((ch = ep->engr_txt[pos]) == ' ')
146 					continue;
147 				ep->engr_txt[pos] = (ch != '?') ? '?' : ' ';
148 			}
149 		}
150 		while (lth && ep->engr_txt[lth - 1] == ' ')
151 			ep->engr_txt[--lth] = 0;
152 		while (ep->engr_txt[0] == ' ')
153 			ep->engr_txt++;
154 		if (!ep->engr_txt[0])
155 			del_engr(ep);
156 	}
157 }
158 
159 void
160 read_engr_at(int x, int y)
161 {
162 	struct engr    *ep = engr_at(x, y);
163 	if (ep && ep->engr_txt[0]) {
164 		switch (ep->engr_type) {
165 		case DUST:
166 			pline("Something is written here in the dust.");
167 			break;
168 		case ENGRAVE:
169 			pline("Something is engraved here on the floor.");
170 			break;
171 		case BURN:
172 			pline("Some text has been burned here in the floor.");
173 			break;
174 		default:
175 			impossible("Something is written in a very strange way.");
176 		}
177 		pline("You read: \"%s\".", ep->engr_txt);
178 	}
179 }
180 
181 void
182 make_engr_at(int x, int y, const char *s)
183 {
184 	struct engr    *ep;
185 
186 	if ((ep = engr_at(x, y)) != NULL)
187 		del_engr(ep);
188 	ep = (struct engr *)
189 		alloc((unsigned) (sizeof(struct engr) + strlen(s) + 1));
190 	ep->nxt_engr = head_engr;
191 	head_engr = ep;
192 	ep->engr_x = x;
193 	ep->engr_y = y;
194 	ep->engr_txt = (char *) (ep + 1);
195 	(void) strcpy(ep->engr_txt, s);
196 	ep->engr_time = 0;
197 	ep->engr_type = DUST;
198 	ep->engr_lth = strlen(s) + 1;
199 }
200 
201 int
202 doengrave(void)
203 {
204 	int             len;
205 	char           *sp;
206 	struct engr    *ep, *oep = engr_at(u.ux, u.uy);
207 	char            buf[BUFSZ];
208 	xchar           type;
209 	int             spct;	/* number of leading spaces */
210 	struct obj     *otmp;
211 	multi = 0;
212 
213 	if (u.uswallow) {
214 		pline("You're joking. Hahaha!");	/* riv05!a3 */
215 		return (0);
216 	}
217 	/* one may write with finger, weapon or wand */
218 	otmp = getobj("#-)/", "write with");
219 	if (!otmp)
220 		return (0);
221 
222 	if (otmp == &zeroobj)
223 		otmp = 0;
224 	if (otmp && otmp->otyp == WAN_FIRE && otmp->spe) {
225 		type = BURN;
226 		otmp->spe--;
227 	} else {
228 		/* first wield otmp */
229 		if (otmp != uwep) {
230 			if (uwep && uwep->cursed) {
231 				/* Andreas Bormann */
232 				pline("Since your weapon is welded to your hand,");
233 				pline("you use the %s.", aobjnam(uwep, (char *) 0));
234 				otmp = uwep;
235 			} else {
236 				if (!otmp)
237 					pline("You are now empty-handed.");
238 				else if (otmp->cursed)
239 					pline("The %s %s to your hand!",
240 					      aobjnam(otmp, "weld"),
241 					      (otmp->quan == 1) ? "itself" : "themselves");
242 				else
243 					pline("You now wield %s.", doname(otmp));
244 				setuwep(otmp);
245 			}
246 		}
247 		if (!otmp)
248 			type = DUST;
249 		else if (otmp->otyp == DAGGER || otmp->otyp == TWO_HANDED_SWORD ||
250 			 otmp->otyp == CRYSKNIFE ||
251 			 otmp->otyp == LONG_SWORD || otmp->otyp == AXE) {
252 			type = ENGRAVE;
253 			if ((int) otmp->spe <= -3) {
254 				type = DUST;
255 				pline("Your %s too dull for engraving.",
256 				      aobjnam(otmp, "are"));
257 				if (oep && oep->engr_type != DUST)
258 					return (1);
259 			}
260 		} else
261 			type = DUST;
262 	}
263 	if (Levitation && type != BURN) {	/* riv05!a3 */
264 		pline("You can't reach the floor!");
265 		return (1);
266 	}
267 	if (oep && oep->engr_type == DUST) {
268 		pline("You wipe out the message that was written here.");
269 		del_engr(oep);
270 		oep = 0;
271 	}
272 	if (type == DUST && oep) {
273 		pline("You cannot wipe out the message that is %s in the rock.",
274 		      (oep->engr_type == BURN) ? "burned" : "engraved");
275 		return (1);
276 	}
277 	pline("What do you want to %s on the floor here? ",
278 	 (type == ENGRAVE) ? "engrave" : (type == BURN) ? "burn" : "write");
279 	getlin(buf);
280 	clrlin();
281 	spct = 0;
282 	sp = buf;
283 	while (*sp == ' ')
284 		spct++, sp++;
285 	len = strlen(sp);
286 	if (!len || *buf == '\033') {
287 		if (type == BURN)
288 			otmp->spe++;
289 		return (0);
290 	}
291 	switch (type) {
292 	case DUST:
293 	case BURN:
294 		if (len > 15) {
295 			multi = -(len / 10);
296 			nomovemsg = "You finished writing.";
297 		}
298 		break;
299 	case ENGRAVE:		/* here otmp != 0 */
300 		{
301 			int             len2 = (otmp->spe + 3) * 2 + 1;
302 
303 			pline("Your %s dull.", aobjnam(otmp, "get"));
304 			if (len2 < len) {
305 				len = len2;
306 				sp[len] = 0;
307 				otmp->spe = -3;
308 				nomovemsg = "You cannot engrave more.";
309 			} else {
310 				otmp->spe -= len / 2;
311 				nomovemsg = "You finished engraving.";
312 			}
313 			multi = -len;
314 		}
315 		break;
316 	}
317 	if (oep)
318 		len += strlen(oep->engr_txt) + spct;
319 	ep = (struct engr *) alloc((unsigned) (sizeof(struct engr) + len + 1));
320 	ep->nxt_engr = head_engr;
321 	head_engr = ep;
322 	ep->engr_x = u.ux;
323 	ep->engr_y = u.uy;
324 	sp = (char *) (ep + 1);	/* (char *)ep + sizeof(struct engr) */
325 	ep->engr_txt = sp;
326 	if (oep) {
327 		(void) strcpy(sp, oep->engr_txt);
328 		(void) strcat(sp, buf);
329 		del_engr(oep);
330 	} else
331 		(void) strcpy(sp, buf);
332 	ep->engr_lth = len + 1;
333 	ep->engr_type = type;
334 	ep->engr_time = moves - multi;
335 
336 	/* kludge to protect pline against excessively long texts */
337 	if (len > BUFSZ - 20)
338 		sp[BUFSZ - 20] = 0;
339 
340 	return (1);
341 }
342 
343 void
344 save_engravings(int fd)
345 {
346 	struct engr    *ep = head_engr;
347 	while (ep) {
348 		if (!ep->engr_lth || !ep->engr_txt[0]) {
349 			ep = ep->nxt_engr;
350 			continue;
351 		}
352 		bwrite(fd, &(ep->engr_lth), sizeof(ep->engr_lth));
353 		bwrite(fd, ep, sizeof(struct engr) + ep->engr_lth);
354 		ep = ep->nxt_engr;
355 	}
356 	bwrite(fd, nul, sizeof(unsigned));
357 	head_engr = 0;
358 }
359 
360 void
361 rest_engravings(int fd)
362 {
363 	struct engr    *ep;
364 	unsigned        lth;
365 	head_engr = 0;
366 	while (1) {
367 		mread(fd, (char *) &lth, sizeof(unsigned));
368 		if (lth == 0)
369 			return;
370 		ep = (struct engr *) alloc(sizeof(struct engr) + lth);
371 		mread(fd, (char *) ep, sizeof(struct engr) + lth);
372 		ep->nxt_engr = head_engr;
373 		ep->engr_txt = (char *) (ep + 1);	/* Andreas Bormann */
374 		head_engr = ep;
375 	}
376 }
377 
378 static void
379 del_engr(struct engr *ep)
380 {
381 	struct engr    *ept;
382 	if (ep == head_engr)
383 		head_engr = ep->nxt_engr;
384 	else {
385 		for (ept = head_engr; ept; ept = ept->nxt_engr) {
386 			if (ept->nxt_engr == ep) {
387 				ept->nxt_engr = ep->nxt_engr;
388 				goto fnd;
389 			}
390 		}
391 		impossible("Error in del_engr?");
392 		return;
393 fnd:		;
394 	}
395 	free((char *) ep);
396 }
397