Difference between revisions of "Source:NetHack 3.4.3/src/allmain.c"

From NetHackWiki
Jump to navigation Jump to search
(Initialization: annotating)
(Rhack essentially reads the keyboard input and kicks off player actions.)
 
(10 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 +
__MIXEDSYNTAXHIGHLIGHT__
 
Below is the full text to src/allmain.c from NetHack 3.4.3. To link to a particular line, write [[allmain.c#line123|<nowiki>[[allmain.c#line123]]</nowiki>]], for example.
 
Below is the full text to src/allmain.c from NetHack 3.4.3. To link to a particular line, write [[allmain.c#line123|<nowiki>[[allmain.c#line123]]</nowiki>]], for example.
  
Line 84: Line 85:
 
  <span id="line65">65.  do_positionbar();</span>
 
  <span id="line65">65.  do_positionbar();</span>
 
  <span id="line66">66.  #endif</span>
 
  <span id="line66">66.  #endif</span>
 +
get_nh_event and do_positionbar are routines related to the current interface.  get_nh_event invokes any system processing related to window updating and do_positionbar generates information related to a horizontal positoning bar that may be present in the window system.
 
  <span id="line67">67.  </span>
 
  <span id="line67">67.  </span>
 
  <span id="line68">68.  didmove = flags.move;</span>
 
  <span id="line68">68.  didmove = flags.move;</span>
 +
flags.move is set whenever the player has performed an action that requires actual game time (moving, fighting, dropping and picking up objects, etc.).
 
  <span id="line69">69.  if(didmove) {</span>
 
  <span id="line69">69.  if(didmove) {</span>
 
  <span id="line70">70.      /* actual time passed */</span>
 
  <span id="line70">70.      /* actual time passed */</span>
 
  <span id="line71">71.      youmonst.movement -= NORMAL_SPEED;</span>
 
  <span id="line71">71.      youmonst.movement -= NORMAL_SPEED;</span>
 +
Any action that takes time requires [[permonst.h#line71|NORMAL_SPEED]] [[speed|movement points]].
 
  <span id="line72">72.  </span>
 
  <span id="line72">72.  </span>
 
  <span id="line73">73.      do { /* hero can't move this turn loop */</span>
 
  <span id="line73">73.      do { /* hero can't move this turn loop */</span>
Line 100: Line 104:
 
  <span id="line81">81.  } while (monscanmove);</span>
 
  <span id="line81">81.  } while (monscanmove);</span>
 
  <span id="line82">82.  flags.mon_moving = FALSE;</span>
 
  <span id="line82">82.  flags.mon_moving = FALSE;</span>
 +
Now that the player has moved, give all monsters at least one chance to move using [[mon.c#movemon|movemon]]. If the player does not have sufficient movement points to move any more this turn keep moving monsters; otherwise give monsters only one chance at a move.
 
  <span id="line83">83.  </span>
 
  <span id="line83">83.  </span>
 
  <span id="line84">84.  if (!monscanmove && youmonst.movement < NORMAL_SPEED) {</span>
 
  <span id="line84">84.  if (!monscanmove && youmonst.movement < NORMAL_SPEED) {</span>
 +
 +
==== Once-per-turn events ====
 +
 
  <span id="line85">85.      /* both you and the monsters are out of steam this round */</span>
 
  <span id="line85">85.      /* both you and the monsters are out of steam this round */</span>
 
  <span id="line86">86.      /* set up for a new turn */</span>
 
  <span id="line86">86.      /* set up for a new turn */</span>
 +
Nothing more can move this turn; therefore prepare to move to the next turn.
 
  <span id="line87">87.      struct monst *mtmp;</span>
 
  <span id="line87">87.      struct monst *mtmp;</span>
 
  <span id="line88">88.      mcalcdistress(); /* adjust monsters' trap, blind, etc */</span>
 
  <span id="line88">88.      mcalcdistress(); /* adjust monsters' trap, blind, etc */</span>
 +
[[mon.c#mcalcdistress|mcalcdistress]] is responsible for updates of change-of-turn monster data.
 
  <span id="line89">89.  </span>
 
  <span id="line89">89.  </span>
 
  <span id="line90">90.      /* reallocate movement rations to monsters */</span>
 
  <span id="line90">90.      /* reallocate movement rations to monsters */</span>
 
  <span id="line91">91.      for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)</span>
 
  <span id="line91">91.      for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)</span>
 
  <span id="line92">92.  mtmp->movement += mcalcmove(mtmp);</span>
 
  <span id="line92">92.  mtmp->movement += mcalcmove(mtmp);</span>
 +
This grants movement points to monsters for the coming turn.  [[mon.c#mcalcmove|mcalcmove]] determines how many points the monster will get.
 
  <span id="line93">93.  </span>
 
  <span id="line93">93.  </span>
 
  <span id="line94">94.      if(!rn2(u.uevent.udemigod ? 25 :</span>
 
  <span id="line94">94.      if(!rn2(u.uevent.udemigod ? 25 :</span>
 
  <span id="line95">95.      (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70))</span>
 
  <span id="line95">95.      (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70))</span>
 
  <span id="line96">96.  (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS);</span>
 
  <span id="line96">96.  (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS);</span>
 +
This important segment is responsible for all random monster generation.  The flag u.uevent.demigod is set after killing the [[Wizard of Yendor]] for the first time or on performing the [[invocation ritual]]; therefore after these events a monster is generated randomly on the level with a 1/25 chance each turn; otherwise there is a 1/50 chance if you are below the [[Castle]] and 1/70 chance if you are not.
 
  <span id="line97">97.  </span>
 
  <span id="line97">97.  </span>
 
  <span id="line98">98.      /* calculate how much time passed. */</span>
 
  <span id="line98">98.      /* calculate how much time passed. */</span>
Line 120: Line 132:
 
  <span id="line101">101.  /* your speed doesn't augment steed's speed */</span>
 
  <span id="line101">101.  /* your speed doesn't augment steed's speed */</span>
 
  <span id="line102">102.  moveamt = mcalcmove(u.usteed);</span>
 
  <span id="line102">102.  moveamt = mcalcmove(u.usteed);</span>
 +
If you are [[steed|mounted]], your movement point allocation is that of your steed.
 
  <span id="line103">103.      } else</span>
 
  <span id="line103">103.      } else</span>
 
  <span id="line104">104.  #endif</span>
 
  <span id="line104">104.  #endif</span>
Line 146: Line 159:
 
  <span id="line127">127.      youmonst.movement += moveamt;</span>
 
  <span id="line127">127.      youmonst.movement += moveamt;</span>
 
  <span id="line128">128.      if (youmonst.movement < 0) youmonst.movement = 0;</span>
 
  <span id="line128">128.      if (youmonst.movement < 0) youmonst.movement = 0;</span>
 +
This segment calculates your [[speed|movement rate]] for the turn.  It is first set to the normal movement rate of your current form (which of course changes if you are [[polymorph]]ed).  If you are [[fast]], you have a 2/3 chance of earning an extra [[permonst.h#line71|NORMAL_SPEED]] / 2 movement points; if you are [[very fast]] you are guaranteed at least NORMAL_SPEED / 2 points with a 1/3 chance of another NORMAL_SPEED / 2.  (Note that NORMAL_SPEED does not vary if you are polymorphed, so the speed intrinsic is more effective if you are in a very slow form and less effective if you are in a very fast form.)  Finally, your speed is adjusted for [[encumbrance]] and added to your current movement point total.
 
  <span id="line129">129.      settrack();</span>
 
  <span id="line129">129.      settrack();</span>
 +
[[track.c#settrack|settrack]] updates your position in the tracking system.
 
  <span id="line130">130.  </span>
 
  <span id="line130">130.  </span>
 
  <span id="line131">131.      monstermoves++;</span>
 
  <span id="line131">131.      monstermoves++;</span>
 
  <span id="line132">132.      moves++;</span>
 
  <span id="line132">132.      moves++;</span>
 +
Finally, the turn counter is incremented; we are now on a new turn.
 
  <span id="line133">133.  </span>
 
  <span id="line133">133.  </span>
 
==== Once-per-turn events ====
 
 
 
  <span id="line134">134.      /********************************/</span>
 
  <span id="line134">134.      /********************************/</span>
 
  <span id="line135">135.      /* once-per-turn things go here */</span>
 
  <span id="line135">135.      /* once-per-turn things go here */</span>
Line 159: Line 172:
 
  <span id="line137">137.  </span>
 
  <span id="line137">137.  </span>
 
  <span id="line138">138.      if (flags.bypasses) clear_bypasses();</span>
 
  <span id="line138">138.      if (flags.bypasses) clear_bypasses();</span>
 +
[[zap.c#clear_bypasses|clear_bypasses]] clears a flag related to whether an object should be hit by a wand zapped at it (amongst other events).
 
  <span id="line139">139.      if(Glib) glibr();</span>
 
  <span id="line139">139.      if(Glib) glibr();</span>
 +
[[do_wear.c#glibr|glibr]] is the code relating to [[slippery fingers]].
 
  <span id="line140">140.      nh_timeout();</span>
 
  <span id="line140">140.      nh_timeout();</span>
 +
[[timeout.c#nh_timeout|nh_timeout]] handles all timeouts related to time-delayed functions such as [[extrinsics]] from [[potion]]s, [[stoning]], [[sliming]], etc.
 
  <span id="line141">141.      run_regions();</span>
 
  <span id="line141">141.      run_regions();</span>
 +
[[region.c#run_regions|run_regions]] handles timeouts for area effects, currently only used for [[scroll of stinking cloud|stinking cloud]]s.
 
  <span id="line142">142.  </span>
 
  <span id="line142">142.  </span>
 
  <span id="line143">143.      if (u.ublesscnt)  u.ublesscnt--;</span>
 
  <span id="line143">143.      if (u.ublesscnt)  u.ublesscnt--;</span>
 +
Decrements the [[prayer]] timeout.
 
  <span id="line144">144.      if(flags.time && !flags.run)</span>
 
  <span id="line144">144.      if(flags.time && !flags.run)</span>
 
  <span id="line145">145.  flags.botl = 1;</span>
 
  <span id="line145">145.  flags.botl = 1;</span>
 +
Indicates that the status line needs to be updated if the turn counter is shown in the bottom line.
 
  <span id="line146">146.  </span>
 
  <span id="line146">146.  </span>
 
  <span id="line147">147.      /* One possible result of prayer is healing.  Whether or</span>
 
  <span id="line147">147.      /* One possible result of prayer is healing.  Whether or</span>
Line 177: Line 196:
 
  <span id="line155">155.  /* for the moment at least, you're in tiptop shape */</span>
 
  <span id="line155">155.  /* for the moment at least, you're in tiptop shape */</span>
 
  <span id="line156">156.  wtcap = UNENCUMBERED;</span>
 
  <span id="line156">156.  wtcap = UNENCUMBERED;</span>
 +
u.uinvulnerable is set whenever you are being protected by your [[deity]] while [[prayer|praying]]; during this time you are not considered to be encumbered.
 
  <span id="line157">157.      } else if (Upolyd && youmonst.data->mlet == S_EEL && !is_pool(u.ux,u.uy) && !Is_waterlevel(&u.uz)) {</span>
 
  <span id="line157">157.      } else if (Upolyd && youmonst.data->mlet == S_EEL && !is_pool(u.ux,u.uy) && !Is_waterlevel(&u.uz)) {</span>
 
  <span id="line158">158.  if (u.mh > 1) {</span>
 
  <span id="line158">158.  if (u.mh > 1) {</span>
Line 183: Line 203:
 
  <span id="line161">161.  } else if (u.mh < 1)</span>
 
  <span id="line161">161.  } else if (u.mh < 1)</span>
 
  <span id="line162">162.      rehumanize();</span>
 
  <span id="line162">162.      rehumanize();</span>
 +
If you are polymorphed into a [[sea monster]] and are out of water, you lose one hit point per turn down to a minimum of one.
 
  <span id="line163">163.      } else if (Upolyd && u.mh < u.mhmax) {</span>
 
  <span id="line163">163.      } else if (Upolyd && u.mh < u.mhmax) {</span>
 
  <span id="line164">164.  if (u.mh < 1)</span>
 
  <span id="line164">164.  if (u.mh < 1)</span>
 
  <span id="line165">165.      rehumanize();</span>
 
  <span id="line165">165.      rehumanize();</span>
 +
If you are killed in a polymorphed form, attempt to return the player to their normal form.
 
  <span id="line166">166.  else if (Regeneration ||</span>
 
  <span id="line166">166.  else if (Regeneration ||</span>
 
  <span id="line167">167.      (wtcap < MOD_ENCUMBER && !(moves%20))) {</span>
 
  <span id="line167">167.      (wtcap < MOD_ENCUMBER && !(moves%20))) {</span>
Line 191: Line 213:
 
  <span id="line169">169.      u.mh++;</span>
 
  <span id="line169">169.      u.mh++;</span>
 
  <span id="line170">170.  }</span>
 
  <span id="line170">170.  }</span>
 +
If you are in a polymorphed form and are either regenerating or on a twentieth move, regain a hitpoint.
 
  <span id="line171">171.      } else if (u.uhp < u.uhpmax &&</span>
 
  <span id="line171">171.      } else if (u.uhp < u.uhpmax &&</span>
 
  <span id="line172">172.  (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) {</span>
 
  <span id="line172">172.  (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) {</span>
Line 212: Line 235:
 
  <span id="line190">190.      u.uhp++;</span>
 
  <span id="line190">190.      u.uhp++;</span>
 
  <span id="line191">191.  }</span>
 
  <span id="line191">191.  }</span>
 +
If you are not polymorphed, regenerate hitpoints.  Every third turn if you are level 10 or above, gain an amount of hitpoints equal to a random value up to your current [[constitution]] if it is 13 or above, or 1 if your current [[constitution]] is below 13.  Otherwise gain one hitpoint if you are regenerating, or you are level 9 or less and a certain number of turns related to your current level has passed.  This requires that you are not [[stressed]] or worse if you are not [[regeneration|regenerating]].
 
  <span id="line192">192.      }</span>
 
  <span id="line192">192.      }</span>
 
  <span id="line193">193.  </span>
 
  <span id="line193">193.  </span>
Line 228: Line 252:
 
  <span id="line206">206.  }</span>
 
  <span id="line206">206.  }</span>
 
  <span id="line207">207.      }</span>
 
  <span id="line207">207.      }</span>
 +
If you are [[strained]] or [[overtaxed]], lose hit points from trying to move around; this is every thirty turns if you are [[strained]] and every ten if you are [[overtaxed]].
 
  <span id="line208">208.  </span>
 
  <span id="line208">208.  </span>
 
  <span id="line209">209.      if ((u.uen < u.uenmax) &&</span>
 
  <span id="line209">209.      if ((u.uen < u.uenmax) &&</span>
Line 238: Line 263:
 
  <span id="line216">216.  flags.botl = 1;</span>
 
  <span id="line216">216.  flags.botl = 1;</span>
 
  <span id="line217">217.      }</span>
 
  <span id="line217">217.      }</span>
 +
Regenerate power if you are not [[stressed]] or worse on every (38 - current level) * 4 moves if you are not a [[wizard]] or * 3 if you are, or have the energy regeneration extrinsic from the [[Eye of the Aethiopica]]; you gain from 1 to 1/15th the sum of your current [[intelligence]] and [[wisdom]] totals.
 
  <span id="line218">218.  </span>
 
  <span id="line218">218.  </span>
 
  <span id="line219">219.      if(!u.uinvulnerable) {</span>
 
  <span id="line219">219.      if(!u.uinvulnerable) {</span>
Line 254: Line 280:
 
  <span id="line232">232.      }</span>
 
  <span id="line232">232.      }</span>
 
  <span id="line233">233.  }</span>
 
  <span id="line233">233.  }</span>
 +
This implements [[teleportitis]], if you are not protected while [[praying]]; if they have the intrinsic, teleport the player on a 1/85th chance each turn.
 
  <span id="line234">234.  /* delayed change may not be valid anymore */</span>
 
  <span id="line234">234.  /* delayed change may not be valid anymore */</span>
 
  <span id="line235">235.  if ((change == 1 && !Polymorph) ||</span>
 
  <span id="line235">235.  if ((change == 1 && !Polymorph) ||</span>
 
  <span id="line236">236.      (change == 2 && u.ulycn == NON_PM))</span>
 
  <span id="line236">236.      (change == 2 && u.ulycn == NON_PM))</span>
 
  <span id="line237">237.      change = 0;</span>
 
  <span id="line237">237.      change = 0;</span>
 +
[[Polymorph]]ing is delayed while wearing an [[amulet of unchanging]]; if such a polymorph is no longer valid cancel it.
 
  <span id="line238">238.  if(Polymorph && !rn2(100))</span>
 
  <span id="line238">238.  if(Polymorph && !rn2(100))</span>
 
  <span id="line239">239.      change = 1;</span>
 
  <span id="line239">239.      change = 1;</span>
 +
If you have the polymorphing intrinsic (from a [[ring of polymorph]]), attempt to polymorph on a 1/100 chance each turn.
 
  <span id="line240">240.  else if (u.ulycn >= LOW_PM && !Upolyd &&</span>
 
  <span id="line240">240.  else if (u.ulycn >= LOW_PM && !Upolyd &&</span>
 
  <span id="line241">241.  !rn2(80 - (20 * night())))</span>
 
  <span id="line241">241.  !rn2(80 - (20 * night())))</span>
 
  <span id="line242">242.      change = 2;</span>
 
  <span id="line242">242.      change = 2;</span>
 +
If you are a [[lycanthrope]], attempt to change on a 1/80 chance (or 1/60 if it is night) per turn.
 
  <span id="line243">243.  if (change && !Unchanging) {</span>
 
  <span id="line243">243.  if (change && !Unchanging) {</span>
 
  <span id="line244">244.      if (multi >= 0) {</span>
 
  <span id="line244">244.      if (multi >= 0) {</span>
Line 273: Line 303:
 
  <span id="line251">251.  change = 0;</span>
 
  <span id="line251">251.  change = 0;</span>
 
  <span id="line252">252.      }</span>
 
  <span id="line252">252.      }</span>
 +
Enact the above polymorphs if you are not wearing an [[amulet of unchanging]]; otherwise delay it (as above).
 
  <span id="line253">253.  }</span>
 
  <span id="line253">253.  }</span>
 
  <span id="line254">254.      }</span>
 
  <span id="line254">254.      }</span>
 
  <span id="line255">255.  </span>
 
  <span id="line255">255.  </span>
 
  <span id="line256">256.      if(Searching && multi >= 0) (void) dosearch0(1);</span>
 
  <span id="line256">256.      if(Searching && multi >= 0) (void) dosearch0(1);</span>
 +
If you have the [[searching]] intrinsic, perform the search.
 
  <span id="line257">257.      dosounds();</span>
 
  <span id="line257">257.      dosounds();</span>
 +
[[sounds.c#dosounds|dosounds]] generates the sounds resulting from dungeon features.
 
  <span id="line258">258.      do_storms();</span>
 
  <span id="line258">258.      do_storms();</span>
 +
[[timeout.c#do_storms|do_storms]] generates storm effects for the [[Plane of Air]].
 
  <span id="line259">259.      gethungry();</span>
 
  <span id="line259">259.      gethungry();</span>
 +
[[eat.c#gethungry|gethungry]] handles normal [[nutrition]] depletion and effects.
 
  <span id="line260">260.      age_spells();</span>
 
  <span id="line260">260.      age_spells();</span>
 +
[[spell.c#age_spells|age_spells]] handles spell timeouts.
 
  <span id="line261">261.      exerchk();</span>
 
  <span id="line261">261.      exerchk();</span>
 +
[[attrib.c#exerchk|exerchk]] checks if attributes have been [[exercise]]d enough for a change to occur.
 
  <span id="line262">262.      invault();</span>
 
  <span id="line262">262.      invault();</span>
 +
[[vault.c#invault|invault]] handles [[vault]] [[guard]] checks.
 
  <span id="line263">263.      if (u.uhave.amulet) amulet();</span>
 
  <span id="line263">263.      if (u.uhave.amulet) amulet();</span>
 +
[[wizard.c#amulet|amulet]] handles turn-to-turn events related to holding the [[Amulet of Yendor]].
 
  <span id="line264">264.      if (!rn2(40+(int)(ACURR(A_DEX)*3)))</span>
 
  <span id="line264">264.      if (!rn2(40+(int)(ACURR(A_DEX)*3)))</span>
 
  <span id="line265">265.  u_wipe_engr(rnd(3));</span>
 
  <span id="line265">265.  u_wipe_engr(rnd(3));</span>
 +
This attempts to scuff engravings at your location on a random chance that decreases with dexterity.
 
  <span id="line266">266.      if (u.uevent.udemigod && !u.uinvulnerable) {</span>
 
  <span id="line266">266.      if (u.uevent.udemigod && !u.uinvulnerable) {</span>
 
  <span id="line267">267.  if (u.udg_cnt) u.udg_cnt--;</span>
 
  <span id="line267">267.  if (u.udg_cnt) u.udg_cnt--;</span>
Line 293: Line 333:
 
  <span id="line271">271.  }</span>
 
  <span id="line271">271.  }</span>
 
  <span id="line272">272.      }</span>
 
  <span id="line272">272.      }</span>
 +
If you have killed the [[Wizard of Yendor]] or performed the [[invocation ritual]], [[wizard.c#intervene|intervene]] is called every 50-249 turns; this is responsible for the Wizard's interventions and resurrections.
 
  <span id="line273">273.      restore_attrib();</span>
 
  <span id="line273">273.      restore_attrib();</span>
 +
[[attrib.c#restore_attrib|restore_attrib]] restores temporary changes of attributes.
 
  <span id="line274">274.      /* underwater and waterlevel vision are done here */</span>
 
  <span id="line274">274.      /* underwater and waterlevel vision are done here */</span>
 
  <span id="line275">275.      if (Is_waterlevel(&u.uz))</span>
 
  <span id="line275">275.      if (Is_waterlevel(&u.uz))</span>
 
  <span id="line276">276.  movebubbles();</span>
 
  <span id="line276">276.  movebubbles();</span>
 +
[[mkmaze.c#movebubbles|movebubbles]] handles bubble movements on the [[Plane of Water]].
 
  <span id="line277">277.      else if (Underwater)</span>
 
  <span id="line277">277.      else if (Underwater)</span>
 
  <span id="line278">278.  under_water(0);</span>
 
  <span id="line278">278.  under_water(0);</span>
 +
[[display.c#under_water|under_water]] handles display routines related to being under water.
 
  <span id="line279">279.      /* vision while buried done here */</span>
 
  <span id="line279">279.      /* vision while buried done here */</span>
 
  <span id="line280">280.      else if (u.uburied) under_ground(0);</span>
 
  <span id="line280">280.      else if (u.uburied) under_ground(0);</span>
 +
[[display.c#under_ground|under_ground]] handles display routines related to being buried (a [[deferred feature]]).
 
  <span id="line281">281.  </span>
 
  <span id="line281">281.  </span>
 
  <span id="line282">282.      /* when immobile, count is in turns */</span>
 
  <span id="line282">282.      /* when immobile, count is in turns */</span>
Line 310: Line 355:
 
  <span id="line288">288.  }</span>
 
  <span id="line288">288.  }</span>
 
  <span id="line289">289.      }</span>
 
  <span id="line289">289.      }</span>
 +
If you are immobile, decrement the turn counter for being immobile and handle any effects meant to occur once the timeout for this reaches zero.
 
  <span id="line290">290.  }</span>
 
  <span id="line290">290.  }</span>
 
  <span id="line291">291.      } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */</span>
 
  <span id="line291">291.      } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */</span>
Line 331: Line 377:
 
  <span id="line303">303.  </span>
 
  <span id="line303">303.  </span>
 
  <span id="line304">304.  find_ac();</span>
 
  <span id="line304">304.  find_ac();</span>
 +
[[do_wear.c#find_ac|find_ac]] calculates and updates the player's armor class.
 
  <span id="line305">305.  if(!flags.mv || Blind) {</span>
 
  <span id="line305">305.  if(!flags.mv || Blind) {</span>
 
  <span id="line306">306.      /* redo monsters if hallu or wearing a helm of telepathy */</span>
 
  <span id="line306">306.      /* redo monsters if hallu or wearing a helm of telepathy */</span>
Line 343: Line 390:
 
  <span id="line315">315.      see_monsters();</span>
 
  <span id="line315">315.      see_monsters();</span>
 
  <span id="line316">316.  </span>
 
  <span id="line316">316.  </span>
 +
[[display.c#see_monsters|see_monsters]], [[display.c#see_objects|see_traps]], and [[display.c#see_traps|traps]] determine which glyphs to display for those features.
 
  <span id="line317">317.      if (vision_full_recalc) vision_recalc(0); /* vision! */</span>
 
  <span id="line317">317.      if (vision_full_recalc) vision_recalc(0); /* vision! */</span>
 +
[[vision.c#vision_recalc|vision_recalc]] calculates which squares are visible to the player.
 
  <span id="line318">318.  }</span>
 
  <span id="line318">318.  }</span>
 
  <span id="line319">319.  if(flags.botl || flags.botlx) bot();</span>
 
  <span id="line319">319.  if(flags.botl || flags.botlx) bot();</span>
 +
If the status line needs to be updated, update it with [[botl.c#bot|bot]].
 
  <span id="line320">320.  </span>
 
  <span id="line320">320.  </span>
 
  <span id="line321">321.  flags.move = 1;</span>
 
  <span id="line321">321.  flags.move = 1;</span>
 +
Assume that the next player action will require time; if it does not flags.move will be reset at that time.
 
  <span id="line322">322.  </span>
 
  <span id="line322">322.  </span>
 
  <span id="line323">323.  if(multi >= 0 && occupation) {</span>
 
  <span id="line323">323.  if(multi >= 0 && occupation) {</span>
 +
multi is greater than zero if a player has entered in a repeated command or some other interruptible action; occupation is set to whatever function represents this action if this is the case.
 
  <span id="line324">324.  #if defined(MICRO) || defined(WIN32)</span>
 
  <span id="line324">324.  #if defined(MICRO) || defined(WIN32)</span>
 
  <span id="line325">325.      abort_lev = 0;</span>
 
  <span id="line325">325.      abort_lev = 0;</span>
Line 373: Line 425:
 
  <span id="line345">345.  reset_eat();</span>
 
  <span id="line345">345.  reset_eat();</span>
 
  <span id="line346">346.      }</span>
 
  <span id="line346">346.      }</span>
 +
If a key has been pressed either when no action is in process or in the middle of an interruptible action, check if that key is [[micro.h#line19|ABORT]] (^A by default); if so, interrupt any current action if possible and if not add the key to the key queue with [[cmd.c#pushch|pushch]].  Actions will also be interrupted if the player senses a monster (checked with [[hack.c#monster_nearby|monster_nearby]]).
 
  <span id="line347">347.  #if defined(MICRO) || defined(WIN32)</span>
 
  <span id="line347">347.  #if defined(MICRO) || defined(WIN32)</span>
 
  <span id="line348">348.      if (!(++occtime % 7))</span>
 
  <span id="line348">348.      if (!(++occtime % 7))</span>
 
  <span id="line349">349.  display_nhwindow(WIN_MAP, FALSE);</span>
 
  <span id="line349">349.  display_nhwindow(WIN_MAP, FALSE);</span>
 
  <span id="line350">350.  #endif</span>
 
  <span id="line350">350.  #endif</span>
 +
On some platforms, update the map on a regular basis.
 
  <span id="line351">351.      continue;</span>
 
  <span id="line351">351.      continue;</span>
 
  <span id="line352">352.  }</span>
 
  <span id="line352">352.  }</span>
Line 384: Line 438:
 
  <span id="line356">356.      !(moves % 15) && !rn2(2))</span>
 
  <span id="line356">356.      !(moves % 15) && !rn2(2))</span>
 
  <span id="line357">357.  do_vicinity_map();</span>
 
  <span id="line357">357.  do_vicinity_map();</span>
 +
If it is a fifteenth turn and you are clairvoyant and not in the [[endgame]], on a one half chance generate the clairvoyance map with [[detect.c#do_vicinity_map|do_vicinity_map]].
 
  <span id="line358">358.  </span>
 
  <span id="line358">358.  </span>
 
  <span id="line359">359.  if(u.utrap && u.utraptype == TT_LAVA) {</span>
 
  <span id="line359">359.  if(u.utrap && u.utraptype == TT_LAVA) {</span>
Line 401: Line 456:
 
  <span id="line373">373.      }</span>
 
  <span id="line373">373.      }</span>
 
  <span id="line374">374.  }</span>
 
  <span id="line374">374.  }</span>
 +
After each player action, when you are in a lava trap, sink into the lava some more. After 11 to 14 actions, kill the player. Note: u.utrap is set at [[trap.c#line3991]].
 
  <span id="line375">375.  </span>
 
  <span id="line375">375.  </span>
 
  <span id="line376">376.  #ifdef WIZARD</span>
 
  <span id="line376">376.  #ifdef WIZARD</span>
Line 406: Line 462:
 
  <span id="line378">378.      sanity_check();</span>
 
  <span id="line378">378.      sanity_check();</span>
 
  <span id="line379">379.  #endif</span>
 
  <span id="line379">379.  #endif</span>
 +
[[cmd.c#sanity_check|sanity_check]] performs some debugging checks if a wizard mode player has them enabled.
 
  <span id="line380">380.  </span>
 
  <span id="line380">380.  </span>
 
  <span id="line381">381.  #ifdef CLIPPING</span>
 
  <span id="line381">381.  #ifdef CLIPPING</span>
 
  <span id="line382">382.  /* just before rhack */</span>
 
  <span id="line382">382.  /* just before rhack */</span>
 
  <span id="line383">383.  cliparound(u.ux, u.uy);</span>
 
  <span id="line383">383.  cliparound(u.ux, u.uy);</span>
 +
cliparound is a window system routine meant to ensure the player is centred in the screen (to the extent that is possible with the windowing system).
 
  <span id="line384">384.  #endif</span>
 
  <span id="line384">384.  #endif</span>
 
  <span id="line385">385.  </span>
 
  <span id="line385">385.  </span>
 
  <span id="line386">386.  u.umoved = FALSE;</span>
 
  <span id="line386">386.  u.umoved = FALSE;</span>
 +
Assume that the player has not entered in a movement command until they actually do so.
 
  <span id="line387">387.  </span>
 
  <span id="line387">387.  </span>
 
  <span id="line388">388.  if (multi > 0) {</span>
 
  <span id="line388">388.  if (multi > 0) {</span>
Line 430: Line 489:
 
  <span id="line402">402.  rhack(save_cm);</span>
 
  <span id="line402">402.  rhack(save_cm);</span>
 
  <span id="line403">403.      }</span>
 
  <span id="line403">403.      }</span>
 +
Repeated command code, also used for interruptible actions.  If nothing interrupts the action (checked with [[hack.c#lookaround|lookaround]]) perform the stored move or command with [[cmd.c#rhack|rhack]]. Rhack essentially reads the keyboard input and kicks off player actions.
 
  <span id="line404">404.  } else if (multi == 0) {</span>
 
  <span id="line404">404.  } else if (multi == 0) {</span>
 
  <span id="line405">405.  #ifdef MAIL</span>
 
  <span id="line405">405.  #ifdef MAIL</span>
Line 435: Line 495:
 
  <span id="line407">407.  #endif</span>
 
  <span id="line407">407.  #endif</span>
 
  <span id="line408">408.      rhack((char *)0);</span>
 
  <span id="line408">408.      rhack((char *)0);</span>
 +
If there are no repeated commands or interruptible actions, bring in the mail daemon as necessary with [[mail.c#ckmailstatus|ckmailstatus]] and then take player input with [[cmd.c#rhack|rhack]].
 
  <span id="line409">409.  }</span>
 
  <span id="line409">409.  }</span>
 
  <span id="line410">410.  if (u.utotype) /* change dungeon level */</span>
 
  <span id="line410">410.  if (u.utotype) /* change dungeon level */</span>
 
  <span id="line411">411.      deferred_goto(); /* after rhack() */</span>
 
  <span id="line411">411.      deferred_goto(); /* after rhack() */</span>
 +
[[do.c#deferred_goto|deferred_goto]] checks if the player has changed levels and takes appropriate action if they have.
 
  <span id="line412">412.  /* !flags.move here: multiple movement command stopped */</span>
 
  <span id="line412">412.  /* !flags.move here: multiple movement command stopped */</span>
 
  <span id="line413">413.  else if (flags.time && (!flags.move || !flags.mv))</span>
 
  <span id="line413">413.  else if (flags.time && (!flags.move || !flags.mv))</span>
Line 443: Line 505:
 
  <span id="line415">415.  </span>
 
  <span id="line415">415.  </span>
 
  <span id="line416">416.  if (vision_full_recalc) vision_recalc(0); /* vision! */</span>
 
  <span id="line416">416.  if (vision_full_recalc) vision_recalc(0); /* vision! */</span>
 +
Recalulate visible tiles if the command just entered necessiates it.
 
  <span id="line417">417.  /* when running in non-tport mode, this gets done through domove() */</span>
 
  <span id="line417">417.  /* when running in non-tport mode, this gets done through domove() */</span>
 
  <span id="line418">418.  if ((!flags.run || iflags.runmode == RUN_TPORT) &&</span>
 
  <span id="line418">418.  if ((!flags.run || iflags.runmode == RUN_TPORT) &&</span>
Line 448: Line 511:
 
  <span id="line420">420.      if (flags.time && flags.run) flags.botl = 1;</span>
 
  <span id="line420">420.      if (flags.time && flags.run) flags.botl = 1;</span>
 
  <span id="line421">421.      display_nhwindow(WIN_MAP, FALSE);</span>
 
  <span id="line421">421.      display_nhwindow(WIN_MAP, FALSE);</span>
 +
Update the map window every seven moves or turns if certain flags are set.
 
  <span id="line422">422.  }</span>
 
  <span id="line422">422.  }</span>
 
  <span id="line423">423.      }</span>
 
  <span id="line423">423.      }</span>

Latest revision as of 08:00, 13 May 2013

Below is the full text to src/allmain.c from NetHack 3.4.3. To link to a particular line, write [[allmain.c#line123]], for example.

Top of file

/*	SCCS Id: @(#)allmain.c	3.4	2003/04/02	*/
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* 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.

/* various code that was replicated in *main.c */

#include "hack.h"

#ifndef NO_SIGNAL
#include <signal.h>
#endif

#ifdef POSITIONBAR
STATIC_DCL void NDECL(do_positionbar);
#endif

moveloop

#ifdef OVL0

void
moveloop()
{
#if defined(MICRO) || defined(WIN32)
char ch;
int abort_lev;
#endif
int moveamt = 0, wtcap = 0, change = 0;
boolean didmove = FALSE, monscanmove = FALSE;

Initialization

flags.moonphase = phase_of_the_moon();
if(flags.moonphase == FULL_MOON) {
	You("are lucky!  Full moon tonight.");
	change_luck(1);
} else if(flags.moonphase == NEW_MOON) {
	pline("Be careful!  New moon tonight.");
}
flags.friday13 = friday_13th();
if (flags.friday13) {
	pline("Watch out!  Bad things can happen on Friday the 13th.");
	change_luck(-1);
}

The luck adjustments are simply to set initial luck using change_luck. Actual base luck is defined in nh_timeout.

initrack();

initrack initialises the tracking system by which pets (and certain monsters such as leprechauns can follow the player.

/* Note:  these initializers don't do anything except guarantee that
	    we're linked properly.
*/
decl_init();
monst_init();
monstr_init();	/* monster strengths */
objects_init();

decl_init, monst_init, monstr_init, and objects_init are all empty routines used to force the appropriate definitions to compile and be available to the rest of the program.

#ifdef WIZARD
if (wizard) add_debug_extended_commands();

add_debug_extended_commands enables the wizard mode extended commands.

#endif

(void) encumber_msg(); /* in case they auto-picked up something */

encumber_msg recalculates the player's encumbrance and displays an appropriate message if it has changed.

u.uz0.dlevel = u.uz.dlevel;
youmonst.movement = NORMAL_SPEED;	/* give the hero some movement points */

Main loop

for(;;) {
	get_nh_event();
#ifdef POSITIONBAR
	do_positionbar();
#endif

get_nh_event and do_positionbar are routines related to the current interface. get_nh_event invokes any system processing related to window updating and do_positionbar generates information related to a horizontal positoning bar that may be present in the window system.

	didmove = flags.move;

flags.move is set whenever the player has performed an action that requires actual game time (moving, fighting, dropping and picking up objects, etc.).

	if(didmove) {
	    /* actual time passed */
	    youmonst.movement -= NORMAL_SPEED;

Any action that takes time requires NORMAL_SPEED movement points.

	    do { /* hero can't move this turn loop */
		wtcap = encumber_msg();

		flags.mon_moving = TRUE;
		do {
		    monscanmove = movemon();
		    if (youmonst.movement > NORMAL_SPEED)
			break;	/* it's now your turn */
		} while (monscanmove);
		flags.mon_moving = FALSE;

Now that the player has moved, give all monsters at least one chance to move using movemon. If the player does not have sufficient movement points to move any more this turn keep moving monsters; otherwise give monsters only one chance at a move.

		if (!monscanmove && youmonst.movement < NORMAL_SPEED) {

Once-per-turn events

		    /* both you and the monsters are out of steam this round */
		    /* set up for a new turn */

Nothing more can move this turn; therefore prepare to move to the next turn.

		    struct monst *mtmp;
		    mcalcdistress();	/* adjust monsters' trap, blind, etc */

mcalcdistress is responsible for updates of change-of-turn monster data.

		    /* reallocate movement rations to monsters */
		    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
			mtmp->movement += mcalcmove(mtmp);

This grants movement points to monsters for the coming turn. mcalcmove determines how many points the monster will get.

		    if(!rn2(u.uevent.udemigod ? 25 :
			    (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70))
			(void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS);

This important segment is responsible for all random monster generation. The flag u.uevent.demigod is set after killing the Wizard of Yendor for the first time or on performing the invocation ritual; therefore after these events a monster is generated randomly on the level with a 1/25 chance each turn; otherwise there is a 1/50 chance if you are below the Castle and 1/70 chance if you are not.

		    /* calculate how much time passed. */
#ifdef STEED
		    if (u.usteed && u.umoved) {
			/* your speed doesn't augment steed's speed */
			moveamt = mcalcmove(u.usteed);

If you are mounted, your movement point allocation is that of your steed.

		    } else
#endif
		    {
			moveamt = youmonst.data->mmove;

			if (Very_fast) {	/* speed boots or potion */
			    /* average movement is 1.67 times normal */
			    moveamt += NORMAL_SPEED / 2;
			    if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2;
			} else if (Fast) {
			    /* average movement is 1.33 times normal */
			    if (rn2(3) != 0) moveamt += NORMAL_SPEED / 2;
			}
		    }

		    switch (wtcap) {
			case UNENCUMBERED: break;
			case SLT_ENCUMBER: moveamt -= (moveamt / 4); break;
			case MOD_ENCUMBER: moveamt -= (moveamt / 2); break;
			case HVY_ENCUMBER: moveamt -= ((moveamt * 3) / 4); break;
			case EXT_ENCUMBER: moveamt -= ((moveamt * 7) / 8); break;
			default: break;
		    }

		    youmonst.movement += moveamt;
		    if (youmonst.movement < 0) youmonst.movement = 0;

This segment calculates your movement rate for the turn. It is first set to the normal movement rate of your current form (which of course changes if you are polymorphed). If you are fast, you have a 2/3 chance of earning an extra NORMAL_SPEED / 2 movement points; if you are very fast you are guaranteed at least NORMAL_SPEED / 2 points with a 1/3 chance of another NORMAL_SPEED / 2. (Note that NORMAL_SPEED does not vary if you are polymorphed, so the speed intrinsic is more effective if you are in a very slow form and less effective if you are in a very fast form.) Finally, your speed is adjusted for encumbrance and added to your current movement point total.

		    settrack();

settrack updates your position in the tracking system.

		    monstermoves++;
		    moves++;

Finally, the turn counter is incremented; we are now on a new turn.

		    /********************************/
		    /* once-per-turn things go here */
		    /********************************/

		    if (flags.bypasses) clear_bypasses();

clear_bypasses clears a flag related to whether an object should be hit by a wand zapped at it (amongst other events).

		    if(Glib) glibr();

glibr is the code relating to slippery fingers.

		    nh_timeout();

nh_timeout handles all timeouts related to time-delayed functions such as extrinsics from potions, stoning, sliming, etc.

		    run_regions();

run_regions handles timeouts for area effects, currently only used for stinking clouds.

		    if (u.ublesscnt)  u.ublesscnt--;

Decrements the prayer timeout.

		    if(flags.time && !flags.run)
			flags.botl = 1;

Indicates that the status line needs to be updated if the turn counter is shown in the bottom line.

		    /* One possible result of prayer is healing.  Whether or
		     * not you get healed depends on your current hit points.
		     * If you are allowed to regenerate during the prayer, the
		     * end-of-prayer calculation messes up on this.
		     * Another possible result is rehumanization, which requires
		     * that encumbrance and movement rate be recalculated.
		     */
		    if (u.uinvulnerable) {
			/* for the moment at least, you're in tiptop shape */
			wtcap = UNENCUMBERED;

u.uinvulnerable is set whenever you are being protected by your deity while praying; during this time you are not considered to be encumbered.

		    } else if (Upolyd && youmonst.data->mlet == S_EEL && !is_pool(u.ux,u.uy) && !Is_waterlevel(&u.uz)) {
			if (u.mh > 1) {
			    u.mh--;
			    flags.botl = 1;
			} else if (u.mh < 1)
			    rehumanize();

If you are polymorphed into a sea monster and are out of water, you lose one hit point per turn down to a minimum of one.

		    } else if (Upolyd && u.mh < u.mhmax) {
			if (u.mh < 1)
			    rehumanize();

If you are killed in a polymorphed form, attempt to return the player to their normal form.

			else if (Regeneration ||
				    (wtcap < MOD_ENCUMBER && !(moves%20))) {
			    flags.botl = 1;
			    u.mh++;
			}

If you are in a polymorphed form and are either regenerating or on a twentieth move, regain a hitpoint.

		    } else if (u.uhp < u.uhpmax &&
			 (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) {
			if (u.ulevel > 9 && !(moves % 3)) {
			    int heal, Con = (int) ACURR(A_CON);

			    if (Con <= 12) {
				heal = 1;
			    } else {
				heal = rnd(Con);
				if (heal > u.ulevel-9) heal = u.ulevel-9;
			    }
			    flags.botl = 1;
			    u.uhp += heal;
			    if(u.uhp > u.uhpmax)
				u.uhp = u.uhpmax;
			} else if (Regeneration ||
			     (u.ulevel <= 9 &&
			      !(moves % ((MAXULEV+12) / (u.ulevel+2) + 1)))) {
			    flags.botl = 1;
			    u.uhp++;
			}

If you are not polymorphed, regenerate hitpoints. Every third turn if you are level 10 or above, gain an amount of hitpoints equal to a random value up to your current constitution if it is 13 or above, or 1 if your current constitution is below 13. Otherwise gain one hitpoint if you are regenerating, or you are level 9 or less and a certain number of turns related to your current level has passed. This requires that you are not stressed or worse if you are not regenerating.

		    }

		    /* moving around while encumbered is hard work */
		    if (wtcap > MOD_ENCUMBER && u.umoved) {
			if(!(wtcap < EXT_ENCUMBER ? moves%30 : moves%10)) {
			    if (Upolyd && u.mh > 1) {
				u.mh--;
			    } else if (!Upolyd && u.uhp > 1) {
				u.uhp--;
			    } else {
				You("pass out from exertion!");
				exercise(A_CON, FALSE);
				fall_asleep(-10, FALSE);
			    }
			}
		    }

If you are strained or overtaxed, lose hit points from trying to move around; this is every thirty turns if you are strained and every ten if you are overtaxed.

		    if ((u.uen < u.uenmax) &&
			((wtcap < MOD_ENCUMBER &&
			  (!(moves%((MAXULEV + 8 - u.ulevel) *
				    (Role_if(PM_WIZARD) ? 3 : 4) / 6))))
			 || Energy_regeneration)) {
			u.uen += rn1((int)(ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1,1);
			if (u.uen > u.uenmax)  u.uen = u.uenmax;
			flags.botl = 1;
		    }

Regenerate power if you are not stressed or worse on every (38 - current level) * 4 moves if you are not a wizard or * 3 if you are, or have the energy regeneration extrinsic from the Eye of the Aethiopica; you gain from 1 to 1/15th the sum of your current intelligence and wisdom totals.

		    if(!u.uinvulnerable) {
			if(Teleportation && !rn2(85)) {
			    xchar old_ux = u.ux, old_uy = u.uy;
			    tele();
			    if (u.ux != old_ux || u.uy != old_uy) {
				if (!next_to_u()) {
				    check_leash(old_ux, old_uy);
				}
#ifdef REDO
				/* clear doagain keystrokes */
				pushch(0);
				savech(0);
#endif
			    }
			}

This implements teleportitis, if you are not protected while praying; if they have the intrinsic, teleport the player on a 1/85th chance each turn.

			/* delayed change may not be valid anymore */
			if ((change == 1 && !Polymorph) ||
			    (change == 2 && u.ulycn == NON_PM))
			    change = 0;

Polymorphing is delayed while wearing an amulet of unchanging; if such a polymorph is no longer valid cancel it.

			if(Polymorph && !rn2(100))
			    change = 1;

If you have the polymorphing intrinsic (from a ring of polymorph), attempt to polymorph on a 1/100 chance each turn.

			else if (u.ulycn >= LOW_PM && !Upolyd &&
				 !rn2(80 - (20 * night())))
			    change = 2;

If you are a lycanthrope, attempt to change on a 1/80 chance (or 1/60 if it is night) per turn.

			if (change && !Unchanging) {
			    if (multi >= 0) {
				if (occupation)
				    stop_occupation();
				else
				    nomul(0);
				if (change == 1) polyself(FALSE);
				else you_were();
				change = 0;
			    }

Enact the above polymorphs if you are not wearing an amulet of unchanging; otherwise delay it (as above).

			}
		    }

		    if(Searching && multi >= 0) (void) dosearch0(1);

If you have the searching intrinsic, perform the search.

		    dosounds();

dosounds generates the sounds resulting from dungeon features.

		    do_storms();

do_storms generates storm effects for the Plane of Air.

		    gethungry();

gethungry handles normal nutrition depletion and effects.

		    age_spells();

age_spells handles spell timeouts.

		    exerchk();

exerchk checks if attributes have been exercised enough for a change to occur.

		    invault();

invault handles vault guard checks.

		    if (u.uhave.amulet) amulet();

amulet handles turn-to-turn events related to holding the Amulet of Yendor.

		    if (!rn2(40+(int)(ACURR(A_DEX)*3)))
			u_wipe_engr(rnd(3));

This attempts to scuff engravings at your location on a random chance that decreases with dexterity.

		    if (u.uevent.udemigod && !u.uinvulnerable) {
			if (u.udg_cnt) u.udg_cnt--;
			if (!u.udg_cnt) {
			    intervene();
			    u.udg_cnt = rn1(200, 50);
			}
		    }

If you have killed the Wizard of Yendor or performed the invocation ritual, intervene is called every 50-249 turns; this is responsible for the Wizard's interventions and resurrections.

		    restore_attrib();

restore_attrib restores temporary changes of attributes.

		    /* underwater and waterlevel vision are done here */
		    if (Is_waterlevel(&u.uz))
			movebubbles();

movebubbles handles bubble movements on the Plane of Water.

		    else if (Underwater)
			under_water(0);

under_water handles display routines related to being under water.

		    /* vision while buried done here */
		    else if (u.uburied) under_ground(0);

under_ground handles display routines related to being buried (a deferred feature).

		    /* when immobile, count is in turns */
		    if(multi < 0) {
			if (++multi == 0) {	/* finished yet? */
			    unmul((char *)0);
			    /* if unmul caused a level change, take it now */
			    if (u.utotype) deferred_goto();
			}
		    }

If you are immobile, decrement the turn counter for being immobile and handle any effects meant to occur once the timeout for this reaches zero.

		}
	    } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */

Once-per-action events

	    /******************************************/
	    /* once-per-hero-took-time things go here */
	    /******************************************/


	} /* actual time passed */

Once-per-input events

	/****************************************/
	/* once-per-player-input things go here */
	/****************************************/

	find_ac();

find_ac calculates and updates the player's armor class.

	if(!flags.mv || Blind) {
	    /* redo monsters if hallu or wearing a helm of telepathy */
	    if (Hallucination) {	/* update screen randomly */
		see_monsters();
		see_objects();
		see_traps();
		if (u.uswallow) swallowed(0);
	    } else if (Unblind_telepat) {
		see_monsters();
	    } else if (Warning || Warn_of_mon)
	     	see_monsters();

see_monsters, see_traps, and traps determine which glyphs to display for those features.

	    if (vision_full_recalc) vision_recalc(0);	/* vision! */

vision_recalc calculates which squares are visible to the player.

	}
	if(flags.botl || flags.botlx) bot();

If the status line needs to be updated, update it with bot.

	flags.move = 1;

Assume that the next player action will require time; if it does not flags.move will be reset at that time.

	if(multi >= 0 && occupation) {

multi is greater than zero if a player has entered in a repeated command or some other interruptible action; occupation is set to whatever function represents this action if this is the case.

#if defined(MICRO) || defined(WIN32)
	    abort_lev = 0;
	    if (kbhit()) {
		if ((ch = Getchar()) == ABORT)
		    abort_lev++;
# ifdef REDO
		else
		    pushch(ch);
# endif /* REDO */
	    }
	    if (!abort_lev && (*occupation)() == 0)
#else
	    if ((*occupation)() == 0)
#endif
		occupation = 0;
	    if(
#if defined(MICRO) || defined(WIN32)
		   abort_lev ||
#endif
		   monster_nearby()) {
		stop_occupation();
		reset_eat();
	    }

If a key has been pressed either when no action is in process or in the middle of an interruptible action, check if that key is ABORT (^A by default); if so, interrupt any current action if possible and if not add the key to the key queue with pushch. Actions will also be interrupted if the player senses a monster (checked with monster_nearby).

#if defined(MICRO) || defined(WIN32)
	    if (!(++occtime % 7))
		display_nhwindow(WIN_MAP, FALSE);
#endif

On some platforms, update the map on a regular basis.

	    continue;
	}

	if ((u.uhave.amulet || Clairvoyant) &&
	    !In_endgame(&u.uz) && !BClairvoyant &&
	    !(moves % 15) && !rn2(2))
		do_vicinity_map();

If it is a fifteenth turn and you are clairvoyant and not in the endgame, on a one half chance generate the clairvoyance map with do_vicinity_map.

	if(u.utrap && u.utraptype == TT_LAVA) {
	    if(!is_lava(u.ux,u.uy))
		u.utrap = 0;
	    else if (!u.uinvulnerable) {
		u.utrap -= 1<<8;
		if(u.utrap < 1<<8) {
		    killer_format = KILLED_BY;
		    killer = "molten lava";
		    You("sink below the surface and die.");
		    done(DISSOLVED);
		} else if(didmove && !u.umoved) {
		    Norep("You sink deeper into the lava.");
		    u.utrap += rnd(4);
		}
	    }
	}

After each player action, when you are in a lava trap, sink into the lava some more. After 11 to 14 actions, kill the player. Note: u.utrap is set at trap.c#line3991.

#ifdef WIZARD
	if (iflags.sanity_check)
	    sanity_check();
#endif

sanity_check performs some debugging checks if a wizard mode player has them enabled.

#ifdef CLIPPING
	/* just before rhack */
	cliparound(u.ux, u.uy);

cliparound is a window system routine meant to ensure the player is centred in the screen (to the extent that is possible with the windowing system).

#endif

	u.umoved = FALSE;

Assume that the player has not entered in a movement command until they actually do so.

	if (multi > 0) {
	    lookaround();
	    if (!multi) {
		/* lookaround may clear multi */
		flags.move = 0;
		if (flags.time) flags.botl = 1;
		continue;
	    }
	    if (flags.mv) {
		if(multi < COLNO && !--multi)
		    flags.travel = iflags.travel1 = flags.mv = flags.run = 0;
		domove();
	    } else {
		--multi;
		rhack(save_cm);
	    }

Repeated command code, also used for interruptible actions. If nothing interrupts the action (checked with lookaround) perform the stored move or command with rhack. Rhack essentially reads the keyboard input and kicks off player actions.

	} else if (multi == 0) {
#ifdef MAIL
	    ckmailstatus();
#endif
	    rhack((char *)0);

If there are no repeated commands or interruptible actions, bring in the mail daemon as necessary with ckmailstatus and then take player input with rhack.

	}
	if (u.utotype)		/* change dungeon level */
	    deferred_goto();	/* after rhack() */

deferred_goto checks if the player has changed levels and takes appropriate action if they have.

	/* !flags.move here: multiple movement command stopped */
	else if (flags.time && (!flags.move || !flags.mv))
	    flags.botl = 1;

	if (vision_full_recalc) vision_recalc(0);	/* vision! */

Recalulate visible tiles if the command just entered necessiates it.

	/* when running in non-tport mode, this gets done through domove() */
	if ((!flags.run || iflags.runmode == RUN_TPORT) &&
		(multi && (!flags.travel ? !(multi % 7) : !(moves % 7L)))) {
	    if (flags.time && flags.run) flags.botl = 1;
	    display_nhwindow(WIN_MAP, FALSE);

Update the map window every seven moves or turns if certain flags are set.

	}
}
}

#endif /* OVL0 */

stop_occupation

#ifdef OVL1

void
stop_occupation()
{
	if(occupation) {
		if (!maybe_finished_meal(TRUE))
		    You("stop %s.", occtxt);
		occupation = 0;
		flags.botl = 1; /* in case u.uhs changed */
/* fainting stops your occupation, there's no reason to sync.
		sync_hunger();
*/
#ifdef REDO
		nomul(0);
		pushch(0);
#endif
	}
}

#endif /* OVL1 */

display_gamewindows

#ifdef OVLB

void
display_gamewindows()
{
WIN_MESSAGE = create_nhwindow(NHW_MESSAGE);
WIN_STATUS = create_nhwindow(NHW_STATUS);
WIN_MAP = create_nhwindow(NHW_MAP);
WIN_INVEN = create_nhwindow(NHW_MENU);

#ifdef MAC
/*
* This _is_ the right place for this - maybe we will
* have to split display_gamewindows into create_gamewindows
* and show_gamewindows to get rid of this ifdef...
*/
	if ( ! strcmp ( windowprocs . name , "mac" ) ) {
	    SanePositions ( ) ;
	}
#endif

/*
* The mac port is not DEPENDENT on the order of these
* displays, but it looks a lot better this way...
*/
display_nhwindow(WIN_STATUS, FALSE);
display_nhwindow(WIN_MESSAGE, FALSE);
clear_glyph_buffer();
display_nhwindow(WIN_MAP, FALSE);
}

newgame

void
newgame()
{
	int i;

#ifdef MFLOPPY
	gameDiskPrompt();
#endif

	flags.ident = 1;

	for (i = 0; i < NUMMONS; i++)
		mvitals[i].mvflags = mons[i].geno & G_NOCORPSE;

	init_objects();		/* must be before u_init() */

	flags.pantheon = -1;	/* role_init() will reset this */
	role_init();		/* must be before init_dungeons(), u_init(),
				 * and init_artifacts() */

	init_dungeons();	/* must be before u_init() to avoid rndmonst()
				 * creating odd monsters for any tins and eggs
				 * in hero's initial inventory */
	init_artifacts();	/* before u_init() in case $WIZKIT specifies
				 * any artifacts */
	u_init();

#ifndef NO_SIGNAL
	(void) signal(SIGINT, (SIG_RET_TYPE) done1);
#endif
#ifdef NEWS
	if(iflags.news) display_file(NEWS, FALSE);
#endif
	load_qtlist();	/* load up the quest text info */
/*	quest_init();*/	/* Now part of role_init() */

	mklev();
	u_on_upstairs();
	vision_reset();		/* set up internals for level (after mklev) */
	check_special_room(FALSE);

	flags.botlx = 1;

	/* Move the monster from under you or else
	 * makedog() will fail when it calls makemon().
	 *			- ucsfcgl!kneller
	 */
	if(MON_AT(u.ux, u.uy)) mnexto(m_at(u.ux, u.uy));
	(void) makedog();
	docrt();

	if (flags.legacy) {
		flush_screen(1);
		com_pager(1);
	}

#ifdef INSURANCE
	save_currentstate();
#endif
	program_state.something_worth_saving++;	/* useful data now exists */

	/* Success! */
	welcome(TRUE);
	return;
}

welcome

/* show "welcome [back] to nethack" message at program startup */
void
welcome(new_game)
boolean new_game;	/* false => restoring an old game */
{
char buf[BUFSZ];
boolean currentgend = Upolyd ? u.mfemale : flags.female;

/*
* The "welcome back" message always describes your innate form
* even when polymorphed or wearing a helm of opposite alignment.
* Alignment is shown unconditionally for new games; for restores
* it's only shown if it has changed from its original value.
* Sex is shown for new games except when it is redundant; for
* restores it's only shown if different from its original value.
*/
*buf = '\0';
if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT])
	Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL]));
if (!urole.name.f &&
	    (new_game ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE|ROLE_FEMALE) :
	     currentgend != flags.initgend))
	Sprintf(eos(buf), " %s", genders[currentgend].adj);

pline(new_game ? "%s %s, welcome to NetHack!  You are a%s %s %s."
		   : "%s %s, the%s %s %s, welcome back to NetHack!",
	  Hello((struct monst *) 0), plname, buf, urace.adj,
	  (currentgend && urole.name.f) ? urole.name.f : urole.name.m);
}

do_positionbar

#ifdef POSITIONBAR
STATIC_DCL void
do_positionbar()
{
	static char pbar[COLNO];
	char *p;
	
	p = pbar;
	/* up stairway */
	if (upstair.sx &&
	   (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) ==
	    S_upstair ||
	    glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) ==
	    S_upladder)) {
		*p++ = '<';
		*p++ = upstair.sx;
	}
	if (sstairs.sx &&
	   (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
	    S_upstair ||
	    glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
	    S_upladder)) {
		*p++ = '<';
		*p++ = sstairs.sx;
	}

	/* down stairway */
	if (dnstair.sx &&
	   (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) ==
	    S_dnstair ||
	    glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) ==
	    S_dnladder)) {
		*p++ = '>';
		*p++ = dnstair.sx;
	}
	if (sstairs.sx &&
	   (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
	    S_dnstair ||
	    glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) ==
	    S_dnladder)) {
		*p++ = '>';
		*p++ = sstairs.sx;
	}

	/* hero location */
	if (u.ux) {
		*p++ = '@';
		*p++ = u.ux;
	}
	/* fence post */
	*p = 0;

	update_positionbar(pbar);
}
#endif

#endif /* OVLB */

/*allmain.c*/