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