1 /* NetHack 3.7 music.c $NHDT-Date: 1596498191 2020/08/03 23:43:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.69 $ */
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 * 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
15 * player 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 void awaken_monsters(int);
32 static void charm_snakes(int);
33 static void calm_nymphs(int);
34 static void charm_monsters(int);
35 static void do_earthquake(int);
36 static const char *generic_lvl_desc(void);
37 static int do_improvisation(struct obj *);
38
39 /*
40 * Wake every monster in range...
41 */
42
43 static void
awaken_monsters(int distance)44 awaken_monsters(int distance)
45 {
46 register struct monst *mtmp;
47 register int distm;
48
49 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
50 if (DEADMONSTER(mtmp))
51 continue;
52 if ((distm = distu(mtmp->mx, mtmp->my)) < distance) {
53 wakeup(mtmp, FALSE, FALSE);
54 mtmp->mcanmove = 1;
55 mtmp->mfrozen = 0;
56 /* may scare some monsters -- waiting monsters excluded */
57 if (!unique_corpstat(mtmp->data)
58 && (mtmp->mstrategy & STRAT_WAITMASK) != 0)
59 mtmp->mstrategy &= ~STRAT_WAITMASK;
60 else if (distm < distance / 3
61 && !resist(mtmp, TOOL_CLASS, 0, NOTELL)
62 /* some monsters are immune */
63 && onscary(0, 0, mtmp))
64 monflee(mtmp, 0, FALSE, TRUE);
65 }
66 }
67 }
68
69 /*
70 * Make monsters fall asleep. Note that they may resist the spell.
71 */
72
73 void
put_monsters_to_sleep(struct monst * caster,int distance)74 put_monsters_to_sleep(struct monst *caster, int distance)
75 {
76 register struct monst *mtmp;
77
78 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
79 if (DEADMONSTER(mtmp))
80 continue;
81 if (mtmp == caster) /* immune to own effects */
82 continue;
83 xchar cx = (caster == &g.youmonst) ? u.ux : caster->mx;
84 xchar cy = (caster == &g.youmonst) ? u.uy : caster->my;
85
86 if (dist2(cx, cy, mtmp->mx, mtmp->my) < distance
87 && sleep_monst(mtmp, d(10, 10), TOOL_CLASS)) {
88 mtmp->msleeping = 1; /* 10d10 turns + wake_nearby to rouse */
89 slept_monst(mtmp);
90 }
91 }
92 }
93
94 /*
95 * Charm snakes in range. Note that the snakes are NOT tamed.
96 */
97
98 static void
charm_snakes(int distance)99 charm_snakes(int distance)
100 {
101 register struct monst *mtmp;
102 int could_see_mon, was_peaceful;
103
104 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
105 if (DEADMONSTER(mtmp))
106 continue;
107 if (mtmp->data->mlet == S_SNAKE && mtmp->mcanmove
108 && distu(mtmp->mx, mtmp->my) < distance) {
109 was_peaceful = mtmp->mpeaceful;
110 mtmp->mpeaceful = 1;
111 mtmp->mavenge = 0;
112 mtmp->mstrategy &= ~STRAT_WAITMASK;
113 could_see_mon = canseemon(mtmp);
114 mtmp->mundetected = 0;
115 newsym(mtmp->mx, mtmp->my);
116 if (canseemon(mtmp)) {
117 if (!could_see_mon)
118 You("notice %s, swaying with the music.", a_monnam(mtmp));
119 else
120 pline("%s freezes, then sways with the music%s.",
121 Monnam(mtmp),
122 was_peaceful ? "" : ", and now seems quieter");
123 }
124 }
125 }
126 }
127
128 /*
129 * Calm nymphs in range.
130 */
131
132 static void
calm_nymphs(int distance)133 calm_nymphs(int distance)
134 {
135 register struct monst *mtmp;
136
137 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
138 if (DEADMONSTER(mtmp))
139 continue;
140 if (mtmp->data->mlet == S_NYMPH && mtmp->mcanmove
141 && distu(mtmp->mx, mtmp->my) < distance) {
142 wakeup(mtmp, FALSE, TRUE);
143 mtmp->mpeaceful = 1;
144 mtmp->mavenge = 0;
145 mtmp->mstrategy &= ~STRAT_WAITMASK;
146 if (canseemon(mtmp))
147 pline(
148 "%s listens cheerfully to the music, then seems quieter.",
149 Monnam(mtmp));
150 }
151 }
152 }
153
154 /* Awake soldiers anywhere the level (and any nearby monster). */
155 void
awaken_soldiers(struct monst * bugler)156 awaken_soldiers(struct monst* bugler /* monster that played instrument */)
157 {
158 register struct monst *mtmp;
159 int distance, distm;
160
161 /* distance of affected non-soldier monsters to bugler */
162 distance = ((bugler == &g.youmonst) ? u.ulevel : bugler->data->mlevel) * 30;
163
164 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
165 if (DEADMONSTER(mtmp))
166 continue;
167 if (is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) {
168 mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0;
169 mtmp->mcanmove = 1;
170 mtmp->mstrategy &= ~STRAT_WAITMASK;
171 if (canseemon(mtmp))
172 pline("%s is now ready for battle!", Monnam(mtmp));
173 else if (!Deaf)
174 Norep("%s the rattle of battle gear being readied.",
175 "You hear"); /* Deaf-aware */
176 } else if ((distm = ((bugler == &g.youmonst)
177 ? distu(mtmp->mx, mtmp->my)
178 : dist2(bugler->mx, bugler->my, mtmp->mx,
179 mtmp->my))) < distance) {
180 wakeup(mtmp, FALSE, FALSE);
181 mtmp->mcanmove = 1;
182 mtmp->mfrozen = 0;
183 /* may scare some monsters -- waiting monsters excluded */
184 if (!unique_corpstat(mtmp->data)
185 && (mtmp->mstrategy & STRAT_WAITMASK) != 0)
186 mtmp->mstrategy &= ~STRAT_WAITMASK;
187 else if (distm < distance / 3
188 && !resist(mtmp, TOOL_CLASS, 0, NOTELL))
189 monflee(mtmp, 0, FALSE, TRUE);
190 }
191 }
192 }
193
194 /* Charm monsters in range. Note that they may resist the spell.
195 * If swallowed, range is reduced to 0.
196 */
197 static void
charm_monsters(int distance)198 charm_monsters(int distance)
199 {
200 struct monst *mtmp, *mtmp2;
201
202 if (u.uswallow) {
203 if (!resist(u.ustuck, TOOL_CLASS, 0, NOTELL))
204 (void) tamedog(u.ustuck, (struct obj *) 0, FALSE);
205 } else {
206 for (mtmp = fmon; mtmp; mtmp = mtmp2) {
207 mtmp2 = mtmp->nmon;
208 if (DEADMONSTER(mtmp))
209 continue;
210
211 if (distu(mtmp->mx, mtmp->my) <= distance) {
212 if (!resist(mtmp, TOOL_CLASS, 0, NOTELL))
213 (void) tamedog(mtmp, (struct obj *) 0, FALSE);
214 }
215 }
216 }
217 }
218
219 /* Generate earthquake :-) of desired force.
220 * That is: create random chasms (pits).
221 */
222 static void
do_earthquake(int force)223 do_earthquake(int force)
224 {
225 static const char into_a_chasm[] = " into a chasm";
226 register int x, y;
227 struct monst *mtmp;
228 struct obj *otmp;
229 struct trap *chasm, *trap_at_u = t_at(u.ux, u.uy);
230 int start_x, start_y, end_x, end_y, amsk;
231 aligntyp algn;
232 schar filltype;
233 unsigned tu_pit = 0;
234
235 if (trap_at_u)
236 tu_pit = is_pit(trap_at_u->ttyp);
237 if (force > 13) /* sanity precaution; maximum used is actually 10 */
238 force = 13;
239 start_x = u.ux - (force * 2);
240 start_y = u.uy - (force * 2);
241 end_x = u.ux + (force * 2);
242 end_y = u.uy + (force * 2);
243 start_x = max(start_x, 1);
244 start_y = max(start_y, 0);
245 end_x = min(end_x, COLNO - 1);
246 end_y = min(end_y, ROWNO - 1);
247 for (x = start_x; x <= end_x; x++)
248 for (y = start_y; y <= end_y; y++) {
249 if ((mtmp = m_at(x, y)) != 0) {
250 /* peaceful monster will become hostile */
251 wakeup(mtmp, TRUE, TRUE);
252 if (mtmp->mundetected) {
253 mtmp->mundetected = 0;
254 newsym(x, y);
255 if (ceiling_hider(mtmp->data)) {
256 if (cansee(x, y))
257 pline("%s is shaken loose from the ceiling!",
258 Amonnam(mtmp));
259 else if (!is_flyer(mtmp->data))
260 You_hear("a thump.");
261 }
262 }
263 if (M_AP_TYPE(mtmp) != M_AP_NOTHING
264 && M_AP_TYPE(mtmp) != M_AP_MONSTER)
265 seemimic(mtmp);
266 }
267 if (rn2(14 - force))
268 continue;
269
270 /*
271 * Possible extensions:
272 * When a door is trapped, explode it instead of silently
273 * turning it into an empty doorway.
274 * Trigger divine wrath when an altar is dumped into a chasm.
275 * Sometimes replace sink with fountain or fountain with pool
276 * instead of always producing a pit.
277 * Sometimes release monster and/or treasure from a grave or
278 * a throne instead of just dumping them into the chasm.
279 * Chance to destroy wall segments? Trees too?
280 * Honor non-diggable for locked doors, walls, and trees.
281 * Treat non-passwall as if it was non-diggable?
282 * Conjoin some of the umpteen pits when they're adjacent?
283 *
284 * Replace 'goto do_pit;' with 'do_pit = TRUE; break;' and
285 * move the pit code to after the switch.
286 */
287
288 switch (levl[x][y].typ) {
289 case FOUNTAIN: /* make the fountain disappear */
290 if (cansee(x, y))
291 pline_The("fountain falls%s.", into_a_chasm);
292 goto do_pit;
293 case SINK:
294 if (cansee(x, y))
295 pline_The("kitchen sink falls%s.", into_a_chasm);
296 goto do_pit;
297 case ALTAR:
298 /* always preserve the high altars */
299 if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))
300 break;
301 /* no need to check for high altar here; we've just
302 excluded those */
303 amsk = altarmask_at(x, y);
304 algn = Amask2align(amsk & AM_MASK);
305 if (cansee(x, y))
306 pline_The("%s altar falls%s.",
307 align_str(algn), into_a_chasm);
308 goto do_pit;
309 case GRAVE:
310 if (cansee(x, y))
311 pline_The("headstone topples%s.", into_a_chasm);
312 goto do_pit;
313 case THRONE:
314 if (cansee(x, y))
315 pline_The("throne falls%s.", into_a_chasm);
316 goto do_pit;
317 case SCORR:
318 levl[x][y].typ = CORR;
319 unblock_point(x, y);
320 if (cansee(x, y))
321 pline("A secret corridor is revealed.");
322 /*FALLTHRU*/
323 case CORR:
324 case ROOM: /* Try to make a pit. */
325 do_pit:
326 /* maketrap() won't replace furniture with a trap,
327 so remove the furniture first */
328 if (levl[x][y].typ != CORR) {
329 if (levl[x][y].typ != DOOR) {
330 levl[x][y].typ = ROOM;
331 /* clear blessed fountain, disturbed grave */
332 levl[x][y].horizontal = 0;
333 }
334 /* clear doormask, altarmask, looted throne */
335 levl[x][y].flags = 0; /* same as 'doormask = D_NODOOR' */
336 }
337 chasm = maketrap(x, y, PIT);
338 if (!chasm)
339 break; /* no pit if portal at that location */
340 chasm->tseen = 1;
341
342 /* Let liquid flow into the newly created chasm.
343 Adjust corresponding code in apply.c for exploding
344 wand of digging if you alter this sequence. */
345 filltype = fillholetyp(x, y, FALSE);
346 if (filltype != ROOM) {
347 levl[x][y].typ = filltype; /* flags set via doormask */
348 liquid_flow(x, y, filltype, chasm, (char *) 0);
349 }
350
351 mtmp = m_at(x, y); /* (redundant?) */
352 if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
353 if (cansee(x, y))
354 pline("KADOOM! The boulder falls into a chasm%s!",
355 (x == u.ux && y == u.uy) ? " below you" : "");
356 if (mtmp)
357 mtmp->mtrapped = 0;
358 obj_extract_self(otmp);
359 (void) flooreffects(otmp, x, y, "");
360 break; /* from switch, not loop */
361 }
362
363 /* We have to check whether monsters or player
364 falls in a chasm... */
365 if (mtmp) {
366 if (grounded(mtmp->data)) {
367 boolean m_already_trapped = mtmp->mtrapped;
368
369 mtmp->mtrapped = 1;
370 if (!m_already_trapped) { /* suppress messages */
371 if (cansee(x, y))
372 pline("%s falls into a chasm!", Monnam(mtmp));
373 else if (humanoid(mtmp->data))
374 You_hear("a scream!");
375 }
376 /* Falling is okay for falling down
377 within a pit from jostling too */
378 mselftouch(mtmp, "Falling, ", TRUE);
379 if (!DEADMONSTER(mtmp)) {
380 mtmp->mhp -= rnd(m_already_trapped ? 4 : 6);
381 if (DEADMONSTER(mtmp)) {
382 if (!cansee(x, y)) {
383 pline("It is destroyed!");
384 } else {
385 You("destroy %s!",
386 mtmp->mtame
387 ? x_monnam(mtmp, ARTICLE_THE, "poor",
388 has_mgivenname(mtmp)
389 ? SUPPRESS_SADDLE : 0,
390 FALSE)
391 : mon_nam(mtmp));
392 }
393 xkilled(mtmp, XKILL_NOMSG);
394 }
395 }
396 }
397 } else if (x == u.ux && y == u.uy) {
398 if (u.utrap && u.utraptype == TT_BURIEDBALL) {
399 /* Note: the chain should break if a pit gets
400 created at the buried ball's location, which
401 is not necessarily here. But if we don't do
402 things this way, entering the new pit below
403 will override current trap anyway, but too
404 late to get Lev and Fly handling. */
405 Your("chain breaks!");
406 reset_utrap(TRUE);
407 }
408 if (Levitation || Flying || !grounded(g.youmonst.data)) {
409 if (!tu_pit) { /* no pit here previously */
410 pline("A chasm opens up under you!");
411 You("don't fall in!");
412 }
413 } else if (!tu_pit || !u.utrap || u.utraptype != TT_PIT) {
414 /* no pit here previously, or you were
415 not in it even if there was */
416 You("fall into a chasm!");
417 set_utrap(rn1(6, 2), TT_PIT);
418 losehp(Maybe_Half_Phys(rnd(6)),
419 "fell into a chasm", NO_KILLER_PREFIX);
420 selftouch("Falling, you");
421 } else if (u.utrap && u.utraptype == TT_PIT) {
422 boolean keepfooting =
423 ((Fumbling && !rn2(5))
424 || (!rnl(Role_if(PM_ARCHEOLOGIST) ? 3 : 9))
425 || ((ACURR(A_DEX) > 7) && rn2(5)));
426
427 You("are jostled around violently!");
428 set_utrap(rn1(6, 2), TT_PIT);
429 losehp(Maybe_Half_Phys(rnd(keepfooting ? 2 : 4)),
430 "hurt in a chasm", NO_KILLER_PREFIX);
431 if (keepfooting)
432 exercise(A_DEX, TRUE);
433 else
434 selftouch((Upolyd && (slithy(g.youmonst.data)
435 || nolimbs(g.youmonst.data)))
436 ? "Shaken, you"
437 : "Falling down, you");
438 }
439 } else {
440 newsym(x, y);
441 }
442 break;
443 case SDOOR:
444 cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */
445 if (cansee(x, y))
446 pline("A secret door is revealed.");
447 /*FALLTHRU*/
448 case DOOR: /* make the door collapse */
449 /* if already doorless, treat like room or corridor */
450 if (doorstate(&levl[x][y]) == D_NODOOR)
451 goto do_pit;
452 /* wasn't doorless, now it will be */
453 set_doorstate(&levl[x][y], D_NODOOR);
454 unblock_point(x, y);
455 newsym(x, y); /* before pline */
456 if (cansee(x, y))
457 pline_The("door collapses.");
458 if (*in_rooms(x, y, SHOPBASE))
459 add_damage(x, y, 0L);
460 break;
461 }
462 }
463 }
464
465 static const char *
generic_lvl_desc(void)466 generic_lvl_desc(void)
467 {
468 if (Is_astralevel(&u.uz))
469 return "astral plane";
470 else if (In_endgame(&u.uz))
471 return "plane";
472 else if (Is_sanctum(&u.uz))
473 return "sanctum";
474 else if (In_sokoban(&u.uz))
475 return "puzzle";
476 else if (In_V_tower(&u.uz))
477 return "tower";
478 else
479 return "dungeon";
480 }
481
482 const char *beats[] = {
483 "stepper", "one drop", "slow two", "triple stroke roll",
484 "double shuffle", "half-time shuffle", "second line", "train"
485 };
486
487 /*
488 * The player is trying to extract something from his/her instrument.
489 */
490 static int
do_improvisation(struct obj * instr)491 do_improvisation(struct obj* instr)
492 {
493 int damage, mode, do_spec = !(Stunned || Confusion);
494 struct obj itmp;
495 boolean mundane = FALSE;
496
497 itmp = *instr;
498 itmp.oextra = (struct oextra *) 0; /* ok on this copy as instr maintains
499 the ptr to free at some point if
500 there is one */
501
502 /* if won't yield special effect, make sound of mundane counterpart */
503 if (!do_spec || instr->spe <= 0)
504 while (objects[itmp.otyp].oc_magic) {
505 itmp.otyp -= 1;
506 mundane = TRUE;
507 }
508
509
510 #define PLAY_NORMAL 0x00
511 #define PLAY_STUNNED 0x01
512 #define PLAY_CONFUSED 0x02
513 #define PLAY_HALLU 0x04
514 mode = PLAY_NORMAL;
515 if (Stunned)
516 mode |= PLAY_STUNNED;
517 if (Confusion)
518 mode |= PLAY_CONFUSED;
519 if (Hallucination)
520 mode |= PLAY_HALLU;
521
522 if (!rn2(2)) {
523 /*
524 * TEMPORARY? for multiple impairments, don't always
525 * give the generic "it's far from music" message.
526 */
527 /* remove if STUNNED+CONFUSED ever gets its own message below */
528 if (mode == (PLAY_STUNNED | PLAY_CONFUSED))
529 mode = !rn2(2) ? PLAY_STUNNED : PLAY_CONFUSED;
530 /* likewise for stunned and/or confused combined with hallucination */
531 if (mode & PLAY_HALLU)
532 mode = PLAY_HALLU;
533 }
534
535 /* 3.6.3: most of these gave "You produce <blah>" and then many of
536 the instrument-specific messages below which immediately follow
537 also gave "You produce <something>." That looked strange so we
538 now use a different verb here */
539 switch (mode) {
540 case PLAY_NORMAL:
541 You("start playing %s.", yname(instr));
542 break;
543 case PLAY_STUNNED:
544 if (!Deaf)
545 You("radiate an obnoxious droning sound.");
546 else
547 You_feel("a monotonous vibration.");
548 break;
549 case PLAY_CONFUSED:
550 if (!Deaf)
551 You("generate a raucous noise.");
552 else
553 You_feel("a jarring vibration.");
554 break;
555 case PLAY_HALLU:
556 You("disseminate a kaleidoscopic display of floating butterflies.");
557 break;
558 /* TODO? give some or all of these combinations their own feedback;
559 hallucination ones should reference senses other than hearing... */
560 case PLAY_STUNNED | PLAY_CONFUSED:
561 case PLAY_STUNNED | PLAY_HALLU:
562 case PLAY_CONFUSED | PLAY_HALLU:
563 case PLAY_STUNNED | PLAY_CONFUSED | PLAY_HALLU:
564 default:
565 pline("What you perform is quite far from music...");
566 break;
567 }
568 #undef PLAY_NORMAL
569 #undef PLAY_STUNNED
570 #undef PLAY_CONFUSED
571 #undef PLAY_HALLU
572
573 switch (itmp.otyp) { /* note: itmp.otyp might differ from instr->otyp */
574 case MAGIC_FLUTE: /* Make monster fall asleep */
575 consume_obj_charge(instr, TRUE);
576
577 You("%sproduce %s music.", !Deaf ? "" : "seem to ",
578 Hallucination ? "elevator" : "soft");
579 put_monsters_to_sleep(&g.youmonst, u.ulevel * 5);
580 exercise(A_DEX, TRUE);
581 break;
582 case FLUTE: /* May charm snakes */
583 do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
584 if (!Deaf)
585 pline("%s.", Tobjnam(instr, do_spec ? "trill" : "toot"));
586 else
587 You_feel("%s %s.", yname(instr), do_spec ? "trill" : "toot");
588 if (do_spec)
589 charm_snakes(u.ulevel * 3);
590 exercise(A_DEX, TRUE);
591 break;
592 case FIRE_HORN: /* Idem wand of fire */
593 case FROST_HORN: /* Idem wand of cold */
594 consume_obj_charge(instr, TRUE);
595
596 if (!getdir((char *) 0)) {
597 pline("%s.", Tobjnam(instr, "vibrate"));
598 break;
599 } else if (!u.dx && !u.dy && !u.dz) {
600 if ((damage = zapyourself(instr, TRUE)) != 0) {
601 char buf[BUFSZ];
602
603 Sprintf(buf, "using a magical horn on %sself", uhim());
604 losehp(damage, buf, KILLED_BY); /* fire or frost damage */
605 }
606 } else {
607 buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1,
608 rn1(6, 6), u.ux, u.uy, u.dx, u.dy);
609 }
610 makeknown(instr->otyp);
611 break;
612 case TOOLED_HORN: /* Awaken or scare monsters */
613 if (!Deaf)
614 You("produce a frightful, grave sound.");
615 else
616 You("blow into the horn.");
617 awaken_monsters(u.ulevel * 30);
618 exercise(A_WIS, FALSE);
619 break;
620 case BUGLE: /* Awaken & attract soldiers */
621 if (!Deaf)
622 You("extract a loud noise from %s.", yname(instr));
623 else
624 You("blow into the bugle.");
625 awaken_soldiers(&g.youmonst);
626 exercise(A_WIS, FALSE);
627 break;
628 case MAGIC_HARP: /* Charm monsters */
629 consume_obj_charge(instr, TRUE);
630
631 if (!Deaf)
632 pline("%s very attractive music.", Tobjnam(instr, "produce"));
633 else
634 You_feel("very soothing vibrations.");
635 charm_monsters((u.ulevel - 1) / 3 + 1);
636 exercise(A_DEX, TRUE);
637 break;
638 case HARP: /* May calm Nymph */
639 do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
640 if (!Deaf)
641 pline("%s %s.", Yname2(instr),
642 do_spec ? "produces a lilting melody" : "twangs");
643 else
644 You_feel("soothing vibrations.");
645 if (do_spec)
646 calm_nymphs(u.ulevel * 3);
647 exercise(A_DEX, TRUE);
648 break;
649 case DRUM_OF_EARTHQUAKE: /* create several pits */
650 /* a drum of earthquake does not cause deafness
651 while still magically functional, nor afterwards
652 when it invokes the LEATHER_DRUM case instead and
653 mundane is flagged */
654 consume_obj_charge(instr, TRUE);
655
656 You("produce a heavy, thunderous rolling!");
657 pline_The("entire %s is shaking around you!", generic_lvl_desc());
658 do_earthquake((u.ulevel - 1) / 3 + 1);
659 /* shake up monsters in a much larger radius... */
660 awaken_monsters(ROWNO * COLNO);
661 makeknown(DRUM_OF_EARTHQUAKE);
662 break;
663 case LEATHER_DRUM: /* Awaken monsters */
664 if (!mundane) {
665 if (!Deaf) {
666 You("beat a deafening row!");
667 incr_itimeout(&HDeaf, rn1(20, 30));
668 } else {
669 You("pound on the drum.");
670 }
671 exercise(A_WIS, FALSE);
672 } else
673 You("%s %s.",
674 rn2(2) ? "butcher" : rn2(2) ? "manage" : "pull off",
675 an(beats[rn2(SIZE(beats))]));
676 awaken_monsters(u.ulevel * (mundane ? 5 : 40));
677 g.context.botl = TRUE;
678 break;
679 default:
680 impossible("What a weird instrument (%d)!", instr->otyp);
681 return 0;
682 }
683 return 2; /* That takes time */
684 }
685
686 /*
687 * So you want music...
688 */
689 int
do_play_instrument(struct obj * instr)690 do_play_instrument(struct obj* instr)
691 {
692 char buf[BUFSZ] = DUMMY, c = 'y';
693 char *s;
694 int x, y;
695 boolean ok;
696
697 if (Underwater) {
698 You_cant("play music underwater!");
699 return 0;
700 } else if ((instr->otyp == FLUTE || instr->otyp == MAGIC_FLUTE
701 || instr->otyp == TOOLED_HORN || instr->otyp == FROST_HORN
702 || instr->otyp == FIRE_HORN || instr->otyp == BUGLE)
703 && !can_blow(&g.youmonst)) {
704 You("are incapable of playing %s.", the(distant_name(instr, xname)));
705 return 0;
706 }
707 if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE
708 && !(Stunned || Confusion || Hallucination)) {
709 c = ynq("Improvise?");
710 if (c == 'q')
711 goto nevermind;
712 }
713
714 if (c == 'n') {
715 if (u.uevent.uheard_tune == 2)
716 c = ynq("Play the passtune?");
717 if (c == 'q') {
718 goto nevermind;
719 } else if (c == 'y') {
720 Strcpy(buf, g.tune);
721 } else {
722 getlin("What tune are you playing? [5 notes, A-G]", buf);
723 (void) mungspaces(buf);
724 if (*buf == '\033')
725 goto nevermind;
726
727 /* convert to uppercase and change any "H" to the expected "B" */
728 for (s = buf; *s; s++) {
729 *s = highc(*s);
730 if (*s == 'H')
731 *s = 'B';
732 }
733 }
734
735 You(!Deaf ? "extract a strange sound from %s!"
736 : "can feel %s emitting vibrations.", the(xname(instr)));
737
738
739 /* Check if there was the Stronghold drawbridge near
740 * and if the tune conforms to what we're waiting for.
741 */
742 if (Is_stronghold(&u.uz)) {
743 exercise(A_WIS, TRUE); /* just for trying */
744 if (!strcmp(buf, g.tune)) {
745 /* Search for the drawbridge */
746 for (y = u.uy - 1; y <= u.uy + 1; y++)
747 for (x = u.ux - 1; x <= u.ux + 1; x++)
748 if (isok(x, y))
749 if (find_drawbridge(&x, &y)) {
750 /* tune now fully known */
751 u.uevent.uheard_tune = 2;
752 if (levl[x][y].typ == DRAWBRIDGE_DOWN)
753 close_drawbridge(x, y);
754 else
755 open_drawbridge(x, y);
756 return 1;
757 }
758 } else if (!Deaf) {
759 if (u.uevent.uheard_tune < 1)
760 u.uevent.uheard_tune = 1;
761 /* Okay, it wasn't the right tune, but perhaps
762 * we can give the player some hints like in the
763 * Mastermind game */
764 ok = FALSE;
765 for (y = u.uy - 1; y <= u.uy + 1 && !ok; y++)
766 for (x = u.ux - 1; x <= u.ux + 1 && !ok; x++)
767 if (isok(x, y))
768 if (IS_DRAWBRIDGE(levl[x][y].typ)
769 || is_drawbridge_wall(x, y) >= 0)
770 ok = TRUE;
771 if (ok) { /* There is a drawbridge near */
772 int tumblers, gears;
773 boolean matched[5];
774
775 tumblers = gears = 0;
776 for (x = 0; x < 5; x++)
777 matched[x] = FALSE;
778
779 for (x = 0; x < (int) strlen(buf); x++)
780 if (x < 5) {
781 if (buf[x] == g.tune[x]) {
782 gears++;
783 matched[x] = TRUE;
784 } else {
785 for (y = 0; y < 5; y++)
786 if (!matched[y] && buf[x] == g.tune[y]
787 && buf[y] != g.tune[y]) {
788 tumblers++;
789 matched[y] = TRUE;
790 break;
791 }
792 }
793 }
794 if (tumblers) {
795 if (gears)
796 You_hear("%d tumbler%s click and %d gear%s turn.",
797 tumblers, plur(tumblers), gears,
798 plur(gears));
799 else
800 You_hear("%d tumbler%s click.", tumblers,
801 plur(tumblers));
802 } else if (gears) {
803 You_hear("%d gear%s turn.", gears, plur(gears));
804 /* could only get `gears == 5' by playing five
805 correct notes followed by excess; otherwise,
806 tune would have matched above */
807 if (gears == 5)
808 u.uevent.uheard_tune = 2;
809 }
810 }
811 }
812 }
813 return 1;
814 } else
815 return do_improvisation(instr);
816
817 nevermind:
818 pline1(Never_mind);
819 return 0;
820 }
821
822 /*music.c*/
823