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
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
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
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
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
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
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
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
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
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
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
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 |
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 |
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
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
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*/