Esempio n. 1
0
void
losestr(int num, int how, const char *killer, struct monst *magr)
{       /* may kill you; cause may be poison or monster like 'a' */
    int ustr = ABASE(A_STR) - num;

    while (ustr < 3) {
        ++ustr;
        --num;
        if (Upolyd) {
            u.mh -= 6;
            u.mhmax -= 6;

            if (u.mh <= 0) {
                if (how == STARVING)
                    pline("You can't go on any more like this.");
                rehumanize(how, killer);
            }
        } else {
            u.uhp -= 6;
            u.uhpmax -= 6;

            if (u.uhp <= 0) {
                if (how == STARVING)
                    pline("You die from hunger and exhaustion.");

                if (magr) /* don't give at the same time as STARVING */
                    done_in_by(magr, killer);
                else
                    done(how, killer);
            }
        }
    }
    adjattrib(A_STR, -num, TRUE);
}
Esempio n. 2
0
void you_unwere(boolean purify)
{
	if (purify) {
	    pline("You feel purified.");
	    u.ulycn = NON_PM;	/* cure lycanthropy */
	}
	if (!Unchanging && is_were(youmonst.data) &&
		(!Polymorph_control || yn("Remain in beast form?") == 'n'))
	    rehumanize();
}
Esempio n. 3
0
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;

    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);
    }

    initrack();


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

    commands_init();

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

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

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

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

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

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

		if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
		    /* both you and the monsters are out of steam this round */
		    /* set up for a new turn */
		    struct monst *mtmp;
		    mcalcdistress();	/* adjust monsters' trap, blind, etc */

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

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

		    /* calculate how much time passed. */
#ifdef STEED
		    if (u.usteed && u.umoved) {
			/* your speed doesn't augment steed's speed */
			moveamt = mcalcmove(u.usteed);
		    } 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;
		    settrack();

		    monstermoves++;
		    moves++;

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

		    if (flags.bypasses) clear_bypasses();
		    if(Glib) glibr();
		    nh_timeout();
		    run_regions();

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

		    /* 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;
		    } else if (Upolyd && youmonst.data->mlet == S_EEL &&
		               !is_pool(u.ux,u.uy) && !Is_waterlevel(&u.uz) &&
			       !(u.uswallow &&
			         u.ustuck->data == &mons[PM_WATER_ELEMENTAL])) {
			if (u.mh > 1) {
			    u.mh--;
			    flags.botl = 1;
			} else if (u.mh < 1)
			    killer_format = KILLED_BY_AN,
			    rehumanize("inability to breathe air");
		    } else if (Upolyd && u.mh < u.mhmax) {
			if (u.mh < 1)
			    rehumanize(0);
			else if (Regeneration ||
				    (wtcap < MOD_ENCUMBER && !(moves%20))) {
			    flags.botl = 1;
			    u.mh++;
			}
		    } 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++;
			}
		    }

		    /* 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 ((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;
		    }

		    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
			    }
			}
			/* delayed change may not be valid anymore */
			if ((change == 1 && !Polymorph) ||
			    (change == 2 && u.ulycn == NON_PM))
			    change = 0;
			if(Polymorph && !rn2(100))
			    change = 1;
			else if (u.ulycn >= LOW_PM && !Upolyd &&
				 !rn2(80 - (20 * night())))
			    change = 2;
			if (change && !Unchanging) {
			    if (multi >= 0) {
				if (occupation)
				    stop_occupation();
				else
				    nomul(0);
				if (change == 1) polyself(FALSE);
				else you_were();
				change = 0;
			    }
			}
	
			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);
				}
			    }
			}
		    }

		    if(Searching && multi >= 0) (void) dosearch0(1);
		    dosounds();
		    /* hack - make sure damage from storms is not blamed
		       on the player */
		    flags.mon_moving = TRUE;
		    do_storms();
		    flags.mon_moving = FALSE;
		    gethungry();
		    age_spells();
		    exerchk();
		    invault();
		    if (u.uhave.amulet) amulet();
		    if (!rn2(40+(int)(ACURR(A_DEX)*3)))
			u_wipe_engr(rnd(3));
		    if (u.uevent.udemigod && !u.uinvulnerable) {
			if (u.udg_cnt) u.udg_cnt--;
			if (!u.udg_cnt) {
			    intervene();
			    u.udg_cnt = rn1(200, 50);
			}
		    }
		    restore_attrib();
		    /* underwater and waterlevel vision are done here */
		    if (Is_waterlevel(&u.uz))
			movebubbles();
		    else if (Underwater)
			under_water(0);
		    /* vision while buried done here */
		    else if (u.uburied) under_ground(0);

		    /* 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();
			}
		    }
		}
	    } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */

	    /******************************************/
	    /* once-per-hero-took-time things go here */
	    /******************************************/
            curmonst = &youmonst;

	} /* actual time passed */

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

	find_ac();
	if(!flags.mv || Blind) {
	    /* redo monsters if hallu or wearing a helm of telepathy */
	    if (HHallucination &&
	       !Halluc_resistance) {	/* update screen randomly */
	    /*
		see_monsters();
		see_objects();
		see_traps();
		if (u.uswallow) swallowed(0);
	    */
                if (u.uswallow) {
            	    swallowed(1);
                } else if (Underwater && !Is_waterlevel(&u.uz)) {
            	    under_water(1);
                } else if (u.uburied) {
            	    under_ground(1);
                } else {
		    register int x, y;
		    register struct rm *lev;

                    vision_recalc(2);

                    /*clear_nhwindow(WIN_MAP);*/
                    clear_glyph_buffer();
                
                    for (x = 1; x < COLNO; x++) {
                	lev = &levl[x][0];
                	for (y = 0; y < ROWNO; y++, lev++)
                	    if (lev->glyph != cmap_to_glyph(S_stone))
                		show_glyph(x,y,lev->glyph);
                    }
                
                    vision_recalc(0);
                
                    see_monsters();
    		}
	    } else if (Unblind_telepat) {
		see_monsters();
	    } else if (Warning || Warn_of_mon)
	     	see_monsters();

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

#ifdef REALTIME_ON_BOTL
        if(iflags.showrealtime) {
            /* Update the bottom line if the number of minutes has
             * changed */
            if(get_realtime() / 60 != realtime_data.last_displayed_time / 60)
                flags.botl = 1;
        }
#endif
  
	if(flags.botl || flags.botlx) bot();

	flags.move = 1;

	if(multi >= 0 && occupation) {
#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 defined(MICRO) || defined(WIN32)
	    if (!(++occtime % 7))
		display_nhwindow(WIN_MAP, FALSE);
#endif
	    continue;
	}

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


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

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

	u.umoved = FALSE;

	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);
	    }
	} else if (multi == 0) {
#ifdef MAIL
	    ckmailstatus();
#endif
	    rhack((char *)0);
	}
	if (u.utotype)		/* change dungeon level */
	    deferred_goto();	/* after rhack() */
	/* !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! */
	/* 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);
	}
    }
}
Esempio n. 4
0
void
nh_timeout()
{
	register struct prop *upp;
	int sleeptime;
	int m_idx;
	int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;

	if (flags.friday13) baseluck -= 1;

	if (u.uluck != baseluck &&
		moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) {
	/* Cursed luckstones stop bad luck from timing out; blessed luckstones
	 * stop good luck from timing out; normal luckstones stop both;
	 * neither is stopped if you don't have a luckstone.
	 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
	 */
	    register int time_luck = stone_luck(FALSE);
	    boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);

	    if(u.uluck > baseluck && (nostone || time_luck < 0))
		u.uluck--;
	    else if(u.uluck < baseluck && (nostone || time_luck > 0))
		u.uluck++;
	}
	if(u.uinvulnerable) return; /* things past this point could kill you */
	if(Stoned) stoned_dialogue();
	if(Slimed) slime_dialogue();
	if(Vomiting) vomiting_dialogue();
	if(Strangled) choke_dialogue();
	if(u.mtimedone && !--u.mtimedone) {
		if (Unchanging)
			u.mtimedone = rnd(100*youmonst.data->mlevel + 1);
		else
			rehumanize();
	}
	if(u.ucreamed) u.ucreamed--;

	/* Dissipate spell-based protection. */
	if (u.usptime) {
	    if (--u.usptime == 0 && u.uspellprot) {
		u.usptime = u.uspmtime;
		u.uspellprot--;
		find_ac();
		if (!Blind)
		    Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
			  u.uspellprot ? "becomes less dense" : "disappears");
	    }
	}

#ifdef STEED
	if (u.ugallop) {
	    if (--u.ugallop == 0L && u.usteed)
	    	pline("%s stops galloping.", Monnam(u.usteed));
	}
#endif

	for(upp = u.uprops; upp < u.uprops+SIZE(u.uprops); upp++)
	    if((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
		switch(upp - u.uprops){
		case STONED:
			if (delayed_killer && !killer) {
				killer = delayed_killer;
				delayed_killer = 0;
			}
			if (!killer) {
				/* leaving killer_format would make it
				   "petrified by petrification" */
				killer_format = NO_KILLER_PREFIX;
				killer = "killed by petrification";
			}
			done(STONING);
			break;
		case SLIMED:
			if (delayed_killer && !killer) {
				killer = delayed_killer;
				delayed_killer = 0;
			}
			if (!killer) {
				killer_format = NO_KILLER_PREFIX;
				killer = "turned into green slime";
			}
			done(TURNED_SLIME);
			break;
		case VOMITING:
			make_vomiting(0L, TRUE);
			break;
		case SICK:
			You("die from your illness.");
			killer_format = KILLED_BY_AN;
			killer = u.usick_cause;
			if ((m_idx = name_to_mon(killer)) >= LOW_PM) {
			    if (type_is_pname(&mons[m_idx])) {
				killer_format = KILLED_BY;
			    } else if (mons[m_idx].geno & G_UNIQ) {
				killer = the(killer);
				Strcpy(u.usick_cause, killer);
				killer_format = KILLED_BY;
			    }
			}
			u.usick_type = 0;
			done(POISONING);
			break;
		case FAST:
			if (!Very_fast)
				You_feel("yourself slowing down%s.",
							Fast ? " a bit" : "");
			break;
		case CONFUSION:
			HConfusion = 1; /* So make_confused works properly */
			make_confused(0L, TRUE);
			stop_occupation();
			break;
		case STUNNED:
			HStun = 1;
			make_stunned(0L, TRUE);
			stop_occupation();
			break;
		case BLINDED:
			Blinded = 1;
			make_blinded(0L, TRUE);
			stop_occupation();
			break;
		case INVIS:
			newsym(u.ux,u.uy);
			if (!Invis && !BInvis && !Blind) {
			    You(!See_invisible ?
				    "are no longer invisible." :
				    "can no longer see through yourself.");
			    stop_occupation();
			}
			break;
		case SEE_INVIS:
			set_mimic_blocking(); /* do special mimic handling */
			see_monsters();		/* make invis mons appear */
			newsym(u.ux,u.uy);	/* make self appear */
			stop_occupation();
			break;
		case WOUNDED_LEGS:
			heal_legs();
			stop_occupation();
			break;
		case HALLUC:
			HHallucination = 1;
			(void) make_hallucinated(0L, TRUE, 0L);
			stop_occupation();
			break;
		case SLEEPING:
			if (unconscious() || Sleep_resistance)
				HSleeping += rnd(100);
			else if (Sleeping) {
				You("fall asleep.");
				sleeptime = rnd(20);
				fall_asleep(-sleeptime, TRUE);
				HSleeping += sleeptime + rnd(100);
			}
			break;
		case LEVITATION:
			(void) float_down(I_SPECIAL|TIMEOUT, 0L);
			break;
		case STRANGLED:
			killer_format = KILLED_BY;
			killer = (u.uburied) ? "suffocation" : "strangulation";
			done(DIED);
			break;
		case FUMBLING:
			/* call this only when a move took place.  */
			/* otherwise handle fumbling msgs locally. */
			if (u.umoved && !Levitation) {
			    slip_or_trip();
			    nomul(-2, "fumbling");
			    nomovemsg = "";
			    /* The more you are carrying the more likely you
			     * are to make noise when you fumble.  Adjustments
			     * to this number must be thoroughly play tested.
			     */
			    if ((inv_weight() > -500)) {
				You("make a lot of noise!");
				wake_nearby();
			    }
			}
			/* from outside means slippery ice; don't reset
			   counter if that's the only fumble reason */
			HFumbling &= ~FROMOUTSIDE;
			if (Fumbling)
			    HFumbling += rnd(20);
			break;
		case DETECT_MONSTERS:
			see_monsters();
			break;
		case PREGNANT: {
			char buf[BUFSZ];
			if (!flags.female) {
			    strcpy(buf, body_part(STOMACH));
			    if (!strcmp(buf, "stomach"))
				strcpy(buf, "belly");
			    pline("Something bursts out of your %s!");
			    killer_format = KILLED_BY;
			    killer = "male childbirth";
			    done(DIED);
			}
			mksobj_at(PLACENTA, u.ux, u.uy, FALSE, FALSE);
			pline("BABIES!"); /* TODO */
			stop_occupation();
			break;
		    }
		}
	}

	run_timers();
}
Esempio n. 5
0
void
moveloop()
{
#ifdef MICRO
	char ch;
	int abort_lev;
#endif
	int moverate = 0;
	boolean didmove = 0;

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

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

	for(;;) {
#ifdef CLIPPING
		cliparound(u.ux, u.uy);
#endif
#if defined(MAC_MPW32) && !defined(MODEL_FAR)
		UnloadAllSegments();  /* Marks non-resident segments as purgeable */
#endif
		get_nh_event();

		didmove = flags.move;
		if(flags.move) {	/* actual time passed */
#ifdef POLYSELF
		    int oldmtimedone;
#endif
		    int wtcap;

		    if (u.utotype) deferred_goto();
		    wtcap = encumber_msg();
#ifdef POLYSELF
		    oldmtimedone = u.mtimedone;
#endif

#ifdef SOUNDS
		    dosounds();
#endif

		    if(moverate <= 0) {
			/* calculate how much time passed. */
			int moveamt = 0;
			if(Fast & ~INTRINSIC) moveamt = 6;
			else if(Fast) moveamt = 8;
			else moveamt = 12;

			switch(wtcap) {
			case UNENCUMBERED: break;
			case SLT_ENCUMBER: moveamt = (moveamt * 4) / 3; break;
			case MOD_ENCUMBER: moveamt *= 2; break;
			case HVY_ENCUMBER: moveamt *= 4; break;
			default: moveamt *= 12; break;
			}
			moverate += moveamt;
			settrack();
		    }

		    if(moverate > 0) {
			movemon();
			/* a monster may have levteleported player -dlc */
			if (u.utotype) deferred_goto();
			if(!rn2(u.uevent.udemigod ? 25 :
				(depth(&u.uz) >
				 depth(&stronghold_level))
				? 50 : 70))
			    (void) makemon((struct permonst *)0, 0, 0);
			++monstermoves;
			remove_cadavers(&fobj);
			remove_cadavers(&invent);
			moverate -= 12;
		    }
		    if(Glib) glibr();
		    nh_timeout();
		    ++moves;
		    if (u.ublesscnt)  u.ublesscnt--;
		    if(flags.time) flags.botl = 1;
		    /* 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.
		     */
		    if (u.uinvulnerable)
			;
		    else
#ifdef POLYSELF
		    if (u.mtimedone && u.mh < u.mhmax) {
			if (u.mh < 1) {
			    rehumanize();
			    moverate = 0;
			} else if (Regeneration ||
				 (wtcap < MOD_ENCUMBER && !(moves%20))) {
			    flags.botl = 1;
			    u.mh++;
			}
		    } else
#endif
		    if(u.uhp < u.uhpmax) {
			if(u.ulevel > 9) {
			    int heal;

			    if(HRegeneration ||
			       (!(moves%3) &&
				(wtcap < MOD_ENCUMBER || !flags.mv))) {
				flags.botl = 1;
				if (ACURR(A_CON) <= 12) heal = 1;
				else heal = rnd((int) ACURR(A_CON)-12);
				if (heal > u.ulevel-9) heal = u.ulevel-9;
				u.uhp += heal;
				if(u.uhp > u.uhpmax)
				    u.uhp = u.uhpmax;
			    }
			} else if(HRegeneration ||
				  ((wtcap < MOD_ENCUMBER || !flags.mv) &&
				   (!(moves%((MAXULEV+12)/(u.ulevel+2)+1))))) {
			    flags.botl = 1;
			    u.uhp++;
			}
		    }

		    if (wtcap > MOD_ENCUMBER && flags.mv) {
			if(!(wtcap < EXT_ENCUMBER ? moves%30 : moves%10)) {
			    if(u.uhp > 1) {
				u.uhp--;
			    } else {
				pline("You pass out from exertion!");
				exercise(A_CON, FALSE);
				nomul(-10);
				u.usleep = 1;
			    }
			}
		    }

		    if ((u.uen < u.uenmax) &&
			((wtcap < MOD_ENCUMBER &&
			  (!(moves%((MAXULEV + 1 - u.ulevel) *
				    (pl_character[0] == 'W' ? 3 : 4) / 2))))
			 || Energy_regeneration)) {
			u.uen +=
			    rn1((int)(ACURR(A_WIS) + ACURR(A_INT)) / 10 + 1,1);
			if (u.uen > u.uenmax)  u.uen = u.uenmax;
			flags.botl = 1;
		    }

		    if(!u.uinvulnerable) {
			if(Teleportation && !rn2(85)) {
#ifdef REDO		    /* clear doagain keystrokes */
			    pushch(0);
			    savech(0);
#endif
			    tele();
			}
#ifdef POLYSELF
			if(Polymorph && !rn2(100)) {
			    if (multi >= 0) {
				if (occupation)
				    stop_occupation();
				else
				    nomul(0);
			    }
			    polyself();
			    moverate = 0;
			} else if (u.ulycn >= 0 && !rn2(80 - (20 * night()))) {
			    if (multi >= 0) {
				if (occupation)
				    stop_occupation();
				else
				    nomul(0);
			    }
			    you_were();
			    moverate = 0;
			}
#endif
		    }

		    if(Searching && multi >= 0) (void) dosearch0(1);
		    do_storms();
		    hatch_eggs();
		    burn_lamps();
		    gethungry();
		    exerchk();
		    invault();
		    amulet();
		    if (!rn2(40+(int)(ACURR(A_DEX)*3))) 
			u_wipe_engr(rnd(3));
		    if (u.uevent.udemigod && !u.uinvulnerable) {
			if (u.udg_cnt) u.udg_cnt--;
			if (!u.udg_cnt) {
			    intervene();
			    u.udg_cnt = rn1(200, 50);
			}
		    }
		    restore_attrib();
		    /* underwater and waterlevel vision are done here */
		    if (Is_waterlevel(&u.uz))
			movebubbles();
		    else if (Underwater)
			under_water(0);

#ifdef POLYSELF
		    if ((oldmtimedone && !u.mtimedone) ||
			(!oldmtimedone && u.mtimedone)) moverate = 0;
#endif
		}
		if(multi < 0) {
			if(!++multi){
				pline("%s",nomovemsg ? nomovemsg :
					(const char *)"You can move again.");
				nomovemsg = 0;
				u.usleep = 0;
				if(afternmv) (*afternmv)();
				afternmv = 0;
			}
		}

		find_ac();
		if(!flags.mv || Blind) {
		    /* redo monsters if hallu or wearing a helm of telepathy */
		    if (Hallucination ||
			(HTelepat & (WORN_HELMET|WORN_AMUL|W_ART)))
			see_monsters();

		    /* redo objects if hallucinating */
		    if (Hallucination) see_objects();

		    /* update swallowed display */
		    if (Hallucination && u.uswallow) swallowed(0);

		    if (vision_full_recalc) vision_recalc(0);	/* vision! */
		}
		if(flags.botl || flags.botlx) bot();

		flags.move = 1;

		if(multi >= 0 && occupation) {
#ifdef MICRO
			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(
#ifdef MICRO
			   abort_lev ||
#endif
			   monster_nearby()) {
				stop_occupation();
				reset_eat();
			}
#ifdef MICRO
			if (!(++occtime % 7))
				display_nhwindow(WIN_MAP, FALSE);
#endif
			continue;
		}

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

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

		u.umoved = FALSE;
		if(!didmove || moverate <= 0) {
		    if(multi > 0) {
			lookaround();
			if(!multi) {	/* lookaround may clear multi */
				flags.move = 0;
				continue;
			}
			if(flags.mv) {
				if(multi < COLNO && !--multi)
					flags.mv = flags.run = 0;
				domove();
			} else {
				--multi;
				rhack(save_cm);
			}
		    } else if(multi == 0) {
#ifdef MAIL
			ckmailstatus();
#endif
			rhack(NULL);
		    }
		}
		if (vision_full_recalc) vision_recalc(0);	/* vision! */
		if(multi && multi%7 == 0)
			display_nhwindow(WIN_MAP, FALSE);
	}
}
Esempio n. 6
0
/* Note: I had to choose one of three possible kinds of "type" when writing
 * this function: a wand type (like in zap.c), an adtyp, or an object type.
 * Wand types get complex because they must be converted to adtyps for
 * determining such things as fire resistance.  Adtyps get complex in that
 * they don't supply enough information--was it a player or a monster that
 * did it, and with a wand, spell, or breath weapon?  Object types share both
 * these disadvantages....
 *
 * The descr argument should be used to describe the explosion. It should be
 * a string suitable for use with an().
 * raylevel is used for explosions caused by skilled wand usage (0=no wand)
 */
void
explode(int x, int y, int type, /* the same as in zap.c */
        int dam, char olet, int expltype, const char *descr, int raylevel)
{
    int i, j, k, damu = dam;
    boolean visible, any_shield, resist_death;
    resist_death = FALSE;
    int uhurt = 0;      /* 0=unhurt, 1=items damaged, 2=you and items damaged */
    const char *str;
    const char *dispbuf = "";   /* lint suppression; I think the code's OK */
    boolean expl_needs_the = TRUE;
    int idamres, idamnonres;
    struct monst *mtmp;
    uchar adtyp;
    int explmask[3][3];

    /* 0=normal explosion, 1=do shieldeff, 2=do nothing */
    boolean shopdamage = FALSE;

#if 0
    /* Damage reduction from wand explosions */
    if (olet == WAND_CLASS)     /* retributive strike */
        switch (Role_switch) {
        case PM_PRIEST:
        case PM_MONK:
        case PM_WIZARD:
            damu /= 5;
            break;
        case PM_HEALER:
        case PM_KNIGHT:
            damu /= 2;
            break;
        default:
            break;
        }
#endif
    if (olet == MON_EXPLODE) {
        str = descr;
        adtyp = AD_PHYS;
        if (Hallucination) {
            int name = rndmonidx();

            dispbuf = msgcat(s_suffix(monnam_for_index(name)), " explosion");
            expl_needs_the = !monnam_is_pname(name);
        } else {
            dispbuf = str;
        }
    } else {
        int whattype = abs(type) % 10;

        adtyp = whattype + 1;
        boolean done = FALSE, hallu = Hallucination;

        if (hallu) {
            do {
                whattype = rn2(8);
            } while (whattype == 3);
        }
tryagain:
        switch (whattype) {
        case 0:
            str = "magical blast";
            break;
        case 1:
            str =
                olet == BURNING_OIL ? "burning oil" : olet ==
                SCROLL_CLASS ? "tower of flame" : "fireball";
            break;
        case 2:
            str = "ball of cold";
            break;
        case 3:
            str = "sleeping gas";
            break;
        case 4:
            str = (olet == WAND_CLASS) ? "death field" : "disintegration field";
            break;
        case 5:
            str = "ball of lightning";
            break;
        case 6:
            str = "poison gas cloud";
            break;
        case 7:
            str = "splash of acid";
            break;
        default:
            impossible("explosion base type %d?", type);
            return;
        }
        if (!done) {
            dispbuf = str;
            done = TRUE;
            if (hallu) {
                whattype = adtyp - 1;
                goto tryagain;
            }
        }
    }

    any_shield = visible = FALSE;
    for (i = 0; i < 3; i++)
        for (j = 0; j < 3; j++) {
            if (!isok(i + x - 1, j + y - 1)) {
                explmask[i][j] = 2;
                continue;
            } else
                explmask[i][j] = 0;

            if (i + x - 1 == u.ux && j + y - 1 == u.uy) {
                switch (adtyp) {
                case AD_PHYS:
                    explmask[i][j] = 0;
                    break;
                case AD_MAGM:
                    explmask[i][j] = !!(raylevel >= P_EXPERT || Antimagic);
                    break;
                case AD_FIRE:
                    explmask[i][j] = !!Fire_resistance;
                    break;
                case AD_COLD:
                    explmask[i][j] = !!Cold_resistance;
                    break;
                case AD_SLEE:
                    explmask[i][j] = !!Sleep_resistance;
                    break;
                case AD_DISN:
                    if (raylevel == P_UNSKILLED && Drain_resistance)
                        resist_death = TRUE;
                    /* why MR doesn't resist general deathfields is beyond me, but... */
                    if (nonliving(youmonst.data) ||
                            is_demon(youmonst.data))
                        resist_death = TRUE;
                    if (raylevel && Antimagic)
                        resist_death = TRUE;
                    if (raylevel >= P_EXPERT && !Drain_resistance)
                        resist_death = FALSE;
                    explmask[i][j] =
                        (olet == WAND_CLASS) ? !!resist_death :
                        !!Disint_resistance;
                    break;
                case AD_ELEC:
                    explmask[i][j] = !!Shock_resistance;
                    break;
                case AD_DRST:
                    explmask[i][j] = !!Poison_resistance;
                    break;
                case AD_ACID:
                    explmask[i][j] = !!Acid_resistance;
                    break;
                default:
                    impossible("explosion type %d?", adtyp);
                    break;
                }
            }
            /* can be both you and mtmp if you're swallowed */
            mtmp = m_at(level, i + x - 1, j + y - 1);
            if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
                mtmp = u.usteed;
            if (mtmp) {
                if (mtmp->mhp < 1)
                    explmask[i][j] = 2;
                else
                    switch (adtyp) {
                    case AD_PHYS:
                        break;
                    case AD_MAGM:
                        explmask[i][j] |= (raylevel >= 4 || resists_magm(mtmp));
                        break;
                    case AD_FIRE:
                        explmask[i][j] |= resists_fire(mtmp);
                        break;
                    case AD_COLD:
                        explmask[i][j] |= resists_cold(mtmp);
                        break;
                    case AD_SLEE:
                        explmask[i][j] |= resists_sleep(mtmp);
                    case AD_DISN:
                        if (raylevel == P_UNSKILLED && resists_drli(mtmp))
                            resist_death = TRUE;
                        if (nonliving(mtmp->data) ||
                                is_demon(mtmp->data))
                            resist_death = TRUE;
                        if (raylevel && resists_magm(mtmp))
                            resist_death = TRUE;
                        if (raylevel >= P_EXPERT && !resists_drli(mtmp))
                            resist_death = FALSE;
                        explmask[i][j] |=
                            (olet == WAND_CLASS) ? resist_death :
                            resists_disint(mtmp);
                        break;
                    case AD_ELEC:
                        explmask[i][j] |= resists_elec(mtmp);
                        break;
                    case AD_DRST:
                        explmask[i][j] |= resists_poison(mtmp);
                        break;
                    case AD_ACID:
                        explmask[i][j] |= resists_acid(mtmp);
                        break;
                    default:
                        impossible("explosion type %d?", adtyp);
                        break;
                    }
            }
            reveal_monster_at(i + x - 1, j + y - 1, TRUE);

            if (cansee(i + x - 1, j + y - 1))
                visible = TRUE;
            if (explmask[i][j] == 1)
                any_shield = TRUE;
        }

    if (visible) {
        struct tmp_sym *tsym = tmpsym_init(DISP_BEAM, 0);

        /* Start the explosion */
        for (i = 0; i < 3; i++)
            for (j = 0; j < 3; j++) {
                if (explmask[i][j] == 2)
                    continue;
                tmpsym_change(tsym, dbuf_explosion(expltype, explosion[i][j]));
                tmpsym_at(tsym, i + x - 1, j + y - 1);
            }
        flush_screen(); /* will flush screen and output */

        if (any_shield && flags.sparkle) {      /* simulate shield effect */
            for (k = 0; k < SHIELD_COUNT; k++) {
                for (i = 0; i < 3; i++)
                    for (j = 0; j < 3; j++) {
                        if (explmask[i][j] == 1)
                            /*
                             * Bypass tmpsym_at() and send the shield glyphs
                             * directly to the buffered screen.  tmpsym_at()
                             * will clean up the location for us later.
                             */
                            dbuf_set_effect(i + x - 1, j + y - 1,
                                            dbuf_effect(E_MISC,
                                                        shield_static[k]));
                    }
                flush_screen(); /* will flush screen and output */
                win_delay_output();
            }

            /* Cover last shield glyph with blast symbol. */
            for (i = 0; i < 3; i++)
                for (j = 0; j < 3; j++) {
                    if (explmask[i][j] == 1)
                        dbuf_set_effect(i + x - 1, j + y - 1,
                                        dbuf_explosion(expltype,
                                                       explosion[i][j]));
                }

        } else {        /* delay a little bit. */
            win_delay_output();
            win_delay_output();
        }

        tmpsym_end(tsym);       /* clear the explosion */
    } else {
        if (olet == MON_EXPLODE) {
            str = "explosion";
        }
        You_hear("a blast.");
    }

    if (dam)
        for (i = 0; i < 3; i++)
            for (j = 0; j < 3; j++) {
                if (explmask[i][j] == 2)
                    continue;
                if (i + x - 1 == u.ux && j + y - 1 == u.uy)
                    uhurt = (explmask[i][j] == 1) ? 1 : 2;
                idamres = idamnonres = 0;
                if (type >= 0)
                    zap_over_floor((xchar) (i + x - 1), (xchar) (j + y - 1),
                                   type, &shopdamage);

                mtmp = m_at(level, i + x - 1, j + y - 1);
                if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
                    mtmp = u.usteed;
                if (!mtmp)
                    continue;
                if (Engulfed && mtmp == u.ustuck) {
                    if (is_animal(u.ustuck->data))
                        pline("%s gets %s!", Monnam(u.ustuck),
                              (adtyp == AD_FIRE) ? "heartburn" :
                              (adtyp == AD_COLD) ? "chilly" :
                              (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
                                                    "irradiated by pure energy"
                                                    : "perforated") :
                              (adtyp == AD_ELEC) ? "shocked" :
                              (adtyp == AD_DRST) ? "poisoned" :
                              (adtyp == AD_ACID) ? "an upset stomach" :
                              "fried");
                    else
                        pline("%s gets slightly %s!", Monnam(u.ustuck),
                              (adtyp == AD_FIRE) ? "toasted" :
                              (adtyp == AD_COLD) ? "chilly" :
                              (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
                                                    "overwhelmed by pure energy"
                                                    : "perforated") :
                              (adtyp == AD_ELEC) ? "shocked" :
                              (adtyp == AD_DRST) ? "intoxicated" :
                              (adtyp == AD_ACID) ? "burned" : "fried");
                } else if (cansee(i + x - 1, j + y - 1)) {
                    if (mtmp->m_ap_type) seemimic(mtmp);
                    pline("%s is caught in %s%s!", Monnam(mtmp),
                          expl_needs_the ? "the " : "", dispbuf);
                }

                idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int)adtyp);
                idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int)adtyp);
                idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int)adtyp);
                idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int)adtyp);
                idamnonres += destroy_mitem(mtmp, RING_CLASS, (int)adtyp);

                if (explmask[i][j] == 1) {
                    golemeffects(mtmp, (int)adtyp, dam + idamres);
                    mtmp->mhp -= idamnonres;
                } else {
                    /* call resist with 0 and do damage manually so 1) we can
                       get out the message before doing the damage, and 2) we
                       can call mondied, not killed, if it's not your blast */
                    int mdam = dam;

                    if (resist(mtmp, olet, 0, FALSE)) {
                        if (cansee(i + x - 1, j + y - 1))
                            pline("%s resists %s%s!", Monnam(mtmp),
                                  expl_needs_the ? "the " : "", dispbuf);
                        mdam = dam / 2;
                    }
                    if (mtmp == u.ustuck)
                        mdam *= 2;
                    if (resists_cold(mtmp) && adtyp == AD_FIRE)
                        mdam *= 2;
                    else if (resists_fire(mtmp) && adtyp == AD_COLD)
                        mdam *= 2;
                    if (adtyp == AD_MAGM && raylevel >= P_EXPERT && resists_magm(mtmp))
                        mdam = (mdam + 1) / 2;
                    if (adtyp == AD_SLEE && raylevel) {
                        sleep_monst(mtmp, mdam, WAND_CLASS);
                        mdam = 0;
                    }
                    if (adtyp == AD_DISN && raylevel) {
                        if (nonliving(mtmp->data) ||
                                is_demon(mtmp->data) ||
                                resists_magm(mtmp) ||
                                raylevel == P_UNSKILLED) {
                            /* monster is deathresistant or raylevel==unskilled,
                               since monster apparently failed to resist earlier,
                               monster must be vulnerable to drli */
                            /* FIXME: make a generic losexp() for monsters */
                            mdam = dice(2, 6);
                            if (cansee(i + x - 1, j + y - 1))
                                pline("%s suddenly seems weaker!", Monnam(mtmp));
                            mtmp->mhpmax -= mdam;
                            if (mtmp->m_lev == 0)
                                mdam = mtmp->mhp;
                            else
                                mtmp->m_lev--;
                        } else
                            mdam = mtmp->mhp; /* instadeath */
                    }
                    mtmp->mhp -= mdam;
                    mtmp->mhp -= (idamres + idamnonres);
                }
                if (mtmp->mhp <= 0) {
                    /* KMH -- Don't blame the player for pets killing gas
                       spores */
                    if (!flags.mon_moving)
                        killed(mtmp);
                    else
                        monkilled(mtmp, "", (int)adtyp);
                } else if (!flags.mon_moving)
                    setmangry(mtmp);
            }

    /* Do your injury last */
    if (uhurt) {
        if ((type >= 0 || adtyp == AD_PHYS) &&  /* gas spores */
                flags.verbose && olet != SCROLL_CLASS)
            pline("You are caught in %s%s!", expl_needs_the ? "the " : "",
                  dispbuf);
        /* do property damage first, in case we end up leaving bones */
        if (adtyp == AD_FIRE)
            burn_away_slime();
        if (u.uinvulnerable) {
            damu = 0;
            pline("You are unharmed!");
        } else if (Half_physical_damage && adtyp == AD_PHYS)
            damu = (damu + 1) / 2;
        else if (raylevel) {
            if (adtyp == AD_MAGM && Antimagic)
                damu = (damu + 1) / 2;
            if (adtyp == AD_SLEE) {
                helpless(damu, hr_asleep, "sleeping", NULL);
                damu = 0;
            }
            if (adtyp == AD_DISN) {
                if (nonliving(youmonst.data) ||
                        is_demon(youmonst.data) ||
                        Antimagic ||
                        raylevel == P_UNSKILLED) {
                    losexp("drained by a death field",FALSE);
                    damu = 0;
                } else {
                    done(DIED, "killed by a death field");
                    damu = 0; /* lifesaved */
                }
            }
        }
        if (adtyp == AD_FIRE) {
            burnarmor(&youmonst);
            set_candles_afire();
        }
        destroy_item(SCROLL_CLASS, (int)adtyp);
        destroy_item(SPBOOK_CLASS, (int)adtyp);
        destroy_item(POTION_CLASS, (int)adtyp);
        destroy_item(RING_CLASS, (int)adtyp);
        destroy_item(WAND_CLASS, (int)adtyp);

        ugolemeffects((int)adtyp, damu);
        if (uhurt == 2) {
            if (Upolyd)
                u.mh -= damu;
            else
                u.uhp -= damu;
        }

        if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
            int death = adtyp == AD_FIRE ? BURNING : DIED;
            const char *killer;

            if (olet == MON_EXPLODE) {
                killer = killer_msg(death, an(str));
            } else if (type >= 0 && olet != SCROLL_CLASS) {
                /* check whether or not we were the source of the explosion */
                if (!flags.mon_moving)
                    killer = msgprintf("caught %sself in %s own %s", uhim(),
                                       uhis(), str);
                else
                    killer = msgprintf("killed by a %s", str);
            } else if (!strcmp(str, "burning oil")) {
                /* This manual check hack really sucks */
                killer = killer_msg(death, str);
            } else {
                killer = killer_msg(death, an(str));
            }
            /* Known BUG: BURNING suppresses corpse in bones data, but done
               does not handle killer reason correctly */
            if (Upolyd) {
                rehumanize(death, killer);
            } else {
                done(death, killer);
            }
        }
        exercise(A_STR, FALSE);
    }

    if (shopdamage) {
        pay_for_damage(adtyp == AD_FIRE ? "burn away" : adtyp ==
                       AD_COLD ? "shatter" : adtyp ==
                       AD_DISN ? "disintegrate" : "destroy", FALSE);
    }

    /* explosions are noisy */
    i = dam * dam;
    if (i < 50)
        i = 50; /* in case random damage is very small */
    wake_nearto(x, y, i);
}
Esempio n. 7
0
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;

    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);
    }
    /* KMH -- February 2 */
    flags.groundhogday = groundhog_day();
    if (flags.groundhogday)
	pline("Happy Groundhog Day!");

    initrack();


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

#ifdef WIZARD
    if (wizard) add_debug_extended_commands();
#endif

    (void) encumber_msg(); /* in case they auto-picked up something */
    if (defer_see_monsters) {
	defer_see_monsters = FALSE;
	see_monsters();
    }

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

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

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

	    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;

		if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
		    /* both you and the monsters are out of steam this round */
		    /* set up for a new turn */
		    struct monst *mtmp;
		    mcalcdistress();	/* adjust monsters' trap, blind, etc */

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

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

		    /* calculate how much time passed. */
#ifdef STEED
		    if (u.usteed && u.umoved) {
			/* your speed doesn't augment steed's speed */
			moveamt = mcalcmove(u.usteed);
		    } 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;
			}
			if (tech_inuse(T_BLINK)) { /* TECH: Blinking! */
			    /* Case    Average  Variance
			     * -------------------------
			     * Normal    12         0
			     * Fast      16        12
			     * V fast    20        12
			     * Blinking  24        12
			     * F & B     28        18
			     * V F & B   30        18
			     */
			    moveamt += NORMAL_SPEED * 2 / 3;
			    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;
		    settrack();

		    monstermoves++;
		    moves++;

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

		    if (flags.bypasses) clear_bypasses();
		    if(Glib) glibr();
		    nh_timeout();
		    run_regions();

#ifdef DUNGEON_GROWTH
		    dgn_growths(TRUE, TRUE);
#endif

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

		    /* 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;
		    } 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();
		    } else if (Upolyd && u.mh < u.mhmax) {
			if (u.mh < 1)
			    rehumanize();
			else if (Regeneration ||
				    (wtcap < MOD_ENCUMBER && !(moves%20))) {
			    flags.botl = 1;
			    u.mh++;
			}
		    } else if (u.uhp < u.uhpmax &&
			 (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) {
/*
 * KMH, balance patch -- New regeneration code
 * Healthstones have been added, which alter your effective
 * experience level and constitution (-2 cursed, +1 uncursed,
 * +2 blessed) for the basis of regeneration calculations.
 */

 			int efflev = u.ulevel + u.uhealbonus;
 			int effcon = ACURR(A_CON) + u.uhealbonus;
			int heal = 1;


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

		    if (!u.uinvulnerable && u.uen > 0 && u.uhp < u.uhpmax &&
			    tech_inuse(T_CHI_HEALING)) {
			u.uen--;
			u.uhp++;
			flags.botl = 1;
		    }

		    /* 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);
			    }
			}
		    }

		    
		    /* KMH -- OK to regenerate if you don't move */
		    if ((u.uen < u.uenmax) && (Energy_regeneration ||
				((wtcap < MOD_ENCUMBER || !flags.mv) &&
				(!(moves%((MAXULEV + 15 - u.ulevel) *                                    
				(Role_if(PM_WIZARD) ? 3 : 4) / 6)))))) {
			u.uen += rn1((int)(ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1,1);
#ifdef WIZ_PATCH_DEBUG
                pline("mana was = %d now = %d",temp,u.uen);
#endif

			if (u.uen > u.uenmax)  u.uen = u.uenmax;
			flags.botl = 1;
		    }

		    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(&youmonst, old_ux, old_uy, TRUE);
				}
#ifdef REDO
				/* clear doagain keystrokes */
				pushch(0);
				savech(0);
#endif
			    }
			}
			long ch = (80 - (40 * night())) / 2 * 
					 (Race_if(PM_HUMAN_WEREWOLF) ? 
					  u.ulevel * u.ulevel :
					  2);
			ch = (ch > LARGEST_INT) ? LARGEST_INT : ch;
			/* delayed change may not be valid anymore */
			if ((change == 1 && !Polymorph) ||
			    (change == 2 && u.ulycn == NON_PM))
			    change = 0;
			if(Polymorph && !rn2(100))
			    change = 1;
			else if (u.ulycn >= LOW_PM && !Upolyd &&
				 !rn2((int)ch))
			    change = 2;
			if (change && !Unchanging) {
			    if (multi >= 0) {
				if (occupation)
				    stop_occupation();
				else
				    nomul(0);
				if (change == 1) polyself(FALSE);
				else you_were();
				change = 0;
			    }
			}
		}	/* !u.uinvulnerable */

		    if(Searching && multi >= 0) (void) dosearch0(1);
		    dosounds();
		    do_storms();
		    gethungry();
		    age_spells();
		    exerchk();
		    invault();
		    if (u.uhave.amulet) amulet();
		if (!rn2(40+(int)(ACURR(A_DEX)*3))) u_wipe_engr(rnd(3));
		    if (u.uevent.udemigod && !u.uinvulnerable) {
			if (u.udg_cnt) u.udg_cnt--;
			if (!u.udg_cnt) {
			    intervene();
			    u.udg_cnt = rn1(200, 50);
			}
		    }
		    restore_attrib();

		    /* underwater and waterlevel vision are done here */
		    if (Is_waterlevel(&u.uz))
			movebubbles();
		    else if (Underwater)
			under_water(0);
		    /* vision while buried done here */
		    else if (u.uburied) under_ground(0);

		    /* 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();
			}
		    }
		}
	    } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */

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


	} /* actual time passed */

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

	find_ac();
	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();

	    if (vision_full_recalc) vision_recalc(0);	/* vision! */
	}
	if(flags.botl || flags.botlx) bot();

	flags.move = 1;

	if(multi >= 0 && occupation) {
#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 defined(MICRO) || defined(WIN32)
	    if (!(++occtime % 7))
		display_nhwindow(WIN_MAP, FALSE);
#endif
	    continue;
	}

	if ((u.uhave.amulet || Clairvoyant) &&
	    !In_endgame(&u.uz) && !BClairvoyant &&
	    !(moves % 15) && !rn2(2))
		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);
		}
	    }
	}

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

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

	u.umoved = FALSE;

	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);
	    }
	} else if (multi == 0) {
#ifdef MAIL
	    ckmailstatus();
#endif
	    rhack((char *)0);
	}
	if (u.utotype)		/* change dungeon level */
	    deferred_goto();	/* after rhack() */
	/* !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! */
	/* 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);
	}
    }
}
Esempio n. 8
0
static void you_moved(void)
{
    int moveamt = 0, wtcap = 0, change = 0;
    boolean monscanmove = FALSE;

    /* Begin turn-tracking for delay_msg. */
    if (delay_start == 0)
	delay_start = moves;

    /* actual time passed */
    youmonst.movement -= NORMAL_SPEED;

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

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

	if (!monscanmove && youmonst.movement < NORMAL_SPEED) {
	    /* both you and the monsters are out of steam this round */
	    /* set up for a new turn */
	    struct monst *mtmp;
	    mcalcdistress();	/* adjust monsters' trap, blind, etc */

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

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

	    /* calculate how much time passed. */
	    if (u.usteed && u.umoved) {
		/* your speed doesn't augment steed's speed */
		moveamt = mcalcmove(u.usteed);
	    } else {
		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;
	    settrack();

	    moves++;
	    level->lastmoves = moves;

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

	    if (flags.bypasses) clear_bypasses();
	    if (Glib) glibr();
	    nh_timeout();
	    run_regions(level);
	    dgn_growths(level, TRUE, TRUE);

	    if (u.ublesscnt)  u.ublesscnt--;
	    iflags.botl = 1;

	    /* 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;
	    } else if (Upolyd && youmonst.data->mlet == S_EEL &&
		!is_pool(level, u.ux,u.uy) && !Is_waterlevel(&u.uz)) {
		if (u.mh > 1) {
		    u.mh--;
		    iflags.botl = 1;
		} else if (u.mh < 1)
		    rehumanize();
	    } else if (Upolyd && u.mh < u.mhmax) {
		if (u.mh < 1)
		    rehumanize();
		else if (Regeneration ||
			    (wtcap < MOD_ENCUMBER && !(moves%20))) {
		    iflags.botl = 1;
		    u.mh++;
		    interrupt_multi("Hit points", u.mh, u.mhmax);
		}
	    } 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;
		    }
		    iflags.botl = 1;
		    u.uhp += heal;
		    if (u.uhp > u.uhpmax)
			u.uhp = u.uhpmax;
		    interrupt_multi("Hit points", u.uhp, u.uhpmax);
		} else if (Regeneration ||
			(u.ulevel <= 9 &&
			!(moves % ((MAXULEV+12) / (u.ulevel+2) + 1)))) {
		    iflags.botl = 1;
		    u.uhp++;
		    interrupt_multi("Hit points", u.uhp, u.uhpmax);
		}
	    }

	    /* 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 {
			pline("你用力过度昏倒了!");
			exercise(A_CON, FALSE);
			fall_asleep(-10, FALSE);
		    }
		}
	    }

	    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;
		iflags.botl = 1;
		interrupt_multi("Magic energy", u.uen, u.uenmax);
	    }

	    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);
			}
		    }
		}
		/* delayed change may not be valid anymore */
		if ((change == 1 && !Polymorph) ||
		    (change == 2 && u.ulycn == NON_PM))
		    change = 0;
		if (Polymorph && !rn2(100))
		    change = 1;
		else if (u.ulycn >= LOW_PM && !Upolyd &&
			    !rn2(80 - (20 * night())))
		    change = 2;
		if (change && !Unchanging) {
		    if (multi >= 0) {
			if (occupation)
			    stop_occupation();
			else
			    nomul(0, NULL);
			if (change == 1) polyself(FALSE);
			else you_were();
			change = 0;
		    }
		}
	    }

	    if (Searching && multi >= 0) dosearch0(1);
	    dosounds();
	    do_storms();
	    gethungry();
	    age_spells();
	    exerchk();
	    invault();
	    if (u.uhave.amulet) amulet();
	    if (!rn2(40+(int)(ACURR(A_DEX)*3)))
		u_wipe_engr(rnd(3));
	    if (u.uevent.udemigod && !u.uinvulnerable) {
		if (u.udg_cnt) u.udg_cnt--;
		if (!u.udg_cnt) {
		    intervene();
		    u.udg_cnt = rn1(200, 50);
		}
	    }
	    restore_attrib();
	    /* underwater and waterlevel vision are done here */
	    if (Is_waterlevel(&u.uz))
		movebubbles();
	    else if (Underwater)
		under_water(0);
	    /* vision while buried done here */
	    else if (u.uburied) under_ground(0);

	    /* when immobile, count is in turns */
	    if (multi < 0) {
		if (++multi == 0) {	/* finished yet? */
		    unmul(NULL);
		    /* if unmul caused a level change, take it now */
		    if (u.utotype) deferred_goto();
		}
	    }
	}
    } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */

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

    if (u.utrap && u.utraptype == TT_LAVA)
	handle_lava_trap(TRUE);

    if (iflags.hp_notify && prev_hp_notify != uhp()) {
	pline("%s", hp_notify_format_str(iflags.hp_notify_fmt ?
					 iflags.hp_notify_fmt : "[HP%c%a=%h]"));
	prev_hp_notify = uhp();
    }
}