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