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