ftp.nice.ch/pub/next/games/strategic/NetHack.s.tar.gz#/NetHackSource/src/worm.c

This is worm.c in view mode; [Download] [Up]

/*	SCCS Id: @(#)worm.c	3.0	88/11/11
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"

#ifdef WORM
#include "wseg.h"

static void FDECL(remseg,(struct monst *,struct wseg *));

/* Each tailed worm has a wormno.  This is used as an index for the following
 * arrays:
 * wsegs: the start of a a linked list of segments, located at the tail.
 * wheads: the end of a linked list of segments, located at the head.  Putting
 *	the tail of the list at the head of the worm and vice versa is an
 *	endless source of confusion, but necessary.  From now on, we will use
 *	"start" and "end" to refer to the list, and "head" and "tail" to refer
 *	to the worm.
 * wgrowtime: obvious.
 *
 * When a worm is moved, we add a new segment at the head (end of the list)
 * and (unless we want it to grow) delete the segment at the tail (beginning
 * of the list).  This new head segment is located in the same square as
 * the actual head of the worm (thus requiring a special case when setting
 * level.monsters upon worm movement).  If we do want to grow the worm, we
 * don't delete the tail segment, and we give the worm extra hit points,
 * which possibly go into its maximum.
 *
 * Non-moving worms (worm_nomove) shrink instead of grow as their tails keep
 * going while their heads are stopped short.  Delete the tail segment,
 * and remove hit points from the worm.
 */
struct wseg *wsegs[32] = DUMMY, *wheads[32] = DUMMY, *m_atseg = 0;
long wgrowtime[32] = DUMMY;

int
getwn(mtmp)
struct monst *mtmp;
{
	register int tmp;

	for(tmp = 1; tmp < 32; tmp++)
	    if(!wsegs[tmp]) {
		mtmp->wormno = tmp;
		return(1);
	    }
	return(0);	/* level infested with worms */
}

/* called to initialize a worm unless cut in half */
void
initworm(mtmp)
struct monst *mtmp;
{
	register struct wseg *wtmp;
	register int tmp = mtmp->wormno;

	if(!tmp) return;
	wheads[tmp] = wsegs[tmp] = wtmp = newseg();
	wgrowtime[tmp] = 0;
	wtmp->wx = mtmp->mx;
	wtmp->wy = mtmp->my;
/*	wtmp->wdispl = 0; */
	wtmp->nseg = 0;
}

static void
remseg(mtmp,wtmp)
struct monst *mtmp;
register struct wseg *wtmp;
{
	if (mtmp->mx != wtmp->wx || mtmp->my != wtmp->wy)
		remove_monster(wtmp->wx, wtmp->wy);
	if(wtmp->wdispl) newsym(wtmp->wx, wtmp->wy);
	free((genericptr_t) wtmp);
}

void
worm_move(mtmp)
struct monst *mtmp;
{
	register struct wseg *wtmp, *whd;
	register int tmp = mtmp->wormno;

	wtmp = newseg();
	wtmp->wx = mtmp->mx;
	wtmp->wy = mtmp->my;
	wtmp->nseg = 0;
/*	wtmp->wdispl = 0; */
	(whd = wheads[tmp])->nseg = wtmp;
	wheads[tmp] = wtmp;
	if(cansee(whd->wx,whd->wy)){
		unpmon(mtmp);
		atl(whd->wx, whd->wy, S_WORM_TAIL);
		whd->wdispl = 1;
	} else	whd->wdispl = 0;
	if(wgrowtime[tmp] <= moves) {
		if(!wgrowtime[tmp]) wgrowtime[tmp] = moves + rnd(5);
		else wgrowtime[tmp] += 2+rnd(15);
		mtmp->mhp += 3;
		if (mtmp->mhp > MHPMAX) mtmp->mhp = MHPMAX;
		if (mtmp->mhp > mtmp->mhpmax) mtmp->mhpmax = mtmp->mhp;
		return;
	}
	whd = wsegs[tmp];
	wsegs[tmp] = whd->nseg;
	remseg(mtmp, whd);
}

void
worm_nomove(mtmp)
register struct monst *mtmp;
{
	register int tmp;
	register struct wseg *wtmp;

	tmp = mtmp->wormno;
	wtmp = wsegs[tmp];
	if(wtmp == wheads[tmp]) return;
	if(wtmp == 0 || wtmp->nseg == 0) panic("worm_nomove?");
	wsegs[tmp] = wtmp->nseg;
	remseg(mtmp, wtmp);
	if (mtmp->mhp > 3) mtmp->mhp -= 3;	/* mhpmax not changed ! */
	else mtmp->mhp = 1;
}

void
wormdead(mtmp)
register struct monst *mtmp;
{
	register int tmp = mtmp->wormno;
	register struct wseg *wtmp, *wtmp2;

	if(!tmp) return;
	mtmp->wormno = 0;
	for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp2) {
		wtmp2 = wtmp->nseg;
		remseg(mtmp, wtmp);
	}
	wsegs[tmp] = 0;
}

void
wormhit(mtmp)
register struct monst *mtmp;
{
	register int tmp = mtmp->wormno;
	register struct wseg *wtmp;

	if(!tmp) return;	/* worm without tail */
	for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp->nseg)
		if (dist(wtmp->wx, wtmp->wy) < 3) (void) mattacku(mtmp);
}

void
wormsee(tmp)
register unsigned int tmp;
{
	register struct wseg *wtmp = wsegs[tmp];

	if(!wtmp) panic("wormsee: wtmp==0");

	for(; wtmp->nseg; wtmp = wtmp->nseg)
		if(!cansee(wtmp->wx,wtmp->wy) && wtmp->wdispl) {
			newsym(wtmp->wx, wtmp->wy);
			wtmp->wdispl = 0;
		}
		else if (cansee(wtmp->wx, wtmp->wy) && !wtmp->wdispl) {
			atl(wtmp->wx, wtmp->wy, S_WORM_TAIL);
			wtmp->wdispl = 1;
		}
}

void
cutworm(mtmp, x, y, weptyp)
struct monst *mtmp;
xchar x,y;
unsigned weptyp;		/* uwep->otyp or 0 */
{
	register struct wseg *wtmp, *wtmp2;
	struct monst *mtmp2;
	int tmp, tmp2;

	if(mtmp->mx == x && mtmp->my == y) return;	/* hit headon */

	/* cutting goes best with axe or sword */
	tmp = rnd(20);
	if(weptyp >= SHORT_SWORD && weptyp <= KATANA ||
	   weptyp == AXE)
		tmp += 5;

	if(tmp < 12) return;

	/* if tail then worm just loses a tail segment */
	tmp = mtmp->wormno;
	wtmp = wsegs[tmp];
	if(wtmp->wx == x && wtmp->wy == y){
		wsegs[tmp] = wtmp->nseg;
		remseg(mtmp, wtmp);
		return;
	}

	/* cut the worm in two halves */
	mtmp2 = newmonst(0);
	*mtmp2 = *mtmp;
	mtmp2->mxlth = mtmp2->mnamelth = 0;

	/* sometimes the tail end dies */
	if(rn2(3) || !getwn(mtmp2)){
		monfree(mtmp2);
		place_worm_seg(mtmp, mtmp2->mx, mtmp2->my);
			/* since mtmp is still on that spot */
		tmp2 = 0;
	} else {
		tmp2 = mtmp2->wormno;
		wsegs[tmp2] = wsegs[tmp];
		wgrowtime[tmp2] = 0;
	}
	/* do-loop: go from the tail to the head.  Segments close to the tail
	 * either die or become part of worm 2.  We stop at the hit segment
	 * and this loop never goes down the entire length of the worm.
	 */
	do {
	    /* The segment immediately next to (tailwards) the one hit, */
	    /* becoes the head of the new second worm.  Note: at this point, */
	    /* wtmp->nseg is the one you hit, wtmp is immediately tailwards, */
	    /* and wtmp->nseg->nseg is immediately headwards. */
	    if(wtmp->nseg->wx == x && wtmp->nseg->wy == y){
		if(tmp2) wheads[tmp2] = wtmp;
		wsegs[tmp] = wtmp->nseg->nseg;
		remseg(mtmp, wtmp->nseg);
		wtmp->nseg = 0;
		if(tmp2) {
		    kludge("You cut %s in half.", mon_nam(mtmp));
		/* devalue the monster level of both halves of the worm */
		    mtmp->m_lev = (mtmp->m_lev <= 3) ? 2 : mtmp->m_lev - 2;
		    mtmp2->m_lev = mtmp->m_lev;
		/* calculate the mhp on the new (lower) monster level */
		    mtmp2->mhpmax = mtmp2->mhp = d((int)mtmp2->m_lev, 8);
		    place_monster(mtmp2, wtmp->wx, wtmp->wy);
		    mtmp2->nmon = fmon;
		    fmon = mtmp2;
		    mtmp2->mdispl = 0;
		    pmon(mtmp2);
		} else {
			if (Blind) You("cut off part of its tail.");
			else You("cut off part of %s's tail.", mon_nam(mtmp));
			remseg(mtmp, wtmp);
		}
		mtmp->mhp /= 2;
		return;
	    }
	/* Worm segments which are closer to the tail than the one you hit, */
	/* get either deleted or transferred from the old to new worms */
	    wtmp2 = wtmp->nseg;
	    if(!tmp2) remseg(mtmp, wtmp);
	    else place_worm_seg(mtmp2, wtmp->wx, wtmp->wy);
	    wtmp = wtmp2;
	} while(wtmp->nseg);
	panic("Cannot find worm segment");
}

#endif /* WORM /**/

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.