1 /*	SCCS Id: @(#)music.c	3.4	2003/05/25	*/
2 /*	Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed.  See license for details. */
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 player
15  *			level.  May also scare monsters.
16  * fire horn		Acts like a wand of fire.
17  * frost horn		Acts like a wand of cold.
18  * bugle		Will awaken soldiers (if any):  area of effect depends
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
awaken_monsters(distance)61 awaken_monsters(distance)
62 int distance;
63 {
64 	register struct monst *mtmp = fmon;
65 	register int distm;
66 
67 	while(mtmp) {
68 	    if (!DEADMONSTER(mtmp)) {
69 		distm = distu(mtmp->mx, mtmp->my);
70 		if (distm < distance) {
71 		    mtmp->msleeping = 0;
72 		    mtmp->mcanmove = 1;
73 		    mtmp->mfrozen = 0;
74 		    /* May scare some monsters */
75 		    if (distm < distance/3 &&
76 			    !resist(mtmp, TOOL_CLASS, 0, NOTELL))
77 			monflee(mtmp, 0, FALSE, TRUE);
78 		}
79 	    }
80 	    mtmp = mtmp->nmon;
81 	}
82 }
83 
84 /*
85  * Make monsters fall asleep.  Note that they may resist the spell.
86  */
87 
88 STATIC_OVL void
put_monsters_to_sleep(distance)89 put_monsters_to_sleep(distance)
90 int distance;
91 {
92 	register struct monst *mtmp = fmon;
93 
94 	while(mtmp) {
95 		if (!DEADMONSTER(mtmp) && distu(mtmp->mx, mtmp->my) < distance &&
96 			sleep_monst(mtmp, d(10,10), TOOL_CLASS)) {
97 		    mtmp->msleeping = 1; /* 10d10 turns + wake_nearby to rouse */
98 		    slept_monst(mtmp);
99 		}
100 		mtmp = mtmp->nmon;
101 	}
102 }
103 
104 /*
105  * Charm snakes in range.  Note that the snakes are NOT tamed.
106  */
107 
108 STATIC_OVL void
charm_snakes(distance)109 charm_snakes(distance)
110 int distance;
111 {
112 	register struct monst *mtmp = fmon;
113 	int could_see_mon, was_peaceful;
114 
115 	while (mtmp) {
116 	    if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_SNAKE && mtmp->mcanmove &&
117 		    distu(mtmp->mx, mtmp->my) < distance) {
118 		was_peaceful = mtmp->mpeaceful;
119 		mtmp->mpeaceful = 1;
120 		mtmp->mavenge = 0;
121 		could_see_mon = canseemon(mtmp);
122 		mtmp->mundetected = 0;
123 		newsym(mtmp->mx, mtmp->my);
124 		if (canseemon(mtmp)) {
125 		    if (!could_see_mon)
126 			You("notice %s, swaying with the music.",
127 			    a_monnam(mtmp));
128 		    else
129 			pline("%s freezes, then sways with the music%s.",
130 			      Monnam(mtmp),
131 			      was_peaceful ? "" : ", and now seems quieter");
132 		}
133 	    }
134 	    mtmp = mtmp->nmon;
135 	}
136 }
137 
138 /*
139  * Calm nymphs in range.
140  */
141 
142 STATIC_OVL void
calm_nymphs(distance)143 calm_nymphs(distance)
144 int distance;
145 {
146 	register struct monst *mtmp = fmon;
147 
148 	while (mtmp) {
149 	    if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_NYMPH && mtmp->mcanmove &&
150 		    distu(mtmp->mx, mtmp->my) < distance) {
151 		mtmp->msleeping = 0;
152 		mtmp->mpeaceful = 1;
153 		mtmp->mavenge = 0;
154 		if (canseemon(mtmp))
155 		    pline(
156 		     "%s listens cheerfully to the music, then seems quieter.",
157 			  Monnam(mtmp));
158 	    }
159 	    mtmp = mtmp->nmon;
160 	}
161 }
162 
163 /* Awake only soldiers of the level. */
164 
165 void
awaken_soldiers()166 awaken_soldiers()
167 {
168 	register struct monst *mtmp = fmon;
169 
170 	while(mtmp) {
171 	    if (!DEADMONSTER(mtmp) &&
172 			is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) {
173 		mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0;
174 		mtmp->mcanmove = 1;
175 		if (canseemon(mtmp))
176 		    pline("%s is now ready for battle!", Monnam(mtmp));
177 		else
178 		    Norep("You hear the rattle of battle gear being readied.");
179 	    }
180 	    mtmp = mtmp->nmon;
181 	}
182 }
183 
184 /* Charm monsters in range.  Note that they may resist the spell.
185  * If swallowed, range is reduced to 0.
186  */
187 
188 STATIC_OVL void
charm_monsters(distance)189 charm_monsters(distance)
190 int distance;
191 {
192 	struct monst *mtmp, *mtmp2;
193 
194 	if (u.uswallow) {
195 	    if (!resist(u.ustuck, TOOL_CLASS, 0, NOTELL))
196 		(void) tamedog(u.ustuck, (struct obj *) 0);
197 	} else {
198 	    for (mtmp = fmon; mtmp; mtmp = mtmp2) {
199 		mtmp2 = mtmp->nmon;
200 		if (DEADMONSTER(mtmp)) continue;
201 
202 		if (distu(mtmp->mx, mtmp->my) <= distance) {
203 		    if (!resist(mtmp, TOOL_CLASS, 0, NOTELL))
204 			(void) tamedog(mtmp, (struct obj *) 0);
205 		}
206 	    }
207 	}
208 
209 }
210 
211 /* Generate earthquake :-) of desired force.
212  * That is:  create random chasms (pits).
213  */
214 
215 STATIC_OVL void
do_earthquake(force)216 do_earthquake(force)
217 int force;
218 {
219 	register int x,y;
220 	struct monst *mtmp;
221 	struct obj *otmp;
222 	struct trap *chasm;
223 	int start_x, start_y, end_x, end_y;
224 
225 	start_x = u.ux - (force * 2);
226 	start_y = u.uy - (force * 2);
227 	end_x = u.ux + (force * 2);
228 	end_y = u.uy + (force * 2);
229 	if (start_x < 1) start_x = 1;
230 	if (start_y < 1) start_y = 1;
231 	if (end_x >= COLNO) end_x = COLNO - 1;
232 	if (end_y >= ROWNO) end_y = ROWNO - 1;
233 	for (x=start_x; x<=end_x; x++) for (y=start_y; y<=end_y; y++) {
234 	    if ((mtmp = m_at(x,y)) != 0) {
235 		wakeup(mtmp);	/* peaceful monster will become hostile */
236 		if (mtmp->mundetected && is_hider(mtmp->data)) {
237 		    mtmp->mundetected = 0;
238 		    if (cansee(x,y))
239 			pline("%s is shaken loose from the ceiling!",
240 							    Amonnam(mtmp));
241 		    else
242 			You_hear("a thumping sound.");
243 		    if (x==u.ux && y==u.uy)
244 			You("easily dodge the falling %s.",
245 							    mon_nam(mtmp));
246 		    newsym(x,y);
247 		}
248 	    }
249 	    if (!rn2(14 - force)) switch (levl[x][y].typ) {
250 		  case FOUNTAIN : /* Make the fountain disappear */
251 			if (cansee(x,y))
252 				pline_The("fountain falls into a chasm.");
253 			goto do_pit;
254 #ifdef SINKS
255 		  case SINK :
256 			if (cansee(x,y))
257 				pline_The("kitchen sink falls into a chasm.");
258 			goto do_pit;
259 #endif
260 		  case ALTAR :
261 			if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) break;
262 
263 			if (cansee(x,y))
264 				pline_The("altar falls into a chasm.");
265 			goto do_pit;
266 		  case GRAVE :
267 			if (cansee(x,y))
268 				pline_The("headstone topples into a chasm.");
269 			goto do_pit;
270 		  case THRONE :
271 			if (cansee(x,y))
272 				pline_The("throne falls into a chasm.");
273 			/* Falls into next case */
274 		  case ROOM :
275 		  case CORR : /* Try to make a pit */
276 do_pit:		    chasm = maketrap(x,y,PIT);
277 		    if (!chasm) break;	/* no pit if portal at that location */
278 		    chasm->tseen = 1;
279 
280 		    levl[x][y].doormask = 0;
281 
282 		    mtmp = m_at(x,y);
283 
284 		    if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
285 			if (cansee(x, y))
286 			   pline("KADOOM! The boulder falls into a chasm%s!",
287 			      ((x == u.ux) && (y == u.uy)) ? " below you" : "");
288 			if (mtmp)
289 				mtmp->mtrapped = 0;
290 			obj_extract_self(otmp);
291 			(void) flooreffects(otmp, x, y, "");
292 			break;
293 		    }
294 
295 		    /* We have to check whether monsters or player
296 		       falls in a chasm... */
297 
298 		    if (mtmp) {
299 			if(!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) {
300 			    mtmp->mtrapped = 1;
301 			    if(cansee(x,y))
302 				pline("%s falls into a chasm!", Monnam(mtmp));
303 			    else if (flags.soundok && humanoid(mtmp->data))
304 				You_hear("a scream!");
305 			    mselftouch(mtmp, "Falling, ", TRUE);
306 			    if (mtmp->mhp > 0)
307 				if ((mtmp->mhp -= rnd(6)) <= 0) {
308 				    if(!cansee(x,y))
309 					pline("It is destroyed!");
310 				    else {
311 					You("destroy %s!", mtmp->mtame ?
312 					    x_monnam(mtmp, ARTICLE_THE, "poor",
313 				mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE):
314 					    mon_nam(mtmp));
315 				    }
316 				    xkilled(mtmp,0);
317 				}
318 			}
319 		    } else if (x == u.ux && y == u.uy) {
320 			    if (Levitation || Flying ||
321 						is_clinger(youmonst.data)) {
322 				    pline("A chasm opens up under you!");
323 				    You("don't fall in!");
324 			    } else {
325 				    You("fall into a chasm!");
326 				    u.utrap = rn1(6,2);
327 				    u.utraptype = TT_PIT;
328 				    losehp(rnd(6),"fell into a chasm",
329 					NO_KILLER_PREFIX);
330 				    selftouch("Falling, you");
331 			    }
332 		    } else newsym(x,y);
333 		    break;
334 		  case DOOR : /* Make the door collapse */
335 		    if (levl[x][y].doormask == D_NODOOR) goto do_pit;
336 		    if (cansee(x,y))
337 			pline_The("door collapses.");
338 		    if (*in_rooms(x, y, SHOPBASE))
339 			add_damage(x, y, 0L);
340 		    levl[x][y].doormask = D_NODOOR;
341 		    unblock_point(x,y);
342 		    newsym(x,y);
343 		    break;
344 	    }
345 	}
346 }
347 
348 /*
349  * The player is trying to extract something from his/her instrument.
350  */
351 
352 STATIC_OVL int
do_improvisation(instr)353 do_improvisation(instr)
354 struct obj *instr;
355 {
356 	int damage, do_spec = !Confusion;
357 #if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined (PCMUSIC)
358 	struct obj itmp;
359 
360 	itmp = *instr;
361 	/* if won't yield special effect, make sound of mundane counterpart */
362 	if (!do_spec || instr->spe <= 0)
363 	    while (objects[itmp.otyp].oc_magic) itmp.otyp -= 1;
364 # ifdef MAC
365 	mac_speaker(&itmp, "C");
366 # endif
367 # ifdef AMIGA
368 	amii_speaker(&itmp, "Cw", AMII_OKAY_VOLUME);
369 # endif
370 # ifdef VPIX_MUSIC
371 	if (sco_flag_console)
372 	    speaker(&itmp, "C");
373 # endif
374 #ifdef PCMUSIC
375 	  pc_speaker ( &itmp, "C");
376 #endif
377 #endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */
378 
379 	if (!do_spec)
380 	    pline("What you produce is quite far from music...");
381 	else
382 	    You("start playing %s.", the(xname(instr)));
383 
384 	switch (instr->otyp) {
385 	case MAGIC_FLUTE:		/* Make monster fall asleep */
386 	    if (do_spec && instr->spe > 0) {
387 		consume_obj_charge(instr, TRUE);
388 
389 		You("produce soft music.");
390 		put_monsters_to_sleep(u.ulevel * 5);
391 		exercise(A_DEX, TRUE);
392 		break;
393 	    } /* else FALLTHRU */
394 	case WOODEN_FLUTE:		/* May charm snakes */
395 	    do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
396 	    pline("%s.", Tobjnam(instr, do_spec ? "trill" : "toot"));
397 	    if (do_spec) charm_snakes(u.ulevel * 3);
398 	    exercise(A_DEX, TRUE);
399 	    break;
400 	case FROST_HORN:		/* Idem wand of cold */
401 	case FIRE_HORN:			/* Idem wand of fire */
402 	    if (do_spec && instr->spe > 0) {
403 		consume_obj_charge(instr, TRUE);
404 
405 		if (!getdir((char *)0)) {
406 		    pline("%s.", Tobjnam(instr, "vibrate"));
407 		    break;
408 		} else if (!u.dx && !u.dy && !u.dz) {
409 		    if ((damage = zapyourself(instr, TRUE)) != 0) {
410 			char buf[BUFSZ];
411 			Sprintf(buf, "using a magical horn on %sself", uhim());
412 			losehp(damage, buf, KILLED_BY);
413 		    }
414 		} else {
415 		    buzz((instr->otyp == FROST_HORN) ? AD_COLD-1 : AD_FIRE-1,
416 			 rn1(6,6), u.ux, u.uy, u.dx, u.dy);
417 		}
418 		makeknown(instr->otyp);
419 		break;
420 	    } /* else FALLTHRU */
421 	case TOOLED_HORN:		/* Awaken or scare monsters */
422 	    You("produce a frightful, grave sound.");
423 	    awaken_monsters(u.ulevel * 30);
424 	    exercise(A_WIS, FALSE);
425 	    break;
426 	case BUGLE:			/* Awaken & attract soldiers */
427 	    You("extract a loud noise from %s.", the(xname(instr)));
428 	    awaken_soldiers();
429 	    exercise(A_WIS, FALSE);
430 	    break;
431 	case MAGIC_HARP:		/* Charm monsters */
432 	    if (do_spec && instr->spe > 0) {
433 		consume_obj_charge(instr, TRUE);
434 
435 		pline("%s very attractive music.", Tobjnam(instr, "produce"));
436 		charm_monsters((u.ulevel - 1) / 3 + 1);
437 		exercise(A_DEX, TRUE);
438 		break;
439 	    } /* else FALLTHRU */
440 	case WOODEN_HARP:		/* May calm Nymph */
441 	    do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
442 	    pline("%s %s.", The(xname(instr)),
443 		  do_spec ? "produces a lilting melody" : "twangs");
444 	    if (do_spec) calm_nymphs(u.ulevel * 3);
445 	    exercise(A_DEX, TRUE);
446 	    break;
447 	case DRUM_OF_EARTHQUAKE:	/* create several pits */
448 	    if (do_spec && instr->spe > 0) {
449 		consume_obj_charge(instr, TRUE);
450 
451 		You("produce a heavy, thunderous rolling!");
452 		pline_The("entire dungeon is shaking around you!");
453 		do_earthquake((u.ulevel - 1) / 3 + 1);
454 		/* shake up monsters in a much larger radius... */
455 		awaken_monsters(ROWNO * COLNO);
456 		makeknown(DRUM_OF_EARTHQUAKE);
457 		break;
458 	    } /* else FALLTHRU */
459 	case LEATHER_DRUM:		/* Awaken monsters */
460 	    You("beat a deafening row!");
461 	    awaken_monsters(u.ulevel * 40);
462 	    exercise(A_WIS, FALSE);
463 	    break;
464 	default:
465 	    impossible("What a weird instrument (%d)!", instr->otyp);
466 	    break;
467 	}
468 	return 2;		/* That takes time */
469 }
470 
471 /*
472  * So you want music...
473  */
474 
475 int
do_play_instrument(instr)476 do_play_instrument(instr)
477 struct obj *instr;
478 {
479     char buf[BUFSZ], c = 'y';
480     char *s;
481     int x,y;
482     boolean ok;
483 
484     if (Underwater) {
485 	You_cant("play music underwater!");
486 	return(0);
487     }
488     if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) {
489 	c = yn("Improvise?");
490     }
491     if (c == 'n') {
492 	if (u.uevent.uheard_tune == 2 && yn("Play the passtune?") == 'y') {
493 	    Strcpy(buf, tune);
494 	} else {
495 	    getlin("What tune are you playing? [5 notes, A-G]", buf);
496 	    (void)mungspaces(buf);
497 	    /* convert to uppercase and change any "H" to the expected "B" */
498 	    for (s = buf; *s; s++) {
499 #ifndef AMIGA
500 		*s = highc(*s);
501 #else
502 		/* The AMIGA supports two octaves of notes */
503 		if (*s == 'h') *s = 'b';
504 #endif
505 		if (*s == 'H') *s = 'B';
506 	    }
507 	}
508 	You("extract a strange sound from %s!", the(xname(instr)));
509 #ifdef UNIX386MUSIC
510 	/* if user is at the console, play through the console speaker */
511 	if (atconsole())
512 	    speaker(instr, buf);
513 #endif
514 #ifdef VPIX_MUSIC
515 	if (sco_flag_console)
516 	    speaker(instr, buf);
517 #endif
518 #ifdef MAC
519 	mac_speaker ( instr , buf ) ;
520 #endif
521 #ifdef PCMUSIC
522 	pc_speaker ( instr, buf );
523 #endif
524 #ifdef AMIGA
525 	{
526 		char nbuf[ 20 ];
527 		int i;
528 		for( i = 0; buf[i] && i < 5; ++i )
529 		{
530 			nbuf[ i*2 ] = buf[ i ];
531 			nbuf[ (i*2)+1 ] = 'h';
532 		}
533 		nbuf[ i*2 ] = 0;
534 		amii_speaker ( instr , nbuf, AMII_OKAY_VOLUME ) ;
535 	}
536 #endif
537 	/* Check if there was the Stronghold drawbridge near
538 	 * and if the tune conforms to what we're waiting for.
539 	 */
540 	if(Is_stronghold(&u.uz)) {
541 	    exercise(A_WIS, TRUE);		/* just for trying */
542 	    if(!strcmp(buf,tune)) {
543 		/* Search for the drawbridge */
544 		for(y=u.uy-1; y<=u.uy+1; y++)
545 		    for(x=u.ux-1;x<=u.ux+1;x++)
546 			if(isok(x,y))
547 			if(find_drawbridge(&x,&y)) {
548 			    u.uevent.uheard_tune = 2; /* tune now fully known */
549 			    if(levl[x][y].typ == DRAWBRIDGE_DOWN)
550 				close_drawbridge(x,y);
551 			    else
552 				open_drawbridge(x,y);
553 			    return 0;
554 			}
555 	    } else if(flags.soundok) {
556 		if (u.uevent.uheard_tune < 1) u.uevent.uheard_tune = 1;
557 		/* Okay, it wasn't the right tune, but perhaps
558 		 * we can give the player some hints like in the
559 		 * Mastermind game */
560 		ok = FALSE;
561 		for(y = u.uy-1; y <= u.uy+1 && !ok; y++)
562 		    for(x = u.ux-1; x <= u.ux+1 && !ok; x++)
563 			if(isok(x,y))
564 			if(IS_DRAWBRIDGE(levl[x][y].typ) ||
565 			   is_drawbridge_wall(x,y) >= 0)
566 				ok = TRUE;
567 		if(ok) { /* There is a drawbridge near */
568 		    int tumblers, gears;
569 		    boolean matched[5];
570 
571 		    tumblers = gears = 0;
572 		    for(x=0; x < 5; x++)
573 			matched[x] = FALSE;
574 
575 		    for(x=0; x < (int)strlen(buf); x++)
576 			if(x < 5) {
577 			    if(buf[x] == tune[x]) {
578 				gears++;
579 				matched[x] = TRUE;
580 			    } else
581 				for(y=0; y < 5; y++)
582 				    if(!matched[y] &&
583 				       buf[x] == tune[y] &&
584 				       buf[y] != tune[y]) {
585 					tumblers++;
586 					matched[y] = TRUE;
587 					break;
588 				    }
589 			}
590 		    if(tumblers)
591 			if(gears)
592 			    You_hear("%d tumbler%s click and %d gear%s turn.",
593 				tumblers, plur(tumblers), gears, plur(gears));
594 			else
595 			    You_hear("%d tumbler%s click.",
596 				tumblers, plur(tumblers));
597 		    else if(gears) {
598 			You_hear("%d gear%s turn.", gears, plur(gears));
599 			/* could only get `gears == 5' by playing five
600 			   correct notes followed by excess; otherwise,
601 			   tune would have matched above */
602 			if (gears == 5) u.uevent.uheard_tune = 2;
603 		    }
604 		}
605 	    }
606 	  }
607 	return 1;
608     } else
609 	    return do_improvisation(instr);
610 }
611 
612 #ifdef UNIX386MUSIC
613 /*
614  * Play audible music on the machine's speaker if appropriate.
615  */
616 
617 STATIC_OVL int
atconsole()618 atconsole()
619 {
620     /*
621      * Kluge alert: This code assumes that your [34]86 has no X terminals
622      * attached and that the console tty type is AT386 (this is always true
623      * under AT&T UNIX for these boxen). The theory here is that your remote
624      * ttys will have terminal type `ansi' or something else other than
625      * `AT386' or `xterm'. We'd like to do better than this, but testing
626      * to see if we're running on the console physical terminal is quite
627      * difficult given the presence of virtual consoles and other modern
628      * UNIX impedimenta...
629      */
630     char	*termtype = nh_getenv("TERM");
631 
632      return(!strcmp(termtype, "AT386") || !strcmp(termtype, "xterm"));
633 }
634 
635 STATIC_OVL void
speaker(instr,buf)636 speaker(instr, buf)
637 struct obj *instr;
638 char	*buf;
639 {
640     /*
641      * For this to work, you need to have installed the PD speaker-control
642      * driver for PC-compatible UNIX boxes that I (esr@snark.thyrsus.com)
643      * posted to comp.sources.unix in Feb 1990.  A copy should be included
644      * with your nethack distribution.
645      */
646     int	fd;
647 
648     if ((fd = open("/dev/speaker", 1)) != -1)
649     {
650 	/* send a prefix to modify instrumental `timbre' */
651 	switch (instr->otyp)
652 	{
653 	case WOODEN_FLUTE:
654 	case MAGIC_FLUTE:
655 	    (void) write(fd, ">ol", 1); /* up one octave & lock */
656 	    break;
657 	case TOOLED_HORN:
658 	case FROST_HORN:
659 	case FIRE_HORN:
660 	    (void) write(fd, "<<ol", 2); /* drop two octaves & lock */
661 	    break;
662 	case BUGLE:
663 	    (void) write(fd, "ol", 2); /* octave lock */
664 	    break;
665 	case WOODEN_HARP:
666 	case MAGIC_HARP:
667 	    (void) write(fd, "l8mlol", 4); /* fast, legato, octave lock */
668 	    break;
669 	}
670 	(void) write(fd, buf, strlen(buf));
671 	(void) close(fd);
672     }
673 }
674 #endif /* UNIX386MUSIC */
675 
676 #ifdef VPIX_MUSIC
677 
678 # if 0
679 #include <sys/types.h>
680 #include <sys/console.h>
681 #include <sys/vtkd.h>
682 # else
683 #define KIOC ('K' << 8)
684 #define KDMKTONE (KIOC | 8)
685 # endif
686 
687 #define noDEBUG
688 
tone(hz,ticks)689 STATIC_OVL void tone(hz, ticks)
690 /* emit tone of frequency hz for given number of ticks */
691 unsigned int hz, ticks;
692 {
693     ioctl(0,KDMKTONE,hz|((ticks*10)<<16));
694 # ifdef DEBUG
695     printf("TONE: %6d %6d\n",hz,ticks * 10);
696 # endif
697     nap(ticks * 10);
698 }
699 
rest(ticks)700 STATIC_OVL void rest(ticks)
701 /* rest for given number of ticks */
702 int	ticks;
703 {
704     nap(ticks * 10);
705 # ifdef DEBUG
706     printf("REST:        %6d\n",ticks * 10);
707 # endif
708 }
709 
710 
711 #include "interp.c"	/* from snd86unx.shr */
712 
713 
714 STATIC_OVL void
speaker(instr,buf)715 speaker(instr, buf)
716 struct obj *instr;
717 char	*buf;
718 {
719     /* emit a prefix to modify instrumental `timbre' */
720     playinit();
721     switch (instr->otyp)
722     {
723 	case WOODEN_FLUTE:
724 	case MAGIC_FLUTE:
725 	    playstring(">ol", 1); /* up one octave & lock */
726 	    break;
727 	case TOOLED_HORN:
728 	case FROST_HORN:
729 	case FIRE_HORN:
730 	    playstring("<<ol", 2); /* drop two octaves & lock */
731 	    break;
732 	case BUGLE:
733 	    playstring("ol", 2); /* octave lock */
734 	    break;
735 	case WOODEN_HARP:
736 	case MAGIC_HARP:
737 	    playstring("l8mlol", 4); /* fast, legato, octave lock */
738 	    break;
739     }
740     playstring( buf, strlen(buf));
741 }
742 
743 # ifdef DEBUG
main(argc,argv)744 main(argc,argv)
745 char *argv[];
746 {
747     if (argc == 2) {
748 	playinit();
749 	playstring(argv[1], strlen(argv[1]));
750     }
751 }
752 # endif
753 #endif	/* VPIX_MUSIC */
754 
755 /*music.c*/
756