1 /* NetHack 3.6 music.c $NHDT-Date: 1446808448 2015/11/06 11:14:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.40 $ */
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
15 * player 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;
67 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
68 if (DEADMONSTER(mtmp))
70 if ((distm = distu(mtmp->mx, mtmp->my)) < distance) {
74 /* may scare some monsters -- waiting monsters excluded */
75 if (!unique_corpstat(mtmp->data)
76 && (mtmp->mstrategy & STRAT_WAITMASK) != 0)
77 mtmp->mstrategy &= ~STRAT_WAITMASK;
78 else if (distm < distance / 3
79 && !resist(mtmp, TOOL_CLASS, 0, NOTELL))
80 monflee(mtmp, 0, FALSE, TRUE);
86 * Make monsters fall asleep. Note that they may resist the spell.
90 put_monsters_to_sleep(distance)
93 register struct monst *mtmp;
95 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
96 if (DEADMONSTER(mtmp))
98 if (distu(mtmp->mx, mtmp->my) < distance
99 && sleep_monst(mtmp, d(10, 10), TOOL_CLASS)) {
100 mtmp->msleeping = 1; /* 10d10 turns + wake_nearby to rouse */
107 * Charm snakes in range. Note that the snakes are NOT tamed.
111 charm_snakes(distance)
114 register struct monst *mtmp;
115 int could_see_mon, was_peaceful;
117 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
118 if (DEADMONSTER(mtmp))
120 if (mtmp->data->mlet == S_SNAKE && mtmp->mcanmove
121 && distu(mtmp->mx, mtmp->my) < distance) {
122 was_peaceful = mtmp->mpeaceful;
125 mtmp->mstrategy &= ~STRAT_WAITMASK;
126 could_see_mon = canseemon(mtmp);
127 mtmp->mundetected = 0;
128 newsym(mtmp->mx, mtmp->my);
129 if (canseemon(mtmp)) {
131 You("notice %s, swaying with the music.", a_monnam(mtmp));
133 pline("%s freezes, then sways with the music%s.",
135 was_peaceful ? "" : ", and now seems quieter");
142 * Calm nymphs in range.
146 calm_nymphs(distance)
149 register struct monst *mtmp;
151 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
152 if (DEADMONSTER(mtmp))
154 if (mtmp->data->mlet == S_NYMPH && mtmp->mcanmove
155 && distu(mtmp->mx, mtmp->my) < distance) {
159 mtmp->mstrategy &= ~STRAT_WAITMASK;
162 "%s listens cheerfully to the music, then seems quieter.",
168 /* Awake soldiers anywhere the level (and any nearby monster). */
170 awaken_soldiers(bugler)
171 struct monst *bugler; /* monster that played instrument */
173 register struct monst *mtmp;
176 /* distance of affected non-soldier monsters to bugler */
177 distance = ((bugler == &youmonst) ? u.ulevel : bugler->data->mlevel) * 30;
179 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
180 if (DEADMONSTER(mtmp))
182 if (is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) {
183 mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0;
185 mtmp->mstrategy &= ~STRAT_WAITMASK;
187 pline("%s is now ready for battle!", Monnam(mtmp));
189 Norep("You hear the rattle of battle gear being readied.");
190 } else if ((distm = ((bugler == &youmonst)
191 ? distu(mtmp->mx, mtmp->my)
192 : dist2(bugler->mx, bugler->my, mtmp->mx,
193 mtmp->my))) < distance) {
197 /* may scare some monsters -- waiting monsters excluded */
198 if (!unique_corpstat(mtmp->data)
199 && (mtmp->mstrategy & STRAT_WAITMASK) != 0)
200 mtmp->mstrategy &= ~STRAT_WAITMASK;
201 else if (distm < distance / 3
202 && !resist(mtmp, TOOL_CLASS, 0, NOTELL))
203 monflee(mtmp, 0, FALSE, TRUE);
208 /* Charm monsters in range. Note that they may resist the spell.
209 * If swallowed, range is reduced to 0.
212 charm_monsters(distance)
215 struct monst *mtmp, *mtmp2;
218 if (!resist(u.ustuck, TOOL_CLASS, 0, NOTELL))
219 (void) tamedog(u.ustuck, (struct obj *) 0);
221 for (mtmp = fmon; mtmp; mtmp = mtmp2) {
223 if (DEADMONSTER(mtmp))
226 if (distu(mtmp->mx, mtmp->my) <= distance) {
227 if (!resist(mtmp, TOOL_CLASS, 0, NOTELL))
228 (void) tamedog(mtmp, (struct obj *) 0);
234 /* Generate earthquake :-) of desired force.
235 * That is: create random chasms (pits).
244 struct trap *chasm, *trap_at_u = t_at(u.ux, u.uy);
245 int start_x, start_y, end_x, end_y;
250 tu_pit = (trap_at_u->ttyp == PIT || trap_at_u->ttyp == SPIKED_PIT);
251 start_x = u.ux - (force * 2);
252 start_y = u.uy - (force * 2);
253 end_x = u.ux + (force * 2);
254 end_y = u.uy + (force * 2);
263 for (x = start_x; x <= end_x; x++)
264 for (y = start_y; y <= end_y; y++) {
265 if ((mtmp = m_at(x, y)) != 0) {
266 wakeup(mtmp); /* peaceful monster will become hostile */
267 if (mtmp->mundetected && is_hider(mtmp->data)) {
268 mtmp->mundetected = 0;
270 pline("%s is shaken loose from the ceiling!",
273 You_hear("a thumping sound.");
274 if (x == u.ux && y == u.uy)
275 You("easily dodge the falling %s.", mon_nam(mtmp));
279 if (!rn2(14 - force))
280 switch (levl[x][y].typ) {
281 case FOUNTAIN: /* Make the fountain disappear */
283 pline_The("fountain falls into a chasm.");
287 pline_The("kitchen sink falls into a chasm.");
290 if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))
294 pline_The("altar falls into a chasm.");
298 pline_The("headstone topples into a chasm.");
302 pline_The("throne falls into a chasm.");
303 /* Falls into next case */
305 case CORR: /* Try to make a pit */
307 chasm = maketrap(x, y, PIT);
309 break; /* no pit if portal at that location */
312 levl[x][y].doormask = 0;
314 * Let liquid flow into the newly created chasm.
315 * Adjust corresponding code in apply.c for
316 * exploding wand of digging if you alter this sequence.
318 filltype = fillholetyp(x, y, FALSE);
319 if (filltype != ROOM) {
320 levl[x][y].typ = filltype;
321 liquid_flow(x, y, filltype, chasm, (char *) 0);
326 if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
328 pline("KADOOM! The boulder falls into a chasm%s!",
329 ((x == u.ux) && (y == u.uy)) ? " below you"
333 obj_extract_self(otmp);
334 (void) flooreffects(otmp, x, y, "");
338 /* We have to check whether monsters or player
339 falls in a chasm... */
341 if (!is_flyer(mtmp->data)
342 && !is_clinger(mtmp->data)) {
343 boolean m_already_trapped = mtmp->mtrapped;
345 if (!m_already_trapped) { /* suppress messages */
347 pline("%s falls into a chasm!",
349 else if (humanoid(mtmp->data))
350 You_hear("a scream!");
352 /* Falling is okay for falling down
353 within a pit from jostling too */
354 mselftouch(mtmp, "Falling, ", TRUE);
357 rnd(m_already_trapped ? 4 : 6)) <= 0) {
359 pline("It is destroyed!");
375 } else if (x == u.ux && y == u.uy) {
376 if (Levitation || Flying
377 || is_clinger(youmonst.data)) {
378 if (!tu_pit) { /* no pit here previously */
379 pline("A chasm opens up under you!");
380 You("don't fall in!");
382 } else if (!tu_pit || !u.utrap
383 || (u.utrap && u.utraptype != TT_PIT)) {
384 /* no pit here previously, or you were
385 not in it even it there was */
386 You("fall into a chasm!");
388 u.utraptype = TT_PIT;
389 losehp(Maybe_Half_Phys(rnd(6)),
390 "fell into a chasm", NO_KILLER_PREFIX);
391 selftouch("Falling, you");
392 } else if (u.utrap && u.utraptype == TT_PIT) {
393 boolean keepfooting =
394 ((Fumbling && !rn2(5))
395 || (!rnl(Role_if(PM_ARCHEOLOGIST) ? 3 : 9))
396 || ((ACURR(A_DEX) > 7) && rn2(5)));
397 You("are jostled around violently!");
399 u.utraptype = TT_PIT; /* superfluous */
400 losehp(Maybe_Half_Phys(rnd(keepfooting ? 2 : 4)),
401 "hurt in a chasm", NO_KILLER_PREFIX);
403 exercise(A_DEX, TRUE);
406 (Upolyd && (slithy(youmonst.data)
407 || nolimbs(youmonst.data)))
409 : "Falling down, you");
414 case DOOR: /* Make the door collapse */
415 if (levl[x][y].doormask == D_NODOOR)
418 pline_The("door collapses.");
419 if (*in_rooms(x, y, SHOPBASE))
420 add_damage(x, y, 0L);
421 levl[x][y].doormask = D_NODOOR;
430 * The player is trying to extract something from his/her instrument.
433 do_improvisation(instr)
436 int damage, do_spec = !Confusion;
437 #if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined(PCMUSIC)
441 itmp.oextra = (struct oextra *) 0; /* ok on this copy as instr maintains
442 the ptr to free at some point if
445 /* if won't yield special effect, make sound of mundane counterpart */
446 if (!do_spec || instr->spe <= 0)
447 while (objects[itmp.otyp].oc_magic)
450 mac_speaker(&itmp, "C");
453 amii_speaker(&itmp, "Cw", AMII_OKAY_VOLUME);
456 if (sco_flag_console)
460 pc_speaker(&itmp, "C");
462 #endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */
465 pline("What you produce is quite far from music...");
467 You("start playing %s.", the(xname(instr)));
469 switch (instr->otyp) {
470 case MAGIC_FLUTE: /* Make monster fall asleep */
471 if (do_spec && instr->spe > 0) {
472 consume_obj_charge(instr, TRUE);
474 You("produce %s music.", Hallucination ? "piped" : "soft");
475 put_monsters_to_sleep(u.ulevel * 5);
476 exercise(A_DEX, TRUE);
478 } /* else FALLTHRU */
479 case WOODEN_FLUTE: /* May charm snakes */
480 do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
481 pline("%s.", Tobjnam(instr, do_spec ? "trill" : "toot"));
483 charm_snakes(u.ulevel * 3);
484 exercise(A_DEX, TRUE);
486 case FIRE_HORN: /* Idem wand of fire */
487 case FROST_HORN: /* Idem wand of cold */
488 if (do_spec && instr->spe > 0) {
489 consume_obj_charge(instr, TRUE);
491 if (!getdir((char *) 0)) {
492 pline("%s.", Tobjnam(instr, "vibrate"));
494 } else if (!u.dx && !u.dy && !u.dz) {
495 if ((damage = zapyourself(instr, TRUE)) != 0) {
498 Sprintf(buf, "using a magical horn on %sself", uhim());
499 losehp(damage, buf, KILLED_BY); /* fire or frost damage */
502 buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1,
503 rn1(6, 6), u.ux, u.uy, u.dx, u.dy);
505 makeknown(instr->otyp);
507 } /* else FALLTHRU */
508 case TOOLED_HORN: /* Awaken or scare monsters */
509 You("produce a frightful, grave sound.");
510 awaken_monsters(u.ulevel * 30);
511 exercise(A_WIS, FALSE);
513 case BUGLE: /* Awaken & attract soldiers */
514 You("extract a loud noise from %s.", the(xname(instr)));
515 awaken_soldiers(&youmonst);
516 exercise(A_WIS, FALSE);
518 case MAGIC_HARP: /* Charm monsters */
519 if (do_spec && instr->spe > 0) {
520 consume_obj_charge(instr, TRUE);
522 pline("%s very attractive music.", Tobjnam(instr, "produce"));
523 charm_monsters((u.ulevel - 1) / 3 + 1);
524 exercise(A_DEX, TRUE);
526 } /* else FALLTHRU */
527 case WOODEN_HARP: /* May calm Nymph */
528 do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
529 pline("%s %s.", The(xname(instr)),
530 do_spec ? "produces a lilting melody" : "twangs");
532 calm_nymphs(u.ulevel * 3);
533 exercise(A_DEX, TRUE);
535 case DRUM_OF_EARTHQUAKE: /* create several pits */
536 if (do_spec && instr->spe > 0) {
537 consume_obj_charge(instr, TRUE);
539 You("produce a heavy, thunderous rolling!");
540 pline_The("entire dungeon is shaking around you!");
541 do_earthquake((u.ulevel - 1) / 3 + 1);
542 /* shake up monsters in a much larger radius... */
543 awaken_monsters(ROWNO * COLNO);
544 makeknown(DRUM_OF_EARTHQUAKE);
546 } /* else FALLTHRU */
547 case LEATHER_DRUM: /* Awaken monsters */
548 You("beat a deafening row!");
549 awaken_monsters(u.ulevel * 40);
550 incr_itimeout(&HDeaf, rn1(20, 30));
551 exercise(A_WIS, FALSE);
554 impossible("What a weird instrument (%d)!", instr->otyp);
557 return 2; /* That takes time */
561 * So you want music...
564 do_play_instrument(instr)
567 char buf[BUFSZ], c = 'y';
573 You_cant("play music underwater!");
575 } else if ((instr->otyp == WOODEN_FLUTE || instr->otyp == MAGIC_FLUTE
576 || instr->otyp == TOOLED_HORN || instr->otyp == FROST_HORN
577 || instr->otyp == FIRE_HORN || instr->otyp == BUGLE)
578 && !can_blow(&youmonst)) {
579 You("are incapable of playing %s.", the(distant_name(instr, xname)));
582 if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) {
583 c = ynq("Improvise?");
588 if (u.uevent.uheard_tune == 2)
589 c = ynq("Play the passtune?");
592 } else if (c == 'y') {
595 getlin("What tune are you playing? [5 notes, A-G]", buf);
596 (void) mungspaces(buf);
600 /* convert to uppercase and change any "H" to the expected "B" */
601 for (s = buf; *s; s++) {
605 /* The AMIGA supports two octaves of notes */
613 You("extract a strange sound from %s!", the(xname(instr)));
615 /* if user is at the console, play through the console speaker */
620 if (sco_flag_console)
624 mac_speaker(instr, buf);
627 pc_speaker(instr, buf);
634 for (i = 0; buf[i] && i < 5; ++i) {
635 nbuf[i * 2] = buf[i];
636 nbuf[(i * 2) + 1] = 'h';
639 amii_speaker(instr, nbuf, AMII_OKAY_VOLUME);
642 /* Check if there was the Stronghold drawbridge near
643 * and if the tune conforms to what we're waiting for.
645 if (Is_stronghold(&u.uz)) {
646 exercise(A_WIS, TRUE); /* just for trying */
647 if (!strcmp(buf, tune)) {
648 /* Search for the drawbridge */
649 for (y = u.uy - 1; y <= u.uy + 1; y++)
650 for (x = u.ux - 1; x <= u.ux + 1; x++)
652 if (find_drawbridge(&x, &y)) {
653 u.uevent.uheard_tune =
654 2; /* tune now fully known */
655 if (levl[x][y].typ == DRAWBRIDGE_DOWN)
656 close_drawbridge(x, y);
658 open_drawbridge(x, y);
662 if (u.uevent.uheard_tune < 1)
663 u.uevent.uheard_tune = 1;
664 /* Okay, it wasn't the right tune, but perhaps
665 * we can give the player some hints like in the
668 for (y = u.uy - 1; y <= u.uy + 1 && !ok; y++)
669 for (x = u.ux - 1; x <= u.ux + 1 && !ok; x++)
671 if (IS_DRAWBRIDGE(levl[x][y].typ)
672 || is_drawbridge_wall(x, y) >= 0)
674 if (ok) { /* There is a drawbridge near */
678 tumblers = gears = 0;
679 for (x = 0; x < 5; x++)
682 for (x = 0; x < (int) strlen(buf); x++)
684 if (buf[x] == tune[x]) {
688 for (y = 0; y < 5; y++)
689 if (!matched[y] && buf[x] == tune[y]
690 && buf[y] != tune[y]) {
698 You_hear("%d tumbler%s click and %d gear%s turn.",
699 tumblers, plur(tumblers), gears,
702 You_hear("%d tumbler%s click.", tumblers,
705 You_hear("%d gear%s turn.", gears, plur(gears));
706 /* could only get `gears == 5' by playing five
707 correct notes followed by excess; otherwise,
708 tune would have matched above */
710 u.uevent.uheard_tune = 2;
717 return do_improvisation(instr);
726 * Play audible music on the machine's speaker if appropriate.
733 * Kluge alert: This code assumes that your [34]86 has no X terminals
734 * attached and that the console tty type is AT386 (this is always true
735 * under AT&T UNIX for these boxen). The theory here is that your remote
736 * ttys will have terminal type `ansi' or something else other than
737 * `AT386' or `xterm'. We'd like to do better than this, but testing
738 * to see if we're running on the console physical terminal is quite
739 * difficult given the presence of virtual consoles and other modern
740 * UNIX impedimenta...
742 char *termtype = nh_getenv("TERM");
744 return (!strcmp(termtype, "AT386") || !strcmp(termtype, "xterm"));
753 * For this to work, you need to have installed the PD speaker-control
754 * driver for PC-compatible UNIX boxes that I (esr@snark.thyrsus.com)
755 * posted to comp.sources.unix in Feb 1990. A copy should be included
756 * with your nethack distribution.
760 if ((fd = open("/dev/speaker", 1)) != -1) {
761 /* send a prefix to modify instrumental `timbre' */
762 switch (instr->otyp) {
765 (void) write(fd, ">ol", 1); /* up one octave & lock */
770 (void) write(fd, "<<ol", 2); /* drop two octaves & lock */
773 (void) write(fd, "ol", 2); /* octave lock */
777 (void) write(fd, "l8mlol", 4); /* fast, legato, octave lock */
780 (void) write(fd, buf, strlen(buf));
784 #endif /* UNIX386MUSIC */
789 #include <sys/types.h>
790 #include <sys/console.h>
791 #include <sys/vtkd.h>
793 #define KIOC ('K' << 8)
794 #define KDMKTONE (KIOC | 8)
799 /* emit tone of frequency hz for given number of ticks */
802 unsigned int hz, ticks;
804 ioctl(0, KDMKTONE, hz | ((ticks * 10) << 16));
806 printf("TONE: %6d %6d\n", hz, ticks * 10);
811 /* rest for given number of ticks */
818 printf("REST: %6d\n", ticks * 10);
822 #include "interp.c" /* from snd86unx.shr */
829 /* emit a prefix to modify instrumental `timbre' */
831 switch (instr->otyp) {
834 playstring(">ol", 1); /* up one octave & lock */
839 playstring("<<ol", 2); /* drop two octaves & lock */
842 playstring("ol", 2); /* octave lock */
846 playstring("l8mlol", 4); /* fast, legato, octave lock */
849 playstring(buf, strlen(buf));
859 playstring(argv[1], strlen(argv[1]));
863 #endif /* VPIX_MUSIC */