Home | History | Annotate | Line # | Download | only in hack
      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 (at) 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.14 2011/08/07 06:03:45 dholland Exp $");
     67 #endif				/* not lint */
     68 
     69 #include <stdlib.h>
     70 #include "hack.h"
     71 #include "extern.h"
     72 
     73 struct 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 
     87 static struct engr *head_engr;
     88 
     89 static void del_engr(struct engr *);
     90 
     91 static struct engr *
     92 engr_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 
    103 int
    104 sengr_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 
    125 void
    126 u_wipe_engr(int cnt)
    127 {
    128 	if (!u.uswallow && !Levitation)
    129 		wipe_engr_at(u.ux, u.uy, cnt);
    130 }
    131 
    132 void
    133 wipe_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 
    162 void
    163 read_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 
    184 void
    185 make_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 
    204 int
    205 doengrave(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 
    346 void
    347 save_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 
    363 void
    364 rest_engravings(int fd)
    365 {
    366 	struct engr    *ep;
    367 	unsigned        lth;
    368 	head_engr = 0;
    369 	while (1) {
    370 		mread(fd, &lth, 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 
    381 static void
    382 del_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;
    396 fnd:		;
    397 	}
    398 	free(ep);
    399 }
    400