OSDN Git Service

add gitignore
[nethackexpress/trunk.git] / src / music.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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*/