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