pc-hack

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

wizard.c (8225B)


      1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
      2 /* wizard.c - version 1.0.3 */
      3 
      4 /* wizard code - inspired by rogue code from Merlyn Leroy (digi-g!brian) */
      5 
      6 #include "hack.h"
      7 extern struct permonst pm_wizard;
      8 extern struct monst *makemon();
      9 
     10 #ifdef DGK
     11 #define	WIZSHOT	    2	/* one chance in WIZSHOT that wizard will try magic */
     12 #else
     13 #define	WIZSHOT	    6	/* one chance in WIZSHOT that wizard will try magic */
     14 #endif
     15 #define	BOLT_LIM    8	/* from this distance D and 1 will try to hit you */
     16 
     17 char wizapp[] = "@DNPTUVXcemntx";
     18 
     19 #ifdef DGK
     20 #define URETREATING(x,y) (movedist(u.ux,u.uy,x,y) > movedist(u.ux0,u.uy0,x,y))
     21 extern char mlarge[];
     22 
     23 movedist(x0, x1, y0, y1)
     24 {
     25 	register int absdx, absdy;
     26 
     27 	absdx = abs(x1 - x0);
     28 	absdy = abs(y1 - y0);
     29 
     30 	return (absdx + absdy - min(absdx, absdy));
     31 }
     32 #endif
     33 
     34 /* If he has found the Amulet, make the wizard appear after some time */
     35 amulet(){
     36 	register struct obj *otmp;
     37 	register struct monst *mtmp;
     38 
     39 	if(!flags.made_amulet || !flags.no_of_wizards)
     40 		return;
     41 	/* find wizard, and wake him if necessary */
     42 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
     43 	    if(mtmp->data->mlet == '1' && mtmp->msleep && !rn2(40))
     44 		for(otmp = invent; otmp; otmp = otmp->nobj)
     45 		    if(otmp->olet == AMULET_SYM && !otmp->spe) {
     46 			mtmp->msleep = 0;
     47 			if(dist(mtmp->mx,mtmp->my) > 2)
     48 			    pline(
     49     "You get the creepy feeling that somebody noticed your taking the Amulet."
     50 			    );
     51 			return;
     52 		    }
     53 }
     54 
     55 wiz_hit(mtmp)
     56 register struct monst *mtmp;
     57 {
     58 	/* if we have stolen or found the amulet, we disappear */
     59 	if(mtmp->minvent && mtmp->minvent->olet == AMULET_SYM &&
     60 	    mtmp->minvent->spe == 0) {
     61 		/* vanish -- very primitive */
     62 		fall_down(mtmp);
     63 		return(1);
     64 	}
     65 
     66 	/* if it is lying around someplace, we teleport to it */
     67 	if(!carrying(AMULET_OF_YENDOR)) {
     68 	    register struct obj *otmp;
     69 
     70 	    for(otmp = fobj; otmp; otmp = otmp->nobj)
     71 		if(otmp->olet == AMULET_SYM && !otmp->spe) {
     72 		    if((u.ux != otmp->ox || u.uy != otmp->oy) &&
     73 		       !m_at(otmp->ox, otmp->oy)) {
     74 
     75 			/* teleport to it and pick it up */
     76 			mtmp->mx = otmp->ox;
     77 			mtmp->my = otmp->oy;
     78 			freeobj(otmp);
     79 			mpickobj(mtmp, otmp);
     80 			pmon(mtmp);
     81 			return(0);
     82 		    }
     83 		    goto hithim;
     84 		}
     85 	    return(0);				/* we don't know where it is */
     86 	}
     87 hithim:
     88 	if(rn2(2)) {				/* hit - perhaps steal */
     89 
     90 	    /* if hit 1/20 chance of stealing amulet & vanish
     91 		- amulet is on level 26 again. */
     92 	    if(hitu(mtmp, d(mtmp->data->damn,mtmp->data->damd))
     93 		&& !rn2(20) && stealamulet(mtmp))
     94 		;
     95 	}
     96 	else
     97 	    inrange(mtmp);			/* try magic */
     98 	return(0);
     99 }
    100 
    101 #ifdef DGK
    102 /* Check if a monster is carrying a particular item.
    103  */
    104 struct obj *
    105 m_carrying(mtmp, type)
    106 struct monst *mtmp;
    107 int type;
    108 {
    109 	register struct obj *otmp;
    110 
    111 	for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
    112 		if(otmp->otyp == type)
    113 			return(otmp);
    114 	return((struct obj *) 0);
    115 }
    116 
    117 /* Remove an item from the monster's inventory.
    118  */
    119 m_useup(mon, obj)
    120 struct monst *mon;
    121 struct obj *obj;
    122 {
    123 	struct obj *otmp, *prev;
    124 
    125 	prev = ((struct obj *) 0);
    126 	for (otmp = mon->minvent; otmp; otmp = otmp->nobj) {
    127 		if (otmp == obj) {
    128 			if (prev)
    129 				prev->nobj = obj->nobj;
    130 			else
    131 				mon->minvent = obj->nobj;
    132 			free((char *) obj);
    133 			break;
    134 		}
    135 		prev = otmp;
    136 	}
    137 }
    138 
    139 m_throw(x, y, dx, dy, range, obj)
    140 register int x,y,dx,dy,range;		/* direction and range */
    141 register struct obj *obj;
    142 {
    143 	register struct monst *mtmp;
    144 	struct objclass *oclass = &objects[obj->otyp];
    145 	char sym = obj->olet;
    146 	int damage;
    147 	extern char *exclam();
    148 
    149 	bhitpos.x = x;
    150 	bhitpos.y = y;
    151 
    152 	if(sym) tmp_at(-1, sym);	/* open call */
    153 	while(range-- > 0) {
    154 		bhitpos.x += dx;
    155 		bhitpos.y += dy;
    156 		if(mtmp = m_at(bhitpos.x,bhitpos.y)) {
    157 			damage = index(mlarge, mtmp->data->mlet)
    158 				? oclass->wldam
    159 				: oclass->wsdam;
    160 			hit(oclass->oc_name, mtmp, exclam(damage));
    161 			mtmp->mhp -= damage;
    162 			if(mtmp->mhp < 1) {
    163 				pline("%s is killed!", Monnam(mtmp));
    164 				mondied(mtmp);
    165 			}
    166 			range = 0;
    167 		}
    168 		if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
    169 			if (multi)
    170 				nomul(0);
    171 			if (!thitu(8, rnd(oclass->wldam), oclass->oc_name)) {
    172 				mksobj_at(obj->otyp, u.ux, u.uy);
    173 				fobj->quan = 1;
    174 				stackobj(fobj);
    175 			}
    176 			range = 0;
    177 		}
    178 		tmp_at(bhitpos.x, bhitpos.y);
    179 	}
    180 	tmp_at(-1, -1);
    181 }
    182 #endif
    183 			
    184 /* Return 1 if it's OK for the monster to move as well as (throw,
    185  * zap, etc).
    186  */
    187 inrange(mtmp)
    188 register struct monst *mtmp;
    189 {
    190 	register schar tx,ty;
    191 #ifdef DGK
    192 	struct obj *otmp;
    193 	register xchar x, y;
    194 #endif
    195 
    196 	/* do nothing if cancelled (but make '1' say something) */
    197 	if(mtmp->data->mlet != '1' && mtmp->mcan)
    198 		return 1;
    199 
    200 	/* spit fire only when both in a room or both in a corridor */
    201 	if(inroom(u.ux,u.uy) != inroom(mtmp->mx,mtmp->my)) return 1;
    202 	tx = u.ux - mtmp->mx;
    203 	ty = u.uy - mtmp->my;
    204 #ifdef DGK
    205 	if ((!tx || !ty || abs(tx) == abs(ty))	/* straight line or diagonal */
    206 		&& movedist(tx, 0,  ty, 0) < BOLT_LIM) {
    207 		/* Check if there are any dead squares between.  If so,
    208 		 * it won't be possible to shoot.
    209 		 */
    210 		for (x = mtmp->mx, y = mtmp->my; x != u.ux || y != u.uy;
    211 				x += sgn(tx), y += sgn(ty))
    212 			if (!ACCESSIBLE(levl[x][y].typ))
    213 				return 1;
    214 
    215 		switch(mtmp->data->mlet) {
    216 		case 'K':
    217 		case 'C':
    218 		/* If you're coming toward the monster, the monster
    219 		 * should try to soften you up with arrows.  If you're
    220 		 * going away, you are probably hurt or running.  Give
    221 		 * chase, but if you're getting too far away, throw.
    222 		 */
    223 		x = mtmp->mx;
    224 		y = mtmp->my;
    225 		otmp = (mtmp->data->mlet == 'K') ? m_carrying(mtmp, DART)
    226 			: m_carrying(mtmp, CROSSBOW_BOLT);
    227 		if (otmp && (!URETREATING(x,y)
    228 			|| !rn2(BOLT_LIM - movedist(x, u.ux, y, u.uy)))) {
    229 				m_throw(mtmp->mx, mtmp->my, sgn(tx), sgn(ty),
    230 					BOLT_LIM,otmp);
    231 				if (!--otmp->quan)
    232 					m_useup(mtmp, otmp);
    233 				return 0;
    234 			}
    235 		break;
    236 #else
    237 	if((!tx && abs(ty) < BOLT_LIM) || (!ty && abs(tx) < BOLT_LIM)
    238 	    || (abs(tx) == abs(ty) && abs(tx) < BOLT_LIM)){
    239 	    switch(mtmp->data->mlet) {
    240 #endif
    241 	    case 'D':
    242 		/* spit fire in the direction of @ (not nec. hitting) */
    243 		buzz(-1,mtmp->mx,mtmp->my,sgn(tx),sgn(ty));
    244 		break;
    245 	    case '1':
    246 		if(rn2(WIZSHOT)) break;
    247 		/* if you zapped wizard with wand of cancellation,
    248 		he has to shake off the effects before he can throw
    249 		spells successfully.  1/2 the time they fail anyway */
    250 		if(mtmp->mcan || rn2(2)) {
    251 		    if(canseemon(mtmp))
    252 			pline("%s makes a gesture, then curses.",
    253 			    Monnam(mtmp));
    254 		    else
    255 			pline("You hear mumbled cursing.");
    256 		    if(!rn2(3)) {
    257 			mtmp->mspeed = 0;
    258 			mtmp->minvis = 0;
    259 		    }
    260 		    if(!rn2(3))
    261 			mtmp->mcan = 0;
    262 		} else {
    263 		    if(canseemon(mtmp)){
    264 			if(!rn2(6) && !Invis) {
    265 			    pline("%s hypnotizes you.", Monnam(mtmp));
    266 #ifdef DGK
    267 	/* bug fix by ab@unido
    268 	 */
    269 			    nomul(-(rn2(3) + 3));
    270 #else
    271 			    nomul(rn2(3) + 3);
    272 #endif
    273 			    break;
    274 			} else
    275 			    pline("%s chants an incantation.",
    276 				Monnam(mtmp));
    277 		    } else
    278 			    pline("You hear a mumbled incantation.");
    279 		    switch(rn2(Invis ? 5 : 6)) {
    280 		    case 0:
    281 			/* create a nasty monster from a deep level */
    282 			/* (for the moment, 'nasty' is not implemented) */
    283 			(void) makemon((struct permonst *)0, u.ux, u.uy);
    284 			break;
    285 		    case 1:
    286 			pline("\"Destroy the thief, my pets!\"");
    287 			aggravate();	/* aggravate all the monsters */
    288 			/* fall into next case */
    289 		    case 2:
    290 			if (flags.no_of_wizards == 1 && rnd(5) == 0)
    291 			    /* if only 1 wizard, clone himself */
    292 			    clonewiz(mtmp);
    293 			break;
    294 		    case 3:
    295 			if(mtmp->mspeed == MSLOW)
    296 				mtmp->mspeed = 0;
    297 			else
    298 				mtmp->mspeed = MFAST;
    299 			break;
    300 		    case 4:
    301 			mtmp->minvis = 1;
    302 			break;
    303 		    case 5:
    304 			/* Only if not Invisible */
    305 			pline("You hear a clap of thunder!");
    306 			/* shoot a bolt of fire or cold, or a sleep ray */
    307 			buzz(-rnd(3),mtmp->mx,mtmp->my,sgn(tx),sgn(ty));
    308 			break;
    309 		    }
    310 		}
    311 	    }
    312 	    if(u.uhp < 1) done_in_by(mtmp);
    313 	}
    314 	return 1;
    315 }
    316 
    317 aggravate()
    318 {
    319 	register struct monst *mtmp;
    320 
    321 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
    322 		mtmp->msleep = 0;
    323 		if(mtmp->mfroz && !rn2(5))
    324 			mtmp->mfroz = 0;
    325 	}
    326 }
    327 
    328 clonewiz(mtmp)
    329 register struct monst *mtmp;
    330 {
    331 	register struct monst *mtmp2;
    332 
    333 	if(mtmp2 = makemon(PM_WIZARD, mtmp->mx, mtmp->my)) {
    334 		flags.no_of_wizards = 2;
    335 		unpmon(mtmp2);
    336 		mtmp2->mappearance = wizapp[rn2(sizeof(wizapp)-1)];
    337 		pmon(mtmp);
    338 	}
    339 }