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

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

/*	SCCS Id: @(#)music.c	3.0	88/10/22
/* 	Copyright (c) 1989 by Jean-Christophe Collet */
/* NetHack may be freely redistributed.  See license for details. */

/*
 * This file contains the different functions designed to manipulate the
 * musical instruments and their various effects.
 *
 * Actually the list of instruments / effects is :
 *
 * Flute		may calm snakes if player has enough dexterity
 * Magic flute		may put monsters to sleep:  area of effect depends
 *			on player level.
 * Horn			Will awaken monsters:  area of effect depends on player
 *			level.  May also scare monsters.
 * Fire horn		Acts like a wand of fire.
 * Frost horn		Acts like a wand of cold.
 * Bugle		Will awaken soldiers (if any):  area of effect depends
 *			on player level.
 * Harp			May calm nymph if player has enough dexterity.
 * Magic harp		Charm monsters:  area of effect depends on player
 *			level.
 * Drum			Will awaken monsters like the horn.
 * Drum of earthquake	Will initiate an earthquake whose intensity depends
 *			on player level.  That is, it creates ramdom pits
 *			called here chasms.
 */


#include "hack.h"

#ifdef MUSIC
#include <ctype.h>

static void FDECL(awaken_monsters,(int));
static void FDECL(put_monsters_to_sleep,(int));
static void FDECL(charm_snakes,(int));
static void FDECL(calm_nymphs,(int));
static void NDECL(awaken_soldiers);
static void FDECL(charm_monsters,(int));
static void FDECL(do_earthquake,(int));
static int FDECL(do_improvisation,(struct obj *));

/*
 * Wake every monster in range...
 */

static void
awaken_monsters(distance)
int distance;
{
	register struct monst *mtmp = fmon;

	while(mtmp) {
		if (dist(mtmp->mx, mtmp->my) < distance/3) {
			/* May scare some monsters */
			if (!resist(mtmp, SCROLL_SYM, 0, NOTELL))
			  mtmp->mflee = 1;
		} else if (dist(mtmp->mx, mtmp->my) < distance) {
			mtmp->msleep = 0;
			mtmp->mcanmove = 1;
			mtmp->mfrozen = 0;
		}
		mtmp = mtmp->nmon;
	}
}

/*
 * Make monsters fall asleep.  Note that they may resist the spell.
 */

static void
put_monsters_to_sleep(distance)
int distance;
{
	register struct monst *mtmp = fmon;

	while(mtmp) {
		  if (dist(mtmp->mx, mtmp->my) < distance)
		    if(mtmp->mcanmove && !resist(mtmp, WAND_SYM, 0, NOTELL))
		      mtmp->mcanmove = mtmp->mfrozen = 0;
		mtmp = mtmp->nmon;
	}
}

/*
 * Charm snakes in range.  Note that the snakes are NOT tamed.
 */

static void
charm_snakes(distance)
int distance;
{
	register struct monst *mtmp = fmon;

	while (mtmp) {
		if (mtmp->data->mlet == S_SNAKE && dist(mtmp->mx, mtmp->my) < distance) {
			mtmp->mpeaceful = 1;
			if (cansee(mtmp->mx, mtmp->my))
			  pline("%s freezes and sways with the music, then seems quieter.",defmonnam(mtmp));
		}
		mtmp = mtmp->nmon;
	}
}

/*
 * Calm nymphs in range.
 */

static void
calm_nymphs(distance)
int distance;
{
	register struct monst *mtmp = fmon;

	while (mtmp) {
		if (mtmp->data->mlet == S_NYMPH && dist(mtmp->mx, mtmp->my) < distance) {
			mtmp->mpeaceful = 1;
			if (cansee(mtmp->mx, mtmp->my))
			  pline("%s listens cheerfully to the music, then seems quieter.",defmonnam(mtmp));
		}
		mtmp = mtmp->nmon;
	}
}

/* Awake only soldiers of the level. */

static void
awaken_soldiers() {
#ifdef ARMY
#define IS_SOLDIER(dat)	((int)((dat) - mons) >= PM_UNARMORED_SOLDIER && \
			 (int) ((dat) - mons) <= PM_CAPTAIN)
	register struct monst *mtmp = fmon;

	while(mtmp) {
		if (IS_SOLDIER(mtmp->data)) {
			mtmp->mpeaceful = mtmp->msleep = 0;
			mtmp->mcanmove = 1;
		}
		mtmp = mtmp->nmon;
	}
#endif /* ARMY /**/
}

/* Charm monsters in range.  Note that they may resist the spell. */

static void
charm_monsters(distance)
int distance;
{
	register struct monst *mtmp = fmon, *mtmp2;

	while(mtmp) {
		mtmp2 = mtmp->nmon;
		if(dist(mtmp->mx, mtmp->my) <= distance)
		    if(!resist(mtmp, SCROLL_SYM, 0, NOTELL))
			(void) tamedog(mtmp, (struct obj *) 0);
		mtmp = mtmp2;
	}

}

/* Generate earthquake :-) of desired force.
 * That is:  create random chasms (pits).
 */

static void
do_earthquake(force)
int force;
{
	register int x,y;
	struct monst *mtmp;
	struct trap *chasm;
	int start_x, start_y, end_x, end_y;

	start_x = u.ux - (force * 2);
	start_y = u.uy - (force * 2);
	end_x = u.ux + (force * 2);
	end_y = u.uy + (force * 2);
	if (start_x < 1) start_x = 1;
	if (start_y < 1) start_y = 1;
	if (end_x >= COLNO) end_x = COLNO - 1;
	if (end_y >= ROWNO) end_y = ROWNO - 1;
	for (x=start_x; x<=end_x; x++)
	  for (y=start_y; y<=end_y; y++)
	    if (!rn2(14 - force)) {
		    switch (levl[x][y].typ) {
#ifdef FOUNTAINS
			  case FOUNTAIN : /* Make the fountain disappear */
			    if (cansee(x,y))
			      pline("The fountain falls into a chasm.");
			    goto do_pit;
#endif
#ifdef SINKS
			  case SINK :
			    if (cansee(x,y))
			      pline("The kitchen sink falls into a chasm.");
			    goto do_pit;
#endif
#ifdef ALTARS
			  case ALTAR :
			    if (cansee(x,y))
			      pline("The altar falls into a chasm.");
			    goto do_pit;
#endif
#ifdef THRONES
			  case THRONE :
			    if (cansee(x,y))
			      pline("The throne falls into a chasm.");
				/* Falls into next case */
#endif
			  case ROOM :
			  case CORR : /* Make a pit */
do_pit:			    chasm = maketrap(x,y,PIT);
			    chasm->tseen = 1;

			    levl[x][y].doormask = 0;

			    /* We have to check whether monsters or player
			       fall in a chasm... */

			    if (MON_AT(x, y)) {
				mtmp = m_at(x,y);
				if(!is_flyer(mtmp->data)) {
				    mtmp->mtrapped = 1;
				    if(cansee(x,y))
					pline("%s falls into a chasm!",
						Monnam(mtmp));
				    else if (flags.soundok && humanoid(mtmp->data))
					You("hear a scream!");
				    if ((mtmp->mhp -= rnd(6)) <= 0) {
					int saved_conf = u.umconf;

					if(!cansee(x,y))
					    pline("It is destroyed!");
					else {
					    You("destroy %s!",
					    mtmp->mtame ?
						a2_monnam(mtmp, "poor") :
						mon_nam(mtmp));
					}
					xkilled(mtmp,0);
					u.umconf = saved_conf;
				    }
				}
			    } else if (x == u.ux && y == u.uy) {
				    if (Levitation
#ifdef POLYSELF
					|| is_flyer(uasmon)
#endif
					) {
					    pline("A chasm opens up under you!");
					    You("don't fall in!");
				    } else {
					    You("fall into a chasm!");
					    u.utrap = rn1(6,2);
					    u.utraptype = TT_PIT;
					    losehp(rnd(6),"fell into a chasm",
						NO_KILLER_PREFIX);
					    selftouch("Falling, you");
				    }
			    } else
				newsym(x,y);
			    break;
			  case DOOR : /* Make the door collapse */
			    if (levl[x][y].doormask == D_NODOOR) break;
			    if (cansee(x,y))
				pline("The door collapses.");
			    levl[x][y].doormask = D_NODOOR;
			    mnewsym(x,y);
			    if (!MON_AT(x, y) && !(x == u.ux && y == u.uy))
				newsym(x,y);
			    if (cansee(x,y)) prl(x,y);
			    break;
		    }
	    }
}

/*
 * The player is trying to extract something from his/her instrument.
 */

static int
do_improvisation(instr)
struct obj *instr;
{
	int damage;

	if (Confusion)
	  pline("What you produce is quite far from music...");
	else
	  You("start playing the %s.", xname(instr));
	switch (instr->otyp) {
	      case FLUTE:	/* May charm snakes */
		if (rn2(ACURR(A_DEX)) + u.ulevel > 25)
		  charm_snakes((int)u.ulevel*3);
		break;
	      case MAGIC_FLUTE: /* Make monster fall asleep */
		if (instr->spe > 0) {
			instr->spe--;
			You("produce soft music.");
			put_monsters_to_sleep((int)u.ulevel*5);
		}
		break;
	      case HORN:	/* Awaken monsters or scare monsters */
		You("produce a frightful, grave sound.");
		awaken_monsters((int)u.ulevel*30);
		break;
	      case FROST_HORN:	/* Idem wand of cold */
	      case FIRE_HORN:	/* Idem wand of fire */
		if (instr->spe > 0) {
			instr->spe--;
			if (!getdir(1)) {
				if (!Blind)
				    pline("The %s glows then fades.", xname(instr));
			} else {
				if (!u.dx && !u.dy && !u.dz) {
					if((damage = zapyourself(instr)))
					  losehp(damage,
		self_pronoun("using a magical horn on %sself", "him"),
					  NO_KILLER_PREFIX);
					makeknown(instr->otyp);
					return(2);
				}
				buzz((instr->otyp == FROST_HORN) ? 3 : 1, rn1(6,6), u.ux, u.uy, u.dx, u.dy);
				makeknown(instr->otyp);
				return(2);
			}
		}
		break;
	      case BUGLE:	/* Awaken & attract soldiers */
		You("extract a loud noise from the %s.",xname(instr));
		awaken_soldiers();
		break;
	      case HARP:	/* May calm Nymph */
		if (rn2(ACURR(A_DEX)) + u.ulevel > 25)
		  calm_nymphs((int)u.ulevel*3);
		break;
	      case MAGIC_HARP:	/* Charm monsters */
		if (instr->spe > 0) {
			pline("The %s produces very attractive music.", xname(instr));
			instr->spe--;
			charm_monsters(((int)u.ulevel - 1) / 3 + 1);
		}
		break;
	      case DRUM:	/* Awaken monsters */
		You("beat a deafening row!");
		awaken_monsters((int)u.ulevel * 40);
		break;
	      case DRUM_OF_EARTHQUAKE:	/* create several pits */
		if (instr->spe > 0) {
			You("produce a heavy, thunderous rolling!");
			pline("The entire dungeon is shaking around you!");
			instr->spe--;
			do_earthquake(((int)u.ulevel - 1) / 3 + 1);
			makeknown(DRUM_OF_EARTHQUAKE);
		}
		break;
	      default:
		impossible("What a weird instrument (%d)!",instr->otyp);
		break;
	}
	return (2);		/* That takes time */
}

/*
 * So you want music...
 */

int
do_play_instrument(instr)
struct obj *instr;
{
#ifdef STRONGHOLD
    char buf[BUFSZ], *s, c = 'y';
    int x,y;
    boolean ok;

    if (instr->otyp != DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) {
	pline("Improvise? ");
	c = yn();
    }
    if (c == 'n') {
	pline("What tune are you playing? [what 5 notes] ");
	getlin(buf);
	for(s=buf;*s;s++)
		if (islower(*s)) *s=toupper(*s);
	You("extract a strange sound from the %s!",xname(instr));
	/* Check if there was the Stronghold drawbridge near
	 * and if the tune conforms to what we're waiting for.
	 */
	if (dlevel == stronghold_level)
	    if (!strcmp(buf,tune)) {
		/* Search for the drawbridge */
		for(y=u.uy-1; y<=u.uy+1; y++)
		    for(x=u.ux-1;x<=u.ux+1;x++)
			if (find_drawbridge(&x,&y)) {
			    if (levl[x][y].typ == DRAWBRIDGE_DOWN)
				close_drawbridge(x,y);
			    else
				open_drawbridge(x,y);
			    return 0;
			}
	    } else if (flags.soundok) {
		/* Okay, it wasn't the right tune, but perhaps
		 * we can give the player some hints like in the
		 * Mastermind game */
		ok = FALSE;
		for(y = u.uy-1; y <= u.uy+1 && !ok; y++)
		    for(x = u.ux-1; x <= u.ux+1 && !ok; x++)
			if(IS_DRAWBRIDGE(levl[x][y].typ) ||
			   is_drawbridge_wall(x,y) >= 0)
				ok = TRUE;
		if (ok) { /* There is a drawbridge near */
		    int tumblers, gears;
		    boolean matched[5];

		    tumblers = gears = 0;
		    for(x=0; x < 5; x++)
			matched[x] = FALSE;

		    for(x=0; x < strlen(buf); x++)
			if(x < 5) {
			    if(buf[x] == tune[x]) {
				gears++;
				matched[x] = TRUE;
			    } else
				for(y=0; y < 5; y++)
				    if(!matched[y] &&
				       buf[x] == tune[y] &&
				       buf[y] != tune[y]) {
					tumblers++;
					matched[y] = TRUE;
					break;
				    }
			}
		    if(tumblers)
			if(gears)
			    You("hear %d tumbler%s click and %d gear%s turn.",
				tumblers, plur((long)tumblers),
				gears, plur((long)gears));
			else
			    You("hear %d tumbler%s click.",
				tumblers, plur((long)tumblers));
		    else if(gears)
			You("hear %d gear%s turn.",
			    gears, plur((long)gears));
		}
	    }
	return 1;
    } else
#endif /* STRONGHOLD /**/
	    return do_improvisation(instr);
}

#endif /* MUSIC /**/

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