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