1 /* NetHack 3.6 music.c $NHDT-Date: 1452660194 2016/01/13 04:43:14 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.42 $ */
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
, TRUE
); /* 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
);
356 mtmp
->mhp
-= rnd(m_already_trapped
? 4 : 6);
357 if (mtmp
->mhp
<= 0) {
359 pline("It is destroyed!");
363 ? x_monnam(mtmp
, ARTICLE_THE
,
371 xkilled(mtmp
, XKILL_NOMSG
);
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
;
432 if (Is_astralevel(&u
.uz
))
433 return "astral plane";
434 else if (In_endgame(&u
.uz
))
436 else if (Is_sanctum(&u
.uz
))
438 else if (In_sokoban(&u
.uz
))
440 else if (In_V_tower(&u
.uz
))
447 * The player is trying to extract something from his/her instrument.
450 do_improvisation(instr
)
453 int damage
, do_spec
= !Confusion
;
454 #if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined(PCMUSIC)
458 itmp
.oextra
= (struct oextra
*) 0; /* ok on this copy as instr maintains
459 the ptr to free at some point if
462 /* if won't yield special effect, make sound of mundane counterpart */
463 if (!do_spec
|| instr
->spe
<= 0)
464 while (objects
[itmp
.otyp
].oc_magic
)
467 mac_speaker(&itmp
, "C");
470 amii_speaker(&itmp
, "Cw", AMII_OKAY_VOLUME
);
473 if (sco_flag_console
)
477 pc_speaker(&itmp
, "C");
479 #endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */
482 pline("What you produce is quite far from music...");
484 You("start playing %s.", the(xname(instr
)));
486 switch (instr
->otyp
) {
487 case MAGIC_FLUTE
: /* Make monster fall asleep */
488 if (do_spec
&& instr
->spe
> 0) {
489 consume_obj_charge(instr
, TRUE
);
491 You("produce %s music.", Hallucination
? "piped" : "soft");
492 put_monsters_to_sleep(u
.ulevel
* 5);
493 exercise(A_DEX
, TRUE
);
495 } /* else FALLTHRU */
496 case WOODEN_FLUTE
: /* May charm snakes */
497 do_spec
&= (rn2(ACURR(A_DEX
)) + u
.ulevel
> 25);
498 pline("%s.", Tobjnam(instr
, do_spec
? "trill" : "toot"));
500 charm_snakes(u
.ulevel
* 3);
501 exercise(A_DEX
, TRUE
);
503 case FIRE_HORN
: /* Idem wand of fire */
504 case FROST_HORN
: /* Idem wand of cold */
505 if (do_spec
&& instr
->spe
> 0) {
506 consume_obj_charge(instr
, TRUE
);
508 if (!getdir((char *) 0)) {
509 pline("%s.", Tobjnam(instr
, "vibrate"));
511 } else if (!u
.dx
&& !u
.dy
&& !u
.dz
) {
512 if ((damage
= zapyourself(instr
, TRUE
)) != 0) {
515 Sprintf(buf
, "using a magical horn on %sself", uhim());
516 losehp(damage
, buf
, KILLED_BY
); /* fire or frost damage */
519 buzz((instr
->otyp
== FROST_HORN
) ? AD_COLD
- 1 : AD_FIRE
- 1,
520 rn1(6, 6), u
.ux
, u
.uy
, u
.dx
, u
.dy
);
522 makeknown(instr
->otyp
);
524 } /* else FALLTHRU */
525 case TOOLED_HORN
: /* Awaken or scare monsters */
526 You("produce a frightful, grave sound.");
527 awaken_monsters(u
.ulevel
* 30);
528 exercise(A_WIS
, FALSE
);
530 case BUGLE
: /* Awaken & attract soldiers */
531 You("extract a loud noise from %s.", the(xname(instr
)));
532 awaken_soldiers(&youmonst
);
533 exercise(A_WIS
, FALSE
);
535 case MAGIC_HARP
: /* Charm monsters */
536 if (do_spec
&& instr
->spe
> 0) {
537 consume_obj_charge(instr
, TRUE
);
539 pline("%s very attractive music.", Tobjnam(instr
, "produce"));
540 charm_monsters((u
.ulevel
- 1) / 3 + 1);
541 exercise(A_DEX
, TRUE
);
543 } /* else FALLTHRU */
544 case WOODEN_HARP
: /* May calm Nymph */
545 do_spec
&= (rn2(ACURR(A_DEX
)) + u
.ulevel
> 25);
546 pline("%s %s.", The(xname(instr
)),
547 do_spec
? "produces a lilting melody" : "twangs");
549 calm_nymphs(u
.ulevel
* 3);
550 exercise(A_DEX
, TRUE
);
552 case DRUM_OF_EARTHQUAKE
: /* create several pits */
553 if (do_spec
&& instr
->spe
> 0) {
554 consume_obj_charge(instr
, TRUE
);
556 You("produce a heavy, thunderous rolling!");
557 pline_The("entire %s is shaking around you!",
559 do_earthquake((u
.ulevel
- 1) / 3 + 1);
560 /* shake up monsters in a much larger radius... */
561 awaken_monsters(ROWNO
* COLNO
);
562 makeknown(DRUM_OF_EARTHQUAKE
);
564 } /* else FALLTHRU */
565 case LEATHER_DRUM
: /* Awaken monsters */
566 You("beat a deafening row!");
567 awaken_monsters(u
.ulevel
* 40);
568 incr_itimeout(&HDeaf
, rn1(20, 30));
569 exercise(A_WIS
, FALSE
);
573 impossible("What a weird instrument (%d)!", instr
->otyp
);
576 return 2; /* That takes time */
580 * So you want music...
583 do_play_instrument(instr
)
586 char buf
[BUFSZ
], c
= 'y';
592 You_cant("play music underwater!");
594 } else if ((instr
->otyp
== WOODEN_FLUTE
|| instr
->otyp
== MAGIC_FLUTE
595 || instr
->otyp
== TOOLED_HORN
|| instr
->otyp
== FROST_HORN
596 || instr
->otyp
== FIRE_HORN
|| instr
->otyp
== BUGLE
)
597 && !can_blow(&youmonst
)) {
598 You("are incapable of playing %s.", the(distant_name(instr
, xname
)));
601 if (instr
->otyp
!= LEATHER_DRUM
&& instr
->otyp
!= DRUM_OF_EARTHQUAKE
) {
602 c
= ynq("Improvise?");
607 if (u
.uevent
.uheard_tune
== 2)
608 c
= ynq("Play the passtune?");
611 } else if (c
== 'y') {
614 getlin("What tune are you playing? [5 notes, A-G]", buf
);
615 (void) mungspaces(buf
);
619 /* convert to uppercase and change any "H" to the expected "B" */
620 for (s
= buf
; *s
; s
++) {
624 /* The AMIGA supports two octaves of notes */
632 You("extract a strange sound from %s!", the(xname(instr
)));
634 /* if user is at the console, play through the console speaker */
639 if (sco_flag_console
)
643 mac_speaker(instr
, buf
);
646 pc_speaker(instr
, buf
);
653 for (i
= 0; buf
[i
] && i
< 5; ++i
) {
654 nbuf
[i
* 2] = buf
[i
];
655 nbuf
[(i
* 2) + 1] = 'h';
658 amii_speaker(instr
, nbuf
, AMII_OKAY_VOLUME
);
661 /* Check if there was the Stronghold drawbridge near
662 * and if the tune conforms to what we're waiting for.
664 if (Is_stronghold(&u
.uz
)) {
665 exercise(A_WIS
, TRUE
); /* just for trying */
666 if (!strcmp(buf
, tune
)) {
667 /* Search for the drawbridge */
668 for (y
= u
.uy
- 1; y
<= u
.uy
+ 1; y
++)
669 for (x
= u
.ux
- 1; x
<= u
.ux
+ 1; x
++)
671 if (find_drawbridge(&x
, &y
)) {
672 u
.uevent
.uheard_tune
=
673 2; /* tune now fully known */
674 if (levl
[x
][y
].typ
== DRAWBRIDGE_DOWN
)
675 close_drawbridge(x
, y
);
677 open_drawbridge(x
, y
);
681 if (u
.uevent
.uheard_tune
< 1)
682 u
.uevent
.uheard_tune
= 1;
683 /* Okay, it wasn't the right tune, but perhaps
684 * we can give the player some hints like in the
687 for (y
= u
.uy
- 1; y
<= u
.uy
+ 1 && !ok
; y
++)
688 for (x
= u
.ux
- 1; x
<= u
.ux
+ 1 && !ok
; x
++)
690 if (IS_DRAWBRIDGE(levl
[x
][y
].typ
)
691 || is_drawbridge_wall(x
, y
) >= 0)
693 if (ok
) { /* There is a drawbridge near */
697 tumblers
= gears
= 0;
698 for (x
= 0; x
< 5; x
++)
701 for (x
= 0; x
< (int) strlen(buf
); x
++)
703 if (buf
[x
] == tune
[x
]) {
707 for (y
= 0; y
< 5; y
++)
708 if (!matched
[y
] && buf
[x
] == tune
[y
]
709 && buf
[y
] != tune
[y
]) {
717 You_hear("%d tumbler%s click and %d gear%s turn.",
718 tumblers
, plur(tumblers
), gears
,
721 You_hear("%d tumbler%s click.", tumblers
,
724 You_hear("%d gear%s turn.", gears
, plur(gears
));
725 /* could only get `gears == 5' by playing five
726 correct notes followed by excess; otherwise,
727 tune would have matched above */
729 u
.uevent
.uheard_tune
= 2;
736 return do_improvisation(instr
);
745 * Play audible music on the machine's speaker if appropriate.
752 * Kluge alert: This code assumes that your [34]86 has no X terminals
753 * attached and that the console tty type is AT386 (this is always true
754 * under AT&T UNIX for these boxen). The theory here is that your remote
755 * ttys will have terminal type `ansi' or something else other than
756 * `AT386' or `xterm'. We'd like to do better than this, but testing
757 * to see if we're running on the console physical terminal is quite
758 * difficult given the presence of virtual consoles and other modern
759 * UNIX impedimenta...
761 char *termtype
= nh_getenv("TERM");
763 return (!strcmp(termtype
, "AT386") || !strcmp(termtype
, "xterm"));
772 * For this to work, you need to have installed the PD speaker-control
773 * driver for PC-compatible UNIX boxes that I (esr@snark.thyrsus.com)
774 * posted to comp.sources.unix in Feb 1990. A copy should be included
775 * with your nethack distribution.
779 if ((fd
= open("/dev/speaker", 1)) != -1) {
780 /* send a prefix to modify instrumental `timbre' */
781 switch (instr
->otyp
) {
784 (void) write(fd
, ">ol", 1); /* up one octave & lock */
789 (void) write(fd
, "<<ol", 2); /* drop two octaves & lock */
792 (void) write(fd
, "ol", 2); /* octave lock */
796 (void) write(fd
, "l8mlol", 4); /* fast, legato, octave lock */
799 (void) write(fd
, buf
, strlen(buf
));
803 #endif /* UNIX386MUSIC */
808 #include <sys/types.h>
809 #include <sys/console.h>
810 #include <sys/vtkd.h>
812 #define KIOC ('K' << 8)
813 #define KDMKTONE (KIOC | 8)
818 /* emit tone of frequency hz for given number of ticks */
821 unsigned int hz
, ticks
;
823 ioctl(0, KDMKTONE
, hz
| ((ticks
* 10) << 16));
825 printf("TONE: %6d %6d\n", hz
, ticks
* 10);
830 /* rest for given number of ticks */
837 printf("REST: %6d\n", ticks
* 10);
841 #include "interp.c" /* from snd86unx.shr */
848 /* emit a prefix to modify instrumental `timbre' */
850 switch (instr
->otyp
) {
853 playstring(">ol", 1); /* up one octave & lock */
858 playstring("<<ol", 2); /* drop two octaves & lock */
861 playstring("ol", 2); /* octave lock */
865 playstring("l8mlol", 4); /* fast, legato, octave lock */
868 playstring(buf
, strlen(buf
));
878 playstring(argv
[1], strlen(argv
[1]));
882 #endif /* VPIX_MUSIC */