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