OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / src / music.c
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. */
4
5 /*
6  * This file contains the different functions designed to manipulate the
7  * musical instruments and their various effects.
8  *
9  * Actually the list of instruments / effects is :
10  *
11  * (wooden) flute       may calm snakes if player has enough dexterity
12  * magic flute          may put monsters to sleep:  area of effect depends
13  *                      on player level.
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
19  *                      on player level.
20  * (wooden) harp        May calm nymph if player has enough dexterity.
21  * magic harp           Charm monsters:  area of effect depends on player
22  *                      level.
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
26  *                      called here chasms.
27  */
28
29 #include "hack.h"
30
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 *));
38
39 #ifdef UNIX386MUSIC
40 STATIC_DCL int NDECL(atconsole);
41 STATIC_DCL void FDECL(speaker, (struct obj *, char *));
42 #endif
43 #ifdef VPIX_MUSIC
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 *));
48 #endif
49 #ifdef PCMUSIC
50 void FDECL(pc_speaker, (struct obj *, char *));
51 #endif
52 #ifdef AMIGA
53 void FDECL(amii_speaker, (struct obj *, char *, int));
54 #endif
55
56 /*
57  * Wake every monster in range...
58  */
59
60 STATIC_OVL void
61 awaken_monsters(distance)
62 int distance;
63 {
64     register struct monst *mtmp;
65     register int distm;
66
67     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
68         if (DEADMONSTER(mtmp))
69             continue;
70         if ((distm = distu(mtmp->mx, mtmp->my)) < distance) {
71             mtmp->msleeping = 0;
72             mtmp->mcanmove = 1;
73             mtmp->mfrozen = 0;
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);
81         }
82     }
83 }
84
85 /*
86  * Make monsters fall asleep.  Note that they may resist the spell.
87  */
88
89 STATIC_OVL void
90 put_monsters_to_sleep(distance)
91 int distance;
92 {
93     register struct monst *mtmp;
94
95     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
96         if (DEADMONSTER(mtmp))
97             continue;
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 */
101             slept_monst(mtmp);
102         }
103     }
104 }
105
106 /*
107  * Charm snakes in range.  Note that the snakes are NOT tamed.
108  */
109
110 STATIC_OVL void
111 charm_snakes(distance)
112 int distance;
113 {
114     register struct monst *mtmp;
115     int could_see_mon, was_peaceful;
116
117     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
118         if (DEADMONSTER(mtmp))
119             continue;
120         if (mtmp->data->mlet == S_SNAKE && mtmp->mcanmove
121             && distu(mtmp->mx, mtmp->my) < distance) {
122             was_peaceful = mtmp->mpeaceful;
123             mtmp->mpeaceful = 1;
124             mtmp->mavenge = 0;
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)) {
130                 if (!could_see_mon)
131                     You("notice %s, swaying with the music.", a_monnam(mtmp));
132                 else
133                     pline("%s freezes, then sways with the music%s.",
134                           Monnam(mtmp),
135                           was_peaceful ? "" : ", and now seems quieter");
136             }
137         }
138     }
139 }
140
141 /*
142  * Calm nymphs in range.
143  */
144
145 STATIC_OVL void
146 calm_nymphs(distance)
147 int distance;
148 {
149     register struct monst *mtmp;
150
151     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
152         if (DEADMONSTER(mtmp))
153             continue;
154         if (mtmp->data->mlet == S_NYMPH && mtmp->mcanmove
155             && distu(mtmp->mx, mtmp->my) < distance) {
156             mtmp->msleeping = 0;
157             mtmp->mpeaceful = 1;
158             mtmp->mavenge = 0;
159             mtmp->mstrategy &= ~STRAT_WAITMASK;
160             if (canseemon(mtmp))
161                 pline(
162                     "%s listens cheerfully to the music, then seems quieter.",
163                       Monnam(mtmp));
164         }
165     }
166 }
167
168 /* Awake soldiers anywhere the level (and any nearby monster). */
169 void
170 awaken_soldiers(bugler)
171 struct monst *bugler; /* monster that played instrument */
172 {
173     register struct monst *mtmp;
174     int distance, distm;
175
176     /* distance of affected non-soldier monsters to bugler */
177     distance = ((bugler == &youmonst) ? u.ulevel : bugler->data->mlevel) * 30;
178
179     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
180         if (DEADMONSTER(mtmp))
181             continue;
182         if (is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) {
183             mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0;
184             mtmp->mcanmove = 1;
185             mtmp->mstrategy &= ~STRAT_WAITMASK;
186             if (canseemon(mtmp))
187                 pline("%s is now ready for battle!", Monnam(mtmp));
188             else
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) {
194             mtmp->msleeping = 0;
195             mtmp->mcanmove = 1;
196             mtmp->mfrozen = 0;
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);
204         }
205     }
206 }
207
208 /* Charm monsters in range.  Note that they may resist the spell.
209  * If swallowed, range is reduced to 0.
210  */
211 STATIC_OVL void
212 charm_monsters(distance)
213 int distance;
214 {
215     struct monst *mtmp, *mtmp2;
216
217     if (u.uswallow) {
218         if (!resist(u.ustuck, TOOL_CLASS, 0, NOTELL))
219             (void) tamedog(u.ustuck, (struct obj *) 0);
220     } else {
221         for (mtmp = fmon; mtmp; mtmp = mtmp2) {
222             mtmp2 = mtmp->nmon;
223             if (DEADMONSTER(mtmp))
224                 continue;
225
226             if (distu(mtmp->mx, mtmp->my) <= distance) {
227                 if (!resist(mtmp, TOOL_CLASS, 0, NOTELL))
228                     (void) tamedog(mtmp, (struct obj *) 0);
229             }
230         }
231     }
232 }
233
234 /* Generate earthquake :-) of desired force.
235  * That is:  create random chasms (pits).
236  */
237 STATIC_OVL void
238 do_earthquake(force)
239 int force;
240 {
241     register int x, y;
242     struct monst *mtmp;
243     struct obj *otmp;
244     struct trap *chasm, *trap_at_u = t_at(u.ux, u.uy);
245     int start_x, start_y, end_x, end_y;
246     schar filltype;
247     unsigned tu_pit = 0;
248
249     if (trap_at_u)
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);
255     if (start_x < 1)
256         start_x = 1;
257     if (start_y < 1)
258         start_y = 1;
259     if (end_x >= COLNO)
260         end_x = COLNO - 1;
261     if (end_y >= ROWNO)
262         end_y = ROWNO - 1;
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;
269                     if (cansee(x, y))
270                         pline("%s is shaken loose from the ceiling!",
271                               Amonnam(mtmp));
272                     else
273                         You_hear("a thumping sound.");
274                     if (x == u.ux && y == u.uy)
275                         You("easily dodge the falling %s.", mon_nam(mtmp));
276                     newsym(x, y);
277                 }
278             }
279             if (!rn2(14 - force))
280                 switch (levl[x][y].typ) {
281                 case FOUNTAIN: /* Make the fountain disappear */
282                     if (cansee(x, y))
283                         pline_The("fountain falls into a chasm.");
284                     goto do_pit;
285                 case SINK:
286                     if (cansee(x, y))
287                         pline_The("kitchen sink falls into a chasm.");
288                     goto do_pit;
289                 case ALTAR:
290                     if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))
291                         break;
292
293                     if (cansee(x, y))
294                         pline_The("altar falls into a chasm.");
295                     goto do_pit;
296                 case GRAVE:
297                     if (cansee(x, y))
298                         pline_The("headstone topples into a chasm.");
299                     goto do_pit;
300                 case THRONE:
301                     if (cansee(x, y))
302                         pline_The("throne falls into a chasm.");
303                 /* Falls into next case */
304                 case ROOM:
305                 case CORR: /* Try to make a pit */
306                 do_pit:
307                     chasm = maketrap(x, y, PIT);
308                     if (!chasm)
309                         break; /* no pit if portal at that location */
310                     chasm->tseen = 1;
311
312                     levl[x][y].doormask = 0;
313                     /*
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.
317                      */
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);
322                     }
323
324                     mtmp = m_at(x, y);
325
326                     if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
327                         if (cansee(x, y))
328                             pline("KADOOM! The boulder falls into a chasm%s!",
329                                   ((x == u.ux) && (y == u.uy)) ? " below you"
330                                                                : "");
331                         if (mtmp)
332                             mtmp->mtrapped = 0;
333                         obj_extract_self(otmp);
334                         (void) flooreffects(otmp, x, y, "");
335                         break;
336                     }
337
338                     /* We have to check whether monsters or player
339                        falls in a chasm... */
340                     if (mtmp) {
341                         if (!is_flyer(mtmp->data)
342                             && !is_clinger(mtmp->data)) {
343                             boolean m_already_trapped = mtmp->mtrapped;
344                             mtmp->mtrapped = 1;
345                             if (!m_already_trapped) { /* suppress messages */
346                                 if (cansee(x, y))
347                                     pline("%s falls into a chasm!",
348                                           Monnam(mtmp));
349                                 else if (humanoid(mtmp->data))
350                                     You_hear("a scream!");
351                             }
352                             /* Falling is okay for falling down
353                                 within a pit from jostling too */
354                             mselftouch(mtmp, "Falling, ", TRUE);
355                             if (mtmp->mhp > 0)
356                                 if ((mtmp->mhp -=
357                                      rnd(m_already_trapped ? 4 : 6)) <= 0) {
358                                     if (!cansee(x, y))
359                                         pline("It is destroyed!");
360                                     else {
361                                         You("destroy %s!",
362                                             mtmp->mtame
363                                                 ? x_monnam(
364                                                       mtmp, ARTICLE_THE,
365                                                       "poor",
366                                                       (has_mname(mtmp))
367                                                           ? SUPPRESS_SADDLE
368                                                           : 0,
369                                                       FALSE)
370                                                 : mon_nam(mtmp));
371                                     }
372                                     xkilled(mtmp, 0);
373                                 }
374                         }
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!");
381                             }
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!");
387                             u.utrap = rn1(6, 2);
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!");
398                             u.utrap = rn1(6, 2);
399                             u.utraptype = TT_PIT; /* superfluous */
400                             losehp(Maybe_Half_Phys(rnd(keepfooting ? 2 : 4)),
401                                    "hurt in a chasm", NO_KILLER_PREFIX);
402                             if (keepfooting)
403                                 exercise(A_DEX, TRUE);
404                             else
405                                 selftouch(
406                                     (Upolyd && (slithy(youmonst.data)
407                                                 || nolimbs(youmonst.data)))
408                                         ? "Shaken, you"
409                                         : "Falling down, you");
410                         }
411                     } else
412                         newsym(x, y);
413                     break;
414                 case DOOR: /* Make the door collapse */
415                     if (levl[x][y].doormask == D_NODOOR)
416                         goto do_pit;
417                     if (cansee(x, y))
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;
422                     unblock_point(x, y);
423                     newsym(x, y);
424                     break;
425                 }
426         }
427 }
428
429 /*
430  * The player is trying to extract something from his/her instrument.
431  */
432 STATIC_OVL int
433 do_improvisation(instr)
434 struct obj *instr;
435 {
436     int damage, do_spec = !Confusion;
437 #if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined(PCMUSIC)
438     struct obj itmp;
439
440     itmp = *instr;
441     itmp.oextra = (struct oextra *) 0; /* ok on this copy as instr maintains
442                                           the ptr to free at some point if
443                                           there is one */
444
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)
448             itmp.otyp -= 1;
449 #ifdef MAC
450     mac_speaker(&itmp, "C");
451 #endif
452 #ifdef AMIGA
453     amii_speaker(&itmp, "Cw", AMII_OKAY_VOLUME);
454 #endif
455 #ifdef VPIX_MUSIC
456     if (sco_flag_console)
457         speaker(&itmp, "C");
458 #endif
459 #ifdef PCMUSIC
460     pc_speaker(&itmp, "C");
461 #endif
462 #endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */
463
464     if (!do_spec)
465         pline("What you produce is quite far from music...");
466     else
467         You("start playing %s.", the(xname(instr)));
468
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);
473
474             You("produce %s music.", Hallucination ? "piped" : "soft");
475             put_monsters_to_sleep(u.ulevel * 5);
476             exercise(A_DEX, TRUE);
477             break;
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"));
482         if (do_spec)
483             charm_snakes(u.ulevel * 3);
484         exercise(A_DEX, TRUE);
485         break;
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);
490
491             if (!getdir((char *) 0)) {
492                 pline("%s.", Tobjnam(instr, "vibrate"));
493                 break;
494             } else if (!u.dx && !u.dy && !u.dz) {
495                 if ((damage = zapyourself(instr, TRUE)) != 0) {
496                     char buf[BUFSZ];
497
498                     Sprintf(buf, "using a magical horn on %sself", uhim());
499                     losehp(damage, buf, KILLED_BY); /* fire or frost damage */
500                 }
501             } else {
502                 buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1,
503                      rn1(6, 6), u.ux, u.uy, u.dx, u.dy);
504             }
505             makeknown(instr->otyp);
506             break;
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);
512         break;
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);
517         break;
518     case MAGIC_HARP: /* Charm monsters */
519         if (do_spec && instr->spe > 0) {
520             consume_obj_charge(instr, TRUE);
521
522             pline("%s very attractive music.", Tobjnam(instr, "produce"));
523             charm_monsters((u.ulevel - 1) / 3 + 1);
524             exercise(A_DEX, TRUE);
525             break;
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");
531         if (do_spec)
532             calm_nymphs(u.ulevel * 3);
533         exercise(A_DEX, TRUE);
534         break;
535     case DRUM_OF_EARTHQUAKE: /* create several pits */
536         if (do_spec && instr->spe > 0) {
537             consume_obj_charge(instr, TRUE);
538
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);
545             break;
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);
552         break;
553     default:
554         impossible("What a weird instrument (%d)!", instr->otyp);
555         break;
556     }
557     return 2; /* That takes time */
558 }
559
560 /*
561  * So you want music...
562  */
563 int
564 do_play_instrument(instr)
565 struct obj *instr;
566 {
567     char buf[BUFSZ], c = 'y';
568     char *s;
569     int x, y;
570     boolean ok;
571
572     if (Underwater) {
573         You_cant("play music underwater!");
574         return 0;
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)));
580         return 0;
581     }
582     if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) {
583         c = ynq("Improvise?");
584         if (c == 'q')
585             goto nevermind;
586     }
587     if (c == 'n') {
588         if (u.uevent.uheard_tune == 2)
589             c = ynq("Play the passtune?");
590         if (c == 'q') {
591             goto nevermind;
592         } else if (c == 'y') {
593             Strcpy(buf, tune);
594         } else {
595             getlin("What tune are you playing? [5 notes, A-G]", buf);
596             (void) mungspaces(buf);
597             if (*buf == '\033')
598                 goto nevermind;
599
600             /* convert to uppercase and change any "H" to the expected "B" */
601             for (s = buf; *s; s++) {
602 #ifndef AMIGA
603                 *s = highc(*s);
604 #else
605                 /* The AMIGA supports two octaves of notes */
606                 if (*s == 'h')
607                     *s = 'b';
608 #endif
609                 if (*s == 'H')
610                     *s = 'B';
611             }
612         }
613         You("extract a strange sound from %s!", the(xname(instr)));
614 #ifdef UNIX386MUSIC
615         /* if user is at the console, play through the console speaker */
616         if (atconsole())
617             speaker(instr, buf);
618 #endif
619 #ifdef VPIX_MUSIC
620         if (sco_flag_console)
621             speaker(instr, buf);
622 #endif
623 #ifdef MAC
624         mac_speaker(instr, buf);
625 #endif
626 #ifdef PCMUSIC
627         pc_speaker(instr, buf);
628 #endif
629 #ifdef AMIGA
630         {
631             char nbuf[20];
632             int i;
633
634             for (i = 0; buf[i] && i < 5; ++i) {
635                 nbuf[i * 2] = buf[i];
636                 nbuf[(i * 2) + 1] = 'h';
637             }
638             nbuf[i * 2] = 0;
639             amii_speaker(instr, nbuf, AMII_OKAY_VOLUME);
640         }
641 #endif
642         /* Check if there was the Stronghold drawbridge near
643          * and if the tune conforms to what we're waiting for.
644          */
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++)
651                         if (isok(x, y))
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);
657                                 else
658                                     open_drawbridge(x, y);
659                                 return 1;
660                             }
661             } else if (!Deaf) {
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
666                  * Mastermind game */
667                 ok = FALSE;
668                 for (y = u.uy - 1; y <= u.uy + 1 && !ok; y++)
669                     for (x = u.ux - 1; x <= u.ux + 1 && !ok; x++)
670                         if (isok(x, y))
671                             if (IS_DRAWBRIDGE(levl[x][y].typ)
672                                 || is_drawbridge_wall(x, y) >= 0)
673                                 ok = TRUE;
674                 if (ok) { /* There is a drawbridge near */
675                     int tumblers, gears;
676                     boolean matched[5];
677
678                     tumblers = gears = 0;
679                     for (x = 0; x < 5; x++)
680                         matched[x] = FALSE;
681
682                     for (x = 0; x < (int) strlen(buf); x++)
683                         if (x < 5) {
684                             if (buf[x] == tune[x]) {
685                                 gears++;
686                                 matched[x] = TRUE;
687                             } else
688                                 for (y = 0; y < 5; y++)
689                                     if (!matched[y] && buf[x] == tune[y]
690                                         && buf[y] != tune[y]) {
691                                         tumblers++;
692                                         matched[y] = TRUE;
693                                         break;
694                                     }
695                         }
696                     if (tumblers)
697                         if (gears)
698                             You_hear("%d tumbler%s click and %d gear%s turn.",
699                                      tumblers, plur(tumblers), gears,
700                                      plur(gears));
701                         else
702                             You_hear("%d tumbler%s click.", tumblers,
703                                      plur(tumblers));
704                     else if (gears) {
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 */
709                         if (gears == 5)
710                             u.uevent.uheard_tune = 2;
711                     }
712                 }
713             }
714         }
715         return 1;
716     } else
717         return do_improvisation(instr);
718
719 nevermind:
720     pline1(Never_mind);
721     return 0;
722 }
723
724 #ifdef UNIX386MUSIC
725 /*
726  * Play audible music on the machine's speaker if appropriate.
727  */
728
729 STATIC_OVL int
730 atconsole()
731 {
732     /*
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...
741      */
742     char *termtype = nh_getenv("TERM");
743
744     return (!strcmp(termtype, "AT386") || !strcmp(termtype, "xterm"));
745 }
746
747 STATIC_OVL void
748 speaker(instr, buf)
749 struct obj *instr;
750 char *buf;
751 {
752     /*
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.
757      */
758     int fd;
759
760     if ((fd = open("/dev/speaker", 1)) != -1) {
761         /* send a prefix to modify instrumental `timbre' */
762         switch (instr->otyp) {
763         case WOODEN_FLUTE:
764         case MAGIC_FLUTE:
765             (void) write(fd, ">ol", 1); /* up one octave & lock */
766             break;
767         case TOOLED_HORN:
768         case FROST_HORN:
769         case FIRE_HORN:
770             (void) write(fd, "<<ol", 2); /* drop two octaves & lock */
771             break;
772         case BUGLE:
773             (void) write(fd, "ol", 2); /* octave lock */
774             break;
775         case WOODEN_HARP:
776         case MAGIC_HARP:
777             (void) write(fd, "l8mlol", 4); /* fast, legato, octave lock */
778             break;
779         }
780         (void) write(fd, buf, strlen(buf));
781         (void) nhclose(fd);
782     }
783 }
784 #endif /* UNIX386MUSIC */
785
786 #ifdef VPIX_MUSIC
787
788 #if 0
789 #include <sys/types.h>
790 #include <sys/console.h>
791 #include <sys/vtkd.h>
792 #else
793 #define KIOC ('K' << 8)
794 #define KDMKTONE (KIOC | 8)
795 #endif
796
797 #define noDEBUG
798
799 /* emit tone of frequency hz for given number of ticks */
800 STATIC_OVL void
801 tone(hz, ticks)
802 unsigned int hz, ticks;
803 {
804     ioctl(0, KDMKTONE, hz | ((ticks * 10) << 16));
805 #ifdef DEBUG
806     printf("TONE: %6d %6d\n", hz, ticks * 10);
807 #endif
808     nap(ticks * 10);
809 }
810
811 /* rest for given number of ticks */
812 STATIC_OVL void
813 rest(ticks)
814 int ticks;
815 {
816     nap(ticks * 10);
817 #ifdef DEBUG
818     printf("REST:        %6d\n", ticks * 10);
819 #endif
820 }
821
822 #include "interp.c" /* from snd86unx.shr */
823
824 STATIC_OVL void
825 speaker(instr, buf)
826 struct obj *instr;
827 char *buf;
828 {
829     /* emit a prefix to modify instrumental `timbre' */
830     playinit();
831     switch (instr->otyp) {
832     case WOODEN_FLUTE:
833     case MAGIC_FLUTE:
834         playstring(">ol", 1); /* up one octave & lock */
835         break;
836     case TOOLED_HORN:
837     case FROST_HORN:
838     case FIRE_HORN:
839         playstring("<<ol", 2); /* drop two octaves & lock */
840         break;
841     case BUGLE:
842         playstring("ol", 2); /* octave lock */
843         break;
844     case WOODEN_HARP:
845     case MAGIC_HARP:
846         playstring("l8mlol", 4); /* fast, legato, octave lock */
847         break;
848     }
849     playstring(buf, strlen(buf));
850 }
851
852 #ifdef VPIX_DEBUG
853 main(argc, argv)
854 int argc;
855 char *argv[];
856 {
857     if (argc == 2) {
858         playinit();
859         playstring(argv[1], strlen(argv[1]));
860     }
861 }
862 #endif
863 #endif /* VPIX_MUSIC */
864
865 /*music.c*/