1 /*        $NetBSD: hack.engrave.c,v 1.14 2011/08/07 06:03:45 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.14 2011/08/07 06:03:45 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 *
engr_at(xchar x,xchar y)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
sengr_at(const char * s,xchar x,xchar y)104 sengr_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 
125 void
u_wipe_engr(int cnt)126 u_wipe_engr(int cnt)
127 {
128           if (!u.uswallow && !Levitation)
129                     wipe_engr_at(u.ux, u.uy, cnt);
130 }
131 
132 void
wipe_engr_at(xchar x,xchar y,xchar cnt)133 wipe_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 
162 void
read_engr_at(int x,int y)163 read_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 
184 void
make_engr_at(int x,int y,const char * s)185 make_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 
204 int
doengrave(void)205 doengrave(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 
346 void
save_engravings(int fd)347 save_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 
363 void
rest_engravings(int fd)364 rest_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 
381 static void
del_engr(struct engr * ep)382 del_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;
396 fnd:                ;
397           }
398           free(ep);
399 }
400