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
31STATIC_DCL void FDECL(awaken_monsters,(int));
32STATIC_DCL void FDECL(put_monsters_to_sleep,(int));
33STATIC_DCL void FDECL(charm_snakes,(int));
34STATIC_DCL void FDECL(calm_nymphs,(int));
35STATIC_DCL void FDECL(charm_monsters,(int));
36STATIC_DCL void FDECL(do_earthquake,(int));
37STATIC_DCL int FDECL(do_improvisation,(struct obj *));
38
39#ifdef UNIX386MUSIC
40STATIC_DCL int NDECL(atconsole);
41STATIC_DCL void FDECL(speaker,(struct obj *,char *));
42#endif
43#ifdef VPIX_MUSIC
44extern int sco_flag_console;	/* will need changing if not _M_UNIX */
45STATIC_DCL void NDECL(playinit);
46STATIC_DCL void FDECL(playstring, (char *,size_t));
47STATIC_DCL void FDECL(speaker,(struct obj *,char *));
48#endif
49#ifdef PCMUSIC
50void FDECL( pc_speaker, ( struct obj *, char * ) );
51#endif
52#ifdef AMIGA
53void FDECL( amii_speaker, ( struct obj *, char *, int ) );
54#endif
55
56/*
57 * Wake every monster in range...
58 */
59
60STATIC_OVL void
61awaken_monsters(distance)
62int 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
88STATIC_OVL void
89put_monsters_to_sleep(distance)
90int 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
108STATIC_OVL void
109charm_snakes(distance)
110int 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
142STATIC_OVL void
143calm_nymphs(distance)
144int 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
165void
166awaken_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
188STATIC_OVL void
189charm_monsters(distance)
190int 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
215STATIC_OVL void
216do_earthquake(force)
217int 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 */
276do_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
352STATIC_OVL int
353do_improvisation(instr)
354struct 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
475int
476do_play_instrument(instr)
477struct 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
617STATIC_OVL int
618atconsole()
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
635STATIC_OVL void
636speaker(instr, buf)
637struct obj *instr;
638char	*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
689STATIC_OVL void tone(hz, ticks)
690/* emit tone of frequency hz for given number of ticks */
691unsigned 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
700STATIC_OVL void rest(ticks)
701/* rest for given number of ticks */
702int	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
714STATIC_OVL void
715speaker(instr, buf)
716struct obj *instr;
717char	*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
744main(argc,argv)
745char *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