pc-hack

PC HACK 3.61 source code (archival)
git clone http://frotz.net/git/pc-hack.git
Log | Files | Refs

do.c (12242B)


      1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
      2 /* do.c - version 1.0.3 */
      3 
      4 /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) and 't' (throw) */
      5 
      6 #include "hack.h"
      7 
      8 extern struct obj *splitobj(), *addinv();
      9 extern boolean hmon();
     10 extern struct monst youmonst;
     11 extern char *Doname();
     12 extern char *nomovemsg;
     13 
     14 static
     15 drop(obj) register struct obj *obj; {
     16 	if(!obj) return(0);
     17 	if(obj->olet == '$') {		/* pseudo object */
     18 		register long amount = OGOLD(obj);
     19 
     20 		if(amount == 0)
     21 			pline("You didn't drop any gold pieces.");
     22 		else {
     23 			mkgold(amount, u.ux, u.uy);
     24 			pline("You dropped %ld gold piece%s.",
     25 				amount, plur(amount));
     26 			if(Invisible) newsym(u.ux, u.uy);
     27 		}
     28 		free((char *) obj);
     29 		return(1);
     30 	}
     31 	if(obj->owornmask & (W_ARMOR | W_RING)){
     32 		pline("You cannot drop something you are wearing.");
     33 		return(0);
     34 	}
     35 	if(obj == uwep) {
     36 		if(uwep->cursed) {
     37 			pline("Your weapon is welded to your hand!");
     38 			return(0);
     39 		}
     40 		setuwep((struct obj *) 0);
     41 	}
     42 	pline("You dropped %s.", doname(obj));
     43 	dropx(obj);
     44 	return(1);
     45 }
     46 
     47 dodrop() {
     48 	return(drop(getobj("0$#", "drop")));
     49 }
     50 
     51 /* Called in several places - should not produce texts */
     52 dropx(obj)
     53 register struct obj *obj;
     54 {
     55 	freeinv(obj);
     56 	dropy(obj);
     57 }
     58 
     59 dropy(obj)
     60 register struct obj *obj;
     61 {
     62 	if(obj->otyp == CRYSKNIFE)
     63 		obj->otyp = WORM_TOOTH;
     64 	obj->ox = u.ux;
     65 	obj->oy = u.uy;
     66 	obj->nobj = fobj;
     67 	fobj = obj;
     68 	if(Invisible) newsym(u.ux,u.uy);
     69 	subfrombill(obj);
     70 	stackobj(obj);
     71 }
     72 
     73 /* drop several things */
     74 doddrop() {
     75 	return(ggetobj("drop", drop, 0));
     76 }
     77 
     78 dodown()
     79 {
     80 	if(u.ux != xdnstair || u.uy != ydnstair) {
     81 		pline("You can't go down here.");
     82 		return(0);
     83 	}
     84 	if(u.ustuck) {
     85 		pline("You are being held, and cannot go down.");
     86 		return(1);
     87 	}
     88 	if(Levitation) {
     89 		pline("You're floating high above the stairs.");
     90 		return(0);
     91 	}
     92 
     93 	goto_level(dlevel+1, TRUE);
     94 	return(1);
     95 }
     96 
     97 doup()
     98 {
     99 	if(u.ux != xupstair || u.uy != yupstair) {
    100 		pline("You can't go up here.");
    101 		return(0);
    102 	}
    103 	if(u.ustuck) {
    104 		pline("You are being held, and cannot go up.");
    105 		return(1);
    106 	}
    107 	if(!Levitation && inv_weight() + 5 > 0) {
    108 		pline("Your load is too heavy to climb the stairs.");
    109 		return(1);
    110 	}
    111 
    112 	goto_level(dlevel-1, TRUE);
    113 	return(1);
    114 }
    115 
    116 goto_level(newlevel, at_stairs)
    117 register int newlevel;
    118 register boolean at_stairs;
    119 {
    120 	register fd;
    121 	register boolean up = (newlevel < dlevel);
    122 
    123 	if(newlevel <= 0) done("escaped");    /* in fact < 0 is impossible */
    124 	if(newlevel > MAXLEVEL) newlevel = MAXLEVEL;	/* strange ... */
    125 	if(newlevel == dlevel) return;	      /* this can happen */
    126 
    127 	glo(dlevel);
    128 #ifdef DGK
    129 	/* Use O_TRUNC to force the file to be shortened if it already
    130 	 * exists and is currently longer.
    131 	 */
    132 	fd = open(lock, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FMASK);
    133 #else
    134 	fd = creat(lock, FMASK);
    135 #endif
    136 	if(fd < 0) {
    137 		/*
    138 		 * This is not quite impossible: e.g., we may have
    139 		 * exceeded our quota. If that is the case then we
    140 		 * cannot leave this level, and cannot save either.
    141 		 * Another possibility is that the directory was not
    142 		 * writable.
    143 		 */
    144 #ifdef DGK
    145 		pline("Cannot create level file '%s'.", lock);
    146 #else
    147 		pline("A mysterious force prevents you from going %s.",
    148 			up ? "up" : "down");
    149 #endif
    150 		return;
    151 	}
    152 
    153 #ifdef DGK
    154 	if (!savelev(fd, dlevel, COUNT)) {
    155 		(void) close(fd);
    156 		(void) unlink(lock);
    157 		pline("HACK is out of disk space for making levels!");
    158 		pline("You can save, quit, or continue playing.");
    159 		return;
    160 	}
    161 #endif
    162 
    163 	if(Punished) unplacebc();
    164 	u.utrap = 0;				/* needed in level_tele */
    165 	u.ustuck = 0;				/* idem */
    166 	keepdogs();
    167 	seeoff(1);
    168 	if(u.uswallow)				/* idem */
    169 		u.uswldtim = u.uswallow = 0;
    170 	flags.nscrinh = 1;
    171 	u.ux = FAR;				/* hack */
    172 	(void) inshop();			/* probably was a trapdoor */
    173 
    174 #ifdef DGK
    175 	savelev(fd,dlevel, WRITE);
    176 #else
    177 	savelev(fd,dlevel);
    178 #endif
    179 	(void) close(fd);
    180 
    181 	dlevel = newlevel;
    182 	if(maxdlevel < dlevel)
    183 		maxdlevel = dlevel;
    184 	glo(dlevel);
    185 
    186 	/* If the level has no where yet, it hasn't been made
    187 	 */
    188 	if(!fileinfo[dlevel].where)
    189 		mklev();
    190 	else {
    191 		extern int hackpid;
    192 
    193 		/* If not currently accessible, swap it in.
    194 		 */
    195 		if (fileinfo[dlevel].where != ACTIVE)
    196 			swapin_file(dlevel);
    197 #ifdef DGK
    198 		if((fd = open(lock, O_RDONLY | O_BINARY)) < 0) {
    199 #else
    200 		if((fd = open(lock,0)) < 0) {
    201 #endif
    202 			pline("Cannot open %s .", lock);
    203 			pline("Probably someone removed it.");
    204 			done("tricked");
    205 		}
    206 		getlev(fd, hackpid, dlevel);
    207 		(void) close(fd);
    208 	}
    209 
    210 	if(at_stairs) {
    211 	    if(up) {
    212 		u.ux = xdnstair;
    213 		u.uy = ydnstair;
    214 		if(!u.ux) {		/* entering a maze from below? */
    215 		    u.ux = xupstair;	/* this will confuse the player! */
    216 		    u.uy = yupstair;
    217 		}
    218 		if(Punished && !Levitation){
    219 			pline("With great effort you climb the stairs.");
    220 			placebc(1);
    221 		}
    222 	    } else {
    223 		u.ux = xupstair;
    224 		u.uy = yupstair;
    225 		if(inv_weight() + 5 > 0 || Punished){
    226 			pline("You fall down the stairs.");	/* %% */
    227 			losehp(rnd(3), "fall");
    228 			if(Punished) {
    229 			    if(uwep != uball && rn2(3)){
    230 				pline("... and are hit by the iron ball.");
    231 				losehp(rnd(20), "iron ball");
    232 			    }
    233 			    placebc(1);
    234 			}
    235 			selftouch("Falling, you");
    236 		}
    237 	    }
    238 	    { register struct monst *mtmp = m_at(u.ux, u.uy);
    239 	      if(mtmp)
    240 		mnexto(mtmp);
    241 	    }
    242 	} else {	/* trapdoor or level_tele */
    243 	    do {
    244 		u.ux = rnd(COLNO-1);
    245 		u.uy = rn2(ROWNO);
    246 	    } while(levl[u.ux][u.uy].typ != ROOM ||
    247 			m_at(u.ux,u.uy));
    248 	    if(Punished){
    249 		if(uwep != uball && !up /* %% */ && rn2(5)){
    250 			pline("The iron ball falls on your head.");
    251 			losehp(rnd(25), "iron ball");
    252 		}
    253 		placebc(1);
    254 	    }
    255 	    selftouch("Falling, you");
    256 	}
    257 	(void) inshop();
    258 	initrack();
    259 
    260 	losedogs();
    261 	{ register struct monst *mtmp;
    262 	  if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp);	/* riv05!a3 */
    263 	}
    264 	flags.nscrinh = 0;
    265 	setsee();
    266 	seeobjs();	/* make old cadavers disappear - riv05!a3 */
    267 	docrt();
    268 	pickup(1);
    269 	read_engr_at(u.ux,u.uy);
    270 }
    271 
    272 donull() {
    273 	return(1);	/* Do nothing, but let other things happen */
    274 }
    275 
    276 dopray() {
    277 	nomovemsg = "You finished your prayer.";
    278 	nomul(-3);
    279 	return(1);
    280 }
    281 
    282 struct monst *bhit(), *boomhit();
    283 dothrow()
    284 {
    285 	register struct obj *obj;
    286 	register struct monst *mon;
    287 	register tmp;
    288 
    289 	obj = getobj("#)", "throw");   /* it is also possible to throw food */
    290 				       /* (or jewels, or iron balls ... ) */
    291 	if(!obj || !getdir(1))	       /* ask "in what direction?" */
    292 		return(0);
    293 	if(obj->owornmask & (W_ARMOR | W_RING)){
    294 		pline("You can't throw something you are wearing.");
    295 		return(0);
    296 	}
    297 
    298 	u_wipe_engr(2);
    299 
    300 	if(obj == uwep){
    301 		if(obj->cursed){
    302 			pline("Your weapon is welded to your hand.");
    303 			return(1);
    304 		}
    305 		if(obj->quan > 1)
    306 			setuwep(splitobj(obj, 1));
    307 		else
    308 			setuwep((struct obj *) 0);
    309 	}
    310 	else if(obj->quan > 1)
    311 		(void) splitobj(obj, 1);
    312 	freeinv(obj);
    313 	if(u.uswallow) {
    314 		mon = u.ustuck;
    315 		bhitpos.x = mon->mx;
    316 		bhitpos.y = mon->my;
    317 	} else if(u.dz) {
    318 	  if(u.dz < 0) {
    319 	    pline("%s hits the ceiling, then falls back on top of your head.",
    320 		Doname(obj));		/* note: obj->quan == 1 */
    321 	    if(obj->olet == POTION_SYM)
    322 		potionhit(&youmonst, obj);
    323 	    else {
    324 		if(uarmh) pline("Fortunately, you are wearing a helmet!");
    325 		losehp(uarmh ? 1 : rnd((int)(obj->owt)), "falling object");
    326 		dropy(obj);
    327 	    }
    328 	  } else {
    329 	    pline("%s hits the floor.", Doname(obj));
    330 	    if(obj->otyp == EXPENSIVE_CAMERA) {
    331 		pline("It is shattered in a thousand pieces!");
    332 		obfree(obj, Null(obj));
    333 	    } else if(obj->otyp == EGG) {
    334 		pline("\"Splash!\"");
    335 		obfree(obj, Null(obj));
    336 	    } else if(obj->olet == POTION_SYM) {
    337 		pline("The flask breaks, and you smell a peculiar odor ...");
    338 		potionbreathe(obj);
    339 		obfree(obj, Null(obj));
    340 	    } else {
    341 		dropy(obj);
    342 	    }
    343 	  }
    344 	  return(1);
    345 	} else if(obj->otyp == BOOMERANG) {
    346 		mon = boomhit(u.dx, u.dy);
    347 		if(mon == &youmonst) {		/* the thing was caught */
    348 			(void) addinv(obj);
    349 			return(1);
    350 		}
    351 	} else {
    352 		if(obj->otyp == PICK_AXE && shkcatch(obj))
    353 		    return(1);
    354 
    355 		mon = bhit(u.dx, u.dy, (obj->otyp == ICE_BOX) ? 1 :
    356 			(!Punished || obj != uball) ? 8 : !u.ustuck ? 5 : 1,
    357 			obj->olet,
    358 			(int (*)()) 0, (int (*)()) 0, obj);
    359 	}
    360 	if(mon) {
    361 		/* awake monster if sleeping */
    362 		wakeup(mon);
    363 
    364 		if(obj->olet == WEAPON_SYM) {
    365 			tmp = -1+u.ulevel+mon->data->ac+abon();
    366 #ifdef DGK
    367 			if(obj->otyp < DART) {	/* a USENET bugfix */
    368 #else			
    369 			if(obj->otyp < ROCK) {
    370 #endif
    371 				if(!uwep ||
    372 				    uwep->otyp != obj->otyp+(BOW-ARROW))
    373 					tmp -= 4;
    374 				else {
    375 					tmp += uwep->spe;
    376 				}
    377 			} else
    378 			if(obj->otyp == BOOMERANG) tmp += 4;
    379 			tmp += obj->spe;
    380 			if(u.uswallow || tmp >= rnd(20)) {
    381 				if(hmon(mon,obj,1) == TRUE){
    382 				  /* mon still alive */
    383 #ifndef NOWORM
    384 				  cutworm(mon,bhitpos.x,bhitpos.y,obj->otyp);
    385 #endif /* NOWORM /**/
    386 				} else mon = 0;
    387 				/* weapons thrown disappear sometimes */
    388 				if(obj->otyp < BOOMERANG && rn2(3)) {
    389 					/* check bill; free */
    390 					obfree(obj, (struct obj *) 0);
    391 					return(1);
    392 				}
    393 			} else miss(objects[obj->otyp].oc_name, mon);
    394 		} else if(obj->otyp == HEAVY_IRON_BALL) {
    395 			tmp = -1+u.ulevel+mon->data->ac+abon();
    396 			if(!Punished || obj != uball) tmp += 2;
    397 			if(u.utrap) tmp -= 2;
    398 			if(u.uswallow || tmp >= rnd(20)) {
    399 				if(hmon(mon,obj,1) == FALSE)
    400 					mon = 0;	/* he died */
    401 			} else miss("iron ball", mon);
    402 		} else if(obj->olet == POTION_SYM && u.ulevel > rn2(15)) {
    403 			potionhit(mon, obj);
    404 			return(1);
    405 		} else {
    406 			if(cansee(bhitpos.x,bhitpos.y))
    407 				pline("You miss %s.",monnam(mon));
    408 			else pline("You miss it.");
    409 			if(obj->olet == FOOD_SYM && mon->data->mlet == 'd')
    410 				if(tamedog(mon,obj)) return(1);
    411 			if(obj->olet == GEM_SYM && mon->data->mlet == 'u' &&
    412 				!mon->mtame){
    413 			 if(obj->dknown && objects[obj->otyp].oc_name_known){
    414 			  if(objects[obj->otyp].g_val > 0){
    415 			    u.uluck += 5;
    416 			    goto valuable;
    417 			  } else {
    418 			    pline("%s is not interested in your junk.",
    419 				Monnam(mon));
    420 			  }
    421 			 } else { /* value unknown to @ */
    422 			    u.uluck++;
    423 			valuable:
    424 			    if(u.uluck > LUCKMAX)	/* dan@ut-ngp */
    425 				u.uluck = LUCKMAX;
    426 			    pline("%s graciously accepts your gift.",
    427 				Monnam(mon));
    428 			    mpickobj(mon, obj);
    429 			    rloc(mon);
    430 			    return(1);
    431 			 }
    432 			}
    433 		}
    434 	}
    435 		/* the code following might become part of dropy() */
    436 	if(obj->otyp == CRYSKNIFE)
    437 		obj->otyp = WORM_TOOTH;
    438 	obj->ox = bhitpos.x;
    439 	obj->oy = bhitpos.y;
    440 	obj->nobj = fobj;
    441 	fobj = obj;
    442 	/* prevent him from throwing articles to the exit and escaping */
    443 	/* subfrombill(obj); */
    444 	stackobj(obj);
    445 	if(Punished && obj == uball &&
    446 		(bhitpos.x != u.ux || bhitpos.y != u.uy)){
    447 		freeobj(uchain);
    448 		unpobj(uchain);
    449 		if(u.utrap){
    450 			if(u.utraptype == TT_PIT)
    451 				pline("The ball pulls you out of the pit!");
    452 			else {
    453 			    register long side =
    454 				rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
    455 			    pline("The ball pulls you out of the bear trap.");
    456 			    pline("Your %s leg is severely damaged.",
    457 				(side == LEFT_SIDE) ? "left" : "right");
    458 			    set_wounded_legs(side, 500+rn2(1000));
    459 			    losehp(2, "thrown ball");
    460 			}
    461 			u.utrap = 0;
    462 		}
    463 		unsee();
    464 		uchain->nobj = fobj;
    465 		fobj = uchain;
    466 		u.ux = uchain->ox = bhitpos.x - u.dx;
    467 		u.uy = uchain->oy = bhitpos.y - u.dy;
    468 		setsee();
    469 		(void) inshop();
    470 	}
    471 	if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y);
    472 	return(1);
    473 }
    474 
    475 /* split obj so that it gets size num */
    476 /* remainder is put in the object structure delivered by this call */
    477 struct obj *
    478 splitobj(obj, num) register struct obj *obj; register int num; {
    479 register struct obj *otmp;
    480 	otmp = newobj(0);
    481 	*otmp = *obj;		/* copies whole structure */
    482 	otmp->o_id = flags.ident++;
    483 	otmp->onamelth = 0;
    484 	obj->quan = num;
    485 	obj->owt = weight(obj);
    486 	otmp->quan -= num;
    487 	otmp->owt = weight(otmp);	/* -= obj->owt ? */
    488 	obj->nobj = otmp;
    489 	if(obj->unpaid) splitbill(obj,otmp);
    490 	return(otmp);
    491 }
    492 
    493 more_experienced(exp,rexp)
    494 register int exp, rexp;
    495 {
    496 	extern char pl_character[];
    497 
    498 	u.uexp += exp;
    499 	u.urexp += 4*exp + rexp;
    500 	if(exp) flags.botl = 1;
    501 	if(u.urexp >= ((pl_character[0] == 'W') ? 1000 : 2000))
    502 		flags.beginner = 0;
    503 }
    504 
    505 set_wounded_legs(side, timex)
    506 register long side;
    507 register int timex;
    508 {
    509 	if(!Wounded_legs || (Wounded_legs & TIMEOUT))
    510 		Wounded_legs |= side + timex;
    511 	else
    512 		Wounded_legs |= side;
    513 }
    514 
    515 heal_legs()
    516 {
    517 	if(Wounded_legs) {
    518 		if((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
    519 			pline("Your legs feel somewhat better.");
    520 		else
    521 			pline("Your leg feels somewhat better.");
    522 		Wounded_legs = 0;
    523 	}
    524 }