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