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