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 *)<h, 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