xref: /dragonfly/games/hack/hack.engrave.c (revision 9f7604d7)
1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.engrave.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.engrave.c,v 1.4 1999/11/16 02:57:04 billf Exp $ */
4 
5 #include "hack.h"
6 
7 extern char nul[];
8 extern struct obj zeroobj;
9 struct engr {
10 	struct engr *nxt_engr;
11 	char *engr_txt;
12 	xchar engr_x, engr_y;
13 	unsigned engr_lth;	/* for save & restore; not length of text */
14 	long engr_time;	/* moment engraving was (will be) finished */
15 	xchar engr_type;
16 #define	DUST	1
17 #define	ENGRAVE	2
18 #define	BURN	3
19 } *head_engr;
20 
21 static struct engr *engr_at(xchar, xchar);
22 static void del_engr(struct engr *);
23 
24 static struct engr *
25 engr_at(xchar x, xchar y)
26 {
27 	struct engr *ep = head_engr;
28 
29 	while (ep) {
30 		if (x == ep->engr_x && y == ep->engr_y)
31 			return(ep);
32 		ep = ep->nxt_engr;
33 	}
34 	return (NULL);
35 }
36 
37 bool
38 sengr_at(const char *s, xchar x, xchar y)
39 {
40 	struct engr *ep = engr_at(x, y);
41 	char *t;
42 	int n;
43 
44 	if (ep && ep->engr_time <= moves) {
45 		t = ep->engr_txt;
46 		n = strlen(s);
47 		while (*t) {
48 			if (!strncmp(s, t, n))
49 				return (1);
50 			t++;
51 		}
52 	}
53 	return (0);
54 }
55 
56 void
57 u_wipe_engr(int cnt)
58 {
59 	if (!u.uswallow && !Levitation)
60 		wipe_engr_at(u.ux, u.uy, cnt);
61 }
62 
63 void
64 wipe_engr_at(xchar x, xchar y, xchar cnt)
65 {
66 	struct engr *ep = engr_at(x, y);
67 	int lth, pos;
68 	char ch;
69 
70 	if (ep) {
71 		if ((ep->engr_type != DUST) || Levitation)
72 			cnt = rn2(1 + 50 / (cnt + 1)) ? 0 : 1;
73 		lth = strlen(ep->engr_txt);
74 		if (lth && cnt > 0) {
75 			while (cnt--) {
76 				pos = rn2(lth);
77 				if ((ch = ep->engr_txt[pos]) == ' ')
78 					continue;
79 				ep->engr_txt[pos] = (ch != '?') ? '?' : ' ';
80 			}
81 		}
82 		while (lth && ep->engr_txt[lth - 1] == ' ')
83 			ep->engr_txt[--lth] = 0;
84 		while (ep->engr_txt[0] == ' ')
85 			ep->engr_txt++;
86 		if (!ep->engr_txt[0])
87 			del_engr(ep);
88 	}
89 }
90 
91 void
92 read_engr_at(int x, int y)
93 {
94 	struct engr *ep = engr_at(x, y);
95 
96 	if (ep && ep->engr_txt[0]) {
97 		switch (ep->engr_type) {
98 		case DUST:
99 			pline("Something is written here in the dust.");
100 			break;
101 		case ENGRAVE:
102 			pline("Something is engraved here on the floor.");
103 			break;
104 		case BURN:
105 			pline("Some text has been burned here in the floor.");
106 			break;
107 		default:
108 			impossible("Something is written in a very strange way.");
109 		}
110 		pline("You read: \"%s\".", ep->engr_txt);
111 	}
112 }
113 
114 void
115 make_engr_at(int x, int y, const char *s)
116 {
117 	struct engr *ep;
118 
119 	if ((ep = engr_at(x, y)))
120 		del_engr(ep);
121 	ep = alloc((unsigned)(sizeof(struct engr) + strlen(s) + 1));
122 	ep->nxt_engr = head_engr;
123 	head_engr = ep;
124 	ep->engr_x = x;
125 	ep->engr_y = y;
126 	ep->engr_txt = (char *)(ep + 1);
127 	strcpy(ep->engr_txt, s);
128 	ep->engr_time = 0;
129 	ep->engr_type = DUST;
130 	ep->engr_lth = strlen(s) + 1;
131 }
132 
133 int
134 doengrave(void)
135 {
136 	int len;
137 	char *sp;
138 	struct engr *ep, *oep = engr_at(u.ux, u.uy);
139 	char buf[BUFSZ];
140 	xchar type;
141 	int spct;	/* number of leading spaces */
142 	struct obj *otmp;
143 
144 	multi = 0;
145 	if (u.uswallow) {
146 		pline("You're joking. Hahaha!");	/* riv05!a3 */
147 		return (0);
148 	}
149 
150 	/* one may write with finger, weapon or wand */
151 	otmp = getobj("#-)/", "write with");
152 	if (!otmp)
153 		return (0);
154 
155 	if (otmp == &zeroobj)
156 		otmp = NULL;
157 	if (otmp && otmp->otyp == WAN_FIRE && otmp->spe) {
158 		type = BURN;
159 		otmp->spe--;
160 	} else {
161 		/* first wield otmp */
162 		if (otmp != uwep) {
163 			if (uwep && uwep->cursed) {
164 				/* Andreas Bormann */
165 				pline("Since your weapon is welded to your hand,");
166 				pline("you use the %s.", aobjnam(uwep, NULL));
167 				otmp = uwep;
168 			} else {
169 				if (!otmp)
170 					pline("You are now empty-handed.");
171 				else if (otmp->cursed)
172 					pline("The %s %s to your hand!",
173 					    aobjnam(otmp, "weld"),
174 					    (otmp->quan == 1) ? "itself" : "themselves");
175 				else
176 					pline("You now wield %s.", doname(otmp));
177 				setuwep(otmp);
178 			}
179 		}
180 
181 		if (!otmp)
182 			type = DUST;
183 		else if (otmp->otyp == DAGGER || otmp->otyp == TWO_HANDED_SWORD ||
184 		    otmp->otyp == CRYSKNIFE ||
185 		    otmp->otyp == LONG_SWORD || otmp->otyp == AXE) {
186 			type = ENGRAVE;
187 			if ((int)otmp->spe <= -3) {
188 				type = DUST;
189 				pline("Your %s too dull for engraving.",
190 				      aobjnam(otmp, "are"));
191 				if (oep && oep->engr_type != DUST)
192 					return (1);
193 			}
194 		} else
195 			type = DUST;
196 	}
197 	if (Levitation && type != BURN) {	/* riv05!a3 */
198 		pline("You can't reach the floor!");
199 		return (1);
200 	}
201 	if (oep && oep->engr_type == DUST) {
202 		pline("You wipe out the message that was written here.");
203 		del_engr(oep);
204 		oep = NULL;
205 	}
206 	if (type == DUST && oep) {
207 		pline("You cannot wipe out the message that is %s in the rock.",
208 		      (oep->engr_type == BURN) ? "burned" : "engraved");
209 		return (1);
210 	}
211 
212 	pline("What do you want to %s on the floor here? ",
213 	      (type == ENGRAVE) ? "engrave" : (type == BURN) ? "burn" : "write");
214 	getlin(buf);
215 	clrlin();
216 	spct = 0;
217 	sp = buf;
218 	while (*sp == ' ') {
219 		spct++;
220 		sp++;
221 	}
222 	len = strlen(sp);
223 	if (!len || *buf == '\033') {
224 		if (type == BURN)
225 			otmp->spe++;
226 		return (0);
227 	}
228 
229 	switch (type) {
230 	case DUST:
231 	case BURN:
232 		if (len > 15) {
233 			multi = -(len / 10);
234 			nomovemsg = "You finished writing.";
235 		}
236 		break;
237 	case ENGRAVE:		/* here otmp != 0 */
238 		{
239 			int len2 = (otmp->spe + 3) * 2 + 1;
240 
241 			pline("Your %s dull.", aobjnam(otmp, "get"));
242 			if (len2 < len) {
243 				len = len2;
244 				sp[len] = 0;
245 				otmp->spe = -3;
246 				nomovemsg = "You cannot engrave more.";
247 			} else {
248 				otmp->spe -= len / 2;
249 				nomovemsg = "You finished engraving.";
250 			}
251 			multi = -len;
252 		}
253 		break;
254 	}
255 	if (oep)
256 		len += strlen(oep->engr_txt) + spct;
257 	ep = alloc((unsigned)(sizeof(struct engr) + len + 1));
258 	ep->nxt_engr = head_engr;
259 	head_engr = ep;
260 	ep->engr_x = u.ux;
261 	ep->engr_y = u.uy;
262 	sp = (char *)(ep + 1);	/* (char *)ep + sizeof(struct engr) */
263 	ep->engr_txt = sp;
264 	if (oep) {
265 		strcpy(sp, oep->engr_txt);
266 		strcat(sp, buf);
267 		del_engr(oep);
268 	} else
269 		strcpy(sp, buf);
270 	ep->engr_lth = len + 1;
271 	ep->engr_type = type;
272 	ep->engr_time = moves - multi;
273 
274 	/* kludge to protect pline against excessively long texts */
275 	if (len > BUFSZ - 20)
276 		sp[BUFSZ - 20] = 0;
277 
278 	return (1);
279 }
280 
281 void
282 save_engravings(int fd)
283 {
284 	struct engr *ep = head_engr;
285 
286 	while (ep) {
287 		if (!ep->engr_lth || !ep->engr_txt[0]) {
288 			ep = ep->nxt_engr;
289 			continue;
290 		}
291 		bwrite(fd, (char *)&(ep->engr_lth), sizeof(ep->engr_lth));
292 		bwrite(fd, (char *)ep, sizeof(struct engr) + ep->engr_lth);
293 		ep = ep->nxt_engr;
294 	}
295 	bwrite(fd, (char *)nul, sizeof(unsigned));
296 	head_engr = NULL;
297 }
298 
299 void
300 rest_engravings(int fd)
301 {
302 	struct engr *ep;
303 	unsigned lth;
304 
305 	head_engr = NULL;
306 	for (;;) {
307 		mread(fd, (char *)&lth, sizeof(unsigned));
308 		if (lth == 0)
309 			return;
310 		ep = alloc(sizeof(struct engr) + lth);
311 		mread(fd, (char *)ep, sizeof(struct engr) + lth);
312 		ep->nxt_engr = head_engr;
313 		ep->engr_txt = (char *)(ep + 1);	/* Andreas Bormann */
314 		head_engr = ep;
315 	}
316 }
317 
318 static void
319 del_engr(struct engr *ep)
320 {
321 	struct engr *ept;
322 
323 	if (ep == head_engr)
324 		head_engr = ep->nxt_engr;
325 	else {
326 		for (ept = head_engr; ept; ept = ept->nxt_engr) {
327 			if (ept->nxt_engr == ep) {
328 				ept->nxt_engr = ep->nxt_engr;
329 				goto fnd;
330 			}
331 		}
332 		impossible("Error in del_engr?");
333 		return;
334 	}
335 fnd:
336 	free(ep);
337 }
338