Unify putting a saddle on steed
[aNetHack.git] / src / read.c
blob815dfe731f9b1031bceb4406adac80ed150ee483
1 /* NetHack 3.6 read.c $NHDT-Date: 1450577673 2015/12/20 02:14:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.131 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 #define Your_Own_Role(mndx) \
8 ((mndx) == urole.malenum \
9 || (urole.femalenum != NON_PM && (mndx) == urole.femalenum))
10 #define Your_Own_Race(mndx) \
11 ((mndx) == urace.malenum \
12 || (urace.femalenum != NON_PM && (mndx) == urace.femalenum))
14 boolean known;
16 static NEARDATA const char readable[] = { ALL_CLASSES, SCROLL_CLASS,
17 SPBOOK_CLASS, 0 };
18 static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
20 STATIC_DCL boolean FDECL(learnscrolltyp, (SHORT_P));
21 STATIC_DCL char * FDECL(erode_obj_text, (struct obj *, char *));
22 STATIC_DCL void NDECL(do_class_genocide);
23 STATIC_DCL void FDECL(stripspe, (struct obj *));
24 STATIC_DCL void FDECL(p_glow1, (struct obj *));
25 STATIC_DCL void FDECL(p_glow2, (struct obj *, const char *));
26 STATIC_DCL void FDECL(randomize, (int *, int));
27 STATIC_DCL void FDECL(forget_single_object, (int));
28 STATIC_DCL void FDECL(forget, (int));
29 STATIC_DCL int FDECL(maybe_tame, (struct monst *, struct obj *));
30 STATIC_DCL boolean FDECL(is_valid_stinking_cloud_pos, (int, int, BOOLEAN_P));
31 STATIC_DCL void FDECL(display_stinking_cloud_positions, (int));
32 STATIC_PTR void FDECL(set_lit, (int, int, genericptr));
34 STATIC_OVL boolean
35 learnscrolltyp(scrolltyp)
36 short scrolltyp;
38 if (!objects[scrolltyp].oc_name_known) {
39 makeknown(scrolltyp);
40 more_experienced(0, 10);
41 return TRUE;
42 } else
43 return FALSE;
46 /* also called from teleport.c for scroll of teleportation */
47 void
48 learnscroll(sobj)
49 struct obj *sobj;
51 /* it's implied that sobj->dknown is set;
52 we couldn't be reading this scroll otherwise */
53 if (sobj->oclass != SPBOOK_CLASS)
54 (void) learnscrolltyp(sobj->otyp);
57 char *
58 erode_obj_text(otmp, buf)
59 struct obj *otmp;
60 char *buf;
62 int erosion = greatest_erosion(otmp);
63 if (erosion)
64 wipeout_text(buf, (int) (strlen(buf) * erosion / (2 * MAX_ERODE)),
65 otmp->o_id ^ (unsigned) ubirthday);
66 return buf;
69 char *
70 tshirt_text(tshirt, buf)
71 struct obj *tshirt;
72 char *buf;
74 static const char *shirt_msgs[] = {
75 /* Scott Bigham */
76 "I explored the Dungeons of Doom and all I got was this lousy T-shirt!",
77 "Is that Mjollnir in your pocket or are you just happy to see me?",
78 "It's not the size of your sword, it's how #enhance'd you are with it.",
79 "Madame Elvira's House O' Succubi Lifetime Customer",
80 "Madame Elvira's House O' Succubi Employee of the Month",
81 "Ludios Vault Guards Do It In Small, Dark Rooms",
82 "Yendor Military Soldiers Do It In Large Groups",
83 "I survived Yendor Military Boot Camp",
84 "Ludios Accounting School Intra-Mural Lacrosse Team",
85 "Oracle(TM) Fountains 10th Annual Wet T-Shirt Contest",
86 "Hey, black dragon! Disintegrate THIS!",
87 "I'm With Stupid -->",
88 "Don't blame me, I voted for Izchak!",
89 "Don't Panic", /* HHGTTG */
90 "Furinkan High School Athletic Dept.", /* Ranma 1/2 */
91 "Hel-LOOO, Nurse!", /* Animaniacs */
92 "=^.^=",
93 "100% goblin hair - do not wash",
94 "Aberzombie and Fitch",
95 "cK -- Cockatrice touches the Kop",
96 "Don't ask me, I only adventure here",
97 "Down with pants!",
98 "d, your dog or a killer?",
99 "FREE PUG AND NEWT!",
100 "Go team ant!",
101 "Got newt?",
102 "Hello, my darlings!", /* Charlie Drake */
103 "Hey! Nymphs! Steal This T-Shirt!",
104 "I <3 Dungeon of Doom",
105 "I <3 Maud",
106 "I am a Valkyrie. If you see me running, try to keep up.",
107 "I am not a pack rat - I am a collector",
108 "I bounced off a rubber tree", /* Monkey Island */
109 "Plunder Island Brimstone Beach Club", /* Monkey Island */
110 "If you can read this, I can hit you with my polearm",
111 "I'm confused!",
112 "I scored with the princess",
113 "I want to live forever or die in the attempt.",
114 "Lichen Park",
115 "LOST IN THOUGHT - please send search party",
116 "Meat is Mordor",
117 "Minetown Better Business Bureau",
118 "Minetown Watch",
119 "Ms. Palm's House of Negotiable Affection -- A Very Reputable House Of Disrepute",
120 "Protection Racketeer",
121 "Real men love Crom",
122 "Somebody stole my Mojo!",
123 "The Hellhound Gang",
124 "The Werewolves",
125 "They Might Be Storm Giants",
126 "Weapons don't kill people, I kill people",
127 "White Zombie",
128 "You're killing me!",
129 "Anhur State University - Home of the Fighting Fire Ants!",
130 "FREE HUGS",
131 "Serial Ascender",
132 "Real men are valkyries",
133 "Young Men's Cavedigging Association",
134 "Occupy Fort Ludios",
135 "I couldn't afford this T-shirt so I stole it!",
136 "Mind flayers suck",
137 "I'm not wearing any pants",
138 "Down with the living!",
139 "Pudding farmer",
140 "Vegetarian",
141 "Hello, I'm War!",
144 Strcpy(buf, shirt_msgs[tshirt->o_id % SIZE(shirt_msgs)]);
145 return erode_obj_text(tshirt, buf);
148 char *
149 apron_text(apron, buf)
150 struct obj *apron;
151 char *buf;
153 static const char *apron_msgs[] = {
154 "Kiss the cook",
155 "I'm making SCIENCE!",
156 "Don't mess with the chef",
157 "Don't make me poison you",
158 "Gehennom's Kitchen",
159 "Rat: The other white meat",
160 "If you can't stand the heat, get out of Gehennom!",
161 "If we weren't meant to eat animals, why are they made out of meat?",
162 "If you don't like the food, I'll stab you",
165 Strcpy(buf, apron_msgs[apron->o_id % SIZE(apron_msgs)]);
166 return erode_obj_text(apron, buf);
170 doread()
172 register struct obj *scroll;
173 boolean confused, nodisappear;
175 known = FALSE;
176 if (check_capacity((char *) 0))
177 return 0;
178 scroll = getobj(readable, "read");
179 if (!scroll)
180 return 0;
182 /* outrumor has its own blindness check */
183 if (scroll->otyp == FORTUNE_COOKIE) {
184 if (flags.verbose)
185 You("break up the cookie and throw away the pieces.");
186 outrumor(bcsign(scroll), BY_COOKIE);
187 if (!Blind)
188 u.uconduct.literate++;
189 useup(scroll);
190 return 1;
191 } else if (scroll->otyp == T_SHIRT || scroll->otyp == ALCHEMY_SMOCK) {
192 char buf[BUFSZ];
193 if (Blind) {
194 You_cant("feel any Braille writing.");
195 return 0;
197 /* can't read shirt worn under suit (under cloak is ok though) */
198 if (scroll->otyp == T_SHIRT && uarm && scroll == uarmu) {
199 pline("%s shirt is obscured by %s%s.",
200 scroll->unpaid ? "That" : "Your", shk_your(buf, uarm),
201 suit_simple_name(uarm));
202 return 0;
204 u.uconduct.literate++;
205 if (flags.verbose)
206 pline("It reads:");
207 pline("\"%s\"", (scroll->otyp == T_SHIRT) ? tshirt_text(scroll, buf)
208 : apron_text(scroll, buf));
209 return 1;
210 } else if (scroll->otyp == CREDIT_CARD) {
211 static const char *card_msgs[] = {
212 "Leprechaun Gold Tru$t - Shamrock Card",
213 "Magic Memory Vault Charge Card", "Larn National Bank", /* Larn */
214 "First Bank of Omega", /* Omega */
215 "Bank of Zork - Frobozz Magic Card", /* Zork */
216 "Ankh-Morpork Merchant's Guild Barter Card",
217 "Ankh-Morpork Thieves' Guild Unlimited Transaction Card",
218 "Ransmannsby Moneylenders Association",
219 "Bank of Gehennom - 99% Interest Card",
220 "Yendorian Express - Copper Card",
221 "Yendorian Express - Silver Card",
222 "Yendorian Express - Gold Card",
223 "Yendorian Express - Mithril Card",
224 "Yendorian Express - Platinum Card", /* must be last */
227 if (Blind) {
228 You("feel the embossed numbers:");
229 } else {
230 if (flags.verbose)
231 pline("It reads:");
232 pline("\"%s\"",
233 scroll->oartifact
234 ? card_msgs[SIZE(card_msgs) - 1]
235 : card_msgs[scroll->o_id % (SIZE(card_msgs) - 1)]);
237 /* Make a credit card number */
238 pline("\"%d0%d %d%d1 0%d%d0\"", ((scroll->o_id % 89) + 10),
239 (scroll->o_id % 4), (((scroll->o_id * 499) % 899999) + 100000),
240 (scroll->o_id % 10), (!(scroll->o_id % 3)),
241 ((scroll->o_id * 7) % 10));
242 u.uconduct.literate++;
243 return 1;
244 } else if (scroll->otyp == CAN_OF_GREASE) {
245 pline("This %s has no label.", singular(scroll, xname));
246 return 0;
247 } else if (scroll->otyp == MAGIC_MARKER) {
248 if (Blind) {
249 You_cant("feel any Braille writing.");
250 return 0;
252 if (flags.verbose)
253 pline("It reads:");
254 pline("\"Magic Marker(TM) Red Ink Marker Pen. Water Soluble.\"");
255 u.uconduct.literate++;
256 return 1;
257 } else if (scroll->oclass == COIN_CLASS) {
258 if (Blind)
259 You("feel the embossed words:");
260 else if (flags.verbose)
261 You("read:");
262 pline("\"1 Zorkmid. 857 GUE. In Frobs We Trust.\"");
263 u.uconduct.literate++;
264 return 1;
265 } else if (scroll->oartifact == ART_ORB_OF_FATE) {
266 if (Blind)
267 You("feel the engraved signature:");
268 else
269 pline("It is signed:");
270 pline("\"Odin.\"");
271 u.uconduct.literate++;
272 return 1;
273 } else if (scroll->otyp == CANDY_BAR) {
274 static const char *wrapper_msgs[] = {
275 "Apollo", /* Lost */
276 "Moon Crunchy", /* South Park */
277 "Snacky Cake", "Chocolate Nuggie", "The Small Bar",
278 "Crispy Yum Yum", "Nilla Crunchie", "Berry Bar",
279 "Choco Nummer", "Om-nom", /* Cat Macro */
280 "Fruity Oaty", /* Serenity */
281 "Wonka Bar" /* Charlie and the Chocolate Factory */
284 if (Blind) {
285 You_cant("feel any Braille writing.");
286 return 0;
288 pline("The wrapper reads: \"%s\"",
289 wrapper_msgs[scroll->o_id % SIZE(wrapper_msgs)]);
290 u.uconduct.literate++;
291 return 1;
292 } else if (scroll->oclass != SCROLL_CLASS
293 && scroll->oclass != SPBOOK_CLASS) {
294 pline(silly_thing_to, "read");
295 return 0;
296 } else if (Blind && (scroll->otyp != SPE_BOOK_OF_THE_DEAD)) {
297 const char *what = 0;
298 if (scroll->oclass == SPBOOK_CLASS)
299 what = "mystic runes";
300 else if (!scroll->dknown)
301 what = "formula on the scroll";
302 if (what) {
303 pline("Being blind, you cannot read the %s.", what);
304 return 0;
308 confused = (Confusion != 0);
309 #ifdef MAIL
310 if (scroll->otyp == SCR_MAIL) {
311 confused = FALSE; /* override */
312 /* reading mail is a convenience for the player and takes
313 place outside the game, so shouldn't affect gameplay;
314 on the other hand, it starts by explicitly making the
315 hero actively read something, which is pretty hard
316 to simply ignore; as a compromise, if the player has
317 maintained illiterate conduct so far, and this mail
318 scroll didn't come from bones, ask for confirmation */
319 if (!u.uconduct.literate) {
320 if (!scroll->spe && yn(
321 "Reading mail will violate \"illiterate\" conduct. Read anyway?"
322 ) != 'y')
323 return 0;
326 #endif
328 /* Actions required to win the game aren't counted towards conduct */
329 /* Novel conduct is handled in read_tribute so exclude it too*/
330 if (scroll->otyp != SPE_BOOK_OF_THE_DEAD
331 && scroll->otyp != SPE_BLANK_PAPER && scroll->otyp != SCR_BLANK_PAPER
332 && scroll->otyp != SPE_NOVEL)
333 u.uconduct.literate++;
335 if (scroll->oclass == SPBOOK_CLASS) {
336 return study_book(scroll);
338 scroll->in_use = TRUE; /* scroll, not spellbook, now being read */
339 if (scroll->otyp != SCR_BLANK_PAPER) {
340 /* a few scroll feedback messages describe something happening
341 to the scroll itself, so avoid "it disappears" for those */
342 nodisappear = (scroll->otyp == SCR_FIRE
343 || (scroll->otyp == SCR_REMOVE_CURSE
344 && scroll->cursed));
345 if (Blind)
346 pline(nodisappear
347 ? "You %s the formula on the scroll."
348 : "As you %s the formula on it, the scroll disappears.",
349 is_silent(youmonst.data) ? "cogitate" : "pronounce");
350 else
351 pline(nodisappear ? "You read the scroll."
352 : "As you read the scroll, it disappears.");
353 if (confused) {
354 if (Hallucination)
355 pline("Being so trippy, you screw up...");
356 else
357 pline("Being confused, you %s the magic words...",
358 is_silent(youmonst.data) ? "misunderstand"
359 : "mispronounce");
362 if (!seffects(scroll)) {
363 if (!objects[scroll->otyp].oc_name_known) {
364 if (known)
365 learnscroll(scroll);
366 else if (!objects[scroll->otyp].oc_uname)
367 docall(scroll);
369 scroll->in_use = FALSE;
370 if (scroll->otyp != SCR_BLANK_PAPER)
371 useup(scroll);
373 return 1;
376 STATIC_OVL void
377 stripspe(obj)
378 register struct obj *obj;
380 if (obj->blessed || obj->spe <= 0) {
381 pline1(nothing_happens);
382 } else {
383 /* order matters: message, shop handling, actual transformation */
384 pline("%s briefly.", Yobjnam2(obj, "vibrate"));
385 costly_alteration(obj, COST_UNCHRG);
386 obj->spe = 0;
387 if (obj->otyp == OIL_LAMP || obj->otyp == BRASS_LANTERN)
388 obj->age = 0;
392 STATIC_OVL void
393 p_glow1(otmp)
394 register struct obj *otmp;
396 pline("%s briefly.", Yobjnam2(otmp, Blind ? "vibrate" : "glow"));
399 STATIC_OVL void
400 p_glow2(otmp, color)
401 register struct obj *otmp;
402 register const char *color;
404 pline("%s%s%s for a moment.", Yobjnam2(otmp, Blind ? "vibrate" : "glow"),
405 Blind ? "" : " ", Blind ? "" : hcolor(color));
408 /* Is the object chargeable? For purposes of inventory display; it is
409 possible to be able to charge things for which this returns FALSE. */
410 boolean
411 is_chargeable(obj)
412 struct obj *obj;
414 if (obj->oclass == WAND_CLASS)
415 return TRUE;
416 /* known && !oc_name_known is possible after amnesia/mind flayer */
417 if (obj->oclass == RING_CLASS)
418 return (boolean) (objects[obj->otyp].oc_charged
419 && (obj->known
420 || (obj->dknown
421 && objects[obj->otyp].oc_name_known)));
422 if (is_weptool(obj)) /* specific check before general tools */
423 return FALSE;
424 if (obj->oclass == TOOL_CLASS)
425 return (boolean) objects[obj->otyp].oc_charged;
426 return FALSE; /* why are weapons/armor considered charged anyway? */
429 /* recharge an object; curse_bless is -1 if the recharging implement
430 was cursed, +1 if blessed, 0 otherwise. */
431 void
432 recharge(obj, curse_bless)
433 struct obj *obj;
434 int curse_bless;
436 register int n;
437 boolean is_cursed, is_blessed;
439 is_cursed = curse_bless < 0;
440 is_blessed = curse_bless > 0;
442 if (obj->oclass == WAND_CLASS) {
443 int lim = (obj->otyp == WAN_WISHING)
445 : (objects[obj->otyp].oc_dir != NODIR) ? 8 : 15;
447 /* undo any prior cancellation, even when is_cursed */
448 if (obj->spe == -1)
449 obj->spe = 0;
452 * Recharging might cause wands to explode.
453 * v = number of previous recharges
454 * v = percentage chance to explode on this attempt
455 * v = cumulative odds for exploding
456 * 0 : 0 0
457 * 1 : 0.29 0.29
458 * 2 : 2.33 2.62
459 * 3 : 7.87 10.28
460 * 4 : 18.66 27.02
461 * 5 : 36.44 53.62
462 * 6 : 62.97 82.83
463 * 7 : 100 100
465 n = (int) obj->recharged;
466 if (n > 0 && (obj->otyp == WAN_WISHING
467 || (n * n * n > rn2(7 * 7 * 7)))) { /* recharge_limit */
468 wand_explode(obj, rnd(lim));
469 return;
471 /* didn't explode, so increment the recharge count */
472 obj->recharged = (unsigned) (n + 1);
474 /* now handle the actual recharging */
475 if (is_cursed) {
476 stripspe(obj);
477 } else {
478 n = (lim == 3) ? 3 : rn1(5, lim + 1 - 5);
479 if (!is_blessed)
480 n = rnd(n);
482 if (obj->spe < n)
483 obj->spe = n;
484 else
485 obj->spe++;
486 if (obj->otyp == WAN_WISHING && obj->spe > 3) {
487 wand_explode(obj, 1);
488 return;
490 if (obj->spe >= lim)
491 p_glow2(obj, NH_BLUE);
492 else
493 p_glow1(obj);
494 #if 0 /*[shop price doesn't vary by charge count]*/
495 /* update shop bill to reflect new higher price */
496 if (obj->unpaid)
497 alter_cost(obj, 0L);
498 #endif
501 } else if (obj->oclass == RING_CLASS && objects[obj->otyp].oc_charged) {
502 /* charging does not affect ring's curse/bless status */
503 int s = is_blessed ? rnd(3) : is_cursed ? -rnd(2) : 1;
504 boolean is_on = (obj == uleft || obj == uright);
506 /* destruction depends on current state, not adjustment */
507 if (obj->spe > rn2(7) || obj->spe <= -5) {
508 pline("%s momentarily, then %s!", Yobjnam2(obj, "pulsate"),
509 otense(obj, "explode"));
510 if (is_on)
511 Ring_gone(obj);
512 s = rnd(3 * abs(obj->spe)); /* amount of damage */
513 useup(obj);
514 losehp(Maybe_Half_Phys(s), "exploding ring", KILLED_BY_AN);
515 } else {
516 long mask = is_on ? (obj == uleft ? LEFT_RING : RIGHT_RING) : 0L;
518 pline("%s spins %sclockwise for a moment.", Yname2(obj),
519 s < 0 ? "counter" : "");
520 if (s < 0)
521 costly_alteration(obj, COST_DECHNT);
522 /* cause attributes and/or properties to be updated */
523 if (is_on)
524 Ring_off(obj);
525 obj->spe += s; /* update the ring while it's off */
526 if (is_on)
527 setworn(obj, mask), Ring_on(obj);
528 /* oartifact: if a touch-sensitive artifact ring is
529 ever created the above will need to be revised */
530 /* update shop bill to reflect new higher price */
531 if (s > 0 && obj->unpaid)
532 alter_cost(obj, 0L);
535 } else if (obj->oclass == TOOL_CLASS) {
536 int rechrg = (int) obj->recharged;
538 if (objects[obj->otyp].oc_charged) {
539 /* tools don't have a limit, but the counter used does */
540 if (rechrg < 7) /* recharge_limit */
541 obj->recharged++;
543 switch (obj->otyp) {
544 case BELL_OF_OPENING:
545 if (is_cursed)
546 stripspe(obj);
547 else if (is_blessed)
548 obj->spe += rnd(3);
549 else
550 obj->spe += 1;
551 if (obj->spe > 5)
552 obj->spe = 5;
553 break;
554 case MAGIC_MARKER:
555 case TINNING_KIT:
556 case EXPENSIVE_CAMERA:
557 if (is_cursed)
558 stripspe(obj);
559 else if (rechrg
560 && obj->otyp
561 == MAGIC_MARKER) { /* previously recharged */
562 obj->recharged = 1; /* override increment done above */
563 if (obj->spe < 3)
564 Your("marker seems permanently dried out.");
565 else
566 pline1(nothing_happens);
567 } else if (is_blessed) {
568 n = rn1(16, 15); /* 15..30 */
569 if (obj->spe + n <= 50)
570 obj->spe = 50;
571 else if (obj->spe + n <= 75)
572 obj->spe = 75;
573 else {
574 int chrg = (int) obj->spe;
575 if ((chrg + n) > 127)
576 obj->spe = 127;
577 else
578 obj->spe += n;
580 p_glow2(obj, NH_BLUE);
581 } else {
582 n = rn1(11, 10); /* 10..20 */
583 if (obj->spe + n <= 50)
584 obj->spe = 50;
585 else {
586 int chrg = (int) obj->spe;
587 if ((chrg + n) > 127)
588 obj->spe = 127;
589 else
590 obj->spe += n;
592 p_glow2(obj, NH_WHITE);
594 break;
595 case OIL_LAMP:
596 case BRASS_LANTERN:
597 if (is_cursed) {
598 stripspe(obj);
599 if (obj->lamplit) {
600 if (!Blind)
601 pline("%s out!", Tobjnam(obj, "go"));
602 end_burn(obj, TRUE);
604 } else if (is_blessed) {
605 obj->spe = 1;
606 obj->age = 1500;
607 p_glow2(obj, NH_BLUE);
608 } else {
609 obj->spe = 1;
610 obj->age += 750;
611 if (obj->age > 1500)
612 obj->age = 1500;
613 p_glow1(obj);
615 break;
616 case CRYSTAL_BALL:
617 if (is_cursed) {
618 stripspe(obj);
619 } else if (is_blessed) {
620 obj->spe = 6;
621 p_glow2(obj, NH_BLUE);
622 } else {
623 if (obj->spe < 5) {
624 obj->spe++;
625 p_glow1(obj);
626 } else
627 pline1(nothing_happens);
629 break;
630 case HORN_OF_PLENTY:
631 case BAG_OF_TRICKS:
632 case CAN_OF_GREASE:
633 if (is_cursed) {
634 stripspe(obj);
635 } else if (is_blessed) {
636 if (obj->spe <= 10)
637 obj->spe += rn1(10, 6);
638 else
639 obj->spe += rn1(5, 6);
640 if (obj->spe > 50)
641 obj->spe = 50;
642 p_glow2(obj, NH_BLUE);
643 } else {
644 obj->spe += rnd(5);
645 if (obj->spe > 50)
646 obj->spe = 50;
647 p_glow1(obj);
649 break;
650 case MAGIC_FLUTE:
651 case MAGIC_HARP:
652 case FROST_HORN:
653 case FIRE_HORN:
654 case DRUM_OF_EARTHQUAKE:
655 if (is_cursed) {
656 stripspe(obj);
657 } else if (is_blessed) {
658 obj->spe += d(2, 4);
659 if (obj->spe > 20)
660 obj->spe = 20;
661 p_glow2(obj, NH_BLUE);
662 } else {
663 obj->spe += rnd(4);
664 if (obj->spe > 20)
665 obj->spe = 20;
666 p_glow1(obj);
668 break;
669 default:
670 goto not_chargable;
671 /*NOTREACHED*/
672 break;
673 } /* switch */
675 } else {
676 not_chargable:
677 You("have a feeling of loss.");
681 /* Forget known information about this object type. */
682 STATIC_OVL void
683 forget_single_object(obj_id)
684 int obj_id;
686 objects[obj_id].oc_name_known = 0;
687 objects[obj_id].oc_pre_discovered = 0; /* a discovery when relearned */
688 if (objects[obj_id].oc_uname) {
689 free((genericptr_t) objects[obj_id].oc_uname);
690 objects[obj_id].oc_uname = 0;
692 undiscover_object(obj_id); /* after clearing oc_name_known */
694 /* clear & free object names from matching inventory items too? */
697 #if 0 /* here if anyone wants it.... */
698 /* Forget everything known about a particular object class. */
699 STATIC_OVL void
700 forget_objclass(oclass)
701 int oclass;
703 int i;
705 for (i = bases[oclass];
706 i < NUM_OBJECTS && objects[i].oc_class == oclass; i++)
707 forget_single_object(i);
709 #endif
711 /* randomize the given list of numbers 0 <= i < count */
712 STATIC_OVL void
713 randomize(indices, count)
714 int *indices;
715 int count;
717 int i, iswap, temp;
719 for (i = count - 1; i > 0; i--) {
720 if ((iswap = rn2(i + 1)) == i)
721 continue;
722 temp = indices[i];
723 indices[i] = indices[iswap];
724 indices[iswap] = temp;
728 /* Forget % of known objects. */
729 void
730 forget_objects(percent)
731 int percent;
733 int i, count;
734 int indices[NUM_OBJECTS];
736 if (percent == 0)
737 return;
738 if (percent <= 0 || percent > 100) {
739 impossible("forget_objects: bad percent %d", percent);
740 return;
743 indices[0] = 0; /* lint suppression */
744 for (count = 0, i = 1; i < NUM_OBJECTS; i++)
745 if (OBJ_DESCR(objects[i])
746 && (objects[i].oc_name_known || objects[i].oc_uname))
747 indices[count++] = i;
749 if (count > 0) {
750 randomize(indices, count);
752 /* forget first % of randomized indices */
753 count = ((count * percent) + rn2(100)) / 100;
754 for (i = 0; i < count; i++)
755 forget_single_object(indices[i]);
759 /* Forget some or all of map (depends on parameters). */
760 void
761 forget_map(howmuch)
762 int howmuch;
764 register int zx, zy;
766 if (Sokoban)
767 return;
769 known = TRUE;
770 for (zx = 0; zx < COLNO; zx++)
771 for (zy = 0; zy < ROWNO; zy++)
772 if (howmuch & ALL_MAP || rn2(7)) {
773 /* Zonk all memory of this location. */
774 levl[zx][zy].seenv = 0;
775 levl[zx][zy].waslit = 0;
776 levl[zx][zy].glyph = cmap_to_glyph(S_stone);
777 lastseentyp[zx][zy] = STONE;
779 /* forget overview data for this level */
780 forget_mapseen(ledger_no(&u.uz));
783 /* Forget all traps on the level. */
784 void
785 forget_traps()
787 register struct trap *trap;
789 /* forget all traps (except the one the hero is in :-) */
790 for (trap = ftrap; trap; trap = trap->ntrap)
791 if ((trap->tx != u.ux || trap->ty != u.uy) && (trap->ttyp != HOLE))
792 trap->tseen = 0;
796 * Forget given % of all levels that the hero has visited and not forgotten,
797 * except this one.
799 void
800 forget_levels(percent)
801 int percent;
803 int i, count;
804 xchar maxl, this_lev;
805 int indices[MAXLINFO];
807 if (percent == 0)
808 return;
810 if (percent <= 0 || percent > 100) {
811 impossible("forget_levels: bad percent %d", percent);
812 return;
815 this_lev = ledger_no(&u.uz);
816 maxl = maxledgerno();
818 /* count & save indices of non-forgotten visited levels */
819 /* Sokoban levels are pre-mapped for the player, and should stay
820 * so, or they become nearly impossible to solve. But try to
821 * shift the forgetting elsewhere by fiddling with percent
822 * instead of forgetting fewer levels.
824 indices[0] = 0; /* lint suppression */
825 for (count = 0, i = 0; i <= maxl; i++)
826 if ((level_info[i].flags & VISITED)
827 && !(level_info[i].flags & FORGOTTEN) && i != this_lev) {
828 if (ledger_to_dnum(i) == sokoban_dnum)
829 percent += 2;
830 else
831 indices[count++] = i;
834 if (percent > 100)
835 percent = 100;
837 if (count > 0) {
838 randomize(indices, count);
840 /* forget first % of randomized indices */
841 count = ((count * percent) + 50) / 100;
842 for (i = 0; i < count; i++) {
843 level_info[indices[i]].flags |= FORGOTTEN;
844 forget_mapseen(indices[i]);
850 * Forget some things (e.g. after reading a scroll of amnesia). When called,
851 * the following are always forgotten:
852 * - felt ball & chain
853 * - traps
854 * - part (6 out of 7) of the map
856 * Other things are subject to flags:
857 * howmuch & ALL_MAP = forget whole map
858 * howmuch & ALL_SPELLS = forget all spells
860 STATIC_OVL void
861 forget(howmuch)
862 int howmuch;
864 if (Punished)
865 u.bc_felt = 0; /* forget felt ball&chain */
867 forget_map(howmuch);
868 forget_traps();
870 /* 1 in 3 chance of forgetting some levels */
871 if (!rn2(3))
872 forget_levels(rn2(25));
874 /* 1 in 3 chance of forgetting some objects */
875 if (!rn2(3))
876 forget_objects(rn2(25));
878 if (howmuch & ALL_SPELLS)
879 losespells();
881 * Make sure that what was seen is restored correctly. To do this,
882 * we need to go blind for an instant --- turn off the display,
883 * then restart it. All this work is needed to correctly handle
884 * walls which are stone on one side and wall on the other. Turning
885 * off the seen bits above will make the wall revert to stone, but
886 * there are cases where we don't want this to happen. The easiest
887 * thing to do is to run it through the vision system again, which
888 * is always correct.
890 docrt(); /* this correctly will reset vision */
893 /* monster is hit by scroll of taming's effect */
894 STATIC_OVL int
895 maybe_tame(mtmp, sobj)
896 struct monst *mtmp;
897 struct obj *sobj;
899 int was_tame = mtmp->mtame;
900 unsigned was_peaceful = mtmp->mpeaceful;
902 if (sobj->cursed) {
903 setmangry(mtmp);
904 if (was_peaceful && !mtmp->mpeaceful)
905 return -1;
906 } else {
907 if (mtmp->isshk)
908 make_happy_shk(mtmp, FALSE);
909 else if (!resist(mtmp, sobj->oclass, 0, NOTELL))
910 (void) tamedog(mtmp, (struct obj *) 0);
911 if ((!was_peaceful && mtmp->mpeaceful) || (!was_tame && mtmp->mtame))
912 return 1;
914 return 0;
917 boolean
918 is_valid_stinking_cloud_pos(x, y, showmsg)
919 int x, y;
920 boolean showmsg;
922 if (!cansee(x, y) || !ACCESSIBLE(levl[x][y].typ) || distu(x, y) >= 32) {
923 if (showmsg)
924 You("smell rotten eggs.");
925 return FALSE;
927 return TRUE;
930 void
931 display_stinking_cloud_positions(state)
932 int state;
934 if (state == 0) {
935 tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos));
936 } else if (state == 1) {
937 int x, y, dx, dy;
938 int dist = 6;
940 for (dx = -dist; dx <= dist; dx++)
941 for (dy = -dist; dy <= dist; dy++) {
942 x = u.ux + dx;
943 y = u.uy + dy;
944 if (isok(x, y) && is_valid_stinking_cloud_pos(x, y, FALSE))
945 tmp_at(x, y);
947 } else {
948 tmp_at(DISP_END, 0);
952 /* scroll effects; return 1 if we use up the scroll and possibly make it
953 become discovered, 0 if caller should take care of those side-effects */
955 seffects(sobj)
956 struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
958 int cval, otyp = sobj->otyp;
959 boolean confused = (Confusion != 0), sblessed = sobj->blessed,
960 scursed = sobj->cursed, already_known, old_erodeproof,
961 new_erodeproof;
962 struct obj *otmp;
964 if (objects[otyp].oc_magic)
965 exercise(A_WIS, TRUE); /* just for trying */
966 already_known = (sobj->oclass == SPBOOK_CLASS /* spell */
967 || objects[otyp].oc_name_known);
969 switch (otyp) {
970 #ifdef MAIL
971 case SCR_MAIL:
972 known = TRUE;
973 if (sobj->spe == 2)
974 /* "stamped scroll" created via magic marker--without a stamp */
975 pline("This scroll is marked \"postage due\".");
976 else if (sobj->spe)
977 /* scroll of mail obtained from bones file or from wishing;
978 * note to the puzzled: the game Larn actually sends you junk
979 * mail if you win!
981 pline(
982 "This seems to be junk mail addressed to the finder of the Eye of Larn.");
983 else
984 readmail(sobj);
985 break;
986 #endif
987 case SCR_ENCHANT_ARMOR: {
988 register schar s;
989 boolean special_armor;
990 boolean same_color;
992 otmp = some_armor(&youmonst);
993 if (!otmp) {
994 strange_feeling(sobj, !Blind
995 ? "Your skin glows then fades."
996 : "Your skin feels warm for a moment.");
997 sobj = 0; /* useup() in strange_feeling() */
998 exercise(A_CON, !scursed);
999 exercise(A_STR, !scursed);
1000 break;
1002 if (confused) {
1003 old_erodeproof = (otmp->oerodeproof != 0);
1004 new_erodeproof = !scursed;
1005 otmp->oerodeproof = 0; /* for messages */
1006 if (Blind) {
1007 otmp->rknown = FALSE;
1008 pline("%s warm for a moment.", Yobjnam2(otmp, "feel"));
1009 } else {
1010 otmp->rknown = TRUE;
1011 pline("%s covered by a %s %s %s!", Yobjnam2(otmp, "are"),
1012 scursed ? "mottled" : "shimmering",
1013 hcolor(scursed ? NH_BLACK : NH_GOLDEN),
1014 scursed ? "glow"
1015 : (is_shield(otmp) ? "layer" : "shield"));
1017 if (new_erodeproof && (otmp->oeroded || otmp->oeroded2)) {
1018 otmp->oeroded = otmp->oeroded2 = 0;
1019 pline("%s as good as new!",
1020 Yobjnam2(otmp, Blind ? "feel" : "look"));
1022 if (old_erodeproof && !new_erodeproof) {
1023 /* restore old_erodeproof before shop charges */
1024 otmp->oerodeproof = 1;
1025 costly_alteration(otmp, COST_DEGRD);
1027 otmp->oerodeproof = new_erodeproof ? 1 : 0;
1028 break;
1030 /* elven armor vibrates warningly when enchanted beyond a limit */
1031 special_armor = is_elven_armor(otmp)
1032 || (Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM);
1033 if (scursed)
1034 same_color = (otmp->otyp == BLACK_DRAGON_SCALE_MAIL
1035 || otmp->otyp == BLACK_DRAGON_SCALES);
1036 else
1037 same_color = (otmp->otyp == SILVER_DRAGON_SCALE_MAIL
1038 || otmp->otyp == SILVER_DRAGON_SCALES
1039 || otmp->otyp == SHIELD_OF_REFLECTION);
1040 if (Blind)
1041 same_color = FALSE;
1043 /* KMH -- catch underflow */
1044 s = scursed ? -otmp->spe : otmp->spe;
1045 if (s > (special_armor ? 5 : 3) && rn2(s)) {
1046 otmp->in_use = TRUE;
1047 pline("%s violently %s%s%s for a while, then %s.", Yname2(otmp),
1048 otense(otmp, Blind ? "vibrate" : "glow"),
1049 (!Blind && !same_color) ? " " : "",
1050 (Blind || same_color) ? "" : hcolor(scursed ? NH_BLACK
1051 : NH_SILVER),
1052 otense(otmp, "evaporate"));
1053 remove_worn_item(otmp, FALSE);
1054 useup(otmp);
1055 break;
1057 s = scursed ? -1
1058 : (otmp->spe >= 9)
1059 ? (rn2(otmp->spe) == 0)
1060 : sblessed
1061 ? rnd(3 - otmp->spe / 3)
1062 : 1;
1063 if (s >= 0 && Is_dragon_scales(otmp)) {
1064 /* dragon scales get turned into dragon scale mail */
1065 pline("%s merges and hardens!", Yname2(otmp));
1066 setworn((struct obj *) 0, W_ARM);
1067 /* assumes same order */
1068 otmp->otyp += GRAY_DRAGON_SCALE_MAIL - GRAY_DRAGON_SCALES;
1069 if (sblessed) {
1070 otmp->spe++;
1071 if (!otmp->blessed)
1072 bless(otmp);
1073 } else if (otmp->cursed)
1074 uncurse(otmp);
1075 otmp->known = 1;
1076 setworn(otmp, W_ARM);
1077 if (otmp->unpaid)
1078 alter_cost(otmp, 0L); /* shop bill */
1079 break;
1081 pline("%s %s%s%s%s for a %s.", Yname2(otmp),
1082 s == 0 ? "violently " : "",
1083 otense(otmp, Blind ? "vibrate" : "glow"),
1084 (!Blind && !same_color) ? " " : "",
1085 (Blind || same_color)
1086 ? "" : hcolor(scursed ? NH_BLACK : NH_SILVER),
1087 (s * s > 1) ? "while" : "moment");
1088 /* [this cost handling will need updating if shop pricing is
1089 ever changed to care about curse/bless status of armor] */
1090 if (s < 0)
1091 costly_alteration(otmp, COST_DECHNT);
1092 if (scursed && !otmp->cursed)
1093 curse(otmp);
1094 else if (sblessed && !otmp->blessed)
1095 bless(otmp);
1096 else if (!scursed && otmp->cursed)
1097 uncurse(otmp);
1098 if (s) {
1099 otmp->spe += s;
1100 adj_abon(otmp, s);
1101 known = otmp->known;
1102 /* update shop bill to reflect new higher price */
1103 if (s > 0 && otmp->unpaid)
1104 alter_cost(otmp, 0L);
1107 if ((otmp->spe > (special_armor ? 5 : 3))
1108 && (special_armor || !rn2(7)))
1109 pline("%s %s.", Yobjnam2(otmp, "suddenly vibrate"),
1110 Blind ? "again" : "unexpectedly");
1111 break;
1113 case SCR_DESTROY_ARMOR: {
1114 otmp = some_armor(&youmonst);
1115 if (confused) {
1116 if (!otmp) {
1117 strange_feeling(sobj, "Your bones itch.");
1118 sobj = 0; /* useup() in strange_feeling() */
1119 exercise(A_STR, FALSE);
1120 exercise(A_CON, FALSE);
1121 break;
1123 old_erodeproof = (otmp->oerodeproof != 0);
1124 new_erodeproof = scursed;
1125 otmp->oerodeproof = 0; /* for messages */
1126 p_glow2(otmp, NH_PURPLE);
1127 if (old_erodeproof && !new_erodeproof) {
1128 /* restore old_erodeproof before shop charges */
1129 otmp->oerodeproof = 1;
1130 costly_alteration(otmp, COST_DEGRD);
1132 otmp->oerodeproof = new_erodeproof ? 1 : 0;
1133 break;
1135 if (!scursed || !otmp || !otmp->cursed) {
1136 if (!destroy_arm(otmp)) {
1137 strange_feeling(sobj, "Your skin itches.");
1138 sobj = 0; /* useup() in strange_feeling() */
1139 exercise(A_STR, FALSE);
1140 exercise(A_CON, FALSE);
1141 break;
1142 } else
1143 known = TRUE;
1144 } else { /* armor and scroll both cursed */
1145 pline("%s.", Yobjnam2(otmp, "vibrate"));
1146 if (otmp->spe >= -6) {
1147 otmp->spe += -1;
1148 adj_abon(otmp, -1);
1150 make_stunned((HStun & TIMEOUT) + (long) rn1(10, 10), TRUE);
1152 } break;
1153 case SCR_CONFUSE_MONSTER:
1154 case SPE_CONFUSE_MONSTER:
1155 if (youmonst.data->mlet != S_HUMAN || scursed) {
1156 if (!HConfusion)
1157 You_feel("confused.");
1158 make_confused(HConfusion + rnd(100), FALSE);
1159 } else if (confused) {
1160 if (!sblessed) {
1161 Your("%s begin to %s%s.", makeplural(body_part(HAND)),
1162 Blind ? "tingle" : "glow ",
1163 Blind ? "" : hcolor(NH_PURPLE));
1164 make_confused(HConfusion + rnd(100), FALSE);
1165 } else {
1166 pline("A %s%s surrounds your %s.",
1167 Blind ? "" : hcolor(NH_RED),
1168 Blind ? "faint buzz" : " glow", body_part(HEAD));
1169 make_confused(0L, TRUE);
1171 } else {
1172 if (!sblessed) {
1173 Your("%s%s %s%s.", makeplural(body_part(HAND)),
1174 Blind ? "" : " begin to glow",
1175 Blind ? (const char *) "tingle" : hcolor(NH_RED),
1176 u.umconf ? " even more" : "");
1177 u.umconf++;
1178 } else {
1179 if (Blind)
1180 Your("%s tingle %s sharply.", makeplural(body_part(HAND)),
1181 u.umconf ? "even more" : "very");
1182 else
1183 Your("%s glow a%s brilliant %s.",
1184 makeplural(body_part(HAND)),
1185 u.umconf ? "n even more" : "", hcolor(NH_RED));
1186 /* after a while, repeated uses become less effective */
1187 if (u.umconf >= 40)
1188 u.umconf++;
1189 else
1190 u.umconf += rn1(8, 2);
1193 break;
1194 case SCR_SCARE_MONSTER:
1195 case SPE_CAUSE_FEAR: {
1196 register int ct = 0;
1197 register struct monst *mtmp;
1199 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1200 if (DEADMONSTER(mtmp))
1201 continue;
1202 if (cansee(mtmp->mx, mtmp->my)) {
1203 if (confused || scursed) {
1204 mtmp->mflee = mtmp->mfrozen = mtmp->msleeping = 0;
1205 mtmp->mcanmove = 1;
1206 } else if (!resist(mtmp, sobj->oclass, 0, NOTELL))
1207 monflee(mtmp, 0, FALSE, FALSE);
1208 if (!mtmp->mtame)
1209 ct++; /* pets don't laugh at you */
1212 if (otyp == SCR_SCARE_MONSTER || !ct)
1213 You_hear("%s %s.", (confused || scursed) ? "sad wailing"
1214 : "maniacal laughter",
1215 !ct ? "in the distance" : "close by");
1216 break;
1218 case SCR_BLANK_PAPER:
1219 if (Blind)
1220 You("don't remember there being any magic words on this scroll.");
1221 else
1222 pline("This scroll seems to be blank.");
1223 known = TRUE;
1224 break;
1225 case SCR_REMOVE_CURSE:
1226 case SPE_REMOVE_CURSE: {
1227 register struct obj *obj;
1229 You_feel(!Hallucination
1230 ? (!confused ? "like someone is helping you."
1231 : "like you need some help.")
1232 : (!confused ? "in touch with the Universal Oneness."
1233 : "the power of the Force against you!"));
1235 if (scursed) {
1236 pline_The("scroll disintegrates.");
1237 } else {
1238 for (obj = invent; obj; obj = obj->nobj) {
1239 long wornmask;
1241 /* gold isn't subject to cursing and blessing */
1242 if (obj->oclass == COIN_CLASS)
1243 continue;
1244 wornmask = (obj->owornmask & ~(W_BALL | W_ART | W_ARTI));
1245 if (wornmask && !sblessed) {
1246 /* handle a couple of special cases; we don't
1247 allow auxiliary weapon slots to be used to
1248 artificially increase number of worn items */
1249 if (obj == uswapwep) {
1250 if (!u.twoweap)
1251 wornmask = 0L;
1252 } else if (obj == uquiver) {
1253 if (obj->oclass == WEAPON_CLASS) {
1254 /* mergeable weapon test covers ammo,
1255 missiles, spears, daggers & knives */
1256 if (!objects[obj->otyp].oc_merge)
1257 wornmask = 0L;
1258 } else if (obj->oclass == GEM_CLASS) {
1259 /* possibly ought to check whether
1260 alternate weapon is a sling... */
1261 if (!uslinging())
1262 wornmask = 0L;
1263 } else {
1264 /* weptools don't merge and aren't
1265 reasonable quivered weapons */
1266 wornmask = 0L;
1270 if (sblessed || wornmask || obj->otyp == LOADSTONE
1271 || (obj->otyp == LEASH && obj->leashmon)) {
1272 /* water price varies by curse/bless status */
1273 boolean shop_h2o = (obj->unpaid && obj->otyp == POT_WATER);
1275 if (confused) {
1276 blessorcurse(obj, 2);
1277 /* lose knowledge of this object's curse/bless
1278 state (even if it didn't actually change) */
1279 obj->bknown = 0;
1280 /* blessorcurse() only affects uncursed items
1281 so no need to worry about price of water
1282 going down (hence no costly_alteration) */
1283 if (shop_h2o && (obj->cursed || obj->blessed))
1284 alter_cost(obj, 0L); /* price goes up */
1285 } else if (obj->cursed) {
1286 if (shop_h2o)
1287 costly_alteration(obj, COST_UNCURS);
1288 uncurse(obj);
1293 if (Punished && !confused)
1294 unpunish();
1295 if (u.utrap && u.utraptype == TT_BURIEDBALL) {
1296 buried_ball_to_freedom();
1297 pline_The("clasp on your %s vanishes.", body_part(LEG));
1299 update_inventory();
1300 break;
1302 case SCR_CREATE_MONSTER:
1303 case SPE_CREATE_MONSTER:
1304 if (create_critters(1 + ((confused || scursed) ? 12 : 0)
1305 + ((sblessed || rn2(73)) ? 0 : rnd(4)),
1306 confused ? &mons[PM_ACID_BLOB]
1307 : (struct permonst *) 0,
1308 FALSE))
1309 known = TRUE;
1310 /* no need to flush monsters; we ask for identification only if the
1311 * monsters are not visible
1313 break;
1314 case SCR_ENCHANT_WEAPON:
1315 if (confused && uwep
1316 && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) {
1317 old_erodeproof = (uwep->oerodeproof != 0);
1318 new_erodeproof = !scursed;
1319 uwep->oerodeproof = 0; /* for messages */
1320 if (Blind) {
1321 uwep->rknown = FALSE;
1322 Your("weapon feels warm for a moment.");
1323 } else {
1324 uwep->rknown = TRUE;
1325 pline("%s covered by a %s %s %s!", Yobjnam2(uwep, "are"),
1326 scursed ? "mottled" : "shimmering",
1327 hcolor(scursed ? NH_PURPLE : NH_GOLDEN),
1328 scursed ? "glow" : "shield");
1330 if (new_erodeproof && (uwep->oeroded || uwep->oeroded2)) {
1331 uwep->oeroded = uwep->oeroded2 = 0;
1332 pline("%s as good as new!",
1333 Yobjnam2(uwep, Blind ? "feel" : "look"));
1335 if (old_erodeproof && !new_erodeproof) {
1336 /* restore old_erodeproof before shop charges */
1337 uwep->oerodeproof = 1;
1338 costly_alteration(uwep, COST_DEGRD);
1340 uwep->oerodeproof = new_erodeproof ? 1 : 0;
1341 break;
1343 if (!chwepon(sobj, scursed ? -1
1344 : !uwep ? 1
1345 : (uwep->spe >= 9) ? !rn2(uwep->spe)
1346 : sblessed ? rnd(3 - uwep->spe / 3)
1347 : 1))
1348 sobj = 0; /* nothing enchanted: strange_feeling -> useup */
1349 break;
1350 case SCR_TAMING:
1351 case SPE_CHARM_MONSTER: {
1352 int candidates, res, results, vis_results;
1354 if (u.uswallow) {
1355 candidates = 1;
1356 results = vis_results = maybe_tame(u.ustuck, sobj);
1357 } else {
1358 int i, j, bd = confused ? 5 : 1;
1359 struct monst *mtmp;
1361 /* note: maybe_tame() can return either positive or
1362 negative values, but not both for the same scroll */
1363 candidates = results = vis_results = 0;
1364 for (i = -bd; i <= bd; i++)
1365 for (j = -bd; j <= bd; j++) {
1366 if (!isok(u.ux + i, u.uy + j))
1367 continue;
1368 if ((mtmp = m_at(u.ux + i, u.uy + j)) != 0
1369 || (!i && !j && (mtmp = u.usteed) != 0)) {
1370 ++candidates;
1371 res = maybe_tame(mtmp, sobj);
1372 results += res;
1373 if (canspotmon(mtmp))
1374 vis_results += res;
1378 if (!results) {
1379 pline("Nothing interesting %s.",
1380 !candidates ? "happens" : "seems to happen");
1381 } else {
1382 pline_The("neighborhood %s %sfriendlier.",
1383 vis_results ? "is" : "seems",
1384 (results < 0) ? "un" : "");
1385 if (vis_results > 0)
1386 known = TRUE;
1388 break;
1390 case SCR_GENOCIDE:
1391 if (!already_known)
1392 You("have found a scroll of genocide!");
1393 known = TRUE;
1394 if (sblessed)
1395 do_class_genocide();
1396 else
1397 do_genocide(!scursed | (2 * !!Confusion));
1398 break;
1399 case SCR_LIGHT:
1400 if (!confused || rn2(5)) {
1401 if (!Blind)
1402 known = TRUE;
1403 litroom(!confused && !scursed, sobj);
1404 if (!confused && !scursed) {
1405 if (lightdamage(sobj, TRUE, 5))
1406 known = TRUE;
1408 } else {
1409 /* could be scroll of create monster, don't set known ...*/
1410 (void) create_critters(1, !scursed ? &mons[PM_YELLOW_LIGHT]
1411 : &mons[PM_BLACK_LIGHT],
1412 TRUE);
1413 if (!objects[sobj->otyp].oc_uname)
1414 docall(sobj);
1416 break;
1417 case SCR_TELEPORTATION:
1418 if (confused || scursed) {
1419 level_tele();
1420 } else {
1421 known = scrolltele(sobj);
1423 break;
1424 case SCR_GOLD_DETECTION:
1425 if ((confused || scursed) ? trap_detect(sobj) : gold_detect(sobj))
1426 sobj = 0; /* failure: strange_feeling() -> useup() */
1427 break;
1428 case SCR_FOOD_DETECTION:
1429 case SPE_DETECT_FOOD:
1430 if (food_detect(sobj))
1431 sobj = 0; /* nothing detected: strange_feeling -> useup */
1432 break;
1433 case SCR_IDENTIFY:
1434 /* known = TRUE; -- handled inline here */
1435 /* use up the scroll first, before makeknown() performs a
1436 perm_invent update; also simplifies empty invent check */
1437 useup(sobj);
1438 sobj = 0; /* it's gone */
1439 if (confused)
1440 You("identify this as an identify scroll.");
1441 else if (!already_known || !invent)
1442 /* force feedback now if invent became
1443 empty after using up this scroll */
1444 pline("This is an identify scroll.");
1445 if (!already_known)
1446 (void) learnscrolltyp(SCR_IDENTIFY);
1447 /*FALLTHRU*/
1448 case SPE_IDENTIFY:
1449 cval = 1;
1450 if (sblessed || (!scursed && !rn2(5))) {
1451 cval = rn2(5);
1452 /* note: if cval==0, identify all items */
1453 if (cval == 1 && sblessed && Luck > 0)
1454 ++cval;
1456 if (invent && !confused) {
1457 identify_pack(cval, !already_known);
1458 } else if (otyp == SPE_IDENTIFY) {
1459 /* when casting a spell we know we're not confused,
1460 so inventory must be empty (another message has
1461 already been given above if reading a scroll) */
1462 pline("You're not carrying anything to be identified.");
1464 break;
1465 case SCR_CHARGING:
1466 if (confused) {
1467 if (scursed) {
1468 You_feel("discharged.");
1469 u.uen = 0;
1470 } else {
1471 You_feel("charged up!");
1472 u.uen += d(sblessed ? 6 : 4, 4);
1473 if (u.uen > u.uenmax) /* if current energy is already at */
1474 u.uenmax = u.uen; /* or near maximum, increase maximum */
1475 else
1476 u.uen = u.uenmax; /* otherwise restore current to max */
1478 context.botl = 1;
1479 break;
1481 /* known = TRUE; -- handled inline here */
1482 if (!already_known) {
1483 pline("This is a charging scroll.");
1484 learnscroll(sobj);
1486 /* use it up now to prevent it from showing in the
1487 getobj picklist because the "disappears" message
1488 was already delivered */
1489 useup(sobj);
1490 sobj = 0; /* it's gone */
1491 otmp = getobj(all_count, "charge");
1492 if (otmp)
1493 recharge(otmp, scursed ? -1 : sblessed ? 1 : 0);
1494 break;
1495 case SCR_MAGIC_MAPPING:
1496 if (level.flags.nommap) {
1497 Your("mind is filled with crazy lines!");
1498 if (Hallucination)
1499 pline("Wow! Modern art.");
1500 else
1501 Your("%s spins in bewilderment.", body_part(HEAD));
1502 make_confused(HConfusion + rnd(30), FALSE);
1503 break;
1505 if (sblessed) {
1506 register int x, y;
1508 for (x = 1; x < COLNO; x++)
1509 for (y = 0; y < ROWNO; y++)
1510 if (levl[x][y].typ == SDOOR)
1511 cvt_sdoor_to_door(&levl[x][y]);
1512 /* do_mapping() already reveals secret passages */
1514 known = TRUE;
1515 case SPE_MAGIC_MAPPING:
1516 if (level.flags.nommap) {
1517 Your("%s spins as %s blocks the spell!", body_part(HEAD),
1518 something);
1519 make_confused(HConfusion + rnd(30), FALSE);
1520 break;
1522 pline("A map coalesces in your mind!");
1523 cval = (scursed && !confused);
1524 if (cval)
1525 HConfusion = 1; /* to screw up map */
1526 do_mapping();
1527 if (cval) {
1528 HConfusion = 0; /* restore */
1529 pline("Unfortunately, you can't grasp the details.");
1531 break;
1532 case SCR_AMNESIA:
1533 known = TRUE;
1534 forget((!sblessed ? ALL_SPELLS : 0)
1535 | (!confused || scursed ? ALL_MAP : 0));
1536 if (Hallucination) /* Ommmmmm! */
1537 Your("mind releases itself from mundane concerns.");
1538 else if (!strncmpi(plname, "Maud", 4))
1539 pline(
1540 "As your mind turns inward on itself, you forget everything else.");
1541 else if (rn2(2))
1542 pline("Who was that Maud person anyway?");
1543 else
1544 pline("Thinking of Maud you forget everything else.");
1545 exercise(A_WIS, FALSE);
1546 break;
1547 case SCR_FIRE:
1548 cval = bcsign(sobj);
1549 useup(sobj);
1550 sobj = 0; /* it's gone */
1551 if (!already_known)
1552 (void) learnscrolltyp(SCR_FIRE);
1553 if (confused) {
1554 if (Fire_resistance) {
1555 shieldeff(u.ux, u.uy);
1556 if (!Blind)
1557 pline("Oh, look, what a pretty fire in your %s.",
1558 makeplural(body_part(HAND)));
1559 else
1560 You_feel("a pleasant warmth in your %s.",
1561 makeplural(body_part(HAND)));
1562 } else {
1563 pline_The("scroll catches fire and you burn your %s.",
1564 makeplural(body_part(HAND)));
1565 losehp(1, "scroll of fire", KILLED_BY_AN);
1567 break;
1569 if (Underwater) {
1570 pline_The("water around you vaporizes violently!");
1571 } else {
1572 pline_The("scroll erupts in a tower of flame!");
1573 iflags.last_msg = PLNMSG_TOWER_OF_FLAME; /* for explode() */
1574 burn_away_slime();
1576 explode(u.ux, u.uy, 11, (2 * (rn1(3, 3) + 2 * cval) + 1) / 3,
1577 SCROLL_CLASS, EXPL_FIERY);
1578 break;
1579 case SCR_EARTH:
1580 /* TODO: handle steeds */
1581 if (!Is_rogue_level(&u.uz) && has_ceiling(&u.uz)
1582 && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) {
1583 register int x, y;
1584 int nboulders = 0;
1586 /* Identify the scroll */
1587 if (u.uswallow)
1588 You_hear("rumbling.");
1589 else
1590 pline_The("%s rumbles %s you!", ceiling(u.ux, u.uy),
1591 sblessed ? "around" : "above");
1592 known = 1;
1593 sokoban_guilt();
1595 /* Loop through the surrounding squares */
1596 if (!scursed)
1597 for (x = u.ux - 1; x <= u.ux + 1; x++) {
1598 for (y = u.uy - 1; y <= u.uy + 1; y++) {
1599 /* Is this a suitable spot? */
1600 if (isok(x, y) && !closed_door(x, y)
1601 && !IS_ROCK(levl[x][y].typ)
1602 && !IS_AIR(levl[x][y].typ)
1603 && (x != u.ux || y != u.uy)) {
1604 nboulders +=
1605 drop_boulder_on_monster(x, y, confused, TRUE);
1609 /* Attack the player */
1610 if (!sblessed) {
1611 drop_boulder_on_player(confused, !scursed, TRUE, FALSE);
1612 } else if (!nboulders)
1613 pline("But nothing else happens.");
1615 break;
1616 case SCR_PUNISHMENT:
1617 known = TRUE;
1618 if (confused || sblessed) {
1619 You_feel("guilty.");
1620 break;
1622 punish(sobj);
1623 break;
1624 case SCR_STINKING_CLOUD: {
1625 coord cc;
1627 if (!already_known)
1628 You("have found a scroll of stinking cloud!");
1629 known = TRUE;
1630 pline("Where do you want to center the %scloud?",
1631 already_known ? "stinking " : "");
1632 cc.x = u.ux;
1633 cc.y = u.uy;
1634 getpos_sethilite(display_stinking_cloud_positions);
1635 if (getpos(&cc, TRUE, "the desired position") < 0) {
1636 pline1(Never_mind);
1637 break;
1639 if (!is_valid_stinking_cloud_pos(cc.x, cc.y, TRUE))
1640 break;
1641 (void) create_gas_cloud(cc.x, cc.y, 3 + bcsign(sobj),
1642 8 + 4 * bcsign(sobj));
1643 break;
1645 default:
1646 impossible("What weird effect is this? (%u)", otyp);
1648 return sobj ? 0 : 1;
1651 void
1652 drop_boulder_on_player(confused, helmet_protects, byu, skip_uswallow)
1653 boolean confused, helmet_protects, byu, skip_uswallow;
1655 int dmg;
1656 struct obj *otmp2;
1658 /* hit monster if swallowed */
1659 if (u.uswallow && !skip_uswallow) {
1660 drop_boulder_on_monster(u.ux, u.uy, confused, byu);
1661 return;
1664 otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE);
1665 if (!otmp2)
1666 return;
1667 otmp2->quan = confused ? rn1(5, 2) : 1;
1668 otmp2->owt = weight(otmp2);
1669 if (!amorphous(youmonst.data) && !Passes_walls
1670 && !noncorporeal(youmonst.data) && !unsolid(youmonst.data)) {
1671 You("are hit by %s!", doname(otmp2));
1672 dmg = dmgval(otmp2, &youmonst) * otmp2->quan;
1673 if (uarmh && helmet_protects) {
1674 if (is_metallic(uarmh)) {
1675 pline("Fortunately, you are wearing a hard helmet.");
1676 if (dmg > 2)
1677 dmg = 2;
1678 } else if (flags.verbose) {
1679 pline("%s does not protect you.", Yname2(uarmh));
1682 } else
1683 dmg = 0;
1684 /* Must be before the losehp(), for bones files */
1685 if (!flooreffects(otmp2, u.ux, u.uy, "fall")) {
1686 place_object(otmp2, u.ux, u.uy);
1687 stackobj(otmp2);
1688 newsym(u.ux, u.uy);
1690 if (dmg)
1691 losehp(Maybe_Half_Phys(dmg), "scroll of earth", KILLED_BY_AN);
1694 boolean
1695 drop_boulder_on_monster(x, y, confused, byu)
1696 int x, y;
1697 boolean confused, byu;
1699 register struct obj *otmp2;
1700 register struct monst *mtmp;
1702 /* Make the object(s) */
1703 otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE);
1704 if (!otmp2)
1705 return FALSE; /* Shouldn't happen */
1706 otmp2->quan = confused ? rn1(5, 2) : 1;
1707 otmp2->owt = weight(otmp2);
1709 /* Find the monster here (won't be player) */
1710 mtmp = m_at(x, y);
1711 if (mtmp && !amorphous(mtmp->data) && !passes_walls(mtmp->data)
1712 && !noncorporeal(mtmp->data) && !unsolid(mtmp->data)) {
1713 struct obj *helmet = which_armor(mtmp, W_ARMH);
1714 int mdmg;
1716 if (cansee(mtmp->mx, mtmp->my)) {
1717 pline("%s is hit by %s!", Monnam(mtmp), doname(otmp2));
1718 if (mtmp->minvis && !canspotmon(mtmp))
1719 map_invisible(mtmp->mx, mtmp->my);
1720 } else if (u.uswallow && mtmp == u.ustuck)
1721 You_hear("something hit %s %s over your %s!",
1722 s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH),
1723 body_part(HEAD));
1725 mdmg = dmgval(otmp2, mtmp) * otmp2->quan;
1726 if (helmet) {
1727 if (is_metallic(helmet)) {
1728 if (canspotmon(mtmp))
1729 pline("Fortunately, %s is wearing a hard helmet.",
1730 mon_nam(mtmp));
1731 else if (!Deaf)
1732 You_hear("a clanging sound.");
1733 if (mdmg > 2)
1734 mdmg = 2;
1735 } else {
1736 if (canspotmon(mtmp))
1737 pline("%s's %s does not protect %s.", Monnam(mtmp),
1738 xname(helmet), mhim(mtmp));
1741 mtmp->mhp -= mdmg;
1742 if (mtmp->mhp <= 0) {
1743 if (byu)
1744 xkilled(mtmp, 1);
1745 else {
1746 pline("%s is killed.", Monnam(mtmp));
1747 mondied(mtmp);
1750 } else if (u.uswallow && mtmp == u.ustuck) {
1751 obfree(otmp2, (struct obj *) 0);
1752 /* fall through to player */
1753 drop_boulder_on_player(confused, TRUE, FALSE, TRUE);
1754 return 1;
1756 /* Drop the rock/boulder to the floor */
1757 if (!flooreffects(otmp2, x, y, "fall")) {
1758 place_object(otmp2, x, y);
1759 stackobj(otmp2);
1760 newsym(x, y); /* map the rock */
1762 return TRUE;
1765 /* overcharging any wand or zapping/engraving cursed wand */
1766 void
1767 wand_explode(obj, chg)
1768 struct obj *obj;
1769 int chg; /* recharging */
1771 const char *expl = !chg ? "suddenly" : "vibrates violently and";
1772 int dmg, n, k;
1774 /* number of damage dice */
1775 if (!chg)
1776 chg = 2; /* zap/engrave adjustment */
1777 n = obj->spe + chg;
1778 if (n < 2)
1779 n = 2; /* arbitrary minimum */
1780 /* size of damage dice */
1781 switch (obj->otyp) {
1782 case WAN_WISHING:
1783 k = 12;
1784 break;
1785 case WAN_CANCELLATION:
1786 case WAN_DEATH:
1787 case WAN_POLYMORPH:
1788 case WAN_UNDEAD_TURNING:
1789 k = 10;
1790 break;
1791 case WAN_COLD:
1792 case WAN_FIRE:
1793 case WAN_LIGHTNING:
1794 case WAN_MAGIC_MISSILE:
1795 k = 8;
1796 break;
1797 case WAN_NOTHING:
1798 k = 4;
1799 break;
1800 default:
1801 k = 6;
1802 break;
1804 /* inflict damage and destroy the wand */
1805 dmg = d(n, k);
1806 obj->in_use = TRUE; /* in case losehp() is fatal (or --More--^C) */
1807 pline("%s %s explodes!", Yname2(obj), expl);
1808 losehp(Maybe_Half_Phys(dmg), "exploding wand", KILLED_BY_AN);
1809 useup(obj);
1810 /* obscure side-effect */
1811 exercise(A_STR, FALSE);
1814 /* used to collect gremlins being hit by light so that they can be processed
1815 after vision for the entire lit area has been brought up to date */
1816 struct litmon {
1817 struct monst *mon;
1818 struct litmon *nxt;
1820 STATIC_VAR struct litmon *gremlins = 0;
1823 * Low-level lit-field update routine.
1825 STATIC_PTR void
1826 set_lit(x, y, val)
1827 int x, y;
1828 genericptr_t val;
1830 struct monst *mtmp;
1831 struct litmon *gremlin;
1833 if (val) {
1834 levl[x][y].lit = 1;
1835 if ((mtmp = m_at(x, y)) != 0 && mtmp->data == &mons[PM_GREMLIN]) {
1836 gremlin = (struct litmon *) alloc(sizeof *gremlin);
1837 gremlin->mon = mtmp;
1838 gremlin->nxt = gremlins;
1839 gremlins = gremlin;
1841 } else {
1842 levl[x][y].lit = 0;
1843 snuff_light_source(x, y);
1847 void
1848 litroom(on, obj)
1849 register boolean on;
1850 struct obj *obj;
1852 char is_lit; /* value is irrelevant; we use its address
1853 as a `not null' flag for set_lit() */
1855 /* first produce the text (provided you're not blind) */
1856 if (!on) {
1857 register struct obj *otmp;
1859 if (!Blind) {
1860 if (u.uswallow) {
1861 pline("It seems even darker in here than before.");
1862 } else {
1863 if (uwep && artifact_light(uwep) && uwep->lamplit)
1864 pline("Suddenly, the only light left comes from %s!",
1865 the(xname(uwep)));
1866 else
1867 You("are surrounded by darkness!");
1871 /* the magic douses lamps, et al, too */
1872 for (otmp = invent; otmp; otmp = otmp->nobj)
1873 if (otmp->lamplit)
1874 (void) snuff_lit(otmp);
1875 } else { /* on */
1876 if (u.uswallow) {
1877 if (Blind)
1878 ; /* no feedback */
1879 else if (is_animal(u.ustuck->data))
1880 pline("%s %s is lit.", s_suffix(Monnam(u.ustuck)),
1881 mbodypart(u.ustuck, STOMACH));
1882 else if (is_whirly(u.ustuck->data))
1883 pline("%s shines briefly.", Monnam(u.ustuck));
1884 else
1885 pline("%s glistens.", Monnam(u.ustuck));
1886 } else if (!Blind)
1887 pline("A lit field surrounds you!");
1890 /* No-op when swallowed or in water */
1891 if (u.uswallow || Underwater || Is_waterlevel(&u.uz))
1892 return;
1894 * If we are darkening the room and the hero is punished but not
1895 * blind, then we have to pick up and replace the ball and chain so
1896 * that we don't remember them if they are out of sight.
1898 if (Punished && !on && !Blind)
1899 move_bc(1, 0, uball->ox, uball->oy, uchain->ox, uchain->oy);
1901 if (Is_rogue_level(&u.uz)) {
1902 /* Can't use do_clear_area because MAX_RADIUS is too small */
1903 /* rogue lighting must light the entire room */
1904 int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET;
1905 int rx, ry;
1907 if (rnum >= 0) {
1908 for (rx = rooms[rnum].lx - 1; rx <= rooms[rnum].hx + 1; rx++)
1909 for (ry = rooms[rnum].ly - 1; ry <= rooms[rnum].hy + 1; ry++)
1910 set_lit(rx, ry,
1911 (genericptr_t) (on ? &is_lit : (char *) 0));
1912 rooms[rnum].rlit = on;
1914 /* hallways remain dark on the rogue level */
1915 } else
1916 do_clear_area(u.ux, u.uy,
1917 (obj && obj->oclass == SCROLL_CLASS && obj->blessed)
1918 ? 9 : 5,
1919 set_lit, (genericptr_t) (on ? &is_lit : (char *) 0));
1922 * If we are not blind, then force a redraw on all positions in sight
1923 * by temporarily blinding the hero. The vision recalculation will
1924 * correctly update all previously seen positions *and* correctly
1925 * set the waslit bit [could be messed up from above].
1927 if (!Blind) {
1928 vision_recalc(2);
1930 /* replace ball&chain */
1931 if (Punished && !on)
1932 move_bc(0, 0, uball->ox, uball->oy, uchain->ox, uchain->oy);
1935 vision_full_recalc = 1; /* delayed vision recalculation */
1936 if (gremlins) {
1937 struct litmon *gremlin;
1939 /* can't delay vision recalc after all */
1940 vision_recalc(0);
1941 /* after vision has been updated, monsters who are affected
1942 when hit by light can now be hit by it */
1943 do {
1944 gremlin = gremlins;
1945 gremlins = gremlin->nxt;
1946 light_hits_gremlin(gremlin->mon, rnd(5));
1947 free((genericptr_t) gremlin);
1948 } while (gremlins);
1952 STATIC_OVL void
1953 do_class_genocide()
1955 int i, j, immunecnt, gonecnt, goodcnt, class, feel_dead = 0;
1956 char buf[BUFSZ];
1957 boolean gameover = FALSE; /* true iff killed self */
1959 for (j = 0;; j++) {
1960 if (j >= 5) {
1961 pline1(thats_enough_tries);
1962 return;
1964 do {
1965 getlin("What class of monsters do you wish to genocide?", buf);
1966 (void) mungspaces(buf);
1967 } while (!*buf);
1968 /* choosing "none" preserves genocideless conduct */
1969 if (*buf == '\033' || !strcmpi(buf, "none")
1970 || !strcmpi(buf, "nothing"))
1971 return;
1973 class = name_to_monclass(buf, (int *) 0);
1974 if (class == 0 && (i = name_to_mon(buf)) != NON_PM)
1975 class = mons[i].mlet;
1976 immunecnt = gonecnt = goodcnt = 0;
1977 for (i = LOW_PM; i < NUMMONS; i++) {
1978 if (mons[i].mlet == class) {
1979 if (!(mons[i].geno & G_GENO))
1980 immunecnt++;
1981 else if (mvitals[i].mvflags & G_GENOD)
1982 gonecnt++;
1983 else
1984 goodcnt++;
1987 if (!goodcnt && class != mons[urole.malenum].mlet
1988 && class != mons[urace.malenum].mlet) {
1989 if (gonecnt)
1990 pline("All such monsters are already nonexistent.");
1991 else if (immunecnt || class == S_invisible)
1992 You("aren't permitted to genocide such monsters.");
1993 else if (wizard && buf[0] == '*') {
1994 register struct monst *mtmp, *mtmp2;
1996 gonecnt = 0;
1997 for (mtmp = fmon; mtmp; mtmp = mtmp2) {
1998 mtmp2 = mtmp->nmon;
1999 if (DEADMONSTER(mtmp))
2000 continue;
2001 mongone(mtmp);
2002 gonecnt++;
2004 pline("Eliminated %d monster%s.", gonecnt, plur(gonecnt));
2005 return;
2006 } else
2007 pline("That %s does not represent any monster.",
2008 strlen(buf) == 1 ? "symbol" : "response");
2009 continue;
2012 for (i = LOW_PM; i < NUMMONS; i++) {
2013 if (mons[i].mlet == class) {
2014 char nam[BUFSZ];
2016 Strcpy(nam, makeplural(mons[i].mname));
2017 /* Although "genus" is Latin for race, the hero benefits
2018 * from both race and role; thus genocide affects either.
2020 if (Your_Own_Role(i) || Your_Own_Race(i)
2021 || ((mons[i].geno & G_GENO)
2022 && !(mvitals[i].mvflags & G_GENOD))) {
2023 /* This check must be first since player monsters might
2024 * have G_GENOD or !G_GENO.
2026 mvitals[i].mvflags |= (G_GENOD | G_NOCORPSE);
2027 reset_rndmonst(i);
2028 kill_genocided_monsters();
2029 update_inventory(); /* eggs & tins */
2030 pline("Wiped out all %s.", nam);
2031 if (Upolyd && i == u.umonnum) {
2032 u.mh = -1;
2033 if (Unchanging) {
2034 if (!feel_dead++)
2035 You("die.");
2036 /* finish genociding this class of
2037 monsters before ultimately dying */
2038 gameover = TRUE;
2039 } else
2040 rehumanize();
2042 /* Self-genocide if it matches either your race
2043 or role. Assumption: male and female forms
2044 share same monster class. */
2045 if (i == urole.malenum || i == urace.malenum) {
2046 u.uhp = -1;
2047 if (Upolyd) {
2048 if (!feel_dead++)
2049 You_feel("dead inside.");
2050 } else {
2051 if (!feel_dead++)
2052 You("die.");
2053 gameover = TRUE;
2056 } else if (mvitals[i].mvflags & G_GENOD) {
2057 if (!gameover)
2058 pline("All %s are already nonexistent.", nam);
2059 } else if (!gameover) {
2060 /* suppress feedback about quest beings except
2061 for those applicable to our own role */
2062 if ((mons[i].msound != MS_LEADER
2063 || quest_info(MS_LEADER) == i)
2064 && (mons[i].msound != MS_NEMESIS
2065 || quest_info(MS_NEMESIS) == i)
2066 && (mons[i].msound != MS_GUARDIAN
2067 || quest_info(MS_GUARDIAN) == i)
2068 /* non-leader/nemesis/guardian role-specific monster
2070 && (i != PM_NINJA /* nuisance */
2071 || Role_if(PM_SAMURAI))) {
2072 boolean named, uniq;
2074 named = type_is_pname(&mons[i]) ? TRUE : FALSE;
2075 uniq = (mons[i].geno & G_UNIQ) ? TRUE : FALSE;
2076 /* one special case */
2077 if (i == PM_HIGH_PRIEST)
2078 uniq = FALSE;
2080 You("aren't permitted to genocide %s%s.",
2081 (uniq && !named) ? "the " : "",
2082 (uniq || named) ? mons[i].mname : nam);
2087 if (gameover || u.uhp == -1) {
2088 killer.format = KILLED_BY_AN;
2089 Strcpy(killer.name, "scroll of genocide");
2090 if (gameover)
2091 done(GENOCIDED);
2093 return;
2097 #define REALLY 1
2098 #define PLAYER 2
2099 #define ONTHRONE 4
2100 void
2101 do_genocide(how)
2102 int how;
2103 /* 0 = no genocide; create monsters (cursed scroll) */
2104 /* 1 = normal genocide */
2105 /* 3 = forced genocide of player */
2106 /* 5 (4 | 1) = normal genocide from throne */
2108 char buf[BUFSZ];
2109 register int i, killplayer = 0;
2110 register int mndx;
2111 register struct permonst *ptr;
2112 const char *which;
2114 if (how & PLAYER) {
2115 mndx = u.umonster; /* non-polymorphed mon num */
2116 ptr = &mons[mndx];
2117 Strcpy(buf, ptr->mname);
2118 killplayer++;
2119 } else {
2120 for (i = 0;; i++) {
2121 if (i >= 5) {
2122 /* cursed effect => no free pass (unless rndmonst() fails) */
2123 if (!(how & REALLY) && (ptr = rndmonst()) != 0)
2124 break;
2126 pline1(thats_enough_tries);
2127 return;
2129 getlin("What monster do you want to genocide? [type the name]",
2130 buf);
2131 (void) mungspaces(buf);
2132 /* choosing "none" preserves genocideless conduct */
2133 if (*buf == '\033' || !strcmpi(buf, "none")
2134 || !strcmpi(buf, "nothing")) {
2135 /* ... but no free pass if cursed */
2136 if (!(how & REALLY) && (ptr = rndmonst()) != 0)
2137 break; /* remaining checks don't apply */
2139 return;
2142 mndx = name_to_mon(buf);
2143 if (mndx == NON_PM || (mvitals[mndx].mvflags & G_GENOD)) {
2144 pline("Such creatures %s exist in this world.",
2145 (mndx == NON_PM) ? "do not" : "no longer");
2146 continue;
2148 ptr = &mons[mndx];
2149 /* Although "genus" is Latin for race, the hero benefits
2150 * from both race and role; thus genocide affects either.
2152 if (Your_Own_Role(mndx) || Your_Own_Race(mndx)) {
2153 killplayer++;
2154 break;
2156 if (is_human(ptr))
2157 adjalign(-sgn(u.ualign.type));
2158 if (is_demon(ptr))
2159 adjalign(sgn(u.ualign.type));
2161 if (!(ptr->geno & G_GENO)) {
2162 if (!Deaf) {
2163 /* FIXME: unconditional "caverns" will be silly in some
2164 * circumstances. Who's speaking? Divine pronouncements
2165 * aren't supposed to be hampered by deafness....
2167 if (flags.verbose)
2168 pline("A thunderous voice booms through the caverns:");
2169 verbalize("No, mortal! That will not be done.");
2171 continue;
2173 /* KMH -- Unchanging prevents rehumanization */
2174 if (Unchanging && ptr == youmonst.data)
2175 killplayer++;
2176 break;
2178 mndx = monsndx(ptr); /* needed for the 'no free pass' cases */
2181 which = "all ";
2182 if (Hallucination) {
2183 if (Upolyd)
2184 Strcpy(buf, youmonst.data->mname);
2185 else {
2186 Strcpy(buf, (flags.female && urole.name.f) ? urole.name.f
2187 : urole.name.m);
2188 buf[0] = lowc(buf[0]);
2190 } else {
2191 Strcpy(buf, ptr->mname); /* make sure we have standard singular */
2192 if ((ptr->geno & G_UNIQ) && ptr != &mons[PM_HIGH_PRIEST])
2193 which = !type_is_pname(ptr) ? "the " : "";
2195 if (how & REALLY) {
2196 /* setting no-corpse affects wishing and random tin generation */
2197 mvitals[mndx].mvflags |= (G_GENOD | G_NOCORPSE);
2198 pline("Wiped out %s%s.", which,
2199 (*which != 'a') ? buf : makeplural(buf));
2201 if (killplayer) {
2202 /* might need to wipe out dual role */
2203 if (urole.femalenum != NON_PM && mndx == urole.malenum)
2204 mvitals[urole.femalenum].mvflags |= (G_GENOD | G_NOCORPSE);
2205 if (urole.femalenum != NON_PM && mndx == urole.femalenum)
2206 mvitals[urole.malenum].mvflags |= (G_GENOD | G_NOCORPSE);
2207 if (urace.femalenum != NON_PM && mndx == urace.malenum)
2208 mvitals[urace.femalenum].mvflags |= (G_GENOD | G_NOCORPSE);
2209 if (urace.femalenum != NON_PM && mndx == urace.femalenum)
2210 mvitals[urace.malenum].mvflags |= (G_GENOD | G_NOCORPSE);
2212 u.uhp = -1;
2213 if (how & PLAYER) {
2214 killer.format = KILLED_BY;
2215 Strcpy(killer.name, "genocidal confusion");
2216 } else if (how & ONTHRONE) {
2217 /* player selected while on a throne */
2218 killer.format = KILLED_BY_AN;
2219 Strcpy(killer.name, "imperious order");
2220 } else { /* selected player deliberately, not confused */
2221 killer.format = KILLED_BY_AN;
2222 Strcpy(killer.name, "scroll of genocide");
2225 /* Polymorphed characters will die as soon as they're rehumanized.
2227 /* KMH -- Unchanging prevents rehumanization */
2228 if (Upolyd && ptr != youmonst.data) {
2229 delayed_killer(POLYMORPH, killer.format, killer.name);
2230 You_feel("dead inside.");
2231 } else
2232 done(GENOCIDED);
2233 } else if (ptr == youmonst.data) {
2234 rehumanize();
2236 reset_rndmonst(mndx);
2237 kill_genocided_monsters();
2238 update_inventory(); /* in case identified eggs were affected */
2239 } else {
2240 int cnt = 0, census = monster_census(FALSE);
2242 if (!(mons[mndx].geno & G_UNIQ)
2243 && !(mvitals[mndx].mvflags & (G_GENOD | G_EXTINCT)))
2244 for (i = rn1(3, 4); i > 0; i--) {
2245 if (!makemon(ptr, u.ux, u.uy, NO_MINVENT))
2246 break; /* couldn't make one */
2247 ++cnt;
2248 if (mvitals[mndx].mvflags & G_EXTINCT)
2249 break; /* just made last one */
2251 if (cnt) {
2252 /* accumulated 'cnt' doesn't take groups into account;
2253 assume bringing in new mon(s) didn't remove any old ones */
2254 cnt = monster_census(FALSE) - census;
2255 pline("Sent in %s%s.", (cnt > 1) ? "some " : "",
2256 (cnt > 1) ? makeplural(buf) : an(buf));
2257 } else
2258 pline1(nothing_happens);
2262 void
2263 punish(sobj)
2264 struct obj *sobj;
2266 struct obj *reuse_ball = (sobj && sobj->otyp == HEAVY_IRON_BALL)
2267 ? sobj : (struct obj *) 0;
2269 /* KMH -- Punishment is still okay when you are riding */
2270 if (!reuse_ball)
2271 You("are being punished for your misbehavior!");
2272 if (Punished) {
2273 Your("iron ball gets heavier.");
2274 uball->owt += IRON_BALL_W_INCR * (1 + sobj->cursed);
2275 return;
2277 if (amorphous(youmonst.data) || is_whirly(youmonst.data)
2278 || unsolid(youmonst.data)) {
2279 if (!reuse_ball) {
2280 pline("A ball and chain appears, then falls away.");
2281 dropy(mkobj(BALL_CLASS, TRUE));
2282 } else {
2283 dropy(reuse_ball);
2285 return;
2287 setworn(mkobj(CHAIN_CLASS, TRUE), W_CHAIN);
2288 if (!reuse_ball)
2289 setworn(mkobj(BALL_CLASS, TRUE), W_BALL);
2290 else
2291 setworn(reuse_ball, W_BALL);
2292 uball->spe = 1; /* special ball (see save) */
2295 * Place ball & chain if not swallowed. If swallowed, the ball &
2296 * chain variables will be set at the next call to placebc().
2298 if (!u.uswallow) {
2299 placebc();
2300 if (Blind)
2301 set_bc(1); /* set up ball and chain variables */
2302 newsym(u.ux, u.uy); /* see ball&chain if can't see self */
2306 /* remove the ball and chain */
2307 void
2308 unpunish()
2310 struct obj *savechain = uchain;
2312 obj_extract_self(uchain);
2313 newsym(uchain->ox, uchain->oy);
2314 setworn((struct obj *) 0, W_CHAIN);
2315 dealloc_obj(savechain);
2316 uball->spe = 0;
2317 setworn((struct obj *) 0, W_BALL);
2320 /* some creatures have special data structures that only make sense in their
2321 * normal locations -- if the player tries to create one elsewhere, or to
2322 * revive one, the disoriented creature becomes a zombie
2324 boolean
2325 cant_revive(mtype, revival, from_obj)
2326 int *mtype;
2327 boolean revival;
2328 struct obj *from_obj;
2330 /* SHOPKEEPERS can be revived now */
2331 if (*mtype == PM_GUARD || (*mtype == PM_SHOPKEEPER && !revival)
2332 || *mtype == PM_HIGH_PRIEST || *mtype == PM_ALIGNED_PRIEST
2333 || *mtype == PM_ANGEL) {
2334 *mtype = PM_HUMAN_ZOMBIE;
2335 return TRUE;
2336 } else if (*mtype == PM_LONG_WORM_TAIL) { /* for create_particular() */
2337 *mtype = PM_LONG_WORM;
2338 return TRUE;
2339 } else if (unique_corpstat(&mons[*mtype])
2340 && (!from_obj || !has_omonst(from_obj))) {
2341 /* unique corpses (from bones or wizard mode wish) or
2342 statues (bones or any wish) end up as shapechangers */
2343 *mtype = PM_DOPPELGANGER;
2344 return TRUE;
2346 return FALSE;
2350 * Make a new monster with the type controlled by the user.
2352 * Note: when creating a monster by class letter, specifying the
2353 * "strange object" (']') symbol produces a random monster rather
2354 * than a mimic. This behavior quirk is useful so don't "fix" it
2355 * (use 'm'--or "mimic"--to create a random mimic).
2357 * Used in wizard mode only (for ^G command and for scroll or spell
2358 * of create monster). Once upon a time, an earlier incarnation of
2359 * this code was also used for the scroll/spell in explore mode.
2361 boolean
2362 create_particular()
2364 char buf[BUFSZ], *bufp, monclass;
2365 char *tmpp;
2366 int which, tryct, i, firstchoice = NON_PM;
2367 struct permonst *whichpm = NULL;
2368 struct monst *mtmp;
2369 boolean madeany = FALSE;
2370 boolean maketame, makepeaceful, makehostile;
2371 boolean randmonst = FALSE;
2372 boolean saddled = FALSE;
2373 boolean invisible = FALSE;
2375 tryct = 5;
2376 do {
2377 monclass = MAXMCLASSES;
2378 which = urole.malenum; /* an arbitrary index into mons[] */
2379 maketame = makepeaceful = makehostile = FALSE;
2380 saddled = invisible = FALSE;
2381 getlin("Create what kind of monster? [type the name or symbol]", buf);
2382 bufp = mungspaces(buf);
2383 if (*bufp == '\033')
2384 return FALSE;
2385 if ((tmpp = strstri(bufp, "saddled ")) != 0) {
2386 saddled = TRUE;
2387 memset(tmpp, ' ', sizeof("saddled ")-1);
2389 if ((tmpp = strstri(bufp, "invisible ")) != 0) {
2390 invisible = TRUE;
2391 memset(tmpp, ' ', sizeof("invisible ")-1);
2393 /* allow the initial disposition to be specified */
2394 if (!strncmpi(bufp, "tame ", 5)) {
2395 bufp += 5;
2396 maketame = TRUE;
2397 } else if (!strncmpi(bufp, "peaceful ", 9)) {
2398 bufp += 9;
2399 makepeaceful = TRUE;
2400 } else if (!strncmpi(bufp, "hostile ", 8)) {
2401 bufp += 8;
2402 makehostile = TRUE;
2404 /* decide whether a valid monster was chosen */
2405 if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "random"))) {
2406 randmonst = TRUE;
2407 break;
2409 which = name_to_mon(bufp);
2410 if (which >= LOW_PM)
2411 break; /* got one */
2412 monclass = name_to_monclass(bufp, &which);
2413 if (which >= LOW_PM) {
2414 monclass = MAXMCLASSES; /* matters below */
2415 break;
2416 } else if (monclass > 0) {
2417 which = urole.malenum; /* reset from NON_PM */
2418 break;
2420 /* no good; try again... */
2421 pline("I've never heard of such monsters.");
2422 } while (--tryct > 0);
2424 if (!tryct) {
2425 pline1(thats_enough_tries);
2426 } else {
2427 if (!randmonst) {
2428 firstchoice = which;
2429 if (cant_revive(&which, FALSE, (struct obj *) 0)) {
2430 /* wizard mode can override handling of special monsters */
2431 Sprintf(buf, "Creating %s instead; force %s?",
2432 mons[which].mname, mons[firstchoice].mname);
2433 if (yn(buf) == 'y')
2434 which = firstchoice;
2436 whichpm = &mons[which];
2438 for (i = 0; i <= multi; i++) {
2439 if (monclass != MAXMCLASSES)
2440 whichpm = mkclass(monclass, 0);
2441 else if (randmonst)
2442 whichpm = rndmonst();
2443 mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS);
2444 if (!mtmp) {
2445 /* quit trying if creation failed and is going to repeat */
2446 if (monclass == MAXMCLASSES && !randmonst)
2447 break;
2448 /* otherwise try again */
2449 continue;
2451 if (maketame) {
2452 (void) tamedog(mtmp, (struct obj *) 0);
2453 } else if (makepeaceful || makehostile) {
2454 mtmp->mtame = 0; /* sanity precaution */
2455 mtmp->mpeaceful = makepeaceful ? 1 : 0;
2456 set_malign(mtmp);
2458 if (saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) {
2459 struct obj *otmp = mksobj(SADDLE, TRUE, FALSE);
2460 put_saddle_on_mon(otmp, mtmp);
2462 if (invisible)
2463 mon_set_minvis(mtmp);
2464 madeany = TRUE;
2465 /* in case we got a doppelganger instead of what was asked
2466 for, make it start out looking like what was asked for */
2467 if (mtmp->cham != NON_PM && firstchoice != NON_PM
2468 && mtmp->cham != firstchoice)
2469 (void) newcham(mtmp, &mons[firstchoice], FALSE, FALSE);
2472 return madeany;
2475 /*read.c*/