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(put_monsters_to_sleep,(int));
32 STATIC_DCL void FDECL(charm_snakes,(int));
33 STATIC_DCL void FDECL(calm_nymphs,(int));
34 STATIC_DCL void FDECL(charm_monsters,(int));
35 STATIC_DCL int FDECL(do_improvisation,(struct obj *));
36 
37 #ifdef UNIX386MUSIC
38 STATIC_DCL int NDECL(atconsole);
39 STATIC_DCL void FDECL(speaker,(struct obj *,char *));
40 #endif
41 #ifdef VPIX_MUSIC
42 extern int sco_flag_console;	/* will need changing if not _M_UNIX */
43 STATIC_DCL void NDECL(playinit);
44 STATIC_DCL void FDECL(playstring, (char *,size_t));
45 STATIC_DCL void FDECL(speaker,(struct obj *,char *));
46 #endif
47 #ifdef PCMUSIC
48 void FDECL( pc_speaker, ( struct obj *, char * ) );
49 #endif
50 #ifdef AMIGA
51 void FDECL( amii_speaker, ( struct obj *, char *, int ) );
52 #endif
53 
54 /*
55  * Wake every monster in range...
56  */
57 
58 void
awaken_monsters(distance)59 awaken_monsters(distance)
60 int distance;
61 {
62 	register struct monst *mtmp = fmon;
63 	register int distm;
64 
65 	while(mtmp) {
66 	    if (!DEADMONSTER(mtmp)) {
67 		distm = distu(mtmp->mx, mtmp->my);
68 		if (distm < distance) {
69 		    mtmp->msleeping = 0;
70 		    mtmp->mcanmove = 1;
71 		    mtmp->mfrozen = 0;
72 		    /* May scare some monsters */
73 		    if (distm < distance/3 &&
74 			    !resist(mtmp, TOOL_CLASS, 0, NOTELL))
75 			monflee(mtmp, 0, FALSE, TRUE);
76 		}
77 	    }
78 	    mtmp = mtmp->nmon;
79 	}
80 }
81 
82 /*
83  * Make monsters fall asleep.  Note that they may resist the spell.
84  */
85 
86 STATIC_OVL void
put_monsters_to_sleep(distance)87 put_monsters_to_sleep(distance)
88 int distance;
89 {
90 	register struct monst *mtmp = fmon;
91 
92 	while(mtmp) {
93 		if (!DEADMONSTER(mtmp) && distu(mtmp->mx, mtmp->my) < distance &&
94 			sleep_monst(mtmp, d(10,10), TOOL_CLASS)) {
95 		    mtmp->msleeping = 1; /* 10d10 turns + wake_nearby to rouse */
96 		    slept_monst(mtmp);
97 		}
98 		mtmp = mtmp->nmon;
99 	}
100 }
101 
102 /*
103  * Charm snakes in range.  Note that the snakes are NOT tamed.
104  */
105 
106 STATIC_OVL void
charm_snakes(distance)107 charm_snakes(distance)
108 int distance;
109 {
110 	register struct monst *mtmp = fmon;
111 	int could_see_mon, was_peaceful;
112 
113 	while (mtmp) {
114 	    if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_SNAKE && mtmp->mcanmove &&
115 		    distu(mtmp->mx, mtmp->my) < distance) {
116 		was_peaceful = mtmp->mpeaceful;
117 		mtmp->mpeaceful = 1;
118 		mtmp->mavenge = 0;
119 		could_see_mon = canseemon(mtmp);
120 		mtmp->mundetected = 0;
121 		newsym(mtmp->mx, mtmp->my);
122 		if (canseemon(mtmp)) {
123 		    if (!could_see_mon)
124 			You("notice %s, swaying with the music.",
125 			    a_monnam(mtmp));
126 		    else
127 			pline("%s freezes, then sways with the music%s.",
128 			      Monnam(mtmp),
129 			      was_peaceful ? "" : ", and now seems quieter");
130 		}
131 	    }
132 	    mtmp = mtmp->nmon;
133 	}
134 }
135 
136 /*
137  * Calm nymphs in range.
138  */
139 
140 STATIC_OVL void
calm_nymphs(distance)141 calm_nymphs(distance)
142 int distance;
143 {
144 	register struct monst *mtmp = fmon;
145 
146 	while (mtmp) {
147 	    if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_NYMPH && mtmp->mcanmove &&
148 		    distu(mtmp->mx, mtmp->my) < distance) {
149 		mtmp->msleeping = 0;
150 		mtmp->mpeaceful = 1;
151 		mtmp->mavenge = 0;
152 		if (canseemon(mtmp))
153 		    pline(
154 		     "%s listens cheerfully to the music, then seems quieter.",
155 			  Monnam(mtmp));
156 	    }
157 	    mtmp = mtmp->nmon;
158 	}
159 }
160 
161 /* Awake only soldiers of the level. */
162 
163 void
awaken_soldiers()164 awaken_soldiers()
165 {
166 	register struct monst *mtmp = fmon;
167 
168 	while(mtmp) {
169 	    if (!DEADMONSTER(mtmp) &&
170 			is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) {
171 		mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0;
172 		mtmp->mcanmove = 1;
173 		if (canseemon(mtmp))
174 		    pline("%s is now ready for battle!", Monnam(mtmp));
175 		else
176 		    Norep("You hear the rattle of battle gear being readied.");
177 	    }
178 	    mtmp = mtmp->nmon;
179 	}
180 }
181 
182 /* Charm monsters in range.  Note that they may resist the spell.
183  * If swallowed, range is reduced to 0.
184  */
185 
186 STATIC_OVL void
charm_monsters(distance)187 charm_monsters(distance)
188 int distance;
189 {
190 	struct monst *mtmp, *mtmp2;
191 
192 	if (u.uswallow) {
193 	    if (!resist(u.ustuck, TOOL_CLASS, 0, NOTELL))
194 		(void) tamedog(u.ustuck, (struct obj *) 0);
195 	} else {
196 	    for (mtmp = fmon; mtmp; mtmp = mtmp2) {
197 		mtmp2 = mtmp->nmon;
198 		if (DEADMONSTER(mtmp)) continue;
199 
200 		if (distu(mtmp->mx, mtmp->my) <= distance) {
201 		    if (!resist(mtmp, TOOL_CLASS, 0, NOTELL))
202 			(void) tamedog(mtmp, (struct obj *) 0);
203 		}
204 	    }
205 	}
206 
207 }
208 
209 /* Generate earthquake :-) of desired force.
210  * That is:  create random chasms (pits).
211  */
212 
213 void
do_earthquake(force)214 do_earthquake(force)
215 int force;
216 {
217 	register int x,y;
218 	struct monst *mtmp;
219 	struct obj *otmp;
220 	struct trap *chasm;
221 	int start_x, start_y, end_x, end_y;
222 
223 	start_x = u.ux - (force * 2);
224 	start_y = u.uy - (force * 2);
225 	end_x = u.ux + (force * 2);
226 	end_y = u.uy + (force * 2);
227 	if (start_x < 1) start_x = 1;
228 	if (start_y < 1) start_y = 1;
229 	if (end_x >= COLNO) end_x = COLNO - 1;
230 	if (end_y >= ROWNO) end_y = ROWNO - 1;
231 	for (x=start_x; x<=end_x; x++) for (y=start_y; y<=end_y; y++) {
232 	    if ((mtmp = m_at(x,y)) != 0) {
233 		wakeup(mtmp);	/* peaceful monster will become hostile */
234 		if (mtmp->mundetected && is_hider(mtmp->data)) {
235 		    mtmp->mundetected = 0;
236 		    if (cansee(x,y))
237 			pline("%s is shaken loose from the ceiling!",
238 							    Amonnam(mtmp));
239 		    else
240 			You_hear("a thumping sound.");
241 		    if (x==u.ux && y==u.uy)
242 			You("easily dodge the falling %s.",
243 							    mon_nam(mtmp));
244 		    newsym(x,y);
245 		}
246 	    }
247 	    if (!rn2(14 - force)) switch (levl[x][y].typ) {
248 		  case FOUNTAIN : /* Make the fountain disappear */
249 			if (cansee(x,y))
250 				pline_The("fountain falls into a chasm.");
251 			goto do_pit;
252 #ifdef SINKS
253 		  case SINK :
254 			if (cansee(x,y))
255 				pline_The("kitchen sink falls into a chasm.");
256 			goto do_pit;
257 #endif
258 		  case ALTAR :
259 			if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) break;
260 
261 			if (cansee(x,y))
262 				pline_The("altar falls into a chasm.");
263 			goto do_pit;
264 		  case GRAVE :
265 			if (cansee(x,y))
266 				pline_The("headstone topples into a chasm.");
267 			goto do_pit;
268 		  case THRONE :
269 			if (cansee(x,y))
270 				pline_The("throne falls into a chasm.");
271 			/* Falls into next case */
272 		  case ROOM :
273 		  case CORR : /* Try to make a pit */
274 do_pit:		    chasm = maketrap(x,y,PIT);
275 		    if (!chasm) break;	/* no pit if portal at that location */
276 		    chasm->tseen = 1;
277 
278 		    levl[x][y].doormask = 0;
279 
280 		    mtmp = m_at(x,y);
281 
282 		    if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
283 			if (cansee(x, y))
284 			   pline("KADOOM! The boulder falls into a chasm%s!",
285 			      ((x == u.ux) && (y == u.uy)) ? " below you" : "");
286 			if (mtmp)
287 				mtmp->mtrapped = 0;
288 			obj_extract_self(otmp);
289 			(void) flooreffects(otmp, x, y, "");
290 			break;
291 		    }
292 
293 		    /* We have to check whether monsters or player
294 		       falls in a chasm... */
295 
296 		    if (mtmp) {
297 			if(!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) {
298 			    mtmp->mtrapped = 1;
299 			    if(cansee(x,y))
300 				pline("%s falls into a chasm!", Monnam(mtmp));
301 			    else if (flags.soundok && humanoid(mtmp->data))
302 				You_hear("a scream!");
303 			    mselftouch(mtmp, "Falling, ", TRUE);
304 			    if (mtmp->mhp > 0)
305 				if ((mtmp->mhp -= rnd(6)) <= 0) {
306 				    if(!cansee(x,y))
307 					pline("It is destroyed!");
308 				    else {
309 					You("destroy %s!", mtmp->mtame ?
310 					    x_monnam(mtmp, ARTICLE_THE, "poor",
311 				mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE):
312 					    mon_nam(mtmp));
313 				    }
314 				    xkilled(mtmp,0);
315 				}
316 			}
317 		    } else if (!u.utrap && x == u.ux && y == u.uy) {
318 			    if (Levitation || Flying ||
319 						is_clinger(youmonst.data)) {
320 				    pline("A chasm opens up under you!");
321 				    You("don't fall in!");
322 			    } else {
323 				    You("fall into a chasm!");
324 				    u.utrap = rn1(6,2);
325 				    u.utraptype = TT_PIT;
326 				    losehp(rnd(6),"fell into a chasm",
327 					NO_KILLER_PREFIX);
328 				    selftouch("Falling, you");
329 			    }
330 		    } else newsym(x,y);
331 		    break;
332 		  case DOOR : /* Make the door collapse */
333 		    /* ALI - artifact doors */
334 		    if (artifact_door(x, y))  break;
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 %s.", Hallucination ? "elevator music" : "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 %s is shaking around you!", get_generic_level_description(&u.uz));
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 	    warning("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 1;
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