NetHack->aNetHack
[aNetHack.git] / src / music.c
blob75ab39d4d5abf155d5774e545ed7ff823d62e509
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. */
5 /*
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
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.
29 #include "hack.h"
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 *));
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
57 * Wake every monster in range...
60 STATIC_OVL void
61 awaken_monsters(distance)
62 int distance;
64 register struct monst *mtmp;
65 register int distm;
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);
86 * Make monsters fall asleep. Note that they may resist the spell.
89 STATIC_OVL void
90 put_monsters_to_sleep(distance)
91 int distance;
93 register struct monst *mtmp;
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);
107 * Charm snakes in range. Note that the snakes are NOT tamed.
110 STATIC_OVL void
111 charm_snakes(distance)
112 int 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))
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");
142 * Calm nymphs in range.
145 STATIC_OVL void
146 calm_nymphs(distance)
147 int distance;
149 register struct monst *mtmp;
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));
168 /* Awake soldiers anywhere the level (and any nearby monster). */
169 void
170 awaken_soldiers(bugler)
171 struct monst *bugler; /* monster that played instrument */
173 register struct monst *mtmp;
174 int distance, distm;
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))
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);
208 /* Charm monsters in range. Note that they may resist the spell.
209 * If swallowed, range is reduced to 0.
211 STATIC_OVL void
212 charm_monsters(distance)
213 int distance;
215 struct monst *mtmp, *mtmp2;
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;
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).
237 STATIC_OVL void
238 do_earthquake(force)
239 int force;
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;
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, TRUE); /* 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);
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;
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;
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);
324 mtmp = m_at(x, y);
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;
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!");
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 mtmp->mhp -= rnd(m_already_trapped ? 4 : 6);
357 if (mtmp->mhp <= 0) {
358 if (!cansee(x, y)) {
359 pline("It is destroyed!");
360 } else {
361 You("destroy %s!",
362 mtmp->mtame
363 ? x_monnam(mtmp, ARTICLE_THE,
364 "poor",
365 has_mname(mtmp)
366 ? SUPPRESS_SADDLE
367 : 0,
368 FALSE)
369 : mon_nam(mtmp));
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!");
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");
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;
429 const char *
430 generic_lvl_desc()
432 if (Is_astralevel(&u.uz))
433 return "astral plane";
434 else if (In_endgame(&u.uz))
435 return "plane";
436 else if (Is_sanctum(&u.uz))
437 return "sanctum";
438 else if (In_sokoban(&u.uz))
439 return "puzzle";
440 else if (In_V_tower(&u.uz))
441 return "tower";
442 else
443 return "dungeon";
447 * The player is trying to extract something from his/her instrument.
449 STATIC_OVL int
450 do_improvisation(instr)
451 struct obj *instr;
453 int damage, do_spec = !Confusion;
454 #if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined(PCMUSIC)
455 struct obj itmp;
457 itmp = *instr;
458 itmp.oextra = (struct oextra *) 0; /* ok on this copy as instr maintains
459 the ptr to free at some point if
460 there is one */
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)
465 itmp.otyp -= 1;
466 #ifdef MAC
467 mac_speaker(&itmp, "C");
468 #endif
469 #ifdef AMIGA
470 amii_speaker(&itmp, "Cw", AMII_OKAY_VOLUME);
471 #endif
472 #ifdef VPIX_MUSIC
473 if (sco_flag_console)
474 speaker(&itmp, "C");
475 #endif
476 #ifdef PCMUSIC
477 pc_speaker(&itmp, "C");
478 #endif
479 #endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */
481 if (!do_spec)
482 pline("What you produce is quite far from music...");
483 else
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);
494 break;
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"));
499 if (do_spec)
500 charm_snakes(u.ulevel * 3);
501 exercise(A_DEX, TRUE);
502 break;
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"));
510 break;
511 } else if (!u.dx && !u.dy && !u.dz) {
512 if ((damage = zapyourself(instr, TRUE)) != 0) {
513 char buf[BUFSZ];
515 Sprintf(buf, "using a magical horn on %sself", uhim());
516 losehp(damage, buf, KILLED_BY); /* fire or frost damage */
518 } else {
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);
523 break;
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);
529 break;
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);
534 break;
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);
542 break;
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");
548 if (do_spec)
549 calm_nymphs(u.ulevel * 3);
550 exercise(A_DEX, TRUE);
551 break;
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!",
558 generic_lvl_desc());
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);
563 break;
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);
570 context.botl = TRUE;
571 break;
572 default:
573 impossible("What a weird instrument (%d)!", instr->otyp);
574 break;
576 return 2; /* That takes time */
580 * So you want music...
583 do_play_instrument(instr)
584 struct obj *instr;
586 char buf[BUFSZ], c = 'y';
587 char *s;
588 int x, y;
589 boolean ok;
591 if (Underwater) {
592 You_cant("play music underwater!");
593 return 0;
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)));
599 return 0;
601 if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) {
602 c = ynq("Improvise?");
603 if (c == 'q')
604 goto nevermind;
606 if (c == 'n') {
607 if (u.uevent.uheard_tune == 2)
608 c = ynq("Play the passtune?");
609 if (c == 'q') {
610 goto nevermind;
611 } else if (c == 'y') {
612 Strcpy(buf, tune);
613 } else {
614 getlin("What tune are you playing? [5 notes, A-G]", buf);
615 (void) mungspaces(buf);
616 if (*buf == '\033')
617 goto nevermind;
619 /* convert to uppercase and change any "H" to the expected "B" */
620 for (s = buf; *s; s++) {
621 #ifndef AMIGA
622 *s = highc(*s);
623 #else
624 /* The AMIGA supports two octaves of notes */
625 if (*s == 'h')
626 *s = 'b';
627 #endif
628 if (*s == 'H')
629 *s = 'B';
632 You("extract a strange sound from %s!", the(xname(instr)));
633 #ifdef UNIX386MUSIC
634 /* if user is at the console, play through the console speaker */
635 if (atconsole())
636 speaker(instr, buf);
637 #endif
638 #ifdef VPIX_MUSIC
639 if (sco_flag_console)
640 speaker(instr, buf);
641 #endif
642 #ifdef MAC
643 mac_speaker(instr, buf);
644 #endif
645 #ifdef PCMUSIC
646 pc_speaker(instr, buf);
647 #endif
648 #ifdef AMIGA
650 char nbuf[20];
651 int i;
653 for (i = 0; buf[i] && i < 5; ++i) {
654 nbuf[i * 2] = buf[i];
655 nbuf[(i * 2) + 1] = 'h';
657 nbuf[i * 2] = 0;
658 amii_speaker(instr, nbuf, AMII_OKAY_VOLUME);
660 #endif
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++)
670 if (isok(x, y))
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);
676 else
677 open_drawbridge(x, y);
678 return 1;
680 } else if (!Deaf) {
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
685 * Mastermind game */
686 ok = FALSE;
687 for (y = u.uy - 1; y <= u.uy + 1 && !ok; y++)
688 for (x = u.ux - 1; x <= u.ux + 1 && !ok; x++)
689 if (isok(x, y))
690 if (IS_DRAWBRIDGE(levl[x][y].typ)
691 || is_drawbridge_wall(x, y) >= 0)
692 ok = TRUE;
693 if (ok) { /* There is a drawbridge near */
694 int tumblers, gears;
695 boolean matched[5];
697 tumblers = gears = 0;
698 for (x = 0; x < 5; x++)
699 matched[x] = FALSE;
701 for (x = 0; x < (int) strlen(buf); x++)
702 if (x < 5) {
703 if (buf[x] == tune[x]) {
704 gears++;
705 matched[x] = TRUE;
706 } else
707 for (y = 0; y < 5; y++)
708 if (!matched[y] && buf[x] == tune[y]
709 && buf[y] != tune[y]) {
710 tumblers++;
711 matched[y] = TRUE;
712 break;
715 if (tumblers)
716 if (gears)
717 You_hear("%d tumbler%s click and %d gear%s turn.",
718 tumblers, plur(tumblers), gears,
719 plur(gears));
720 else
721 You_hear("%d tumbler%s click.", tumblers,
722 plur(tumblers));
723 else if (gears) {
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 */
728 if (gears == 5)
729 u.uevent.uheard_tune = 2;
734 return 1;
735 } else
736 return do_improvisation(instr);
738 nevermind:
739 pline1(Never_mind);
740 return 0;
743 #ifdef UNIX386MUSIC
745 * Play audible music on the machine's speaker if appropriate.
748 STATIC_OVL int
749 atconsole()
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"));
766 STATIC_OVL void
767 speaker(instr, buf)
768 struct obj *instr;
769 char *buf;
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.
777 int fd;
779 if ((fd = open("/dev/speaker", 1)) != -1) {
780 /* send a prefix to modify instrumental `timbre' */
781 switch (instr->otyp) {
782 case WOODEN_FLUTE:
783 case MAGIC_FLUTE:
784 (void) write(fd, ">ol", 1); /* up one octave & lock */
785 break;
786 case TOOLED_HORN:
787 case FROST_HORN:
788 case FIRE_HORN:
789 (void) write(fd, "<<ol", 2); /* drop two octaves & lock */
790 break;
791 case BUGLE:
792 (void) write(fd, "ol", 2); /* octave lock */
793 break;
794 case WOODEN_HARP:
795 case MAGIC_HARP:
796 (void) write(fd, "l8mlol", 4); /* fast, legato, octave lock */
797 break;
799 (void) write(fd, buf, strlen(buf));
800 (void) nhclose(fd);
803 #endif /* UNIX386MUSIC */
805 #ifdef VPIX_MUSIC
807 #if 0
808 #include <sys/types.h>
809 #include <sys/console.h>
810 #include <sys/vtkd.h>
811 #else
812 #define KIOC ('K' << 8)
813 #define KDMKTONE (KIOC | 8)
814 #endif
816 #define noDEBUG
818 /* emit tone of frequency hz for given number of ticks */
819 STATIC_OVL void
820 tone(hz, ticks)
821 unsigned int hz, ticks;
823 ioctl(0, KDMKTONE, hz | ((ticks * 10) << 16));
824 #ifdef DEBUG
825 printf("TONE: %6d %6d\n", hz, ticks * 10);
826 #endif
827 nap(ticks * 10);
830 /* rest for given number of ticks */
831 STATIC_OVL void
832 rest(ticks)
833 int ticks;
835 nap(ticks * 10);
836 #ifdef DEBUG
837 printf("REST: %6d\n", ticks * 10);
838 #endif
841 #include "interp.c" /* from snd86unx.shr */
843 STATIC_OVL void
844 speaker(instr, buf)
845 struct obj *instr;
846 char *buf;
848 /* emit a prefix to modify instrumental `timbre' */
849 playinit();
850 switch (instr->otyp) {
851 case WOODEN_FLUTE:
852 case MAGIC_FLUTE:
853 playstring(">ol", 1); /* up one octave & lock */
854 break;
855 case TOOLED_HORN:
856 case FROST_HORN:
857 case FIRE_HORN:
858 playstring("<<ol", 2); /* drop two octaves & lock */
859 break;
860 case BUGLE:
861 playstring("ol", 2); /* octave lock */
862 break;
863 case WOODEN_HARP:
864 case MAGIC_HARP:
865 playstring("l8mlol", 4); /* fast, legato, octave lock */
866 break;
868 playstring(buf, strlen(buf));
871 #ifdef VPIX_DEBUG
872 main(argc, argv)
873 int argc;
874 char *argv[];
876 if (argc == 2) {
877 playinit();
878 playstring(argv[1], strlen(argv[1]));
881 #endif
882 #endif /* VPIX_MUSIC */
884 /*music.c*/