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