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