1 /* SCCS Id: @(#)music.c 3.4 2003/05/25 */
2 /* Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed. See license for details. */
6 * This file contains the different functions designed to manipulate the
7 * musical instruments and their various effects.
9 * Actually the list of instruments / effects is :
11 * (wooden) flute may calm snakes if player has enough dexterity
12 * magic flute may put monsters to sleep: area of effect depends
14 * (tooled) horn Will awaken monsters: area of effect depends on player
15 * level. May also scare monsters.
16 * fire horn Acts like a wand of fire.
17 * frost horn Acts like a wand of cold.
18 * bugle Will awaken soldiers (if any): area of effect depends
20 * (wooden) harp May calm nymph if player has enough dexterity.
21 * magic harp Charm monsters: area of effect depends on player
23 * (leather) drum Will awaken monsters like the horn.
24 * drum of earthquake Will initiate an earthquake whose intensity depends
25 * on player level. That is, it creates random pits
31 STATIC_DCL void FDECL(awaken_monsters,(int));
32 STATIC_DCL void FDECL(put_monsters_to_sleep,(int));
33 STATIC_DCL void FDECL(charm_snakes,(int));
34 STATIC_DCL void FDECL(calm_nymphs,(int));
35 STATIC_DCL void FDECL(charm_monsters,(int));
36 STATIC_DCL void FDECL(do_earthquake,(int));
37 STATIC_DCL int FDECL(do_improvisation,(struct obj *));
40 STATIC_DCL int NDECL(atconsole);
41 STATIC_DCL void FDECL(speaker,(struct obj *,char *));
44 extern int sco_flag_console; /* will need changing if not _M_UNIX */
45 STATIC_DCL void NDECL(playinit);
46 STATIC_DCL void FDECL(playstring, (char *,size_t));
47 STATIC_DCL void FDECL(speaker,(struct obj *,char *));
50 void FDECL( pc_speaker, ( struct obj *, char * ) );
53 void FDECL( amii_speaker, ( struct obj *, char *, int ) );
57 * Wake every monster in range...
61 awaken_monsters(distance)
64 register struct monst *mtmp = fmon;
68 if (!DEADMONSTER(mtmp)) {
69 distm = distu(mtmp->mx, mtmp->my);
70 if (distm < distance) {
74 /* May scare some monsters */
75 if (distm < distance/3 &&
76 !resist(mtmp, TOOL_CLASS, 0, NOTELL))
77 monflee(mtmp, 0, FALSE, TRUE);
85 * Make monsters fall asleep. Note that they may resist the spell.
89 put_monsters_to_sleep(distance)
92 register struct monst *mtmp = fmon;
95 if (!DEADMONSTER(mtmp) && distu(mtmp->mx, mtmp->my) < distance &&
96 sleep_monst(mtmp, d(10,10), TOOL_CLASS)) {
97 mtmp->msleeping = 1; /* 10d10 turns + wake_nearby to rouse */
105 * Charm snakes in range. Note that the snakes are NOT tamed.
109 charm_snakes(distance)
112 register struct monst *mtmp = fmon;
113 int could_see_mon, was_peaceful;
116 if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_SNAKE && mtmp->mcanmove &&
117 distu(mtmp->mx, mtmp->my) < distance) {
118 was_peaceful = mtmp->mpeaceful;
121 could_see_mon = canseemon(mtmp);
122 mtmp->mundetected = 0;
123 newsym(mtmp->mx, mtmp->my);
124 if (canseemon(mtmp)) {
126 You("notice %s, swaying with the music.",
129 pline("%s freezes, then sways with the music%s.",
131 was_peaceful ? "" : ", and now seems quieter");
139 * Calm nymphs in range.
143 calm_nymphs(distance)
146 register struct monst *mtmp = fmon;
149 if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_NYMPH && mtmp->mcanmove &&
150 distu(mtmp->mx, mtmp->my) < distance) {
156 "%s listens cheerfully to the music, then seems quieter.",
163 /* Awake only soldiers of the level. */
168 register struct monst *mtmp = fmon;
171 if (!DEADMONSTER(mtmp) &&
172 is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) {
173 mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0;
176 pline("%s is now ready for battle!", Monnam(mtmp));
178 Norep("You hear the rattle of battle gear being readied.");
184 /* Charm monsters in range. Note that they may resist the spell.
185 * If swallowed, range is reduced to 0.
189 charm_monsters(distance)
192 struct monst *mtmp, *mtmp2;
195 if (!resist(u.ustuck, TOOL_CLASS, 0, NOTELL))
196 (void) tamedog(u.ustuck, (struct obj *) 0);
198 for (mtmp = fmon; mtmp; mtmp = mtmp2) {
200 if (DEADMONSTER(mtmp)) continue;
202 if (distu(mtmp->mx, mtmp->my) <= distance) {
203 if (!resist(mtmp, TOOL_CLASS, 0, NOTELL))
204 (void) tamedog(mtmp, (struct obj *) 0);
211 /* Generate earthquake :-) of desired force.
212 * That is: create random chasms (pits).
223 int start_x, start_y, end_x, end_y;
225 start_x = u.ux - (force * 2);
226 start_y = u.uy - (force * 2);
227 end_x = u.ux + (force * 2);
228 end_y = u.uy + (force * 2);
229 if (start_x < 1) start_x = 1;
230 if (start_y < 1) start_y = 1;
231 if (end_x >= COLNO) end_x = COLNO - 1;
232 if (end_y >= ROWNO) end_y = ROWNO - 1;
233 for (x=start_x; x<=end_x; x++) for (y=start_y; y<=end_y; y++) {
234 if ((mtmp = m_at(x,y)) != 0) {
235 wakeup(mtmp); /* peaceful monster will become hostile */
236 if (mtmp->mundetected && is_hider(mtmp->data)) {
237 mtmp->mundetected = 0;
239 pline("%s is shaken loose from the ceiling!",
242 You_hear("a thumping sound.");
243 if (x==u.ux && y==u.uy)
244 You("easily dodge the falling %s.",
249 if (!rn2(14 - force)) switch (levl[x][y].typ) {
250 case FOUNTAIN : /* Make the fountain disappear */
252 pline_The("fountain falls into a chasm.");
257 pline_The("kitchen sink falls into a chasm.");
261 if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) break;
264 pline_The("altar falls into a chasm.");
268 pline_The("headstone topples into a chasm.");
272 pline_The("throne falls into a chasm.");
273 /* Falls into next case */
275 case CORR : /* Try to make a pit */
276 do_pit: chasm = maketrap(x,y,PIT);
277 if (!chasm) break; /* no pit if portal at that location */
280 levl[x][y].doormask = 0;
284 if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
286 pline("KADOOM! The boulder falls into a chasm%s!",
287 ((x == u.ux) && (y == u.uy)) ? " below you" : "");
290 obj_extract_self(otmp);
291 (void) flooreffects(otmp, x, y, "");
295 /* We have to check whether monsters or player
296 falls in a chasm... */
299 if(!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) {
302 pline("%s falls into a chasm!", Monnam(mtmp));
303 else if (flags.soundok && humanoid(mtmp->data))
304 You_hear("a scream!");
305 mselftouch(mtmp, "Falling, ", TRUE);
307 if ((mtmp->mhp -= rnd(6)) <= 0) {
309 pline("It is destroyed!");
311 You("destroy %s!", mtmp->mtame ?
312 x_monnam(mtmp, ARTICLE_THE, "poor",
313 mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE):
319 } else if (x == u.ux && y == u.uy) {
320 if (Levitation || Flying ||
321 is_clinger(youmonst.data)) {
322 pline("A chasm opens up under you!");
323 You("don't fall in!");
325 You("fall into a chasm!");
327 u.utraptype = TT_PIT;
328 losehp(rnd(6),"fell into a chasm",
330 selftouch("Falling, you");
334 case DOOR : /* Make the door collapse */
335 if (levl[x][y].doormask == D_NODOOR) goto do_pit;
337 pline_The("door collapses.");
338 if (*in_rooms(x, y, SHOPBASE))
339 add_damage(x, y, 0L);
340 levl[x][y].doormask = D_NODOOR;
349 * The player is trying to extract something from his/her instrument.
353 do_improvisation(instr)
356 int damage, do_spec = !Confusion;
357 #if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined (PCMUSIC)
361 /* if won't yield special effect, make sound of mundane counterpart */
362 if (!do_spec || instr->spe <= 0)
363 while (objects[itmp.otyp].oc_magic) itmp.otyp -= 1;
365 mac_speaker(&itmp, "C");
368 amii_speaker(&itmp, "Cw", AMII_OKAY_VOLUME);
371 if (sco_flag_console)
375 pc_speaker ( &itmp, "C");
377 #endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */
380 pline("What you produce is quite far from music...");
382 You("start playing %s.", the(xname(instr)));
384 switch (instr->otyp) {
385 case MAGIC_FLUTE: /* Make monster fall asleep */
386 if (do_spec && instr->spe > 0) {
387 consume_obj_charge(instr, TRUE);
389 You("produce soft music.");
390 put_monsters_to_sleep(u.ulevel * 5);
391 exercise(A_DEX, TRUE);
393 } /* else FALLTHRU */
394 case WOODEN_FLUTE: /* May charm snakes */
395 do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
396 pline("%s.", Tobjnam(instr, do_spec ? "trill" : "toot"));
397 if (do_spec) charm_snakes(u.ulevel * 3);
398 exercise(A_DEX, TRUE);
400 case FROST_HORN: /* Idem wand of cold */
401 case FIRE_HORN: /* Idem wand of fire */
402 if (do_spec && instr->spe > 0) {
403 consume_obj_charge(instr, TRUE);
405 if (!getdir((char *)0)) {
406 pline("%s.", Tobjnam(instr, "vibrate"));
408 } else if (!u.dx && !u.dy && !u.dz) {
409 if ((damage = zapyourself(instr, TRUE)) != 0) {
411 Sprintf(buf, "using a magical horn on %sself", uhim());
412 losehp(damage, buf, KILLED_BY);
415 buzz((instr->otyp == FROST_HORN) ? AD_COLD-1 : AD_FIRE-1,
416 rn1(6,6), u.ux, u.uy, u.dx, u.dy);
418 makeknown(instr->otyp);
420 } /* else FALLTHRU */
421 case TOOLED_HORN: /* Awaken or scare monsters */
422 You("produce a frightful, grave sound.");
423 awaken_monsters(u.ulevel * 30);
424 exercise(A_WIS, FALSE);
426 case BUGLE: /* Awaken & attract soldiers */
427 You("extract a loud noise from %s.", the(xname(instr)));
429 exercise(A_WIS, FALSE);
431 case MAGIC_HARP: /* Charm monsters */
432 if (do_spec && instr->spe > 0) {
433 consume_obj_charge(instr, TRUE);
435 pline("%s very attractive music.", Tobjnam(instr, "produce"));
436 charm_monsters((u.ulevel - 1) / 3 + 1);
437 exercise(A_DEX, TRUE);
439 } /* else FALLTHRU */
440 case WOODEN_HARP: /* May calm Nymph */
441 do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
442 pline("%s %s.", The(xname(instr)),
443 do_spec ? "produces a lilting melody" : "twangs");
444 if (do_spec) calm_nymphs(u.ulevel * 3);
445 exercise(A_DEX, TRUE);
447 case DRUM_OF_EARTHQUAKE: /* create several pits */
448 if (do_spec && instr->spe > 0) {
449 consume_obj_charge(instr, TRUE);
451 You("produce a heavy, thunderous rolling!");
452 pline_The("entire dungeon is shaking around you!");
453 do_earthquake((u.ulevel - 1) / 3 + 1);
454 /* shake up monsters in a much larger radius... */
455 awaken_monsters(ROWNO * COLNO);
456 makeknown(DRUM_OF_EARTHQUAKE);
458 } /* else FALLTHRU */
459 case LEATHER_DRUM: /* Awaken monsters */
460 You("beat a deafening row!");
461 awaken_monsters(u.ulevel * 40);
462 exercise(A_WIS, FALSE);
465 impossible("What a weird instrument (%d)!", instr->otyp);
468 return 2; /* That takes time */
472 * So you want music...
476 do_play_instrument(instr)
479 char buf[BUFSZ], c = 'y';
485 You_cant("play music underwater!");
488 if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) {
489 c = yn("Improvise?");
492 if (u.uevent.uheard_tune == 2 && yn("Play the passtune?") == 'y') {
495 getlin("What tune are you playing? [5 notes, A-G]", buf);
496 (void)mungspaces(buf);
497 /* convert to uppercase and change any "H" to the expected "B" */
498 for (s = buf; *s; s++) {
502 /* The AMIGA supports two octaves of notes */
503 if (*s == 'h') *s = 'b';
505 if (*s == 'H') *s = 'B';
508 You("extract a strange sound from %s!", the(xname(instr)));
510 /* if user is at the console, play through the console speaker */
515 if (sco_flag_console)
519 mac_speaker ( instr , buf ) ;
522 pc_speaker ( instr, buf );
528 for( i = 0; buf[i] && i < 5; ++i )
530 nbuf[ i*2 ] = buf[ i ];
531 nbuf[ (i*2)+1 ] = 'h';
534 amii_speaker ( instr , nbuf, AMII_OKAY_VOLUME ) ;
537 /* Check if there was the Stronghold drawbridge near
538 * and if the tune conforms to what we're waiting for.
540 if(Is_stronghold(&u.uz)) {
541 exercise(A_WIS, TRUE); /* just for trying */
542 if(!strcmp(buf,tune)) {
543 /* Search for the drawbridge */
544 for(y=u.uy-1; y<=u.uy+1; y++)
545 for(x=u.ux-1;x<=u.ux+1;x++)
547 if(find_drawbridge(&x,&y)) {
548 u.uevent.uheard_tune = 2; /* tune now fully known */
549 if(levl[x][y].typ == DRAWBRIDGE_DOWN)
550 close_drawbridge(x,y);
552 open_drawbridge(x,y);
555 } else if(flags.soundok) {
556 if (u.uevent.uheard_tune < 1) u.uevent.uheard_tune = 1;
557 /* Okay, it wasn't the right tune, but perhaps
558 * we can give the player some hints like in the
561 for(y = u.uy-1; y <= u.uy+1 && !ok; y++)
562 for(x = u.ux-1; x <= u.ux+1 && !ok; x++)
564 if(IS_DRAWBRIDGE(levl[x][y].typ) ||
565 is_drawbridge_wall(x,y) >= 0)
567 if(ok) { /* There is a drawbridge near */
571 tumblers = gears = 0;
575 for(x=0; x < (int)strlen(buf); x++)
577 if(buf[x] == tune[x]) {
592 You_hear("%d tumbler%s click and %d gear%s turn.",
593 tumblers, plur(tumblers), gears, plur(gears));
595 You_hear("%d tumbler%s click.",
596 tumblers, plur(tumblers));
598 You_hear("%d gear%s turn.", gears, plur(gears));
599 /* could only get `gears == 5' by playing five
600 correct notes followed by excess; otherwise,
601 tune would have matched above */
602 if (gears == 5) u.uevent.uheard_tune = 2;
609 return do_improvisation(instr);
614 * Play audible music on the machine's speaker if appropriate.
621 * Kluge alert: This code assumes that your [34]86 has no X terminals
622 * attached and that the console tty type is AT386 (this is always true
623 * under AT&T UNIX for these boxen). The theory here is that your remote
624 * ttys will have terminal type `ansi' or something else other than
625 * `AT386' or `xterm'. We'd like to do better than this, but testing
626 * to see if we're running on the console physical terminal is quite
627 * difficult given the presence of virtual consoles and other modern
628 * UNIX impedimenta...
630 char *termtype = nh_getenv("TERM");
632 return(!strcmp(termtype, "AT386") || !strcmp(termtype, "xterm"));
641 * For this to work, you need to have installed the PD speaker-control
642 * driver for PC-compatible UNIX boxes that I (esr@snark.thyrsus.com)
643 * posted to comp.sources.unix in Feb 1990. A copy should be included
644 * with your nethack distribution.
648 if ((fd = open("/dev/speaker", 1)) != -1)
650 /* send a prefix to modify instrumental `timbre' */
655 (void) write(fd, ">ol", 1); /* up one octave & lock */
660 (void) write(fd, "<<ol", 2); /* drop two octaves & lock */
663 (void) write(fd, "ol", 2); /* octave lock */
667 (void) write(fd, "l8mlol", 4); /* fast, legato, octave lock */
670 (void) write(fd, buf, strlen(buf));
674 #endif /* UNIX386MUSIC */
679 #include <sys/types.h>
680 #include <sys/console.h>
681 #include <sys/vtkd.h>
683 #define KIOC ('K' << 8)
684 #define KDMKTONE (KIOC | 8)
689 STATIC_OVL void tone(hz, ticks)
690 /* emit tone of frequency hz for given number of ticks */
691 unsigned int hz, ticks;
693 ioctl(0,KDMKTONE,hz|((ticks*10)<<16));
695 printf("TONE: %6d %6d\n",hz,ticks * 10);
700 STATIC_OVL void rest(ticks)
701 /* rest for given number of ticks */
706 printf("REST: %6d\n",ticks * 10);
711 #include "interp.c" /* from snd86unx.shr */
719 /* emit a prefix to modify instrumental `timbre' */
725 playstring(">ol", 1); /* up one octave & lock */
730 playstring("<<ol", 2); /* drop two octaves & lock */
733 playstring("ol", 2); /* octave lock */
737 playstring("l8mlol", 4); /* fast, legato, octave lock */
740 playstring( buf, strlen(buf));
749 playstring(argv[1], strlen(argv[1]));
753 #endif /* VPIX_MUSIC */