Source:NetHack 3.6.1/src/read.c

From NetHackWiki
(Redirected from Source:Ref/maybe tame)
Jump to: navigation, search

Below is the full text to read.c from the source code of NetHack 3.6.1. To link to a particular line, write [[Source:NetHack 3.6.1/src/read.c#line123]], for example.

Top of file

  1.  /* NetHack 3.6	read.c	$NHDT-Date: 1515802375 2018/01/13 00:12:55 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.150 $ */
  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. */

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

  1.  
  2.  #include "hack.h"
  3.  
  4.  #define Your_Own_Role(mndx)  \
  5.      ((mndx) == urole.malenum \
  6.       || (urole.femalenum != NON_PM && (mndx) == urole.femalenum))
  7.  #define Your_Own_Race(mndx)  \
  8.      ((mndx) == urace.malenum \
  9.       || (urace.femalenum != NON_PM && (mndx) == urace.femalenum))
  10.  
  11.  boolean known;
  12.  
  13.  static NEARDATA const char readable[] = { ALL_CLASSES, SCROLL_CLASS,
  14.                                            SPBOOK_CLASS, 0 };
  15.  static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
  16.  
  17.  STATIC_DCL boolean FDECL(learnscrolltyp, (SHORT_P));
  18.  STATIC_DCL char * FDECL(erode_obj_text, (struct obj *, char *));
  19.  STATIC_DCL void NDECL(do_class_genocide);
  20.  STATIC_DCL void FDECL(stripspe, (struct obj *));
  21.  STATIC_DCL void FDECL(p_glow1, (struct obj *));
  22.  STATIC_DCL void FDECL(p_glow2, (struct obj *, const char *));
  23.  STATIC_DCL void FDECL(randomize, (int *, int));
  24.  STATIC_DCL void FDECL(forget_single_object, (int));
  25.  STATIC_DCL void FDECL(forget, (int));
  26.  STATIC_DCL int FDECL(maybe_tame, (struct monst *, struct obj *));
  27.  STATIC_DCL boolean FDECL(is_valid_stinking_cloud_pos, (int, int, BOOLEAN_P));
  28.  STATIC_DCL void FDECL(display_stinking_cloud_positions, (int));
  29.  STATIC_DCL boolean FDECL(get_valid_stinking_cloud_pos, (int, int));
  30.  STATIC_PTR void FDECL(set_lit, (int, int, genericptr));
  31.  

learnscrolltyp

  1.  STATIC_OVL boolean
  2.  learnscrolltyp(scrolltyp)
  3.  short scrolltyp;
  4.  {
  5.      if (!objects[scrolltyp].oc_name_known) {
  6.          makeknown(scrolltyp);
  7.          more_experienced(0, 10);
  8.          return TRUE;
  9.      } else
  10.          return FALSE;
  11.  }
  12.  

learnscroll

  1.  /* also called from teleport.c for scroll of teleportation */
  2.  void
  3.  learnscroll(sobj)
  4.  struct obj *sobj;
  5.  {
  6.      /* it's implied that sobj->dknown is set;
  7.         we couldn't be reading this scroll otherwise */
  8.      if (sobj->oclass != SPBOOK_CLASS)
  9.          (void) learnscrolltyp(sobj->otyp);
  10.  }
  11.  

erode_obj_text

  1.  char *
  2.  erode_obj_text(otmp, buf)
  3.  struct obj *otmp;
  4.  char *buf;
  5.  {
  6.      int erosion = greatest_erosion(otmp);
  7.  
  8.      if (erosion)
  9.          wipeout_text(buf, (int) (strlen(buf) * erosion / (2 * MAX_ERODE)),
  10.                       otmp->o_id ^ (unsigned) ubirthday);
  11.      return buf;
  12.  }
  13.  

tshirt_text

  1.  char *
  2.  tshirt_text(tshirt, buf)
  3.  struct obj *tshirt;
  4.  char *buf;
  5.  {
  6.      static const char *shirt_msgs[] = {
  7.          /* Scott Bigham */
  8.        "I explored the Dungeons of Doom and all I got was this lousy T-shirt!",
  9.          "Is that Mjollnir in your pocket or are you just happy to see me?",
  10.        "It's not the size of your sword, it's how #enhance'd you are with it.",
  11.          "Madame Elvira's House O' Succubi Lifetime Customer",
  12.          "Madame Elvira's House O' Succubi Employee of the Month",
  13.          "Ludios Vault Guards Do It In Small, Dark Rooms",
  14.          "Yendor Military Soldiers Do It In Large Groups",
  15.          "I survived Yendor Military Boot Camp",
  16.          "Ludios Accounting School Intra-Mural Lacrosse Team",
  17.          "Oracle(TM) Fountains 10th Annual Wet T-Shirt Contest",
  18.          "Hey, black dragon!  Disintegrate THIS!",
  19.          "I'm With Stupid -->",
  20.          "Don't blame me, I voted for Izchak!",
  21.          "Don't Panic", /* HHGTTG */
  22.          "Furinkan High School Athletic Dept.",                /* Ranma 1/2 */
  23.          "Hel-LOOO, Nurse!",                                   /* Animaniacs */
  24.          "=^.^=",
  25.          "100% goblin hair - do not wash",
  26.          "Aberzombie and Fitch",
  27.          "cK -- Cockatrice touches the Kop",
  28.          "Don't ask me, I only adventure here",
  29.          "Down with pants!",
  30.          "d, your dog or a killer?",
  31.          "FREE PUG AND NEWT!",
  32.          "Go team ant!",
  33.          "Got newt?",
  34.          "Hello, my darlings!", /* Charlie Drake */
  35.          "Hey!  Nymphs!  Steal This T-Shirt!",
  36.          "I <3 Dungeon of Doom",
  37.          "I <3 Maud",
  38.          "I am a Valkyrie.  If you see me running, try to keep up.",
  39.          "I am not a pack rat - I am a collector",
  40.          "I bounced off a rubber tree",         /* Monkey Island */
  41.          "Plunder Island Brimstone Beach Club", /* Monkey Island */
  42.          "If you can read this, I can hit you with my polearm",
  43.          "I'm confused!",
  44.          "I scored with the princess",
  45.          "I want to live forever or die in the attempt.",
  46.          "Lichen Park",
  47.          "LOST IN THOUGHT - please send search party",
  48.          "Meat is Mordor",
  49.          "Minetown Better Business Bureau",
  50.          "Minetown Watch",
  51.   "Ms. Palm's House of Negotiable Affection -- A Very Reputable House Of Disrepute",
  52.          "Protection Racketeer",
  53.          "Real men love Crom",
  54.          "Somebody stole my Mojo!",
  55.          "The Hellhound Gang",
  56.          "The Werewolves",
  57.          "They Might Be Storm Giants",
  58.          "Weapons don't kill people, I kill people",
  59.          "White Zombie",
  60.          "You're killing me!",
  61.          "Anhur State University - Home of the Fighting Fire Ants!",
  62.          "FREE HUGS",
  63.          "Serial Ascender",
  64.          "Real men are valkyries",
  65.          "Young Men's Cavedigging Association",
  66.          "Occupy Fort Ludios",
  67.          "I couldn't afford this T-shirt so I stole it!",
  68.          "Mind flayers suck",
  69.          "I'm not wearing any pants",
  70.          "Down with the living!",
  71.          "Pudding farmer",
  72.          "Vegetarian",
  73.          "Hello, I'm War!",
  74.          "It is better to light a candle than to curse the darkness",
  75.          "It is easier to curse the darkness than to light a candle",
  76.          /* expanded "rock--paper--scissors" featured in TV show "Big Bang
  77.             Theory" although they didn't create it (and an actual T-shirt
  78.             with pentagonal diagram showing which choices defeat which) */
  79.          "rock--paper--scissors--lizard--Spock!",
  80.          /* "All men must die -- all men must serve" challange and response
  81.             from book series _A_Song_of_Ice_and_Fire_ by George R.R. Martin,
  82.             TV show "Game of Thrones" (probably an actual T-shirt too...) */
  83.          "/Valar morghulis/ -- /Valar dohaeris/",
  84.      };
  85.  
  86.      Strcpy(buf, shirt_msgs[tshirt->o_id % SIZE(shirt_msgs)]);
  87.      return erode_obj_text(tshirt, buf);
  88.  }
  89.  

apron_text

  1.  char *
  2.  apron_text(apron, buf)
  3.  struct obj *apron;
  4.  char *buf;
  5.  {
  6.      static const char *apron_msgs[] = {
  7.          "Kiss the cook",
  8.          "I'm making SCIENCE!",
  9.          "Don't mess with the chef",
  10.          "Don't make me poison you",
  11.          "Gehennom's Kitchen",
  12.          "Rat: The other white meat",
  13.          "If you can't stand the heat, get out of Gehennom!",
  14.          "If we weren't meant to eat animals, why are they made out of meat?",
  15.          "If you don't like the food, I'll stab you",
  16.      };
  17.  
  18.      Strcpy(buf, apron_msgs[apron->o_id % SIZE(apron_msgs)]);
  19.      return erode_obj_text(apron, buf);
  20.  }
  21.  

doread

  1.  int
  2.  doread()
  3.  {
  4.      register struct obj *scroll;
  5.      boolean confused, nodisappear;
  6.  
  7.      known = FALSE;
  8.      if (check_capacity((char *) 0))
  9.          return 0;
  10.      scroll = getobj(readable, "read");
  11.      if (!scroll)
  12.          return 0;
  13.  
  14.      /* outrumor has its own blindness check */
  15.      if (scroll->otyp == FORTUNE_COOKIE) {
  16.          if (flags.verbose)
  17.              You("break up the cookie and throw away the pieces.");
  18.          outrumor(bcsign(scroll), BY_COOKIE);
  19.          if (!Blind)
  20.              u.uconduct.literate++;
  21.          useup(scroll);
  22.          return 1;
  23.      } else if (scroll->otyp == T_SHIRT || scroll->otyp == ALCHEMY_SMOCK) {
  24.          char buf[BUFSZ], *mesg;
  25.          const char *endpunct;
  26.  
  27.          if (Blind) {
  28.              You_cant("feel any Braille writing.");
  29.              return 0;
  30.          }
  31.          /* can't read shirt worn under suit (under cloak is ok though) */
  32.          if (scroll->otyp == T_SHIRT && uarm && scroll == uarmu) {
  33.              pline("%s shirt is obscured by %s%s.",
  34.                    scroll->unpaid ? "That" : "Your", shk_your(buf, uarm),
  35.                    suit_simple_name(uarm));
  36.              return 0;
  37.          }
  38.          u.uconduct.literate++;
  39.          /* populate 'buf[]' */
  40.          mesg = (scroll->otyp == T_SHIRT) ? tshirt_text(scroll, buf)
  41.                                           : apron_text(scroll, buf);
  42.          endpunct = "";
  43.          if (flags.verbose) {
  44.              int ln = (int) strlen(mesg);
  45.  
  46.              /* we will be displaying a sentence; need ending punctuation */
  47.              if (ln > 0 && !index(".!?", mesg[ln - 1]))
  48.                  endpunct = ".";
  49.              pline("It reads:");
  50.          }
  51.          pline("\"%s\"%s", mesg, endpunct);
  52.          return 1;
  53.      } else if (scroll->otyp == CREDIT_CARD) {
  54.          static const char *card_msgs[] = {
  55.              "Leprechaun Gold Tru$t - Shamrock Card",
  56.              "Magic Memory Vault Charge Card",
  57.              "Larn National Bank",                /* Larn */
  58.              "First Bank of Omega",               /* Omega */
  59.              "Bank of Zork - Frobozz Magic Card", /* Zork */
  60.              "Ankh-Morpork Merchant's Guild Barter Card",
  61.              "Ankh-Morpork Thieves' Guild Unlimited Transaction Card",
  62.              "Ransmannsby Moneylenders Association",
  63.              "Bank of Gehennom - 99% Interest Card",
  64.              "Yendorian Express - Copper Card",
  65.              "Yendorian Express - Silver Card",
  66.              "Yendorian Express - Gold Card",
  67.              "Yendorian Express - Mithril Card",
  68.              "Yendorian Express - Platinum Card", /* must be last */
  69.          };
  70.  
  71.          if (Blind) {
  72.              You("feel the embossed numbers:");
  73.          } else {
  74.              if (flags.verbose)
  75.                  pline("It reads:");
  76.              pline("\"%s\"",
  77.                    scroll->oartifact
  78.                        ? card_msgs[SIZE(card_msgs) - 1]
  79.                        : card_msgs[scroll->o_id % (SIZE(card_msgs) - 1)]);
  80.          }
  81.          /* Make a credit card number */
  82.          pline("\"%d0%d %ld%d1 0%d%d0\"%s",
  83.                (((int) scroll->o_id % 89) + 10),
  84.                ((int) scroll->o_id % 4),
  85.                ((((long) scroll->o_id * 499L) % 899999L) + 100000L),
  86.                ((int) scroll->o_id % 10),
  87.                (!((int) scroll->o_id % 3)),
  88.                (((int) scroll->o_id * 7) % 10),
  89.                (flags.verbose || Blind) ? "." : "");
  90.          u.uconduct.literate++;
  91.          return 1;
  92.      } else if (scroll->otyp == CAN_OF_GREASE) {
  93.          pline("This %s has no label.", singular(scroll, xname));
  94.          return 0;
  95.      } else if (scroll->otyp == MAGIC_MARKER) {
  96.          if (Blind) {
  97.              You_cant("feel any Braille writing.");
  98.              return 0;
  99.          }
  100.          if (flags.verbose)
  101.              pline("It reads:");
  102.          pline("\"Magic Marker(TM) Red Ink Marker Pen.  Water Soluble.\"");
  103.          u.uconduct.literate++;
  104.          return 1;
  105.      } else if (scroll->oclass == COIN_CLASS) {
  106.          if (Blind)
  107.              You("feel the embossed words:");
  108.          else if (flags.verbose)
  109.              You("read:");
  110.          pline("\"1 Zorkmid.  857 GUE.  In Frobs We Trust.\"");
  111.          u.uconduct.literate++;
  112.          return 1;
  113.      } else if (scroll->oartifact == ART_ORB_OF_FATE) {
  114.          if (Blind)
  115.              You("feel the engraved signature:");
  116.          else
  117.              pline("It is signed:");
  118.          pline("\"Odin.\"");
  119.          u.uconduct.literate++;
  120.          return 1;
  121.      } else if (scroll->otyp == CANDY_BAR) {
  122.          static const char *wrapper_msgs[] = {
  123.              "Apollo",       /* Lost */
  124.              "Moon Crunchy", /* South Park */
  125.              "Snacky Cake",    "Chocolate Nuggie", "The Small Bar",
  126.              "Crispy Yum Yum", "Nilla Crunchie",   "Berry Bar",
  127.              "Choco Nummer",   "Om-nom", /* Cat Macro */
  128.              "Fruity Oaty",              /* Serenity */
  129.              "Wonka Bar" /* Charlie and the Chocolate Factory */
  130.          };
  131.  
  132.          if (Blind) {
  133.              You_cant("feel any Braille writing.");
  134.              return 0;
  135.          }
  136.          pline("The wrapper reads: \"%s\".",
  137.                wrapper_msgs[scroll->o_id % SIZE(wrapper_msgs)]);
  138.          u.uconduct.literate++;
  139.          return 1;
  140.      } else if (scroll->oclass != SCROLL_CLASS
  141.                 && scroll->oclass != SPBOOK_CLASS) {
  142.          pline(silly_thing_to, "read");
  143.          return 0;
  144.      } else if (Blind && (scroll->otyp != SPE_BOOK_OF_THE_DEAD)) {
  145.          const char *what = 0;
  146.          if (scroll->oclass == SPBOOK_CLASS)
  147.              what = "mystic runes";
  148.          else if (!scroll->dknown)
  149.              what = "formula on the scroll";
  150.          if (what) {
  151.              pline("Being blind, you cannot read the %s.", what);
  152.              return 0;
  153.          }
  154.      }
  155.  
  156.      confused = (Confusion != 0);
  157.  #ifdef MAIL
  158.      if (scroll->otyp == SCR_MAIL) {
  159.          confused = FALSE; /* override */
  160.          /* reading mail is a convenience for the player and takes
  161.             place outside the game, so shouldn't affect gameplay;
  162.             on the other hand, it starts by explicitly making the
  163.             hero actively read something, which is pretty hard
  164.             to simply ignore; as a compromise, if the player has
  165.             maintained illiterate conduct so far, and this mail
  166.             scroll didn't come from bones, ask for confirmation */
  167.          if (!u.uconduct.literate) {
  168.              if (!scroll->spe && yn(
  169.               "Reading mail will violate \"illiterate\" conduct.  Read anyway?"
  170.                                     ) != 'y')
  171.                  return 0;
  172.          }
  173.      }
  174.  #endif
  175.  
  176.      /* Actions required to win the game aren't counted towards conduct */
  177.      /* Novel conduct is handled in read_tribute so exclude it too*/
  178.      if (scroll->otyp != SPE_BOOK_OF_THE_DEAD
  179.          && scroll->otyp != SPE_BLANK_PAPER && scroll->otyp != SCR_BLANK_PAPER
  180.          && scroll->otyp != SPE_NOVEL)
  181.          u.uconduct.literate++;
  182.  
  183.      if (scroll->oclass == SPBOOK_CLASS) {
  184.          return study_book(scroll);
  185.      }
  186.      scroll->in_use = TRUE; /* scroll, not spellbook, now being read */
  187.      if (scroll->otyp != SCR_BLANK_PAPER) {
  188.          boolean silently = !can_chant(&youmonst);
  189.  
  190.          /* a few scroll feedback messages describe something happening
  191.             to the scroll itself, so avoid "it disappears" for those */
  192.          nodisappear = (scroll->otyp == SCR_FIRE
  193.                         || (scroll->otyp == SCR_REMOVE_CURSE
  194.                             && scroll->cursed));
  195.          if (Blind)
  196.              pline(nodisappear
  197.                        ? "You %s the formula on the scroll."
  198.                        : "As you %s the formula on it, the scroll disappears.",
  199.                    silently ? "cogitate" : "pronounce");
  200.          else
  201.              pline(nodisappear ? "You read the scroll."
  202.                                : "As you read the scroll, it disappears.");
  203.          if (confused) {
  204.              if (Hallucination)
  205.                  pline("Being so trippy, you screw up...");
  206.              else
  207.                  pline("Being confused, you %s the magic words...",
  208.                        silently ? "misunderstand" : "mispronounce");
  209.          }
  210.      }
  211.      if (!seffects(scroll)) {
  212.          if (!objects[scroll->otyp].oc_name_known) {
  213.              if (known)
  214.                  learnscroll(scroll);
  215.              else if (!objects[scroll->otyp].oc_uname)
  216.                  docall(scroll);
  217.          }
  218.          scroll->in_use = FALSE;
  219.          if (scroll->otyp != SCR_BLANK_PAPER)
  220.              useup(scroll);
  221.      }
  222.      return 1;
  223.  }
  224.  

stripspe

  1.  STATIC_OVL void
  2.  stripspe(obj)
  3.  register struct obj *obj;
  4.  {
  5.      if (obj->blessed || obj->spe <= 0) {
  6.          pline1(nothing_happens);
  7.      } else {
  8.          /* order matters: message, shop handling, actual transformation */
  9.          pline("%s briefly.", Yobjnam2(obj, "vibrate"));
  10.          costly_alteration(obj, COST_UNCHRG);
  11.          obj->spe = 0;
  12.          if (obj->otyp == OIL_LAMP || obj->otyp == BRASS_LANTERN)
  13.              obj->age = 0;
  14.      }
  15.  }
  16.  

p_glow1

  1.  STATIC_OVL void
  2.  p_glow1(otmp)
  3.  register struct obj *otmp;
  4.  {
  5.      pline("%s briefly.", Yobjnam2(otmp, Blind ? "vibrate" : "glow"));
  6.  }
  7.  

p_glow2

  1.  STATIC_OVL void
  2.  p_glow2(otmp, color)
  3.  register struct obj *otmp;
  4.  register const char *color;
  5.  {
  6.      pline("%s%s%s for a moment.", Yobjnam2(otmp, Blind ? "vibrate" : "glow"),
  7.            Blind ? "" : " ", Blind ? "" : hcolor(color));
  8.  }
  9.  

is_chargeable

  1.  /* Is the object chargeable?  For purposes of inventory display; it is
  2.     possible to be able to charge things for which this returns FALSE. */
  3.  boolean
  4.  is_chargeable(obj)
  5.  struct obj *obj;
  6.  {
  7.      if (obj->oclass == WAND_CLASS)
  8.          return TRUE;
  9.      /* known && !oc_name_known is possible after amnesia/mind flayer */
  10.      if (obj->oclass == RING_CLASS)
  11.          return (boolean) (objects[obj->otyp].oc_charged
  12.                            && (obj->known
  13.                                || (obj->dknown
  14.                                    && objects[obj->otyp].oc_name_known)));
  15.      if (is_weptool(obj)) /* specific check before general tools */
  16.          return FALSE;
  17.      if (obj->oclass == TOOL_CLASS)
  18.          return (boolean) objects[obj->otyp].oc_charged;
  19.      return FALSE; /* why are weapons/armor considered charged anyway? */
  20.  }
  21.  

recharge

  1.  /* recharge an object; curse_bless is -1 if the recharging implement
  2.     was cursed, +1 if blessed, 0 otherwise. */
  3.  void
  4.  recharge(obj, curse_bless)
  5.  struct obj *obj;
  6.  int curse_bless;
  7.  {
  8.      register int n;
  9.      boolean is_cursed, is_blessed;
  10.  
  11.      is_cursed = curse_bless < 0;
  12.      is_blessed = curse_bless > 0;
  13.  
  14.      if (obj->oclass == WAND_CLASS) {
  15.          int lim = (obj->otyp == WAN_WISHING)
  16.                        ? 3
  17.                        : (objects[obj->otyp].oc_dir != NODIR) ? 8 : 15;
  18.  
  19.          /* undo any prior cancellation, even when is_cursed */
  20.          if (obj->spe == -1)
  21.              obj->spe = 0;
  22.  
  23.          /*
  24.           * Recharging might cause wands to explode.
  25.           *      v = number of previous recharges
  26.           *            v = percentage chance to explode on this attempt
  27.           *                    v = cumulative odds for exploding
  28.           *      0 :   0       0
  29.           *      1 :   0.29    0.29
  30.           *      2 :   2.33    2.62
  31.           *      3 :   7.87   10.28
  32.           *      4 :  18.66   27.02
  33.           *      5 :  36.44   53.62
  34.           *      6 :  62.97   82.83
  35.           *      7 : 100     100
  36.           */
  37.          n = (int) obj->recharged;
  38.          if (n > 0 && (obj->otyp == WAN_WISHING
  39.                        || (n * n * n > rn2(7 * 7 * 7)))) { /* recharge_limit */
  40.              wand_explode(obj, rnd(lim));
  41.              return;
  42.          }
  43.          /* didn't explode, so increment the recharge count */
  44.          obj->recharged = (unsigned) (n + 1);
  45.  
  46.          /* now handle the actual recharging */
  47.          if (is_cursed) {
  48.              stripspe(obj);
  49.          } else {
  50.              n = (lim == 3) ? 3 : rn1(5, lim + 1 - 5);
  51.              if (!is_blessed)
  52.                  n = rnd(n);
  53.  
  54.              if (obj->spe < n)
  55.                  obj->spe = n;
  56.              else
  57.                  obj->spe++;
  58.              if (obj->otyp == WAN_WISHING && obj->spe > 3) {
  59.                  wand_explode(obj, 1);
  60.                  return;
  61.              }
  62.              if (obj->spe >= lim)
  63.                  p_glow2(obj, NH_BLUE);
  64.              else
  65.                  p_glow1(obj);
  66.  #if 0 /*[shop price doesn't vary by charge count]*/
  67.              /* update shop bill to reflect new higher price */
  68.              if (obj->unpaid)
  69.                  alter_cost(obj, 0L);
  70.  #endif
  71.          }
  72.  
  73.      } else if (obj->oclass == RING_CLASS && objects[obj->otyp].oc_charged) {
  74.          /* charging does not affect ring's curse/bless status */
  75.          int s = is_blessed ? rnd(3) : is_cursed ? -rnd(2) : 1;
  76.          boolean is_on = (obj == uleft || obj == uright);
  77.  
  78.          /* destruction depends on current state, not adjustment */
  79.          if (obj->spe > rn2(7) || obj->spe <= -5) {
  80.              pline("%s momentarily, then %s!", Yobjnam2(obj, "pulsate"),
  81.                    otense(obj, "explode"));
  82.              if (is_on)
  83.                  Ring_gone(obj);
  84.              s = rnd(3 * abs(obj->spe)); /* amount of damage */
  85.              useup(obj);
  86.              losehp(Maybe_Half_Phys(s), "exploding ring", KILLED_BY_AN);
  87.          } else {
  88.              long mask = is_on ? (obj == uleft ? LEFT_RING : RIGHT_RING) : 0L;
  89.  
  90.              pline("%s spins %sclockwise for a moment.", Yname2(obj),
  91.                    s < 0 ? "counter" : "");
  92.              if (s < 0)
  93.                  costly_alteration(obj, COST_DECHNT);
  94.              /* cause attributes and/or properties to be updated */
  95.              if (is_on)
  96.                  Ring_off(obj);
  97.              obj->spe += s; /* update the ring while it's off */
  98.              if (is_on)
  99.                  setworn(obj, mask), Ring_on(obj);
  100.              /* oartifact: if a touch-sensitive artifact ring is
  101.                 ever created the above will need to be revised  */
  102.              /* update shop bill to reflect new higher price */
  103.              if (s > 0 && obj->unpaid)
  104.                  alter_cost(obj, 0L);
  105.          }
  106.  
  107.      } else if (obj->oclass == TOOL_CLASS) {
  108.          int rechrg = (int) obj->recharged;
  109.  
  110.          if (objects[obj->otyp].oc_charged) {
  111.              /* tools don't have a limit, but the counter used does */
  112.              if (rechrg < 7) /* recharge_limit */
  113.                  obj->recharged++;
  114.          }
  115.          switch (obj->otyp) {
  116.          case BELL_OF_OPENING:
  117.              if (is_cursed)
  118.                  stripspe(obj);
  119.              else if (is_blessed)
  120.                  obj->spe += rnd(3);
  121.              else
  122.                  obj->spe += 1;
  123.              if (obj->spe > 5)
  124.                  obj->spe = 5;
  125.              break;
  126.          case MAGIC_MARKER:
  127.          case TINNING_KIT:
  128.          case EXPENSIVE_CAMERA:
  129.              if (is_cursed)
  130.                  stripspe(obj);
  131.              else if (rechrg
  132.                       && obj->otyp
  133.                              == MAGIC_MARKER) { /* previously recharged */
  134.                  obj->recharged = 1; /* override increment done above */
  135.                  if (obj->spe < 3)
  136.                      Your("marker seems permanently dried out.");
  137.                  else
  138.                      pline1(nothing_happens);
  139.              } else if (is_blessed) {
  140.                  n = rn1(16, 15); /* 15..30 */
  141.                  if (obj->spe + n <= 50)
  142.                      obj->spe = 50;
  143.                  else if (obj->spe + n <= 75)
  144.                      obj->spe = 75;
  145.                  else {
  146.                      int chrg = (int) obj->spe;
  147.                      if ((chrg + n) > 127)
  148.                          obj->spe = 127;
  149.                      else
  150.                          obj->spe += n;
  151.                  }
  152.                  p_glow2(obj, NH_BLUE);
  153.              } else {
  154.                  n = rn1(11, 10); /* 10..20 */
  155.                  if (obj->spe + n <= 50)
  156.                      obj->spe = 50;
  157.                  else {
  158.                      int chrg = (int) obj->spe;
  159.                      if ((chrg + n) > 127)
  160.                          obj->spe = 127;
  161.                      else
  162.                          obj->spe += n;
  163.                  }
  164.                  p_glow2(obj, NH_WHITE);
  165.              }
  166.              break;
  167.          case OIL_LAMP:
  168.          case BRASS_LANTERN:
  169.              if (is_cursed) {
  170.                  stripspe(obj);
  171.                  if (obj->lamplit) {
  172.                      if (!Blind)
  173.                          pline("%s out!", Tobjnam(obj, "go"));
  174.                      end_burn(obj, TRUE);
  175.                  }
  176.              } else if (is_blessed) {
  177.                  obj->spe = 1;
  178.                  obj->age = 1500;
  179.                  p_glow2(obj, NH_BLUE);
  180.              } else {
  181.                  obj->spe = 1;
  182.                  obj->age += 750;
  183.                  if (obj->age > 1500)
  184.                      obj->age = 1500;
  185.                  p_glow1(obj);
  186.              }
  187.              break;
  188.          case CRYSTAL_BALL:
  189.              if (is_cursed) {
  190.                  stripspe(obj);
  191.              } else if (is_blessed) {
  192.                  obj->spe = 6;
  193.                  p_glow2(obj, NH_BLUE);
  194.              } else {
  195.                  if (obj->spe < 5) {
  196.                      obj->spe++;
  197.                      p_glow1(obj);
  198.                  } else
  199.                      pline1(nothing_happens);
  200.              }
  201.              break;
  202.          case HORN_OF_PLENTY:
  203.          case BAG_OF_TRICKS:
  204.          case CAN_OF_GREASE:
  205.              if (is_cursed) {
  206.                  stripspe(obj);
  207.              } else if (is_blessed) {
  208.                  if (obj->spe <= 10)
  209.                      obj->spe += rn1(10, 6);
  210.                  else
  211.                      obj->spe += rn1(5, 6);
  212.                  if (obj->spe > 50)
  213.                      obj->spe = 50;
  214.                  p_glow2(obj, NH_BLUE);
  215.              } else {
  216.                  obj->spe += rnd(5);
  217.                  if (obj->spe > 50)
  218.                      obj->spe = 50;
  219.                  p_glow1(obj);
  220.              }
  221.              break;
  222.          case MAGIC_FLUTE:
  223.          case MAGIC_HARP:
  224.          case FROST_HORN:
  225.          case FIRE_HORN:
  226.          case DRUM_OF_EARTHQUAKE:
  227.              if (is_cursed) {
  228.                  stripspe(obj);
  229.              } else if (is_blessed) {
  230.                  obj->spe += d(2, 4);
  231.                  if (obj->spe > 20)
  232.                      obj->spe = 20;
  233.                  p_glow2(obj, NH_BLUE);
  234.              } else {
  235.                  obj->spe += rnd(4);
  236.                  if (obj->spe > 20)
  237.                      obj->spe = 20;
  238.                  p_glow1(obj);
  239.              }
  240.              break;
  241.          default:
  242.              goto not_chargable;
  243.              /*NOTREACHED*/
  244.              break;
  245.          } /* switch */
  246.  
  247.      } else {
  248.      not_chargable:
  249.          You("have a feeling of loss.");
  250.      }
  251.  }
  252.  

forget_single_object

  1.  /* Forget known information about this object type. */
  2.  STATIC_OVL void
  3.  forget_single_object(obj_id)
  4.  int obj_id;
  5.  {
  6.      objects[obj_id].oc_name_known = 0;
  7.      objects[obj_id].oc_pre_discovered = 0; /* a discovery when relearned */
  8.      if (objects[obj_id].oc_uname) {
  9.          free((genericptr_t) objects[obj_id].oc_uname);
  10.          objects[obj_id].oc_uname = 0;
  11.      }
  12.      undiscover_object(obj_id); /* after clearing oc_name_known */
  13.  
  14.      /* clear & free object names from matching inventory items too? */
  15.  }
  16.  
  17.  #if 0 /* here if anyone wants it.... */
  18.  /* Forget everything known about a particular object class. */
  19.  STATIC_OVL void
  20.  forget_objclass(oclass)
  21.  int oclass;
  22.  {
  23.      int i;
  24.  
  25.      for (i = bases[oclass];
  26.           i < NUM_OBJECTS && objects[i].oc_class == oclass; i++)
  27.          forget_single_object(i);
  28.  }
  29.  #endif
  30.  

randomize

  1.  /* randomize the given list of numbers  0 <= i < count */
  2.  STATIC_OVL void
  3.  randomize(indices, count)
  4.  int *indices;
  5.  int count;
  6.  {
  7.      int i, iswap, temp;
  8.  
  9.      for (i = count - 1; i > 0; i--) {
  10.          if ((iswap = rn2(i + 1)) == i)
  11.              continue;
  12.          temp = indices[i];
  13.          indices[i] = indices[iswap];
  14.          indices[iswap] = temp;
  15.      }
  16.  }
  17.  

forget_objects

  1.  /* Forget % of known objects. */
  2.  void
  3.  forget_objects(percent)
  4.  int percent;
  5.  {
  6.      int i, count;
  7.      int indices[NUM_OBJECTS];
  8.  
  9.      if (percent == 0)
  10.          return;
  11.      if (percent <= 0 || percent > 100) {
  12.          impossible("forget_objects: bad percent %d", percent);
  13.          return;
  14.      }
  15.  
  16.      indices[0] = 0; /* lint suppression */
  17.      for (count = 0, i = 1; i < NUM_OBJECTS; i++)
  18.          if (OBJ_DESCR(objects[i])
  19.              && (objects[i].oc_name_known || objects[i].oc_uname))
  20.              indices[count++] = i;
  21.  
  22.      if (count > 0) {
  23.          randomize(indices, count);
  24.  
  25.          /* forget first % of randomized indices */
  26.          count = ((count * percent) + rn2(100)) / 100;
  27.          for (i = 0; i < count; i++)
  28.              forget_single_object(indices[i]);
  29.      }
  30.  }
  31.  

forget_map

  1.  /* Forget some or all of map (depends on parameters). */
  2.  void
  3.  forget_map(howmuch)
  4.  int howmuch;
  5.  {
  6.      register int zx, zy;
  7.  
  8.      if (Sokoban)
  9.          return;
  10.  
  11.      known = TRUE;
  12.      for (zx = 0; zx < COLNO; zx++)
  13.          for (zy = 0; zy < ROWNO; zy++)
  14.              if (howmuch & ALL_MAP || rn2(7)) {
  15.                  /* Zonk all memory of this location. */
  16.                  levl[zx][zy].seenv = 0;
  17.                  levl[zx][zy].waslit = 0;
  18.                  levl[zx][zy].glyph = cmap_to_glyph(S_stone);
  19.                  lastseentyp[zx][zy] = STONE;
  20.              }
  21.      /* forget overview data for this level */
  22.      forget_mapseen(ledger_no(&u.uz));
  23.  }
  24.  

forget_traps

  1.  /* Forget all traps on the level. */
  2.  void
  3.  forget_traps()
  4.  {
  5.      register struct trap *trap;
  6.  
  7.      /* forget all traps (except the one the hero is in :-) */
  8.      for (trap = ftrap; trap; trap = trap->ntrap)
  9.          if ((trap->tx != u.ux || trap->ty != u.uy) && (trap->ttyp != HOLE))
  10.              trap->tseen = 0;
  11.  }
  12.  

forget_levels

  1.  /*
  2.   * Forget given % of all levels that the hero has visited and not forgotten,
  3.   * except this one.
  4.   */
  5.  void
  6.  forget_levels(percent)
  7.  int percent;
  8.  {
  9.      int i, count;
  10.      xchar maxl, this_lev;
  11.      int indices[MAXLINFO];
  12.  
  13.      if (percent == 0)
  14.          return;
  15.  
  16.      if (percent <= 0 || percent > 100) {
  17.          impossible("forget_levels: bad percent %d", percent);
  18.          return;
  19.      }
  20.  
  21.      this_lev = ledger_no(&u.uz);
  22.      maxl = maxledgerno();
  23.  
  24.      /* count & save indices of non-forgotten visited levels */
  25.      /* Sokoban levels are pre-mapped for the player, and should stay
  26.       * so, or they become nearly impossible to solve.  But try to
  27.       * shift the forgetting elsewhere by fiddling with percent
  28.       * instead of forgetting fewer levels.
  29.       */
  30.      indices[0] = 0; /* lint suppression */
  31.      for (count = 0, i = 0; i <= maxl; i++)
  32.          if ((level_info[i].flags & VISITED)
  33.              && !(level_info[i].flags & FORGOTTEN) && i != this_lev) {
  34.              if (ledger_to_dnum(i) == sokoban_dnum)
  35.                  percent += 2;
  36.              else
  37.                  indices[count++] = i;
  38.          }
  39.  
  40.      if (percent > 100)
  41.          percent = 100;
  42.  
  43.      if (count > 0) {
  44.          randomize(indices, count);
  45.  
  46.          /* forget first % of randomized indices */
  47.          count = ((count * percent) + 50) / 100;
  48.          for (i = 0; i < count; i++) {
  49.              level_info[indices[i]].flags |= FORGOTTEN;
  50.              forget_mapseen(indices[i]);
  51.          }
  52.      }
  53.  }
  54.  

forget

  1.  /*
  2.   * Forget some things (e.g. after reading a scroll of amnesia).  When called,
  3.   * the following are always forgotten:
  4.   *      - felt ball & chain
  5.   *      - traps
  6.   *      - part (6 out of 7) of the map
  7.   *
  8.   * Other things are subject to flags:
  9.   *      howmuch & ALL_MAP       = forget whole map
  10.   *      howmuch & ALL_SPELLS    = forget all spells
  11.   */
  12.  STATIC_OVL void
  13.  forget(howmuch)
  14.  int howmuch;
  15.  {
  16.      if (Punished)
  17.          u.bc_felt = 0; /* forget felt ball&chain */
  18.  
  19.      forget_map(howmuch);
  20.      forget_traps();
  21.  
  22.      /* 1 in 3 chance of forgetting some levels */
  23.      if (!rn2(3))
  24.          forget_levels(rn2(25));
  25.  
  26.      /* 1 in 3 chance of forgetting some objects */
  27.      if (!rn2(3))
  28.          forget_objects(rn2(25));
  29.  
  30.      if (howmuch & ALL_SPELLS)
  31.          losespells();
  32.      /*
  33.       * Make sure that what was seen is restored correctly.  To do this,
  34.       * we need to go blind for an instant --- turn off the display,
  35.       * then restart it.  All this work is needed to correctly handle
  36.       * walls which are stone on one side and wall on the other.  Turning
  37.       * off the seen bits above will make the wall revert to stone,  but
  38.       * there are cases where we don't want this to happen.  The easiest
  39.       * thing to do is to run it through the vision system again, which
  40.       * is always correct.
  41.       */
  42.      docrt(); /* this correctly will reset vision */
  43.  }
  44.  

maybe_tame

  1.  /* monster is hit by scroll of taming's effect */
  2.  STATIC_OVL int
  3.  maybe_tame(mtmp, sobj)
  4.  struct monst *mtmp;
  5.  struct obj *sobj;
  6.  {
  7.      int was_tame = mtmp->mtame;
  8.      unsigned was_peaceful = mtmp->mpeaceful;
  9.  
  10.      if (sobj->cursed) {
  11.          setmangry(mtmp, FALSE);
  12.          if (was_peaceful && !mtmp->mpeaceful)
  13.              return -1;
  14.      } else {
  15.          if (mtmp->isshk)
  16.              make_happy_shk(mtmp, FALSE);
  17.          else if (!resist(mtmp, sobj->oclass, 0, NOTELL))
  18.              (void) tamedog(mtmp, (struct obj *) 0);
  19.          if ((!was_peaceful && mtmp->mpeaceful) || (!was_tame && mtmp->mtame))
  20.              return 1;
  21.      }
  22.      return 0;
  23.  }
  24.  

get_valid_stinking_cloud_pos

  1.  STATIC_OVL boolean
  2.  get_valid_stinking_cloud_pos(x,y)
  3.  int x,y;
  4.  {
  5.      return (!(!isok(x,y) || !cansee(x, y)
  6.                || !ACCESSIBLE(levl[x][y].typ)
  7.                || distu(x, y) >= 32));
  8.  }
  9.  

is_valid_stinking_cloud_pos

  1.  boolean
  2.  is_valid_stinking_cloud_pos(x, y, showmsg)
  3.  int x, y;
  4.  boolean showmsg;
  5.  {
  6.      if (!get_valid_stinking_cloud_pos(x,y)) {
  7.          if (showmsg)
  8.              You("smell rotten eggs.");
  9.          return FALSE;
  10.      }
  11.      return TRUE;
  12.  }
  13.  

display_stinking_cloud_positions

  1.  void
  2.  display_stinking_cloud_positions(state)
  3.  int state;
  4.  {
  5.      if (state == 0) {
  6.          tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos));
  7.      } else if (state == 1) {
  8.          int x, y, dx, dy;
  9.          int dist = 6;
  10.  
  11.          for (dx = -dist; dx <= dist; dx++)
  12.              for (dy = -dist; dy <= dist; dy++) {
  13.                  x = u.ux + dx;
  14.                  y = u.uy + dy;
  15.                  if (get_valid_stinking_cloud_pos(x,y))
  16.                      tmp_at(x, y);
  17.              }
  18.      } else {
  19.          tmp_at(DISP_END, 0);
  20.      }
  21.  }
  22.  

seffects

  1.  /* scroll effects; return 1 if we use up the scroll and possibly make it
  2.     become discovered, 0 if caller should take care of those side-effects */
  3.  int
  4.  seffects(sobj)
  5.  struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
  6.  {
  7.      int cval, otyp = sobj->otyp;
  8.      boolean confused = (Confusion != 0), sblessed = sobj->blessed,
  9.              scursed = sobj->cursed, already_known, old_erodeproof,
  10.              new_erodeproof;
  11.      struct obj *otmp;
  12.  
  13.      if (objects[otyp].oc_magic)
  14.          exercise(A_WIS, TRUE);                       /* just for trying */
  15.      already_known = (sobj->oclass == SPBOOK_CLASS /* spell */
  16.                       || objects[otyp].oc_name_known);
  17.  
  18.      switch (otyp) {
  19.  #ifdef MAIL
  20.      case SCR_MAIL:
  21.          known = TRUE;
  22.          if (sobj->spe == 2)
  23.              /* "stamped scroll" created via magic marker--without a stamp */
  24.              pline("This scroll is marked \"postage due\".");
  25.          else if (sobj->spe)
  26.              /* scroll of mail obtained from bones file or from wishing;
  27.               * note to the puzzled: the game Larn actually sends you junk
  28.               * mail if you win!
  29.               */
  30.              pline(
  31.      "This seems to be junk mail addressed to the finder of the Eye of Larn.");
  32.          else
  33.              readmail(sobj);
  34.          break;
  35.  #endif
  36.      case SCR_ENCHANT_ARMOR: {
  37.          register schar s;
  38.          boolean special_armor;
  39.          boolean same_color;
  40.  
  41.          otmp = some_armor(&youmonst);
  42.          if (!otmp) {
  43.              strange_feeling(sobj, !Blind
  44.                                        ? "Your skin glows then fades."
  45.                                        : "Your skin feels warm for a moment.");
  46.              sobj = 0; /* useup() in strange_feeling() */
  47.              exercise(A_CON, !scursed);
  48.              exercise(A_STR, !scursed);
  49.              break;
  50.          }
  51.          if (confused) {
  52.              old_erodeproof = (otmp->oerodeproof != 0);
  53.              new_erodeproof = !scursed;
  54.              otmp->oerodeproof = 0; /* for messages */
  55.              if (Blind) {
  56.                  otmp->rknown = FALSE;
  57.                  pline("%s warm for a moment.", Yobjnam2(otmp, "feel"));
  58.              } else {
  59.                  otmp->rknown = TRUE;
  60.                  pline("%s covered by a %s %s %s!", Yobjnam2(otmp, "are"),
  61.                        scursed ? "mottled" : "shimmering",
  62.                        hcolor(scursed ? NH_BLACK : NH_GOLDEN),
  63.                        scursed ? "glow"
  64.                                : (is_shield(otmp) ? "layer" : "shield"));
  65.              }
  66.              if (new_erodeproof && (otmp->oeroded || otmp->oeroded2)) {
  67.                  otmp->oeroded = otmp->oeroded2 = 0;
  68.                  pline("%s as good as new!",
  69.                        Yobjnam2(otmp, Blind ? "feel" : "look"));
  70.              }
  71.              if (old_erodeproof && !new_erodeproof) {
  72.                  /* restore old_erodeproof before shop charges */
  73.                  otmp->oerodeproof = 1;
  74.                  costly_alteration(otmp, COST_DEGRD);
  75.              }
  76.              otmp->oerodeproof = new_erodeproof ? 1 : 0;
  77.              break;
  78.          }
  79.          /* elven armor vibrates warningly when enchanted beyond a limit */
  80.          special_armor = is_elven_armor(otmp)
  81.                          || (Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM);
  82.          if (scursed)
  83.              same_color = (otmp->otyp == BLACK_DRAGON_SCALE_MAIL
  84.                            || otmp->otyp == BLACK_DRAGON_SCALES);
  85.          else
  86.              same_color = (otmp->otyp == SILVER_DRAGON_SCALE_MAIL
  87.                            || otmp->otyp == SILVER_DRAGON_SCALES
  88.                            || otmp->otyp == SHIELD_OF_REFLECTION);
  89.          if (Blind)
  90.              same_color = FALSE;
  91.  
  92.          /* KMH -- catch underflow */
  93.          s = scursed ? -otmp->spe : otmp->spe;
  94.          if (s > (special_armor ? 5 : 3) && rn2(s)) {
  95.              otmp->in_use = TRUE;
  96.              pline("%s violently %s%s%s for a while, then %s.", Yname2(otmp),
  97.                    otense(otmp, Blind ? "vibrate" : "glow"),
  98.                    (!Blind && !same_color) ? " " : "",
  99.                    (Blind || same_color) ? "" : hcolor(scursed ? NH_BLACK
  100.                                                                : NH_SILVER),
  101.                    otense(otmp, "evaporate"));
  102.              remove_worn_item(otmp, FALSE);
  103.              useup(otmp);
  104.              break;
  105.          }
  106.          s = scursed ? -1
  107.                      : (otmp->spe >= 9)
  108.                         ? (rn2(otmp->spe) == 0)
  109.                         : sblessed
  110.                            ? rnd(3 - otmp->spe / 3)
  111.                            : 1;
  112.          if (s >= 0 && Is_dragon_scales(otmp)) {
  113.              /* dragon scales get turned into dragon scale mail */
  114.              pline("%s merges and hardens!", Yname2(otmp));
  115.              setworn((struct obj *) 0, W_ARM);
  116.              /* assumes same order */
  117.              otmp->otyp += GRAY_DRAGON_SCALE_MAIL - GRAY_DRAGON_SCALES;
  118.              if (sblessed) {
  119.                  otmp->spe++;
  120.                  if (!otmp->blessed)
  121.                      bless(otmp);
  122.              } else if (otmp->cursed)
  123.                  uncurse(otmp);
  124.              otmp->known = 1;
  125.              setworn(otmp, W_ARM);
  126.              if (otmp->unpaid)
  127.                  alter_cost(otmp, 0L); /* shop bill */
  128.              break;
  129.          }
  130.          pline("%s %s%s%s%s for a %s.", Yname2(otmp),
  131.                s == 0 ? "violently " : "",
  132.                otense(otmp, Blind ? "vibrate" : "glow"),
  133.                (!Blind && !same_color) ? " " : "",
  134.                (Blind || same_color)
  135.                   ? "" : hcolor(scursed ? NH_BLACK : NH_SILVER),
  136.                (s * s > 1) ? "while" : "moment");
  137.          /* [this cost handling will need updating if shop pricing is
  138.             ever changed to care about curse/bless status of armor] */
  139.          if (s < 0)
  140.              costly_alteration(otmp, COST_DECHNT);
  141.          if (scursed && !otmp->cursed)
  142.              curse(otmp);
  143.          else if (sblessed && !otmp->blessed)
  144.              bless(otmp);
  145.          else if (!scursed && otmp->cursed)
  146.              uncurse(otmp);
  147.          if (s) {
  148.              otmp->spe += s;
  149.              adj_abon(otmp, s);
  150.              known = otmp->known;
  151.              /* update shop bill to reflect new higher price */
  152.              if (s > 0 && otmp->unpaid)
  153.                  alter_cost(otmp, 0L);
  154.          }
  155.  
  156.          if ((otmp->spe > (special_armor ? 5 : 3))
  157.              && (special_armor || !rn2(7)))
  158.              pline("%s %s.", Yobjnam2(otmp, "suddenly vibrate"),
  159.                    Blind ? "again" : "unexpectedly");
  160.          break;
  161.      }
  162.      case SCR_DESTROY_ARMOR: {
  163.          otmp = some_armor(&youmonst);
  164.          if (confused) {
  165.              if (!otmp) {
  166.                  strange_feeling(sobj, "Your bones itch.");
  167.                  sobj = 0; /* useup() in strange_feeling() */
  168.                  exercise(A_STR, FALSE);
  169.                  exercise(A_CON, FALSE);
  170.                  break;
  171.              }
  172.              old_erodeproof = (otmp->oerodeproof != 0);
  173.              new_erodeproof = scursed;
  174.              otmp->oerodeproof = 0; /* for messages */
  175.              p_glow2(otmp, NH_PURPLE);
  176.              if (old_erodeproof && !new_erodeproof) {
  177.                  /* restore old_erodeproof before shop charges */
  178.                  otmp->oerodeproof = 1;
  179.                  costly_alteration(otmp, COST_DEGRD);
  180.              }
  181.              otmp->oerodeproof = new_erodeproof ? 1 : 0;
  182.              break;
  183.          }
  184.          if (!scursed || !otmp || !otmp->cursed) {
  185.              if (!destroy_arm(otmp)) {
  186.                  strange_feeling(sobj, "Your skin itches.");
  187.                  sobj = 0; /* useup() in strange_feeling() */
  188.                  exercise(A_STR, FALSE);
  189.                  exercise(A_CON, FALSE);
  190.                  break;
  191.              } else
  192.                  known = TRUE;
  193.          } else { /* armor and scroll both cursed */
  194.              pline("%s.", Yobjnam2(otmp, "vibrate"));
  195.              if (otmp->spe >= -6) {
  196.                  otmp->spe += -1;
  197.                  adj_abon(otmp, -1);
  198.              }
  199.              make_stunned((HStun & TIMEOUT) + (long) rn1(10, 10), TRUE);
  200.          }
  201.      } break;
  202.      case SCR_CONFUSE_MONSTER:
  203.      case SPE_CONFUSE_MONSTER:
  204.          if (youmonst.data->mlet != S_HUMAN || scursed) {
  205.              if (!HConfusion)
  206.                  You_feel("confused.");
  207.              make_confused(HConfusion + rnd(100), FALSE);
  208.          } else if (confused) {
  209.              if (!sblessed) {
  210.                  Your("%s begin to %s%s.", makeplural(body_part(HAND)),
  211.                       Blind ? "tingle" : "glow ",
  212.                       Blind ? "" : hcolor(NH_PURPLE));
  213.                  make_confused(HConfusion + rnd(100), FALSE);
  214.              } else {
  215.                  pline("A %s%s surrounds your %s.",
  216.                        Blind ? "" : hcolor(NH_RED),
  217.                        Blind ? "faint buzz" : " glow", body_part(HEAD));
  218.                  make_confused(0L, TRUE);
  219.              }
  220.          } else {
  221.              if (!sblessed) {
  222.                  Your("%s%s %s%s.", makeplural(body_part(HAND)),
  223.                       Blind ? "" : " begin to glow",
  224.                       Blind ? (const char *) "tingle" : hcolor(NH_RED),
  225.                       u.umconf ? " even more" : "");
  226.                  u.umconf++;
  227.              } else {
  228.                  if (Blind)
  229.                      Your("%s tingle %s sharply.", makeplural(body_part(HAND)),
  230.                           u.umconf ? "even more" : "very");
  231.                  else
  232.                      Your("%s glow a%s brilliant %s.",
  233.                           makeplural(body_part(HAND)),
  234.                           u.umconf ? "n even more" : "", hcolor(NH_RED));
  235.                  /* after a while, repeated uses become less effective */
  236.                  if (u.umconf >= 40)
  237.                      u.umconf++;
  238.                  else
  239.                      u.umconf += rn1(8, 2);
  240.              }
  241.          }
  242.          break;
  243.      case SCR_SCARE_MONSTER:
  244.      case SPE_CAUSE_FEAR: {
  245.          register int ct = 0;
  246.          register struct monst *mtmp;
  247.  
  248.          for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  249.              if (DEADMONSTER(mtmp))
  250.                  continue;
  251.              if (cansee(mtmp->mx, mtmp->my)) {
  252.                  if (confused || scursed) {
  253.                      mtmp->mflee = mtmp->mfrozen = mtmp->msleeping = 0;
  254.                      mtmp->mcanmove = 1;
  255.                  } else if (!resist(mtmp, sobj->oclass, 0, NOTELL))
  256.                      monflee(mtmp, 0, FALSE, FALSE);
  257.                  if (!mtmp->mtame)
  258.                      ct++; /* pets don't laugh at you */
  259.              }
  260.          }
  261.          if (otyp == SCR_SCARE_MONSTER || !ct)
  262.              You_hear("%s %s.", (confused || scursed) ? "sad wailing"
  263.                                                       : "maniacal laughter",
  264.                       !ct ? "in the distance" : "close by");
  265.          break;
  266.      }
  267.      case SCR_BLANK_PAPER:
  268.          if (Blind)
  269.              You("don't remember there being any magic words on this scroll.");
  270.          else
  271.              pline("This scroll seems to be blank.");
  272.          known = TRUE;
  273.          break;
  274.      case SCR_REMOVE_CURSE:
  275.      case SPE_REMOVE_CURSE: {
  276.          register struct obj *obj;
  277.  
  278.          You_feel(!Hallucination
  279.                       ? (!confused ? "like someone is helping you."
  280.                                    : "like you need some help.")
  281.                       : (!confused ? "in touch with the Universal Oneness."
  282.                                    : "the power of the Force against you!"));
  283.  
  284.          if (scursed) {
  285.              pline_The("scroll disintegrates.");
  286.          } else {
  287.              for (obj = invent; obj; obj = obj->nobj) {
  288.                  long wornmask;
  289.  
  290.                  /* gold isn't subject to cursing and blessing */
  291.                  if (obj->oclass == COIN_CLASS)
  292.                      continue;
  293.                  wornmask = (obj->owornmask & ~(W_BALL | W_ART | W_ARTI));
  294.                  if (wornmask && !sblessed) {
  295.                      /* handle a couple of special cases; we don't
  296.                         allow auxiliary weapon slots to be used to
  297.                         artificially increase number of worn items */
  298.                      if (obj == uswapwep) {
  299.                          if (!u.twoweap)
  300.                              wornmask = 0L;
  301.                      } else if (obj == uquiver) {
  302.                          if (obj->oclass == WEAPON_CLASS) {
  303.                              /* mergeable weapon test covers ammo,
  304.                                 missiles, spears, daggers & knives */
  305.                              if (!objects[obj->otyp].oc_merge)
  306.                                  wornmask = 0L;
  307.                          } else if (obj->oclass == GEM_CLASS) {
  308.                              /* possibly ought to check whether
  309.                                 alternate weapon is a sling... */
  310.                              if (!uslinging())
  311.                                  wornmask = 0L;
  312.                          } else {
  313.                              /* weptools don't merge and aren't
  314.                                 reasonable quivered weapons */
  315.                              wornmask = 0L;
  316.                          }
  317.                      }
  318.                  }
  319.                  if (sblessed || wornmask || obj->otyp == LOADSTONE
  320.                      || (obj->otyp == LEASH && obj->leashmon)) {
  321.                      /* water price varies by curse/bless status */
  322.                      boolean shop_h2o = (obj->unpaid && obj->otyp == POT_WATER);
  323.  
  324.                      if (confused) {
  325.                          blessorcurse(obj, 2);
  326.                          /* lose knowledge of this object's curse/bless
  327.                             state (even if it didn't actually change) */
  328.                          obj->bknown = 0;
  329.                          /* blessorcurse() only affects uncursed items
  330.                             so no need to worry about price of water
  331.                             going down (hence no costly_alteration) */
  332.                          if (shop_h2o && (obj->cursed || obj->blessed))
  333.                              alter_cost(obj, 0L); /* price goes up */
  334.                      } else if (obj->cursed) {
  335.                          if (shop_h2o)
  336.                              costly_alteration(obj, COST_UNCURS);
  337.                          uncurse(obj);
  338.                      }
  339.                  }
  340.              }
  341.          }
  342.          if (Punished && !confused)
  343.              unpunish();
  344.          if (u.utrap && u.utraptype == TT_BURIEDBALL) {
  345.              buried_ball_to_freedom();
  346.              pline_The("clasp on your %s vanishes.", body_part(LEG));
  347.          }
  348.          update_inventory();
  349.          break;
  350.      }
  351.      case SCR_CREATE_MONSTER:
  352.      case SPE_CREATE_MONSTER:
  353.          if (create_critters(1 + ((confused || scursed) ? 12 : 0)
  354.                                  + ((sblessed || rn2(73)) ? 0 : rnd(4)),
  355.                              confused ? &mons[PM_ACID_BLOB]
  356.                                       : (struct permonst *) 0,
  357.                              FALSE))
  358.              known = TRUE;
  359.          /* no need to flush monsters; we ask for identification only if the
  360.           * monsters are not visible
  361.           */
  362.          break;
  363.      case SCR_ENCHANT_WEAPON:
  364.          /* [What about twoweapon mode?  Proofing/repairing/enchanting both
  365.             would be too powerful, but shouldn't we choose randomly between
  366.             primary and secondary instead of always acting on primary?] */
  367.          if (confused && uwep
  368.              && erosion_matters(uwep) && uwep->oclass != ARMOR_CLASS) {
  369.              old_erodeproof = (uwep->oerodeproof != 0);
  370.              new_erodeproof = !scursed;
  371.              uwep->oerodeproof = 0; /* for messages */
  372.              if (Blind) {
  373.                  uwep->rknown = FALSE;
  374.                  Your("weapon feels warm for a moment.");
  375.              } else {
  376.                  uwep->rknown = TRUE;
  377.                  pline("%s covered by a %s %s %s!", Yobjnam2(uwep, "are"),
  378.                        scursed ? "mottled" : "shimmering",
  379.                        hcolor(scursed ? NH_PURPLE : NH_GOLDEN),
  380.                        scursed ? "glow" : "shield");
  381.              }
  382.              if (new_erodeproof && (uwep->oeroded || uwep->oeroded2)) {
  383.                  uwep->oeroded = uwep->oeroded2 = 0;
  384.                  pline("%s as good as new!",
  385.                        Yobjnam2(uwep, Blind ? "feel" : "look"));
  386.              }
  387.              if (old_erodeproof && !new_erodeproof) {
  388.                  /* restore old_erodeproof before shop charges */
  389.                  uwep->oerodeproof = 1;
  390.                  costly_alteration(uwep, COST_DEGRD);
  391.              }
  392.              uwep->oerodeproof = new_erodeproof ? 1 : 0;
  393.              break;
  394.          }
  395.          if (!chwepon(sobj, scursed ? -1
  396.                               : !uwep ? 1
  397.                                 : (uwep->spe >= 9) ? !rn2(uwep->spe)
  398.                                   : sblessed ? rnd(3 - uwep->spe / 3)
  399.                                     : 1))
  400.              sobj = 0; /* nothing enchanted: strange_feeling -> useup */
  401.          break;
  402.      case SCR_TAMING:
  403.      case SPE_CHARM_MONSTER: {
  404.          int candidates, res, results, vis_results;
  405.  
  406.          if (u.uswallow) {
  407.              candidates = 1;
  408.              results = vis_results = maybe_tame(u.ustuck, sobj);
  409.          } else {
  410.              int i, j, bd = confused ? 5 : 1;
  411.              struct monst *mtmp;
  412.  
  413.              /* note: maybe_tame() can return either positive or
  414.                 negative values, but not both for the same scroll */
  415.              candidates = results = vis_results = 0;
  416.              for (i = -bd; i <= bd; i++)
  417.                  for (j = -bd; j <= bd; j++) {
  418.                      if (!isok(u.ux + i, u.uy + j))
  419.                          continue;
  420.                      if ((mtmp = m_at(u.ux + i, u.uy + j)) != 0
  421.                          || (!i && !j && (mtmp = u.usteed) != 0)) {
  422.                          ++candidates;
  423.                          res = maybe_tame(mtmp, sobj);
  424.                          results += res;
  425.                          if (canspotmon(mtmp))
  426.                              vis_results += res;
  427.                      }
  428.                  }
  429.          }
  430.          if (!results) {
  431.              pline("Nothing interesting %s.",
  432.                    !candidates ? "happens" : "seems to happen");
  433.          } else {
  434.              pline_The("neighborhood %s %sfriendlier.",
  435.                        vis_results ? "is" : "seems",
  436.                        (results < 0) ? "un" : "");
  437.              if (vis_results > 0)
  438.                  known = TRUE;
  439.          }
  440.          break;
  441.      }
  442.      case SCR_GENOCIDE:
  443.          if (!already_known)
  444.              You("have found a scroll of genocide!");
  445.          known = TRUE;
  446.          if (sblessed)
  447.              do_class_genocide();
  448.          else
  449.              do_genocide((!scursed) | (2 * !!Confusion));
  450.          break;
  451.      case SCR_LIGHT:
  452.          if (!confused || rn2(5)) {
  453.              if (!Blind)
  454.                  known = TRUE;
  455.              litroom(!confused && !scursed, sobj);
  456.              if (!confused && !scursed) {
  457.                  if (lightdamage(sobj, TRUE, 5))
  458.                      known = TRUE;
  459.              }
  460.          } else {
  461.              /* could be scroll of create monster, don't set known ...*/
  462.              (void) create_critters(1, !scursed ? &mons[PM_YELLOW_LIGHT]
  463.                                                 : &mons[PM_BLACK_LIGHT],
  464.                                     TRUE);
  465.          }
  466.          break;
  467.      case SCR_TELEPORTATION:
  468.          if (confused || scursed) {
  469.              level_tele();
  470.          } else {
  471.              known = scrolltele(sobj);
  472.          }
  473.          break;
  474.      case SCR_GOLD_DETECTION:
  475.          if ((confused || scursed) ? trap_detect(sobj) : gold_detect(sobj))
  476.              sobj = 0; /* failure: strange_feeling() -> useup() */
  477.          break;
  478.      case SCR_FOOD_DETECTION:
  479.      case SPE_DETECT_FOOD:
  480.          if (food_detect(sobj))
  481.              sobj = 0; /* nothing detected: strange_feeling -> useup */
  482.          break;
  483.      case SCR_IDENTIFY:
  484.          /* known = TRUE; -- handled inline here */
  485.          /* use up the scroll first, before makeknown() performs a
  486.             perm_invent update; also simplifies empty invent check */
  487.          useup(sobj);
  488.          sobj = 0; /* it's gone */
  489.          if (confused)
  490.              You("identify this as an identify scroll.");
  491.          else if (!already_known || !invent)
  492.              /* force feedback now if invent became
  493.                 empty after using up this scroll */
  494.              pline("This is an identify scroll.");
  495.          if (!already_known)
  496.              (void) learnscrolltyp(SCR_IDENTIFY);
  497.          /*FALLTHRU*/
  498.      case SPE_IDENTIFY:
  499.          cval = 1;
  500.          if (sblessed || (!scursed && !rn2(5))) {
  501.              cval = rn2(5);
  502.              /* note: if cval==0, identify all items */
  503.              if (cval == 1 && sblessed && Luck > 0)
  504.                  ++cval;
  505.          }
  506.          if (invent && !confused) {
  507.              identify_pack(cval, !already_known);
  508.          } else if (otyp == SPE_IDENTIFY) {
  509.              /* when casting a spell we know we're not confused,
  510.                 so inventory must be empty (another message has
  511.                 already been given above if reading a scroll) */
  512.              pline("You're not carrying anything to be identified.");
  513.          }
  514.          break;
  515.      case SCR_CHARGING:
  516.          if (confused) {
  517.              if (scursed) {
  518.                  You_feel("discharged.");
  519.                  u.uen = 0;
  520.              } else {
  521.                  You_feel("charged up!");
  522.                  u.uen += d(sblessed ? 6 : 4, 4);
  523.                  if (u.uen > u.uenmax) /* if current energy is already at   */
  524.                      u.uenmax = u.uen; /* or near maximum, increase maximum */
  525.                  else
  526.                      u.uen = u.uenmax; /* otherwise restore current to max  */
  527.              }
  528.              context.botl = 1;
  529.              break;
  530.          }
  531.          /* known = TRUE; -- handled inline here */
  532.          if (!already_known) {
  533.              pline("This is a charging scroll.");
  534.              learnscroll(sobj);
  535.          }
  536.          /* use it up now to prevent it from showing in the
  537.             getobj picklist because the "disappears" message
  538.             was already delivered */
  539.          useup(sobj);
  540.          sobj = 0; /* it's gone */
  541.          otmp = getobj(all_count, "charge");
  542.          if (otmp)
  543.              recharge(otmp, scursed ? -1 : sblessed ? 1 : 0);
  544.          break;
  545.      case SCR_MAGIC_MAPPING:
  546.          if (level.flags.nommap) {
  547.              Your("mind is filled with crazy lines!");
  548.              if (Hallucination)
  549.                  pline("Wow!  Modern art.");
  550.              else
  551.                  Your("%s spins in bewilderment.", body_part(HEAD));
  552.              make_confused(HConfusion + rnd(30), FALSE);
  553.              break;
  554.          }
  555.          if (sblessed) {
  556.              register int x, y;
  557.  
  558.              for (x = 1; x < COLNO; x++)
  559.                  for (y = 0; y < ROWNO; y++)
  560.                      if (levl[x][y].typ == SDOOR)
  561.                          cvt_sdoor_to_door(&levl[x][y]);
  562.              /* do_mapping() already reveals secret passages */
  563.          }
  564.          known = TRUE;
  565.          /*FALLTHRU*/
  566.      case SPE_MAGIC_MAPPING:
  567.          if (level.flags.nommap) {
  568.              Your("%s spins as %s blocks the spell!", body_part(HEAD),
  569.                   something);
  570.              make_confused(HConfusion + rnd(30), FALSE);
  571.              break;
  572.          }
  573.          pline("A map coalesces in your mind!");
  574.          cval = (scursed && !confused);
  575.          if (cval)
  576.              HConfusion = 1; /* to screw up map */
  577.          do_mapping();
  578.          if (cval) {
  579.              HConfusion = 0; /* restore */
  580.              pline("Unfortunately, you can't grasp the details.");
  581.          }
  582.          break;
  583.      case SCR_AMNESIA:
  584.          known = TRUE;
  585.          forget((!sblessed ? ALL_SPELLS : 0)
  586.                 | (!confused || scursed ? ALL_MAP : 0));
  587.          if (Hallucination) /* Ommmmmm! */
  588.              Your("mind releases itself from mundane concerns.");
  589.          else if (!strncmpi(plname, "Maud", 4))
  590.              pline(
  591.            "As your mind turns inward on itself, you forget everything else.");
  592.          else if (rn2(2))
  593.              pline("Who was that Maud person anyway?");
  594.          else
  595.              pline("Thinking of Maud you forget everything else.");
  596.          exercise(A_WIS, FALSE);
  597.          break;
  598.      case SCR_FIRE: {
  599.          coord cc;
  600.          int dam;
  601.  
  602.          cc.x = u.ux;
  603.          cc.y = u.uy;
  604.          cval = bcsign(sobj);
  605.          dam = (2 * (rn1(3, 3) + 2 * cval) + 1) / 3;
  606.          useup(sobj);
  607.          sobj = 0; /* it's gone */
  608.          if (!already_known)
  609.              (void) learnscrolltyp(SCR_FIRE);
  610.          if (confused) {
  611.              if (Fire_resistance) {
  612.                  shieldeff(u.ux, u.uy);
  613.                  if (!Blind)
  614.                      pline("Oh, look, what a pretty fire in your %s.",
  615.                            makeplural(body_part(HAND)));
  616.                  else
  617.                      You_feel("a pleasant warmth in your %s.",
  618.                               makeplural(body_part(HAND)));
  619.              } else {
  620.                  pline_The("scroll catches fire and you burn your %s.",
  621.                            makeplural(body_part(HAND)));
  622.                  losehp(1, "scroll of fire", KILLED_BY_AN);
  623.              }
  624.              break;
  625.          }
  626.          if (Underwater) {
  627.              pline_The("%s around you vaporizes violently!", hliquid("water"));
  628.          } else {
  629.              if (sblessed) {
  630.                  if (!already_known)
  631.                      pline("This is a scroll of fire!");
  632.                  dam *= 5;
  633.                  pline("Where do you want to center the explosion?");
  634.                  getpos_sethilite(display_stinking_cloud_positions, get_valid_stinking_cloud_pos);
  635.                  (void) getpos(&cc, TRUE, "the desired position");
  636.                  if (!is_valid_stinking_cloud_pos(cc.x, cc.y, FALSE)) {
  637.                      /* try to reach too far, get burned */
  638.                      cc.x = u.ux;
  639.                      cc.y = u.uy;
  640.                  }
  641.              }
  642.              if (cc.x == u.ux && cc.y == u.uy) {
  643.                  pline_The("scroll erupts in a tower of flame!");
  644.                  iflags.last_msg = PLNMSG_TOWER_OF_FLAME; /* for explode() */
  645.                  burn_away_slime();
  646.              }
  647.          }
  648.          explode(cc.x, cc.y, 11, dam, SCROLL_CLASS, EXPL_FIERY);
  649.          break;
  650.      }
  651.      case SCR_EARTH:
  652.          /* TODO: handle steeds */
  653.          if (!Is_rogue_level(&u.uz) && has_ceiling(&u.uz)
  654.              && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) {
  655.              register int x, y;
  656.              int nboulders = 0;
  657.  
  658.              /* Identify the scroll */
  659.              if (u.uswallow)
  660.                  You_hear("rumbling.");
  661.              else
  662.                  pline_The("%s rumbles %s you!", ceiling(u.ux, u.uy),
  663.                            sblessed ? "around" : "above");
  664.              known = 1;
  665.              sokoban_guilt();
  666.  
  667.              /* Loop through the surrounding squares */
  668.              if (!scursed)
  669.                  for (x = u.ux - 1; x <= u.ux + 1; x++) {
  670.                      for (y = u.uy - 1; y <= u.uy + 1; y++) {
  671.                          /* Is this a suitable spot? */
  672.                          if (isok(x, y) && !closed_door(x, y)
  673.                              && !IS_ROCK(levl[x][y].typ)
  674.                              && !IS_AIR(levl[x][y].typ)
  675.                              && (x != u.ux || y != u.uy)) {
  676.                              nboulders +=
  677.                                  drop_boulder_on_monster(x, y, confused, TRUE);
  678.                          }
  679.                      }
  680.                  }
  681.              /* Attack the player */
  682.              if (!sblessed) {
  683.                  drop_boulder_on_player(confused, !scursed, TRUE, FALSE);
  684.              } else if (!nboulders)
  685.                  pline("But nothing else happens.");
  686.          }
  687.          break;
  688.      case SCR_PUNISHMENT:
  689.          known = TRUE;
  690.          if (confused || sblessed) {
  691.              You_feel("guilty.");
  692.              break;
  693.          }
  694.          punish(sobj);
  695.          break;
  696.      case SCR_STINKING_CLOUD: {
  697.          coord cc;
  698.  
  699.          if (!already_known)
  700.              You("have found a scroll of stinking cloud!");
  701.          known = TRUE;
  702.          pline("Where do you want to center the %scloud?",
  703.                already_known ? "stinking " : "");
  704.          cc.x = u.ux;
  705.          cc.y = u.uy;
  706.          getpos_sethilite(display_stinking_cloud_positions, get_valid_stinking_cloud_pos);
  707.          if (getpos(&cc, TRUE, "the desired position") < 0) {
  708.              pline1(Never_mind);
  709.              break;
  710.          }
  711.          if (!is_valid_stinking_cloud_pos(cc.x, cc.y, TRUE))
  712.              break;
  713.          (void) create_gas_cloud(cc.x, cc.y, 3 + bcsign(sobj),
  714.                                  8 + 4 * bcsign(sobj));
  715.          break;
  716.      }
  717.      default:
  718.          impossible("What weird effect is this? (%u)", otyp);
  719.      }
  720.      return sobj ? 0 : 1;
  721.  }
  722.  

drop_boulder_on_player

  1.  void
  2.  drop_boulder_on_player(confused, helmet_protects, byu, skip_uswallow)
  3.  boolean confused, helmet_protects, byu, skip_uswallow;
  4.  {
  5.      int dmg;
  6.      struct obj *otmp2;
  7.  
  8.      /* hit monster if swallowed */
  9.      if (u.uswallow && !skip_uswallow) {
  10.          drop_boulder_on_monster(u.ux, u.uy, confused, byu);
  11.          return;
  12.      }
  13.  
  14.      otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE);
  15.      if (!otmp2)
  16.          return;
  17.      otmp2->quan = confused ? rn1(5, 2) : 1;
  18.      otmp2->owt = weight(otmp2);
  19.      if (!amorphous(youmonst.data) && !Passes_walls
  20.          && !noncorporeal(youmonst.data) && !unsolid(youmonst.data)) {
  21.          You("are hit by %s!", doname(otmp2));
  22.          dmg = dmgval(otmp2, &youmonst) * otmp2->quan;
  23.          if (uarmh && helmet_protects) {
  24.              if (is_metallic(uarmh)) {
  25.                  pline("Fortunately, you are wearing a hard helmet.");
  26.                  if (dmg > 2)
  27.                      dmg = 2;
  28.              } else if (flags.verbose) {
  29.                  pline("%s does not protect you.", Yname2(uarmh));
  30.              }
  31.          }
  32.      } else
  33.          dmg = 0;
  34.      wake_nearto(u.ux, u.uy, 4 * 4);
  35.      /* Must be before the losehp(), for bones files */
  36.      if (!flooreffects(otmp2, u.ux, u.uy, "fall")) {
  37.          place_object(otmp2, u.ux, u.uy);
  38.          stackobj(otmp2);
  39.          newsym(u.ux, u.uy);
  40.      }
  41.      if (dmg)
  42.          losehp(Maybe_Half_Phys(dmg), "scroll of earth", KILLED_BY_AN);
  43.  }
  44.  

drop_boulder_on_monster

  1.  boolean
  2.  drop_boulder_on_monster(x, y, confused, byu)
  3.  int x, y;
  4.  boolean confused, byu;
  5.  {
  6.      register struct obj *otmp2;
  7.      register struct monst *mtmp;
  8.  
  9.      /* Make the object(s) */
  10.      otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE);
  11.      if (!otmp2)
  12.          return FALSE; /* Shouldn't happen */
  13.      otmp2->quan = confused ? rn1(5, 2) : 1;
  14.      otmp2->owt = weight(otmp2);
  15.  
  16.      /* Find the monster here (won't be player) */
  17.      mtmp = m_at(x, y);
  18.      if (mtmp && !amorphous(mtmp->data) && !passes_walls(mtmp->data)
  19.          && !noncorporeal(mtmp->data) && !unsolid(mtmp->data)) {
  20.          struct obj *helmet = which_armor(mtmp, W_ARMH);
  21.          int mdmg;
  22.  
  23.          if (cansee(mtmp->mx, mtmp->my)) {
  24.              pline("%s is hit by %s!", Monnam(mtmp), doname(otmp2));
  25.              if (mtmp->minvis && !canspotmon(mtmp))
  26.                  map_invisible(mtmp->mx, mtmp->my);
  27.          } else if (u.uswallow && mtmp == u.ustuck)
  28.              You_hear("something hit %s %s over your %s!",
  29.                       s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH),
  30.                       body_part(HEAD));
  31.  
  32.          mdmg = dmgval(otmp2, mtmp) * otmp2->quan;
  33.          if (helmet) {
  34.              if (is_metallic(helmet)) {
  35.                  if (canspotmon(mtmp))
  36.                      pline("Fortunately, %s is wearing a hard helmet.",
  37.                            mon_nam(mtmp));
  38.                  else if (!Deaf)
  39.                      You_hear("a clanging sound.");
  40.                  if (mdmg > 2)
  41.                      mdmg = 2;
  42.              } else {
  43.                  if (canspotmon(mtmp))
  44.                      pline("%s's %s does not protect %s.", Monnam(mtmp),
  45.                            xname(helmet), mhim(mtmp));
  46.              }
  47.          }
  48.          mtmp->mhp -= mdmg;
  49.          if (mtmp->mhp <= 0) {
  50.              if (byu) {
  51.                  killed(mtmp);
  52.              } else {
  53.                  pline("%s is killed.", Monnam(mtmp));
  54.                  mondied(mtmp);
  55.              }
  56.          } else {
  57.              wakeup(mtmp, byu);
  58.          }
  59.          wake_nearto(x, y, 4 * 4);
  60.      } else if (u.uswallow && mtmp == u.ustuck) {
  61.          obfree(otmp2, (struct obj *) 0);
  62.          /* fall through to player */
  63.          drop_boulder_on_player(confused, TRUE, FALSE, TRUE);
  64.          return 1;
  65.      }
  66.      /* Drop the rock/boulder to the floor */
  67.      if (!flooreffects(otmp2, x, y, "fall")) {
  68.          place_object(otmp2, x, y);
  69.          stackobj(otmp2);
  70.          newsym(x, y); /* map the rock */
  71.      }
  72.      return TRUE;
  73.  }
  74.  

wand_explode

  1.  /* overcharging any wand or zapping/engraving cursed wand */
  2.  void
  3.  wand_explode(obj, chg)
  4.  struct obj *obj;
  5.  int chg; /* recharging */
  6.  {
  7.      const char *expl = !chg ? "suddenly" : "vibrates violently and";
  8.      int dmg, n, k;
  9.  
  10.      /* number of damage dice */
  11.      if (!chg)
  12.          chg = 2; /* zap/engrave adjustment */
  13.      n = obj->spe + chg;
  14.      if (n < 2)
  15.          n = 2; /* arbitrary minimum */
  16.      /* size of damage dice */
  17.      switch (obj->otyp) {
  18.      case WAN_WISHING:
  19.          k = 12;
  20.          break;
  21.      case WAN_CANCELLATION:
  22.      case WAN_DEATH:
  23.      case WAN_POLYMORPH:
  24.      case WAN_UNDEAD_TURNING:
  25.          k = 10;
  26.          break;
  27.      case WAN_COLD:
  28.      case WAN_FIRE:
  29.      case WAN_LIGHTNING:
  30.      case WAN_MAGIC_MISSILE:
  31.          k = 8;
  32.          break;
  33.      case WAN_NOTHING:
  34.          k = 4;
  35.          break;
  36.      default:
  37.          k = 6;
  38.          break;
  39.      }
  40.      /* inflict damage and destroy the wand */
  41.      dmg = d(n, k);
  42.      obj->in_use = TRUE; /* in case losehp() is fatal (or --More--^C) */
  43.      pline("%s %s explodes!", Yname2(obj), expl);
  44.      losehp(Maybe_Half_Phys(dmg), "exploding wand", KILLED_BY_AN);
  45.      useup(obj);
  46.      /* obscure side-effect */
  47.      exercise(A_STR, FALSE);
  48.  }
  49.  
  50.  /* used to collect gremlins being hit by light so that they can be processed
  51.     after vision for the entire lit area has been brought up to date */
  52.  struct litmon {
  53.      struct monst *mon;
  54.      struct litmon *nxt;
  55.  };
  56.  STATIC_VAR struct litmon *gremlins = 0;
  57.  

set_lit

  1.  /*
  2.   * Low-level lit-field update routine.
  3.   */
  4.  STATIC_PTR void
  5.  set_lit(x, y, val)
  6.  int x, y;
  7.  genericptr_t val;
  8.  {
  9.      struct monst *mtmp;
  10.      struct litmon *gremlin;
  11.  
  12.      if (val) {
  13.          levl[x][y].lit = 1;
  14.          if ((mtmp = m_at(x, y)) != 0 && mtmp->data == &mons[PM_GREMLIN]) {
  15.              gremlin = (struct litmon *) alloc(sizeof *gremlin);
  16.              gremlin->mon = mtmp;
  17.              gremlin->nxt = gremlins;
  18.              gremlins = gremlin;
  19.          }
  20.      } else {
  21.          levl[x][y].lit = 0;
  22.          snuff_light_source(x, y);
  23.      }
  24.  }
  25.  

litroom

  1.  void
  2.  litroom(on, obj)
  3.  register boolean on;
  4.  struct obj *obj;
  5.  {
  6.      char is_lit; /* value is irrelevant; we use its address
  7.                      as a `not null' flag for set_lit() */
  8.  
  9.      /* first produce the text (provided you're not blind) */
  10.      if (!on) {
  11.          register struct obj *otmp;
  12.  
  13.          if (!Blind) {
  14.              if (u.uswallow) {
  15.                  pline("It seems even darker in here than before.");
  16.              } else {
  17.                  if (uwep && artifact_light(uwep) && uwep->lamplit)
  18.                      pline("Suddenly, the only light left comes from %s!",
  19.                            the(xname(uwep)));
  20.                  else
  21.                      You("are surrounded by darkness!");
  22.              }
  23.          }
  24.  
  25.          /* the magic douses lamps, et al, too */
  26.          for (otmp = invent; otmp; otmp = otmp->nobj)
  27.              if (otmp->lamplit)
  28.                  (void) snuff_lit(otmp);
  29.      } else { /* on */
  30.          if (u.uswallow) {
  31.              if (Blind)
  32.                  ; /* no feedback */
  33.              else if (is_animal(u.ustuck->data))
  34.                  pline("%s %s is lit.", s_suffix(Monnam(u.ustuck)),
  35.                        mbodypart(u.ustuck, STOMACH));
  36.              else if (is_whirly(u.ustuck->data))
  37.                  pline("%s shines briefly.", Monnam(u.ustuck));
  38.              else
  39.                  pline("%s glistens.", Monnam(u.ustuck));
  40.          } else if (!Blind)
  41.              pline("A lit field surrounds you!");
  42.      }
  43.  
  44.      /* No-op when swallowed or in water */
  45.      if (u.uswallow || Underwater || Is_waterlevel(&u.uz))
  46.          return;
  47.      /*
  48.       *  If we are darkening the room and the hero is punished but not
  49.       *  blind, then we have to pick up and replace the ball and chain so
  50.       *  that we don't remember them if they are out of sight.
  51.       */
  52.      if (Punished && !on && !Blind)
  53.          move_bc(1, 0, uball->ox, uball->oy, uchain->ox, uchain->oy);
  54.  
  55.      if (Is_rogue_level(&u.uz)) {
  56.          /* Can't use do_clear_area because MAX_RADIUS is too small */
  57.          /* rogue lighting must light the entire room */
  58.          int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET;
  59.          int rx, ry;
  60.  
  61.          if (rnum >= 0) {
  62.              for (rx = rooms[rnum].lx - 1; rx <= rooms[rnum].hx + 1; rx++)
  63.                  for (ry = rooms[rnum].ly - 1; ry <= rooms[rnum].hy + 1; ry++)
  64.                      set_lit(rx, ry,
  65.                              (genericptr_t) (on ? &is_lit : (char *) 0));
  66.              rooms[rnum].rlit = on;
  67.          }
  68.          /* hallways remain dark on the rogue level */
  69.      } else
  70.          do_clear_area(u.ux, u.uy,
  71.                        (obj && obj->oclass == SCROLL_CLASS && obj->blessed)
  72.                           ? 9 : 5,
  73.                        set_lit, (genericptr_t) (on ? &is_lit : (char *) 0));
  74.  
  75.      /*
  76.       *  If we are not blind, then force a redraw on all positions in sight
  77.       *  by temporarily blinding the hero.  The vision recalculation will
  78.       *  correctly update all previously seen positions *and* correctly
  79.       *  set the waslit bit [could be messed up from above].
  80.       */
  81.      if (!Blind) {
  82.          vision_recalc(2);
  83.  
  84.          /* replace ball&chain */
  85.          if (Punished && !on)
  86.              move_bc(0, 0, uball->ox, uball->oy, uchain->ox, uchain->oy);
  87.      }
  88.  
  89.      vision_full_recalc = 1; /* delayed vision recalculation */
  90.      if (gremlins) {
  91.          struct litmon *gremlin;
  92.  
  93.          /* can't delay vision recalc after all */
  94.          vision_recalc(0);
  95.          /* after vision has been updated, monsters who are affected
  96.             when hit by light can now be hit by it */
  97.          do {
  98.              gremlin = gremlins;
  99.              gremlins = gremlin->nxt;
  100.              light_hits_gremlin(gremlin->mon, rnd(5));
  101.              free((genericptr_t) gremlin);
  102.          } while (gremlins);
  103.      }
  104.  }
  105.  

do_class_genocide

  1.  STATIC_OVL void
  2.  do_class_genocide()
  3.  {
  4.      int i, j, immunecnt, gonecnt, goodcnt, class, feel_dead = 0;
  5.      char buf[BUFSZ] = DUMMY;
  6.      boolean gameover = FALSE; /* true iff killed self */
  7.  
  8.      for (j = 0;; j++) {
  9.          if (j >= 5) {
  10.              pline1(thats_enough_tries);
  11.              return;
  12.          }
  13.          do {
  14.              getlin("What class of monsters do you wish to genocide?", buf);
  15.              (void) mungspaces(buf);
  16.          } while (!*buf);
  17.          /* choosing "none" preserves genocideless conduct */
  18.          if (*buf == '\033' || !strcmpi(buf, "none")
  19.              || !strcmpi(buf, "nothing"))
  20.              return;
  21.  
  22.          class = name_to_monclass(buf, (int *) 0);
  23.          if (class == 0 && (i = name_to_mon(buf)) != NON_PM)
  24.              class = mons[i].mlet;
  25.          immunecnt = gonecnt = goodcnt = 0;
  26.          for (i = LOW_PM; i < NUMMONS; i++) {
  27.              if (mons[i].mlet == class) {
  28.                  if (!(mons[i].geno & G_GENO))
  29.                      immunecnt++;
  30.                  else if (mvitals[i].mvflags & G_GENOD)
  31.                      gonecnt++;
  32.                  else
  33.                      goodcnt++;
  34.              }
  35.          }
  36.          if (!goodcnt && class != mons[urole.malenum].mlet
  37.              && class != mons[urace.malenum].mlet) {
  38.              if (gonecnt)
  39.                  pline("All such monsters are already nonexistent.");
  40.              else if (immunecnt || class == S_invisible)
  41.                  You("aren't permitted to genocide such monsters.");
  42.              else if (wizard && buf[0] == '*') {
  43.                  register struct monst *mtmp, *mtmp2;
  44.  
  45.                  gonecnt = 0;
  46.                  for (mtmp = fmon; mtmp; mtmp = mtmp2) {
  47.                      mtmp2 = mtmp->nmon;
  48.                      if (DEADMONSTER(mtmp))
  49.                          continue;
  50.                      mongone(mtmp);
  51.                      gonecnt++;
  52.                  }
  53.                  pline("Eliminated %d monster%s.", gonecnt, plur(gonecnt));
  54.                  return;
  55.              } else
  56.                  pline("That %s does not represent any monster.",
  57.                        strlen(buf) == 1 ? "symbol" : "response");
  58.              continue;
  59.          }
  60.  
  61.          for (i = LOW_PM; i < NUMMONS; i++) {
  62.              if (mons[i].mlet == class) {
  63.                  char nam[BUFSZ];
  64.  
  65.                  Strcpy(nam, makeplural(mons[i].mname));
  66.                  /* Although "genus" is Latin for race, the hero benefits
  67.                   * from both race and role; thus genocide affects either.
  68.                   */
  69.                  if (Your_Own_Role(i) || Your_Own_Race(i)
  70.                      || ((mons[i].geno & G_GENO)
  71.                          && !(mvitals[i].mvflags & G_GENOD))) {
  72.                      /* This check must be first since player monsters might
  73.                       * have G_GENOD or !G_GENO.
  74.                       */
  75.                      mvitals[i].mvflags |= (G_GENOD | G_NOCORPSE);
  76.                      reset_rndmonst(i);
  77.                      kill_genocided_monsters();
  78.                      update_inventory(); /* eggs & tins */
  79.                      pline("Wiped out all %s.", nam);
  80.                      if (Upolyd && i == u.umonnum) {
  81.                          u.mh = -1;
  82.                          if (Unchanging) {
  83.                              if (!feel_dead++)
  84.                                  You("die.");
  85.                              /* finish genociding this class of
  86.                                 monsters before ultimately dying */
  87.                              gameover = TRUE;
  88.                          } else
  89.                              rehumanize();
  90.                      }
  91.                      /* Self-genocide if it matches either your race
  92.                         or role.  Assumption:  male and female forms
  93.                         share same monster class. */
  94.                      if (i == urole.malenum || i == urace.malenum) {
  95.                          u.uhp = -1;
  96.                          if (Upolyd) {
  97.                              if (!feel_dead++)
  98.                                  You_feel("%s inside.", udeadinside());
  99.                          } else {
  100.                              if (!feel_dead++)
  101.                                  You("die.");
  102.                              gameover = TRUE;
  103.                          }
  104.                      }
  105.                  } else if (mvitals[i].mvflags & G_GENOD) {
  106.                      if (!gameover)
  107.                          pline("All %s are already nonexistent.", nam);
  108.                  } else if (!gameover) {
  109.                      /* suppress feedback about quest beings except
  110.                         for those applicable to our own role */
  111.                      if ((mons[i].msound != MS_LEADER
  112.                           || quest_info(MS_LEADER) == i)
  113.                          && (mons[i].msound != MS_NEMESIS
  114.                              || quest_info(MS_NEMESIS) == i)
  115.                          && (mons[i].msound != MS_GUARDIAN
  116.                              || quest_info(MS_GUARDIAN) == i)
  117.                          /* non-leader/nemesis/guardian role-specific monster
  118.                             */
  119.                          && (i != PM_NINJA /* nuisance */
  120.                              || Role_if(PM_SAMURAI))) {
  121.                          boolean named, uniq;
  122.  
  123.                          named = type_is_pname(&mons[i]) ? TRUE : FALSE;
  124.                          uniq = (mons[i].geno & G_UNIQ) ? TRUE : FALSE;
  125.                          /* one special case */
  126.                          if (i == PM_HIGH_PRIEST)
  127.                              uniq = FALSE;
  128.  
  129.                          You("aren't permitted to genocide %s%s.",
  130.                              (uniq && !named) ? "the " : "",
  131.                              (uniq || named) ? mons[i].mname : nam);
  132.                      }
  133.                  }
  134.              }
  135.          }
  136.          if (gameover || u.uhp == -1) {
  137.              killer.format = KILLED_BY_AN;
  138.              Strcpy(killer.name, "scroll of genocide");
  139.              if (gameover)
  140.                  done(GENOCIDED);
  141.          }
  142.          return;
  143.      }
  144.  }
  145.  
  146.  #define REALLY 1
  147.  #define PLAYER 2
  148.  #define ONTHRONE 4

do_genocide

  1.  void
  2.  do_genocide(how)
  3.  int how;
  4.  /* 0 = no genocide; create monsters (cursed scroll) */
  5.  /* 1 = normal genocide */
  6.  /* 3 = forced genocide of player */
  7.  /* 5 (4 | 1) = normal genocide from throne */
  8.  {
  9.      char buf[BUFSZ] = DUMMY;
  10.      register int i, killplayer = 0;
  11.      register int mndx;
  12.      register struct permonst *ptr;
  13.      const char *which;
  14.  
  15.      if (how & PLAYER) {
  16.          mndx = u.umonster; /* non-polymorphed mon num */
  17.          ptr = &mons[mndx];
  18.          Strcpy(buf, ptr->mname);
  19.          killplayer++;
  20.      } else {
  21.          for (i = 0;; i++) {
  22.              if (i >= 5) {
  23.                  /* cursed effect => no free pass (unless rndmonst() fails) */
  24.                  if (!(how & REALLY) && (ptr = rndmonst()) != 0)
  25.                      break;
  26.  
  27.                  pline1(thats_enough_tries);
  28.                  return;
  29.              }
  30.              getlin("What monster do you want to genocide? [type the name]",
  31.                     buf);
  32.              (void) mungspaces(buf);
  33.              /* choosing "none" preserves genocideless conduct */
  34.              if (*buf == '\033' || !strcmpi(buf, "none")
  35.                  || !strcmpi(buf, "nothing")) {
  36.                  /* ... but no free pass if cursed */
  37.                  if (!(how & REALLY) && (ptr = rndmonst()) != 0)
  38.                      break; /* remaining checks don't apply */
  39.  
  40.                  return;
  41.              }
  42.  
  43.              mndx = name_to_mon(buf);
  44.              if (mndx == NON_PM || (mvitals[mndx].mvflags & G_GENOD)) {
  45.                  pline("Such creatures %s exist in this world.",
  46.                        (mndx == NON_PM) ? "do not" : "no longer");
  47.                  continue;
  48.              }
  49.              ptr = &mons[mndx];
  50.              /* Although "genus" is Latin for race, the hero benefits
  51.               * from both race and role; thus genocide affects either.
  52.               */
  53.              if (Your_Own_Role(mndx) || Your_Own_Race(mndx)) {
  54.                  killplayer++;
  55.                  break;
  56.              }
  57.              if (is_human(ptr))
  58.                  adjalign(-sgn(u.ualign.type));
  59.              if (is_demon(ptr))
  60.                  adjalign(sgn(u.ualign.type));
  61.  
  62.              if (!(ptr->geno & G_GENO)) {
  63.                  if (!Deaf) {
  64.                      /* FIXME: unconditional "caverns" will be silly in some
  65.                       * circumstances.  Who's speaking?  Divine pronouncements
  66.                       * aren't supposed to be hampered by deafness....
  67.                       */
  68.                      if (flags.verbose)
  69.                          pline("A thunderous voice booms through the caverns:");
  70.                      verbalize("No, mortal!  That will not be done.");
  71.                  }
  72.                  continue;
  73.              }
  74.              /* KMH -- Unchanging prevents rehumanization */
  75.              if (Unchanging && ptr == youmonst.data)
  76.                  killplayer++;
  77.              break;
  78.          }
  79.          mndx = monsndx(ptr); /* needed for the 'no free pass' cases */
  80.      }
  81.  
  82.      which = "all ";
  83.      if (Hallucination) {
  84.          if (Upolyd)
  85.              Strcpy(buf, youmonst.data->mname);
  86.          else {
  87.              Strcpy(buf, (flags.female && urole.name.f) ? urole.name.f
  88.                                                         : urole.name.m);
  89.              buf[0] = lowc(buf[0]);
  90.          }
  91.      } else {
  92.          Strcpy(buf, ptr->mname); /* make sure we have standard singular */
  93.          if ((ptr->geno & G_UNIQ) && ptr != &mons[PM_HIGH_PRIEST])
  94.              which = !type_is_pname(ptr) ? "the " : "";
  95.      }
  96.      if (how & REALLY) {
  97.          /* setting no-corpse affects wishing and random tin generation */
  98.          mvitals[mndx].mvflags |= (G_GENOD | G_NOCORPSE);
  99.          pline("Wiped out %s%s.", which,
  100.                (*which != 'a') ? buf : makeplural(buf));
  101.  
  102.          if (killplayer) {
  103.              /* might need to wipe out dual role */
  104.              if (urole.femalenum != NON_PM && mndx == urole.malenum)
  105.                  mvitals[urole.femalenum].mvflags |= (G_GENOD | G_NOCORPSE);
  106.              if (urole.femalenum != NON_PM && mndx == urole.femalenum)
  107.                  mvitals[urole.malenum].mvflags |= (G_GENOD | G_NOCORPSE);
  108.              if (urace.femalenum != NON_PM && mndx == urace.malenum)
  109.                  mvitals[urace.femalenum].mvflags |= (G_GENOD | G_NOCORPSE);
  110.              if (urace.femalenum != NON_PM && mndx == urace.femalenum)
  111.                  mvitals[urace.malenum].mvflags |= (G_GENOD | G_NOCORPSE);
  112.  
  113.              u.uhp = -1;
  114.              if (how & PLAYER) {
  115.                  killer.format = KILLED_BY;
  116.                  Strcpy(killer.name, "genocidal confusion");
  117.              } else if (how & ONTHRONE) {
  118.                  /* player selected while on a throne */
  119.                  killer.format = KILLED_BY_AN;
  120.                  Strcpy(killer.name, "imperious order");
  121.              } else { /* selected player deliberately, not confused */
  122.                  killer.format = KILLED_BY_AN;
  123.                  Strcpy(killer.name, "scroll of genocide");
  124.              }
  125.  
  126.              /* Polymorphed characters will die as soon as they're rehumanized.
  127.               */
  128.              /* KMH -- Unchanging prevents rehumanization */
  129.              if (Upolyd && ptr != youmonst.data) {
  130.                  delayed_killer(POLYMORPH, killer.format, killer.name);
  131.                  You_feel("%s inside.", udeadinside());
  132.              } else
  133.                  done(GENOCIDED);
  134.          } else if (ptr == youmonst.data) {
  135.              rehumanize();
  136.          }
  137.          reset_rndmonst(mndx);
  138.          kill_genocided_monsters();
  139.          update_inventory(); /* in case identified eggs were affected */
  140.      } else {
  141.          int cnt = 0, census = monster_census(FALSE);
  142.  
  143.          if (!(mons[mndx].geno & G_UNIQ)
  144.              && !(mvitals[mndx].mvflags & (G_GENOD | G_EXTINCT)))
  145.              for (i = rn1(3, 4); i > 0; i--) {
  146.                  if (!makemon(ptr, u.ux, u.uy, NO_MINVENT))
  147.                      break; /* couldn't make one */
  148.                  ++cnt;
  149.                  if (mvitals[mndx].mvflags & G_EXTINCT)
  150.                      break; /* just made last one */
  151.              }
  152.          if (cnt) {
  153.              /* accumulated 'cnt' doesn't take groups into account;
  154.                 assume bringing in new mon(s) didn't remove any old ones */
  155.              cnt = monster_census(FALSE) - census;
  156.              pline("Sent in %s%s.", (cnt > 1) ? "some " : "",
  157.                    (cnt > 1) ? makeplural(buf) : an(buf));
  158.          } else
  159.              pline1(nothing_happens);
  160.      }
  161.  }
  162.  

punish

  1.  void
  2.  punish(sobj)
  3.  struct obj *sobj;
  4.  {
  5.      struct obj *reuse_ball = (sobj && sobj->otyp == HEAVY_IRON_BALL)
  6.                                  ? sobj : (struct obj *) 0;
  7.  
  8.      /* KMH -- Punishment is still okay when you are riding */
  9.      if (!reuse_ball)
  10.          You("are being punished for your misbehavior!");
  11.      if (Punished) {
  12.          Your("iron ball gets heavier.");
  13.          uball->owt += IRON_BALL_W_INCR * (1 + sobj->cursed);
  14.          return;
  15.      }
  16.      if (amorphous(youmonst.data) || is_whirly(youmonst.data)
  17.          || unsolid(youmonst.data)) {
  18.          if (!reuse_ball) {
  19.              pline("A ball and chain appears, then falls away.");
  20.              dropy(mkobj(BALL_CLASS, TRUE));
  21.          } else {
  22.              dropy(reuse_ball);
  23.          }
  24.          return;
  25.      }
  26.      setworn(mkobj(CHAIN_CLASS, TRUE), W_CHAIN);
  27.      if (!reuse_ball)
  28.          setworn(mkobj(BALL_CLASS, TRUE), W_BALL);
  29.      else
  30.          setworn(reuse_ball, W_BALL);
  31.      uball->spe = 1; /* special ball (see save) */
  32.  
  33.      /*
  34.       *  Place ball & chain if not swallowed.  If swallowed, the ball &
  35.       *  chain variables will be set at the next call to placebc().
  36.       */
  37.      if (!u.uswallow) {
  38.          placebc();
  39.          if (Blind)
  40.              set_bc(1);      /* set up ball and chain variables */
  41.          newsym(u.ux, u.uy); /* see ball&chain if can't see self */
  42.      }
  43.  }
  44.  

unpunish

  1.  /* remove the ball and chain */
  2.  void
  3.  unpunish()
  4.  {
  5.      struct obj *savechain = uchain;
  6.  
  7.      obj_extract_self(uchain);
  8.      newsym(uchain->ox, uchain->oy);
  9.      setworn((struct obj *) 0, W_CHAIN);
  10.      dealloc_obj(savechain);
  11.      uball->spe = 0;
  12.      setworn((struct obj *) 0, W_BALL);
  13.  }
  14.  

cant_revive

  1.  /* some creatures have special data structures that only make sense in their
  2.   * normal locations -- if the player tries to create one elsewhere, or to
  3.   * revive one, the disoriented creature becomes a zombie
  4.   */
  5.  boolean
  6.  cant_revive(mtype, revival, from_obj)
  7.  int *mtype;
  8.  boolean revival;
  9.  struct obj *from_obj;
  10.  {
  11.      /* SHOPKEEPERS can be revived now */
  12.      if (*mtype == PM_GUARD || (*mtype == PM_SHOPKEEPER && !revival)
  13.          || *mtype == PM_HIGH_PRIEST || *mtype == PM_ALIGNED_PRIEST
  14.          || *mtype == PM_ANGEL) {
  15.          *mtype = PM_HUMAN_ZOMBIE;
  16.          return TRUE;
  17.      } else if (*mtype == PM_LONG_WORM_TAIL) { /* for create_particular() */
  18.          *mtype = PM_LONG_WORM;
  19.          return TRUE;
  20.      } else if (unique_corpstat(&mons[*mtype])
  21.                 && (!from_obj || !has_omonst(from_obj))) {
  22.          /* unique corpses (from bones or wizard mode wish) or
  23.             statues (bones or any wish) end up as shapechangers */
  24.          *mtype = PM_DOPPELGANGER;
  25.          return TRUE;
  26.      }
  27.      return FALSE;
  28.  }
  29.  

create_particular

  1.  /*
  2.   * Make a new monster with the type controlled by the user.
  3.   *
  4.   * Note:  when creating a monster by class letter, specifying the
  5.   * "strange object" (']') symbol produces a random monster rather
  6.   * than a mimic.  This behavior quirk is useful so don't "fix" it
  7.   * (use 'm'--or "mimic"--to create a random mimic).
  8.   *
  9.   * Used in wizard mode only (for ^G command and for scroll or spell
  10.   * of create monster).  Once upon a time, an earlier incarnation of
  11.   * this code was also used for the scroll/spell in explore mode.
  12.   */
  13.  boolean
  14.  create_particular()
  15.  {
  16.      char buf[BUFSZ] = DUMMY, *bufp, monclass;
  17.      char *tmpp;
  18.      int which, tryct, i, firstchoice = NON_PM;
  19.      struct permonst *whichpm = NULL;
  20.      struct monst *mtmp;
  21.      boolean madeany = FALSE, randmonst = FALSE,
  22.          maketame, makepeaceful, makehostile, saddled, invisible,
  23.          sleeping;
  24.      int fem;
  25.  
  26.      tryct = 5;
  27.      do {
  28.          monclass = MAXMCLASSES;
  29.          which = urole.malenum; /* an arbitrary index into mons[] */
  30.          maketame = makepeaceful = makehostile = FALSE;
  31.          sleeping = saddled = invisible = FALSE;
  32.          fem = -1; /* gender not specified */
  33.          getlin("Create what kind of monster? [type the name or symbol]", buf);
  34.          bufp = mungspaces(buf);
  35.          if (*bufp == '\033')
  36.              return FALSE;
  37.          if ((tmpp = strstri(bufp, "saddled ")) != 0) {
  38.              saddled = TRUE;
  39.              (void) memset(tmpp, ' ', sizeof "saddled " - 1);
  40.          }
  41.          if ((tmpp = strstri(bufp, "sleeping ")) != 0) {
  42.              sleeping = TRUE;
  43.              (void) memset(tmpp, ' ', sizeof "sleeping " - 1);
  44.          }
  45.          if ((tmpp = strstri(bufp, "invisible ")) != 0) {
  46.              invisible = TRUE;
  47.              (void) memset(tmpp, ' ', sizeof "invisible " - 1);
  48.          }
  49.          /* check "female" before "male" to avoid false hit mid-word */
  50.          if ((tmpp = strstri(bufp, "female ")) != 0) {
  51.              fem = 1;
  52.              (void) memset(tmpp, ' ', sizeof "female " - 1);
  53.          }
  54.          if ((tmpp = strstri(bufp, "male ")) != 0) {
  55.              fem = 0;
  56.              (void) memset(tmpp, ' ', sizeof "male " - 1);
  57.          }
  58.          bufp = mungspaces(bufp); /* after potential memset(' ') */
  59.          /* allow the initial disposition to be specified */
  60.          if (!strncmpi(bufp, "tame ", 5)) {
  61.              bufp += 5;
  62.              maketame = TRUE;
  63.          } else if (!strncmpi(bufp, "peaceful ", 9)) {
  64.              bufp += 9;
  65.              makepeaceful = TRUE;
  66.          } else if (!strncmpi(bufp, "hostile ", 8)) {
  67.              bufp += 8;
  68.              makehostile = TRUE;
  69.          }
  70.          /* decide whether a valid monster was chosen */
  71.          if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "random"))) {
  72.              randmonst = TRUE;
  73.              break;
  74.          }
  75.          which = name_to_mon(bufp);
  76.          if (which >= LOW_PM)
  77.              break; /* got one */
  78.          monclass = name_to_monclass(bufp, &which);
  79.          if (which >= LOW_PM) {
  80.              monclass = MAXMCLASSES; /* matters below */
  81.              break;
  82.          } else if (monclass > 0) {
  83.              which = urole.malenum; /* reset from NON_PM */
  84.              break;
  85.          }
  86.          /* no good; try again... */
  87.          pline("I've never heard of such monsters.");
  88.      } while (--tryct > 0);
  89.  
  90.      if (!tryct) {
  91.          pline1(thats_enough_tries);
  92.      } else {
  93.          if (!randmonst) {
  94.              firstchoice = which;
  95.              if (cant_revive(&which, FALSE, (struct obj *) 0)) {
  96.                  /* wizard mode can override handling of special monsters */
  97.                  Sprintf(buf, "Creating %s instead; force %s?",
  98.                          mons[which].mname, mons[firstchoice].mname);
  99.                  if (yn(buf) == 'y')
  100.                      which = firstchoice;
  101.              }
  102.              whichpm = &mons[which];
  103.          }
  104.          for (i = 0; i <= multi; i++) {
  105.              if (monclass != MAXMCLASSES)
  106.                  whichpm = mkclass(monclass, 0);
  107.              else if (randmonst)
  108.                  whichpm = rndmonst();
  109.              mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS);
  110.              if (!mtmp) {
  111.                  /* quit trying if creation failed and is going to repeat */
  112.                  if (monclass == MAXMCLASSES && !randmonst)
  113.                      break;
  114.                  /* otherwise try again */
  115.                  continue;
  116.              }
  117.              /* 'is_FOO()' ought to be called 'always_FOO()' */
  118.              if (fem != -1 && !is_male(mtmp->data) && !is_female(mtmp->data))
  119.                  mtmp->female = fem; /* ignored for is_neuter() */
  120.              if (maketame) {
  121.                  (void) tamedog(mtmp, (struct obj *) 0);
  122.              } else if (makepeaceful || makehostile) {
  123.                  mtmp->mtame = 0; /* sanity precaution */
  124.                  mtmp->mpeaceful = makepeaceful ? 1 : 0;
  125.                  set_malign(mtmp);
  126.              }
  127.              if (saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) {
  128.                  struct obj *otmp = mksobj(SADDLE, TRUE, FALSE);
  129.  
  130.                  put_saddle_on_mon(otmp, mtmp);
  131.              }
  132.              if (invisible)
  133.                  mon_set_minvis(mtmp);
  134.              if (sleeping)
  135.                  mtmp->msleeping = 1;
  136.              madeany = TRUE;
  137.              /* in case we got a doppelganger instead of what was asked
  138.                 for, make it start out looking like what was asked for */
  139.              if (mtmp->cham != NON_PM && firstchoice != NON_PM
  140.                  && mtmp->cham != firstchoice)
  141.                  (void) newcham(mtmp, &mons[firstchoice], FALSE, FALSE);
  142.          }
  143.      }
  144.      return madeany;
  145.  }
  146.  
  147.  /*read.c*/