void losexp(const char *drainer) /* e.g., hit by drain life attack */ /* cause of death, if drain should be fatal */ { register int num; #ifdef WIZARD /* override life-drain resistance when handling an explicit wizard mode request to reduce level; never fatal though */ if (drainer && !strcmp(drainer, "#levelchange")) drainer = 0; else #endif if (resists_drli(&youmonst)) return; if (u.ulevel > 1) { pline("%s level %d.", Goodbye(), u.ulevel--); /* remove intrinsic abilities */ adjabil(u.ulevel + 1, u.ulevel); reset_rndmonst(NON_PM); /* new monster selection */ } else { if (drainer) { killer_format = KILLED_BY; killer = drainer; done(DIED); } /* no drainer or lifesaved */ u.uexp = 0; } num = newhp(); u.uhpmax -= num; check_uhpmax(); if (u.uhpmax < 1) u.uhpmax = 1; u.uhp -= num; if (u.uhp < 1) u.uhp = 1; else if (u.uhp > u.uhpmax) u.uhp = u.uhpmax; if (u.ulevel < urole.xlev) num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd, urole.enadv.lofix + urace.enadv.lofix); else num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd, urole.enadv.hifix + urace.enadv.hifix); num = enermod(num); /* M. Stephenson */ u.uenmax -= num; if (u.uenmax < 0) u.uenmax = 0; u.uen -= num; if (u.uen < 0) u.uen = 0; else if (u.uen > u.uenmax) u.uen = u.uenmax; if (u.uexp > 0) u.uexp = newuexp(u.ulevel) - 1; flags.botl = 1; }
void exercise(int i, boolean inc_or_dec) { if (i == A_INT || i == A_CHA) return; /* can't exercise these */ /* no physical exercise while polymorphed; the body's temporary */ if (Upolyd && i != A_WIS) return; if (abs(AEXE(i)) < AVAL) { /* * Law of diminishing returns (Part I): * * Gain is harder at higher attribute values. * 79% at "3" --> 0% at "18" * Loss is even at all levels (50%). * * Note: *YES* ACURR is the right one to use. */ AEXE(i) += (inc_or_dec) ? (rn2(19) > ACURR(i)) : -rn2(2); } if (moves > 0 && (i == A_STR || i == A_CON)) encumber_msg(); }
/* condense clumsy ACURR(A_STR) value into value that fits into game formulas */ signed char acurrstr (void) { int str = ACURR(A_STR); if (str <= 18) return((signed char)str); if (str <= 121) return((signed char)(19 + str / 50)); /* map to 19-21 */ else return((signed char)(str - 100)); }
int dothrow() { register struct obj *obj; if(check_capacity(NULL)) return(0); obj = getobj(toss_objs, "throw"); /* it is also possible to throw food */ /* (or jewels, or iron balls... ) */ if(!obj || !getdir(NULL)) { /* ask "in what direction?" */ if (obj && obj->oclass == GOLD_CLASS) { u.ugold += obj->quan; flags.botl = 1; dealloc_obj(obj); } return(0); } if(obj->oclass == GOLD_CLASS) return(throw_gold(obj)); if(!canletgo(obj,"throw")) return(0); if (obj->oartifact == ART_MJOLLNIR && obj != uwep) { You("must be wielding %s in order to throw it.", xname(obj)); return(0); } if ((obj->oartifact == ART_MJOLLNIR && ACURR(A_STR) != 125) || (obj->otyp == BOULDER #ifdef POLYSELF && !throws_rocks(uasmon) #endif )) { pline("It's too heavy."); return(1); } if(!u.dx && !u.dy && !u.dz) { You("cannot throw an object at yourself."); return(0); } u_wipe_engr(2); if(obj == uwep) { if(welded(obj)) { weldmsg(obj, FALSE); return(1); } if(obj->quan > 1L) setuwep(splitobj(obj, 1L)); else { setuwep((struct obj *)0); if (uwep) return(1); /* unwielded, died, rewielded */ } } else if(obj->quan > 1L) (void) splitobj(obj, 1L); freeinv(obj); return(throwit(obj)); }
int do_mname(void) { char buf[BUFSZ]; coord cc; int cx,cy; struct monst *mtmp; char qbuf[QBUFSZ]; if (Hallucination) { pline("You would never recognize it anyway."); return 0; } cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, FALSE, "the monster you want to name") < 0 || (cx = cc.x) < 0) return 0; cy = cc.y; if (cx == u.ux && cy == u.uy) { if (u.usteed && canspotmon(u.usteed)) mtmp = u.usteed; else { pline("This %s creature is called %s and cannot be renamed.", ACURR(A_CHA) > 14 ? (flags.female ? "beautiful" : "handsome") : "ugly", plname); return 0; } } else mtmp = m_at(level, cx, cy); if (!mtmp || (!sensemon(mtmp) && (!(cansee(cx,cy) || see_with_infrared(mtmp)) || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT || (mtmp->minvis && !See_invisible)))) { pline("I see no monster there."); return 0; } /* special case similar to the one in lookat() */ distant_monnam(mtmp, ARTICLE_THE, buf); sprintf(qbuf, "What do you want to call %s?", buf); getlin(qbuf,buf); if (!*buf || *buf == '\033') return 0; /* strip leading and trailing spaces; unnames monster if all spaces */ mungspaces(buf); if (mtmp->data->geno & G_UNIQ) { distant_monnam(mtmp, ARTICLE_THE, buf); *buf = highc(*buf); pline("%s doesn't like being called names!", buf); } else christen_monst(mtmp, buf); return 0; }
void pluslvl(boolean incr) /* true iff via incremental experience growth */ { /* (false for potion of gain level) */ register int num; if (!incr) You_feel("more experienced."); num = newhp(); u.uhpmax += num; u.uhp += num; if (Upolyd) { num = rnd(8); u.mhmax += num; u.mh += num; } if (u.ulevel < urole.xlev) num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd, urole.enadv.lofix + urace.enadv.lofix); else num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd, urole.enadv.hifix + urace.enadv.hifix); num = enermod(num); /* M. Stephenson */ if (!Role_if(PM_TOURIST)) { /* Tourists have no innate magic abilities */ u.uenmax += num; u.uen += num; } if (u.ulevel < MAXULEV) { if (incr) { long tmp = newuexp(u.ulevel + 1); if (u.uexp >= tmp) u.uexp = tmp - 1; } else { u.uexp = newuexp(u.ulevel); } ++u.ulevel; if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel; pline("Welcome to experience level %d.", u.ulevel); adjabil(u.ulevel - 1, u.ulevel); /* give new intrinsics */ reset_rndmonst(NON_PM); /* new monster selection */ } flags.botl = 1; }
/* adjust an attribute; return true if change is made, false otherwise */ // int msgflg; /* positive => no message, zero => message, and */ // /* negative => conditional (msg if change made) */ bool adjattrib(int ndx, int incr, int msgflg) { if (Fixed_abil || !incr) return false; if ((ndx == A_INT || ndx == A_WIS) && uarmh && uarmh->otyp == DUNCE_CAP) { if (msgflg == 0) Your("cap constricts briefly, then relaxes again."); return false; } if (incr > 0) { if ((AMAX(ndx) >= ATTRMAX(ndx)) && (ACURR(ndx) >= AMAX(ndx))) { if (msgflg == 0 && flags.verbose) pline("You're already as %s as you can get.", plusattr[ndx]); ABASE(ndx) = AMAX(ndx) = ATTRMAX(ndx); /* just in case */ return false; } ABASE(ndx) += incr; if(ABASE(ndx) > AMAX(ndx)) { incr = ABASE(ndx) - AMAX(ndx); AMAX(ndx) += incr; if(AMAX(ndx) > ATTRMAX(ndx)) AMAX(ndx) = ATTRMAX(ndx); ABASE(ndx) = AMAX(ndx); } } else { if (ABASE(ndx) <= ATTRMIN(ndx)) { if (msgflg == 0 && flags.verbose) pline("You're already as %s as you can get.", minusattr[ndx]); ABASE(ndx) = ATTRMIN(ndx); /* just in case */ return false; } ABASE(ndx) += incr; if(ABASE(ndx) < ATTRMIN(ndx)) { incr = ABASE(ndx) - ATTRMIN(ndx); ABASE(ndx) = ATTRMIN(ndx); AMAX(ndx) += incr; if(AMAX(ndx) < ATTRMIN(ndx)) AMAX(ndx) = ATTRMIN(ndx); } } if (msgflg <= 0) You_feel("%s%s!", (incr > 1 || incr < -1) ? "very ": "", (incr > 0) ? plusattr[ndx] : minusattr[ndx]); if (moves > 1 && (ndx == A_STR || ndx == A_CON)) (void)encumber_msg(); return true; }
/* Finds the probability per turn of succeeding in unlocking a lock. */ static int get_unlock_chance(void) { struct obj *pick = get_current_unlock_tool(); int factor; if (!pick) return 0; factor = pick->cursed ? 2 : 1; switch (pick->otyp) { case CREDIT_CARD: return (2 * ACURR(A_DEX) + 20 * Role_if(PM_ROGUE)) / factor; case LOCK_PICK: return (3 * ACURR(A_DEX) + 30 * Role_if(PM_ROGUE)) / factor; case SKELETON_KEY: return (70 + ACURR(A_DEX)) / factor; default: return 0; } }
void restore_attrib (void) { int i; for(i = 0; i < A_MAX; i++) { /* all temporary losses/gains */ if(ATEMP(i) && ATIME(i)) { if(!(--(ATIME(i)))) { /* countdown for change */ ATEMP(i) += ATEMP(i) > 0 ? -1 : 1; if(ATEMP(i)) /* reset timer */ ATIME(i) = 100 / ACURR(A_CON); } } } (void)encumber_msg(); }
int newhp(void) { int hp, conplus; if (u.ulevel == 0) { /* Initialize hit points */ hp = urole.hpadv.infix + urace.hpadv.infix; if (urole.hpadv.inrnd > 0) hp += 1 + rn2_on_rng(urole.hpadv.inrnd, rng_charstats_role); if (urace.hpadv.inrnd > 0) hp += 1 + rn2_on_rng(urace.hpadv.inrnd, rng_charstats_race); /* Initialize alignment stuff */ u.ualign.type = aligns[u.initalign].value; u.ualign.record = urole.initrecord; return hp; } else { if (u.ulevel < urole.xlev) { hp = urole.hpadv.lofix + urace.hpadv.lofix; if (urole.hpadv.lornd > 0) hp += 1 + rn2_on_rng(urole.hpadv.lornd, rng_charstats_role); if (urace.hpadv.lornd > 0) hp += 1 + rn2_on_rng(urace.hpadv.lornd, rng_charstats_race); } else { hp = urole.hpadv.hifix + urace.hpadv.hifix; if (urole.hpadv.hirnd > 0) hp += 1 + rn2_on_rng(urole.hpadv.hirnd, rng_charstats_role); if (urace.hpadv.hirnd > 0) hp += 1 + rn2_on_rng(urace.hpadv.hirnd, rng_charstats_race); } } if (ACURR(A_CON) <= 3) conplus = -2; else if (ACURR(A_CON) <= 6) conplus = -1; else if (ACURR(A_CON) <= 14) conplus = 0; else if (ACURR(A_CON) <= 16) conplus = 1; else if (ACURR(A_CON) == 17) conplus = 2; else if (ACURR(A_CON) == 18) conplus = 3; else conplus = 4; hp += conplus; return (hp <= 0) ? 1 : hp; }
int dotwoweapon(void) { /* You can always toggle it off */ if (u.twoweap) { pline("You switch to your primary weapon."); u.twoweap = 0; update_inventory(); return 0; } /* May we use two weapons? */ if (can_twoweapon()) { /* Success! */ pline("You begin two-weapon combat."); u.twoweap = 1; update_inventory(); return rnd(20) > ACURR(A_DEX); } return 0; }
/* try to close a door */ int doclose(const struct nh_cmd_arg *arg) { struct rm *door; struct monst *mtmp; coord cc; schar dx, dy, dz; if (nohands(youmonst.data)) { pline(msgc_cancelled, "You can't close anything -- you have no hands!"); return 0; } if (u.utrap && u.utraptype == TT_PIT) { pline(msgc_cancelled, "You can't reach over the edge of the pit."); return 0; } if (!getargdir(arg, NULL, &dx, &dy, &dz)) return 0; cc.x = youmonst.mx + dx; cc.y = youmonst.my + dy; if (!isok(cc.x, cc.y)) return 0; if ((cc.x == youmonst.mx) && (cc.y == youmonst.my)) { pline(msgc_cancelled1, "You are in the way!"); return 1; } if ((mtmp = m_at(level, cc.x, cc.y)) && mtmp->m_ap_type == M_AP_FURNITURE && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp, dx, dy); return 1; } door = &level->locations[cc.x][cc.y]; if (!IS_DOOR(door->typ)) { if (door->typ == DRAWBRIDGE_DOWN) pline(msgc_cancelled, "There is no obvious way to close the drawbridge."); else pline(msgc_mispaste, "You %s no door there.", Blind ? "feel" : "see"); return 0; } if (door->doormask == D_NODOOR) { pline(msgc_cancelled, "This doorway has no door."); return 0; } if (obstructed(cc.x, cc.y, msgc_cancelled)) return 0; if (door->doormask == D_BROKEN) { pline(msgc_cancelled, "This door is broken."); return 0; } if (door->doormask & (D_CLOSED | D_LOCKED)) { pline(msgc_cancelled, "This door is already closed."); return 0; } if (door->doormask == D_ISOPEN) { if (verysmall(youmonst.data) && !u.usteed) { pline(msgc_cancelled, "You're too small to push the door closed."); return 0; } if (u.usteed || rn2(25) < (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3) { pline(msgc_actionok, "The door closes."); door->doormask = D_CLOSED; door->mem_door_l = 1; /* map_background here sets the mem_door flags correctly; and it's redundant to both feel_location and newsym with a door. Exception: if we remember an invisible monster on the door square, but in this case, we want to set the memory of a door there anyway because we know there's a door there because we just closed it, and in Nitro this doesn't clash with keeping the I there. */ map_background(cc.x, cc.y, TRUE); if (Blind) feel_location(cc.x, cc.y); /* the hero knows she closed it */ else newsym(cc.x, cc.y); block_point(cc.x, cc.y); /* vision: no longer see there */ } else { exercise(A_STR, TRUE); pline(msgc_failrandom, "The door resists!"); } } return 1; }
void polyself(boolean forcecontrol) { char buf[BUFSZ]; int old_light, new_light; int mntmp = NON_PM; int tries=0; boolean draconian = (uarm && uarm->otyp >= GRAY_DRAGON_SCALE_MAIL && uarm->otyp <= YELLOW_DRAGON_SCALES); boolean iswere = (u.ulycn >= LOW_PM || is_were(youmonst.data)); boolean isvamp = (youmonst.data->mlet == S_VAMPIRE || u.umonnum == PM_VAMPIRE_BAT); boolean was_floating = (Levitation || Flying); if (!Polymorph_control && !forcecontrol && !draconian && !iswere && !isvamp) { if (rn2(20) > ACURR(A_CON)) { pline("You shudder for a moment."); losehp(rnd(30), "system shock", KILLED_BY_AN); exercise(A_CON, FALSE); return; } } old_light = Upolyd ? emits_light(youmonst.data) : 0; if (Polymorph_control || forcecontrol) { do { getlin("Become what kind of monster? [type the name]", buf); mntmp = name_to_mon(buf); if (mntmp < LOW_PM) pline("I've never heard of such monsters."); /* Note: humans are illegal as monsters, but an * illegal monster forces newman(), which is what we * want if they specified a human.... */ else if (!polyok(&mons[mntmp]) && !your_race(&mons[mntmp])) pline("You cannot polymorph into that."); else break; } while (++tries < 5); if (tries==5) pline("That's enough tries!"); /* allow skin merging, even when polymorph is controlled */ if (draconian && (mntmp == armor_to_dragon(uarm->otyp) || tries == 5)) goto do_merge; } else if (draconian || iswere || isvamp) { /* special changes that don't require polyok() */ if (draconian) { do_merge: mntmp = armor_to_dragon(uarm->otyp); if (!(mvitals[mntmp].mvflags & G_GENOD)) { /* allow G_EXTINCT */ pline("You merge with your scaly armor."); uskin = uarm; uarm = NULL; /* save/restore hack */ uskin->owornmask |= I_SPECIAL; } } else if (iswere) { if (is_were(youmonst.data)) mntmp = PM_HUMAN; /* Illegal; force newman() */ else mntmp = u.ulycn; } else { if (youmonst.data->mlet == S_VAMPIRE) mntmp = PM_VAMPIRE_BAT; else mntmp = PM_VAMPIRE; } /* if polymon fails, "you feel" message has been given so don't follow up with another polymon or newman */ if (mntmp == PM_HUMAN) newman(); /* werecritter */ else polymon(mntmp); goto made_change; /* maybe not, but this is right anyway */ } if (mntmp < LOW_PM) { tries = 0; do { /* randomly pick an "ordinary" monster */ mntmp = rn1(SPECIAL_PM - LOW_PM, LOW_PM); } while ((!polyok(&mons[mntmp]) || is_placeholder(&mons[mntmp])) && tries++ < 200); } /* The below polyok() fails either if everything is genocided, or if * we deliberately chose something illegal to force newman(). */ if (!polyok(&mons[mntmp]) || !rn2(5) || your_race(&mons[mntmp])) newman(); else if (!polymon(mntmp)) return; if (!uarmg) selftouch("No longer petrify-resistant, you"); made_change: new_light = Upolyd ? emits_light(youmonst.data) : 0; if (old_light != new_light) { if (old_light) del_light_source(level, LS_MONSTER, &youmonst); if (new_light == 1) ++new_light; /* otherwise it's undetectable */ if (new_light) new_light_source(level, u.ux, u.uy, new_light, LS_MONSTER, &youmonst); } if (is_pool(level, u.ux,u.uy) && was_floating && !(Levitation || Flying) && !breathless(youmonst.data) && !amphibious(youmonst.data) && !Swimming) drown(); }
/* try to open a door */ int doopen(const struct nh_cmd_arg *arg) { coord cc; struct rm *door; struct monst *mtmp; schar dx, dy, dz; if (nohands(youmonst.data)) { pline(msgc_cancelled, "You can't open, close, or unlock anything " "-- you have no hands!"); return 0; } if (u.utrap && u.utraptype == TT_PIT) { pline(msgc_cancelled, "You can't reach over the edge of the pit."); return 0; } if (!getargdir(arg, NULL, &dx, &dy, &dz)) return 0; cc.x = youmonst.mx + dx; cc.y = youmonst.my + dy; if (!isok(cc.x, cc.y)) return 0; if ((cc.x == youmonst.mx) && (cc.y == youmonst.my)) return 0; if ((mtmp = m_at(level, cc.x, cc.y)) && mtmp->m_ap_type == M_AP_FURNITURE && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp, cc.x - youmonst.mx, cc.y - youmonst.my); return 1; } door = &level->locations[cc.x][cc.y]; if (!IS_DOOR(door->typ)) { if (is_db_wall(cc.x, cc.y)) { pline(msgc_cancelled, "There is no obvious way to open the drawbridge."); return 0; } pline(msgc_mispaste, "You %s no door there.", Blind ? "feel" : "see"); return 0; } if (door->doormask == D_ISOPEN) { struct nh_cmd_arg newarg; arg_from_delta(dx, dy, dz, &newarg); return doclose(&newarg); } if (!(door->doormask & D_CLOSED)) { const char *mesg; switch (door->doormask) { case D_BROKEN: mesg = " is broken"; break; case D_NODOOR: mesg = "way has no door"; break; case D_ISOPEN: mesg = " is already open"; break; default: if (last_command_was("open") && door->mem_door_l) { /* With the "open" command given explicitly (rather than implicitly via doorbumping), unlock the door. */ struct obj *bestpick = get_current_unlock_tool(); struct nh_cmd_arg newarg; arg_from_delta(dx, dy, dz, &newarg); if (!bestpick) pline(msgc_cancelled, "You have nothing to unlock that with."); else if (!bestpick->lastused) /* not msgc_controlhelp, or many players would get no message */ pline(msgc_hint, "Use an unlocking tool manually so I know " "which one you want to use."); else return pick_lock(bestpick, &newarg); } door->mem_door_l = 1; map_background(cc.x, cc.y, TRUE); mesg = " is locked"; break; } pline(msgc_cancelled, "This door%s.", mesg); if (Blind) feel_location(cc.x, cc.y); return 0; } if (verysmall(youmonst.data)) { pline(msgc_cancelled, "You're too small to pull the door open."); return 0; } /* door is known to be CLOSED */ if (rnl(20) < (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3) { pline(msgc_actionok, "The door opens."); if (door->doormask & D_TRAPPED) { b_trapped("door", FINGER); door->doormask = D_NODOOR; if (*in_rooms(level, cc.x, cc.y, SHOPBASE)) add_damage(cc.x, cc.y, 0L); } else door->doormask = D_ISOPEN; if (Blind) feel_location(cc.x, cc.y); /* the hero knows she opened it */ else newsym(cc.x, cc.y); unblock_point(cc.x, cc.y); /* vision: new see through there */ } else { exercise(A_STR, TRUE); door->mem_door_l = 1; map_background(cc.x, cc.y, TRUE); pline(msgc_failrandom, "The door resists!"); } return 1; }
int use_saddle(struct obj *otmp, const struct nh_cmd_arg *arg) { struct monst *mtmp; const struct permonst *ptr; int chance; const char *s; schar dx, dy, dz; /* Can you use it? */ if (nohands(youmonst.data)) { pline("You have no hands!"); /* not `body_part(HAND)' */ return 0; } else if (!freehand()) { pline("You have no free %s.", body_part(HAND)); return 0; } /* Select an animal */ if (Engulfed || Underwater || !getargdir(arg, NULL, &dx, &dy, &dz)) { pline("Never mind."); return 0; } if (!dx && !dy) { pline("Saddle yourself? Very funny..."); return 0; } if (!isok(u.ux + dx, u.uy + dy) || !((mtmp = m_at(level, u.ux + dx, u.uy + dy))) || !canspotmon(mtmp)) { if (knownwormtail(u.ux + dx, u.uy + dy)) pline("It's hard to strap a saddle to a tail."); else pline("I see nobody there."); return 0; } /* Is this a valid monster? */ if (mtmp->misc_worn_check & W_MASK(os_saddle) || which_armor(mtmp, os_saddle)) { pline("%s doesn't need another one.", Monnam(mtmp)); return 0; } ptr = mtmp->data; if (!uarmg && touched_monster(ptr - mons)) { pline("You touch %s.", mon_nam(mtmp)); instapetrify(killer_msg(STONING, msgcat("attempting to saddle ", an(mtmp->data->mname)))); } if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) { pline("Shame on you!"); exercise(A_WIS, FALSE); return 1; } if (mtmp->isminion || mtmp->isshk || mtmp->ispriest || mtmp->isgd || mtmp->iswiz) { pline("I think %s would mind.", mon_nam(mtmp)); return 0; } if (!can_saddle(mtmp)) { pline("You can't saddle such a creature."); return 0; } /* Calculate your chance */ chance = ACURR(A_DEX) + ACURR(A_CHA) / 2 + 2 * mtmp->mtame; chance += u.ulevel * (mtmp->mtame ? 20 : 5); if (!mtmp->mtame) chance -= 10 * mtmp->m_lev; if (Role_if(PM_KNIGHT)) chance += 20; switch (P_SKILL(P_RIDING)) { case P_ISRESTRICTED: case P_UNSKILLED: default: chance -= 20; break; case P_BASIC: break; case P_SKILLED: chance += 15; break; case P_EXPERT: chance += 30; break; } if (Confusion || Fumbling || Glib) chance -= 20; else if (uarmg && (s = OBJ_DESCR(objects[uarmg->otyp])) != NULL && !strncmp(s, "riding ", 7)) /* Bonus for wearing "riding" (but not fumbling) gloves */ chance += 10; else if (uarmf && (s = OBJ_DESCR(objects[uarmf->otyp])) != NULL && !strncmp(s, "riding ", 7)) /* ... or for "riding boots" */ chance += 10; if (otmp->cursed) chance -= 50; /* steed becomes alert if possible */ maybewakesteed(mtmp); /* Make the attempt */ if (rn2(100) < chance) { pline("You put the saddle on %s.", mon_nam(mtmp)); if (otmp->owornmask) remove_worn_item(otmp, FALSE); freeinv(otmp); /* mpickobj may free otmp it if merges, but we have already checked for a saddle above, so no merger should happen */ mpickobj(mtmp, otmp); mtmp->misc_worn_check |= W_MASK(os_saddle); otmp->owornmask = W_MASK(os_saddle); otmp->leashmon = mtmp->m_id; update_mon_intrinsics(mtmp, otmp, TRUE, FALSE); } else pline("%s resists!", Monnam(mtmp)); return 1; }
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); } } }
/* set height of the status box */ sz->cy = tm.tmHeight * data->nhstat_format; SelectObject(hdc, saveFont); ReleaseDC(hWnd, hdc); } } extern const char *hu_stat[]; /* defined in eat.c */ extern const char *enc_stat[]; /* define in botl.c */ void FormatStatusString(char *text, int format) { register char *nb; int hp, hpmax; int cap = near_capacity(); Strcpy(text, plname); if ('a' <= text[0] && text[0] <= 'z') text[0] += 'A' - 'a'; text[10] = 0; Sprintf(nb = eos(text), " the "); if (Upolyd) { char mbot[BUFSZ]; int k = 0; Strcpy(mbot, mons[u.umonnum].mname); while (mbot[k] != 0) { if ((k == 0 || (k > 0 && mbot[k - 1] == ' ')) && 'a' <= mbot[k] && mbot[k] <= 'z') mbot[k] += 'A' - 'a'; k++; } Sprintf(nb = eos(nb), mbot); } else Sprintf(nb = eos(nb), rank_of(u.ulevel, Role_switch, flags.female)); if (format == NHSTAT_LINES_4) Sprintf(nb = eos(nb), "\r\n"); if (ACURR(A_STR) > 18) { if (ACURR(A_STR) > STR18(100)) Sprintf(nb = eos(nb), "St:%2d ", ACURR(A_STR) - 100); else if (ACURR(A_STR) < STR18(100)) Sprintf(nb = eos(nb), "St:18/%02d ", ACURR(A_STR) - 18); else Sprintf(nb = eos(nb), "St:18/** "); } else Sprintf(nb = eos(nb), "St:%-1d ", ACURR(A_STR)); Sprintf(nb = eos(nb), "Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d", ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS), ACURR(A_CHA)); Sprintf(nb = eos(nb), (u.ualign.type == A_CHAOTIC) ? " Chaotic" : (u.ualign.type == A_NEUTRAL) ? " Neutral" : " Lawful"); #ifdef SCORE_ON_BOTL if (flags.showscore) Sprintf(nb = eos(nb), " S:%ld", botl_score()); #endif if (format == NHSTAT_LINES_4 || format == NHSTAT_LINES_2) strcat(text, "\r\n"); /* third line */ hp = Upolyd ? u.mh : u.uhp; hpmax = Upolyd ? u.mhmax : u.uhpmax; if (hp < 0) hp = 0; (void) describe_level(nb = eos(nb)); Sprintf(nb = eos(nb), "%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", showsyms[COIN_CLASS + SYM_OFF_O], money_cnt(invent), hp, hpmax, u.uen, u.uenmax, u.uac); if (Upolyd) Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel); else if (flags.showexp) Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel, u.uexp); else Sprintf(nb = eos(nb), " Exp:%u", u.ulevel); if (format == NHSTAT_LINES_4) strcat(text, "\r\n"); else strcat(text, " "); /* forth line */ if (flags.time) Sprintf(nb = eos(nb), "T:%ld ", moves); if (strcmp(hu_stat[u.uhs], " ")) { Strcat(text, hu_stat[u.uhs]); Sprintf(nb = eos(nb), " "); } if (Confusion) Sprintf(nb = eos(nb), "Conf"); if (Sick) { if (u.usick_type & SICK_VOMITABLE) Sprintf(nb = eos(nb), " FoodPois"); if (u.usick_type & SICK_NONVOMITABLE) Sprintf(nb = eos(nb), " Ill"); } if (Blind) Sprintf(nb = eos(nb), " Blind"); if (Stunned) Sprintf(nb = eos(nb), " Stun"); if (Hallucination) Sprintf(nb = eos(nb), " Hallu"); if (Slimed) Sprintf(nb = eos(nb), " Slime"); if (cap > UNENCUMBERED) Sprintf(nb = eos(nb), " %s", enc_stat[cap]); }
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); } }
/* Return "beautiful", "handsome" or "ugly" * according to gender and charisma. */ const char * beautiful(void) { return ACURR(A_CHA) > 14 ? (poly_gender() == 1 ? "beautiful" : "handsome") : "ugly"; }
int study_book(struct obj *spellbook, const struct nh_cmd_arg *arg) { int booktype = spellbook->otyp; boolean confused = (Confusion != 0); boolean too_hard = FALSE; if (u.uoccupation_progress[tos_book] && !confused && spellbook == u.utracked[tos_book] && /* handle the sequence: start reading, get interrupted, have book become erased somehow, resume reading it */ booktype != SPE_BLANK_PAPER) { if (turnstate.continue_message) pline("You continue your efforts to memorize the spell."); } else { /* Restarting reading the book */ /* KMH -- Simplified this code */ if (booktype == SPE_BLANK_PAPER) { pline("This spellbook is all blank."); makeknown(booktype); return 1; } switch (objects[booktype].oc_level) { case 1: case 2: u.uoccupation_progress[tos_book] = -objects[booktype].oc_delay; break; case 3: case 4: u.uoccupation_progress[tos_book] = -(objects[booktype].oc_level - 1) * objects[booktype].oc_delay; break; case 5: case 6: u.uoccupation_progress[tos_book] = -objects[booktype].oc_level * objects[booktype].oc_delay; break; case 7: u.uoccupation_progress[tos_book] = -8 * objects[booktype].oc_delay; break; default: impossible("Unknown spellbook level %d, book %d;", objects[booktype].oc_level, booktype); return 0; } /* Books are often wiser than their readers (Rus.) */ spellbook->in_use = TRUE; if (!spellbook->blessed && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { if (spellbook->cursed) { too_hard = TRUE; } else { /* uncursed - chance to fail */ int read_ability = ACURR(A_INT) + 4 + u.ulevel / 2 - 2 * objects[booktype].oc_level + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0); /* only wizards know if a spell is too difficult */ if (Role_if(PM_WIZARD) && read_ability < 20 && !confused) { const char *qbuf; qbuf = msgprintf("This spellbook is %sdifficult to " "comprehend. Continue?", (read_ability < 12 ? "very " : "")); if (yn(qbuf) != 'y') { spellbook->in_use = FALSE; return 1; } } /* it's up to random luck now */ if (rnd(20) > read_ability) { too_hard = TRUE; } } } if (too_hard) { boolean gone = cursed_book(spellbook); helpless(-u.uoccupation_progress[tos_book], hr_paralyzed, "frozen by a spellbook", NULL); u.uoccupation_progress[tos_book] = 0; if (gone || !rn2(3)) { if (!gone) pline("The spellbook crumbles to dust!"); if (!objects[spellbook->otyp].oc_name_known && !objects[spellbook->otyp].oc_uname) docall(spellbook); useup(spellbook); } else spellbook->in_use = FALSE; return 1; } else if (confused) { if (!confused_book(spellbook)) { spellbook->in_use = FALSE; } helpless(-u.uoccupation_progress[tos_book], hr_busy, "absorbed in a spellbook", "You're finally able to put the book down."); u.uoccupation_progress[tos_book] = 0; u.utracked[tos_book] = 0; return 1; } spellbook->in_use = FALSE; pline("You begin to %s the runes.", spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" : "memorize"); } u.utracked[tos_book] = spellbook; one_occupation_turn(learn, "studying", occ_book); return 1; }
int spelleffects(int spell, boolean atme, const struct nh_cmd_arg *arg) { int energy, damage, chance, n, intell; int skill, role_skill; boolean confused = (Confusion != 0); struct obj *pseudo; boolean dummy; coord cc; schar dx = 0, dy = 0, dz = 0; if (!SPELL_IS_FROM_SPELLBOOK(spell)) { /* At the moment, we implement this via calling the code for the shortcut command. Eventually, it would make sense to invert this (and make the shortcut commands wrappers for spelleffects). */ switch (spellid(spell)) { case SPID_PRAY: return dopray(arg); case SPID_TURN: return doturn(arg); case SPID_RLOC: return dotele(arg); case SPID_JUMP: return dojump(arg); case SPID_MONS: return domonability(arg); default: impossible("Unknown spell number %d?", spellid(spell)); return 0; } } /* * Find the skill the hero has in a spell type category. * See spell_skilltype for categories. */ skill = spell_skilltype(spellid(spell)); role_skill = P_SKILL(skill); /* Get the direction or target, if applicable. We want to do this *before* determining spell success, both for interface consistency and to cut down on needless mksobj calls. */ switch (spellid(spell)) { /* These spells ask the user to target a specific space. */ case SPE_CONE_OF_COLD: case SPE_FIREBALL: /* If Skilled or better, get a specific space. */ if (role_skill >= P_SKILLED) { if (throwspell(&dx, &dy, arg)) { dz = 0; break; } else { /* Decided not to target anything. Abort the spell. */ pline("Spell canceled."); return 0; } } /* If not Skilled, fall through. */ /* These spells ask the user to target a direction. */ case SPE_FORCE_BOLT: case SPE_SLEEP: case SPE_MAGIC_MISSILE: case SPE_KNOCK: case SPE_SLOW_MONSTER: case SPE_WIZARD_LOCK: case SPE_DIG: case SPE_TURN_UNDEAD: case SPE_POLYMORPH: case SPE_TELEPORT_AWAY: case SPE_CANCELLATION: case SPE_FINGER_OF_DEATH: case SPE_HEALING: case SPE_EXTRA_HEALING: case SPE_DRAIN_LIFE: case SPE_STONE_TO_FLESH: if (atme) dx = dy = dz = 0; else if (!getargdir(arg, NULL, &dx, &dy, &dz)) { /* getdir cancelled, abort */ pline("Spell canceled."); return 0; } break; case SPE_JUMPING: if(!get_jump_coords(arg, &cc, max(role_skill, 1))) { /* No jumping after all, I guess. */ pline("Spell canceled."); return 0; } break; /* The rest of the spells don't have targeting. */ default: break; } /* Spell casting no longer affects knowledge of the spell. A decrement of spell knowledge is done every turn. */ if (spellknow(spell) <= 0) { pline("Your knowledge of this spell is twisted."); pline("It invokes nightmarish images in your mind..."); spell_backfire(spell); return 0; } else if (spellknow(spell) <= 200) { /* 1% */ pline("You strain to recall the spell."); } else if (spellknow(spell) <= 1000) { /* 5% */ pline("Your knowledge of this spell is growing faint."); } energy = (spellev(spell) * 5); /* 5 <= energy <= 35 */ if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) { pline("You are too hungry to cast that spell."); return 0; } else if (ACURR(A_STR) < 4) { pline("You lack the strength to cast spells."); return 0; } else if (check_capacity ("Your concentration falters while carrying so much stuff.")) { return 1; } else if (!freehand()) { pline("Your arms are not free to cast!"); return 0; } if (Uhave_amulet) { pline("You feel the amulet draining your energy away."); energy += rnd(2 * energy); } if (energy > u.uen) { pline("You don't have enough energy to cast that spell."); return 0; } else { if (spellid(spell) != SPE_DETECT_FOOD) { int hungr = energy * 2; /* * If hero is a wizard, their current intelligence * (bonuses + temporary + current) * affects hunger reduction in casting a spell. * 1. int = 17-18 no reduction * 2. int = 16 1/4 hungr * 3. int = 15 1/2 hungr * 4. int = 1-14 normal reduction * The reason for this is: * a) Intelligence affects the amount of exertion * in thinking. * b) Wizards have spent their life at magic and * understand quite well how to cast spells. */ intell = acurr(A_INT); if (!Role_if(PM_WIZARD)) intell = 10; if (intell >= 17) hungr = 0; else if (intell == 16) hungr /= 4; else if (intell == 15) hungr /= 2; /* don't put player (quite) into fainting from casting a spell, particularly since they might not even be hungry at the beginning; however, this is low enough that they must eat before casting anything else except detect food */ if (hungr > u.uhunger - 3) hungr = u.uhunger - 3; morehungry(hungr); } } chance = percent_success(spell); if (confused || (rnd(100) > chance)) { pline("You fail to cast the spell correctly."); u.uen -= energy / 2; return 1; } u.uen -= energy; /* pseudo is a temporary "false" object containing the spell stats */ pseudo = mktemp_sobj(level, spellid(spell)); pseudo->blessed = pseudo->cursed = 0; pseudo->quan = 20L; /* do not let useup get it */ switch (pseudo->otyp) { /* * At first spells act as expected. As the hero increases in skill * with the appropriate spell type, some spells increase in their * effects, e.g. more damage, further distance, and so on, without * additional cost to the spellcaster. */ case SPE_CONE_OF_COLD: case SPE_FIREBALL: if (role_skill >= P_SKILLED) { cc.x = dx; cc.y = dy; n = rnd(8) + 1; while (n--) { if (!dx && !dy && !dz) { if ((damage = zapyourself(pseudo, TRUE)) != 0) losehp(damage, msgprintf( "zapped %sself with an exploding spell", uhim())); } else { explode(dx, dy, pseudo->otyp - SPE_MAGIC_MISSILE + 10, u.ulevel / 2 + 1 + spell_damage_bonus(), 0, (pseudo->otyp == SPE_CONE_OF_COLD) ? EXPL_FROSTY : EXPL_FIERY, NULL, 0); } dx = cc.x + rnd(3) - 2; dy = cc.y + rnd(3) - 2; if (!isok(dx, dy) || !cansee(dx, dy) || IS_STWALL(level->locations[dx][dy].typ) || Engulfed) { /* Spell is reflected back to center */ dx = cc.x; dy = cc.y; } } break; } /* else fall through... */ /* these spells are all duplicates of wand effects */ case SPE_FORCE_BOLT: case SPE_SLEEP: case SPE_MAGIC_MISSILE: case SPE_KNOCK: case SPE_SLOW_MONSTER: case SPE_WIZARD_LOCK: case SPE_DIG: case SPE_TURN_UNDEAD: case SPE_POLYMORPH: case SPE_TELEPORT_AWAY: case SPE_CANCELLATION: case SPE_FINGER_OF_DEATH: case SPE_LIGHT: case SPE_DETECT_UNSEEN: case SPE_HEALING: case SPE_EXTRA_HEALING: case SPE_DRAIN_LIFE: case SPE_STONE_TO_FLESH: if (objects[pseudo->otyp].oc_dir != NODIR) { if (!dx && !dy && !dz) { if ((damage = zapyourself(pseudo, TRUE)) != 0) { losehp(damage, msgprintf("zapped %sself with a spell", uhim())); } } else weffects(pseudo, dx, dy, dz); } else weffects(pseudo, 0, 0, 0); update_inventory(); /* spell may modify inventory */ break; /* these are all duplicates of scroll effects */ case SPE_REMOVE_CURSE: case SPE_CONFUSE_MONSTER: case SPE_DETECT_FOOD: case SPE_CAUSE_FEAR: /* high skill yields effect equivalent to blessed scroll */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; /* fall through */ case SPE_CHARM_MONSTER: case SPE_MAGIC_MAPPING: case SPE_CREATE_MONSTER: case SPE_IDENTIFY: seffects(pseudo, &dummy); break; /* these are all duplicates of potion effects */ case SPE_HASTE_SELF: case SPE_DETECT_TREASURE: case SPE_DETECT_MONSTERS: case SPE_LEVITATION: case SPE_RESTORE_ABILITY: /* high skill yields effect equivalent to blessed potion */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; /* fall through */ case SPE_INVISIBILITY: peffects(pseudo); break; case SPE_CURE_BLINDNESS: healup(0, 0, FALSE, TRUE); break; case SPE_CURE_SICKNESS: if (Sick) pline("You are no longer ill."); if (Slimed) { pline("The slime disappears!"); Slimed = 0; } healup(0, 0, TRUE, FALSE); break; case SPE_CREATE_FAMILIAR: make_familiar(NULL, u.ux, u.uy, FALSE); break; case SPE_CLAIRVOYANCE: if (!BClairvoyant) do_vicinity_map(); /* at present, only one thing blocks clairvoyance */ else if (uarmh && uarmh->otyp == CORNUTHAUM) pline("You sense a pointy hat on top of your %s.", body_part(HEAD)); break; case SPE_PROTECTION: cast_protection(); break; case SPE_JUMPING: jump_to_coords(&cc); break; default: impossible("Unknown spell %d attempted.", spell); obfree(pseudo, NULL); return 0; } /* gain skill for successful cast */ use_skill(skill, spellev(spell)); obfree(pseudo, NULL); /* now, get rid of it */ return 1; }
/* The player is trying to extract something from his/her instrument. */ static int do_improvisation(struct obj *instr, const struct nh_cmd_arg *arg) { int do_spec = !Confusion; if (!do_spec) pline(msgc_yafm, "What you produce is quite far from music..."); else pline(msgc_occstart, "You start playing %s.", the(xname(instr))); switch (instr->otyp) { case MAGIC_FLUTE: /* Make monster fall asleep */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline(msgc_actionok, "You produce soft music."); put_monsters_to_sleep(youmonst.m_lev * 5); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_FLUTE: /* May charm snakes */ do_spec &= (rn2(ACURR(A_DEX)) + youmonst.m_lev > 25); pline(do_spec ? msgc_actionok : msgc_failrandom, "%s.", Tobjnam(instr, do_spec ? "trill" : "toot")); if (do_spec) charm_snakes(youmonst.m_lev * 3); exercise(A_DEX, TRUE); break; case FROST_HORN: /* Idem wand of cold */ case FIRE_HORN: /* Idem wand of fire */ if (do_spec && instr->spe > 0) { schar dx, dy, dz; consume_obj_charge(instr, TRUE); if (!getargdir(arg, NULL, &dx, &dy, &dz)) { pline(msgc_yafm, "%s.", Tobjnam(instr, "vibrate")); break; } else { buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1, rn1(6, 6), youmonst.mx, youmonst.my, dx, dy, 0); } makeknown(instr->otyp); break; } /* else FALLTHRU */ case TOOLED_HORN: /* Awaken or scare monsters */ pline(msgc_actionok, "You produce a frightful, grave sound."); awaken_monsters(&youmonst, youmonst.m_lev * 30); exercise(A_WIS, FALSE); break; case BUGLE: /* Awaken & attract soldiers */ pline(msgc_actionok, "You extract a loud noise from %s.", the(xname(instr))); awaken_soldiers(&youmonst); exercise(A_WIS, FALSE); break; case MAGIC_HARP: /* Charm monsters */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline(msgc_actionok, "%s very attractive music.", Tobjnam(instr, "produce")); charm_monsters((youmonst.m_lev - 1) / 3 + 1); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_HARP: /* May calm Nymph */ do_spec &= (rn2(ACURR(A_DEX)) + youmonst.m_lev > 25); pline(do_spec ? msgc_actionok : msgc_failrandom, "%s %s.", The(xname(instr)), do_spec ? "produces a lilting melody" : "twangs"); if (do_spec) calm_nymphs(youmonst.m_lev * 3); exercise(A_DEX, TRUE); break; case DRUM_OF_EARTHQUAKE: /* create several pits */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline(msgc_occstart, "You produce a heavy, thunderous rolling!"); pline_implied(msgc_occstart, "The entire dungeon is shaking around you!"); do_earthquake((youmonst.m_lev - 1) / 3 + 1); /* shake up monsters in a much larger radius... */ awaken_monsters(&youmonst, ROWNO * COLNO); makeknown(DRUM_OF_EARTHQUAKE); break; } /* else FALLTHRU */ case LEATHER_DRUM: /* Awaken monsters */ pline(msgc_actionok, "You beat a deafening row!"); awaken_monsters(&youmonst, youmonst.m_lev * 40); exercise(A_WIS, FALSE); break; default: impossible("What a weird instrument (%d)!", instr->otyp); break; } return 2; /* That takes time */ }
void ghack_status_window_update_stats() { char buf[BUFSZ]; gchar *buf1; const char *hung; const char *enc; static int firstTime = TRUE; long umoney; /* First, fill in the player name and the dungeon level */ strcpy(buf, plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A' - 'a'; strcat(buf, " the "); if (u.mtimedone) { char mname[BUFSZ]; int k = 0; strcpy(mname, mons[u.umonnum].mname); while (mname[k] != 0) { if ((k == 0 || (k > 0 && mname[k - 1] == ' ')) && 'a' <= mname[k] && mname[k] <= 'z') { mname[k] += 'A' - 'a'; } k++; } strcat(buf, mname); } else { strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female)); } gtk_label_get(GTK_LABEL(titleLabel), &buf1); if (strcmp(buf1, buf) != 0 && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(titleLabel, bigStyle, bigGreenStyle); } gtk_label_set(GTK_LABEL(titleLabel), buf); if (In_endgame(&u.uz)) { strcpy(buf, (Is_astralevel(&u.uz) ? "Astral Plane" : "End Game")); } else { sprintf(buf, "%s, level %d", dungeons[u.uz.dnum].dname, depth(&u.uz)); } if (lastDepth > depth(&u.uz) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(dgnLevelLabel, bigStyle, bigRedStyle); } else if (lastDepth < depth(&u.uz) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(dgnLevelLabel, bigStyle, bigGreenStyle); } lastDepth = depth(&u.uz); gtk_label_set(GTK_LABEL(dgnLevelLabel), buf); /* Next, fill in the player's stats */ if (ACURR(A_STR) > 118) { sprintf(buf, "STR:%d", ACURR(A_STR) - 100); } else if (ACURR(A_STR) == 118) { sprintf(buf, "STR:18/**"); } else if (ACURR(A_STR) > 18) { sprintf(buf, "STR:18/%02d", ACURR(A_STR) - 18); } else { sprintf(buf, "STR:%d", ACURR(A_STR)); } if (lastStr < ACURR(A_STR) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(strLabel, normalStyle, greenStyle); } else if (lastStr > ACURR(A_STR) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(strLabel, normalStyle, redStyle); } lastStr = ACURR(A_STR); gtk_label_set(GTK_LABEL(strLabel), buf); sprintf(buf, "INT:%d", ACURR(A_INT)); if (lastInt < ACURR(A_INT) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(intLabel, normalStyle, greenStyle); } else if (lastInt > ACURR(A_INT) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(intLabel, normalStyle, redStyle); } lastInt = ACURR(A_INT); gtk_label_set(GTK_LABEL(intLabel), buf); sprintf(buf, "WIS:%d", ACURR(A_WIS)); if (lastWis < ACURR(A_WIS) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(wisLabel, normalStyle, greenStyle); } else if (lastWis > ACURR(A_WIS) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(wisLabel, normalStyle, redStyle); } lastWis = ACURR(A_WIS); gtk_label_set(GTK_LABEL(wisLabel), buf); sprintf(buf, "DEX:%d", ACURR(A_DEX)); if (lastDex < ACURR(A_DEX) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(dexLabel, normalStyle, greenStyle); } else if (lastDex > ACURR(A_DEX) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(dexLabel, normalStyle, redStyle); } lastDex = ACURR(A_DEX); gtk_label_set(GTK_LABEL(dexLabel), buf); sprintf(buf, "CON:%d", ACURR(A_CON)); if (lastCon < ACURR(A_CON) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(conLabel, normalStyle, greenStyle); } else if (lastCon > ACURR(A_CON) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(conLabel, normalStyle, redStyle); } lastCon = ACURR(A_CON); gtk_label_set(GTK_LABEL(conLabel), buf); sprintf(buf, "CHA:%d", ACURR(A_CHA)); if (lastCha < ACURR(A_CHA) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(chaLabel, normalStyle, greenStyle); } else if (lastCha > ACURR(A_CHA) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(chaLabel, normalStyle, redStyle); } lastCha = ACURR(A_CHA); gtk_label_set(GTK_LABEL(chaLabel), buf); /* Now do the non-pixmaped stats (gold and such) */ umoney = money_cnt(invent); sprintf(buf, "Au:%ld", umoney); if (lastAu < umoney && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(goldLabel, normalStyle, greenStyle); } else if (lastAu > umoney && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(goldLabel, normalStyle, redStyle); } lastAu = umoney; gtk_label_set(GTK_LABEL(goldLabel), buf); if (u.mtimedone) { /* special case: when polymorphed, show "HD", disable exp */ sprintf(buf, "HP:%d/%d", ((u.mh > 0) ? u.mh : 0), u.mhmax); if ((lastHP < u.mh || lastMHP < u.mhmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hpLabel, normalStyle, greenStyle); } else if ((lastHP > u.mh || lastMHP > u.mhmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hpLabel, normalStyle, redStyle); } lastHP = u.mh; lastMHP = u.mhmax; } else { sprintf(buf, "HP:%d/%d", ((u.uhp > 0) ? u.uhp : 0), u.uhpmax); if ((lastHP < u.uhp || lastMHP < u.uhpmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hpLabel, normalStyle, greenStyle); } else if ((lastHP > u.uhp || lastMHP > u.uhpmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hpLabel, normalStyle, redStyle); } lastHP = u.uhp; lastMHP = u.uhpmax; } gtk_label_set(GTK_LABEL(hpLabel), buf); if (u.mtimedone) { /* special case: when polymorphed, show "HD", disable exp */ sprintf(buf, "HD:%d", mons[u.umonnum].mlevel); if (lastLevel < mons[u.umonnum].mlevel && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(levlLabel, normalStyle, greenStyle); } else if (lastLevel > mons[u.umonnum].mlevel && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(levlLabel, normalStyle, redStyle); } lastLevel = mons[u.umonnum].mlevel; } else { sprintf(buf, "Level:%d", u.ulevel); if (lastLevel < u.ulevel && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(levlLabel, normalStyle, greenStyle); } else if (lastLevel > u.ulevel && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(levlLabel, normalStyle, redStyle); } lastLevel = u.ulevel; } gtk_label_set(GTK_LABEL(levlLabel), buf); sprintf(buf, "Power:%d/%d", u.uen, u.uenmax); if ((lastPOW < u.uen || lastMPOW < u.uenmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(powLabel, normalStyle, greenStyle); } if ((lastPOW > u.uen || lastMPOW > u.uenmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(powLabel, normalStyle, redStyle); } lastPOW = u.uen; lastMPOW = u.uenmax; gtk_label_set(GTK_LABEL(powLabel), buf); sprintf(buf, "AC:%d", u.uac); if (lastAC > u.uac && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(acLabel, normalStyle, greenStyle); } else if (lastAC < u.uac && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(acLabel, normalStyle, redStyle); } lastAC = u.uac; gtk_label_set(GTK_LABEL(acLabel), buf); if (flags.showexp) { sprintf(buf, "Exp:%ld", u.uexp); if (lastExp < u.uexp && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(expLabel, normalStyle, greenStyle); } else if (lastExp > u.uexp && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(expLabel, normalStyle, redStyle); } lastExp = u.uexp; gtk_label_set(GTK_LABEL(expLabel), buf); } else { gtk_label_set(GTK_LABEL(expLabel), ""); } if (flags.time) { sprintf(buf, "Time:%ld", moves); gtk_label_set(GTK_LABEL(timeLabel), buf); } else gtk_label_set(GTK_LABEL(timeLabel), ""); #ifdef SCORE_ON_BOTL if (flags.showscore) { sprintf(buf, "Score:%ld", botl_score()); gtk_label_set(GTK_LABEL(scoreLabel), buf); } else gtk_label_set(GTK_LABEL(scoreLabel), ""); #else { gtk_label_set(GTK_LABEL(scoreLabel), ""); } #endif /* See if their alignment has changed */ if (lastAlignment != u.ualign.type) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(alignLabel, normalStyle, redStyle); } lastAlignment = u.ualign.type; /* looks like their alignment has changed -- change out the icon */ if (u.ualign.type == A_CHAOTIC) { gtk_label_set(GTK_LABEL(alignLabel), "Chaotic"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(alignPix), chaotic_xpm); } else if (u.ualign.type == A_NEUTRAL) { gtk_label_set(GTK_LABEL(alignLabel), "Neutral"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(alignPix), neutral_xpm); } else { gtk_label_set(GTK_LABEL(alignLabel), "Lawful"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(alignPix), lawful_xpm); } } hung = hu_stat[u.uhs]; if (lastHungr != u.uhs) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hungerLabel, normalStyle, redStyle); } lastHungr = u.uhs; if (hung[0] == ' ') { gtk_label_set(GTK_LABEL(hungerLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(hungerPix), nothing_xpm); } else if (u.uhs == 0 /* SATIATED */) { gtk_label_set(GTK_LABEL(hungerLabel), hung); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(hungerPix), satiated_xpm); } else { gtk_label_set(GTK_LABEL(hungerLabel), hung); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(hungerPix), hungry_xpm); } } if (lastConf != Confusion) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(confuLabel, normalStyle, redStyle); } lastConf = Confusion; if (Confusion) { gtk_label_set(GTK_LABEL(confuLabel), "Confused"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(confuPix), confused_xpm); } else { gtk_label_set(GTK_LABEL(confuLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(confuPix), nothing_xpm); } } if (lastBlind != Blind) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(blindLabel, normalStyle, redStyle); } lastBlind = Blind; if (Blind) { gtk_label_set(GTK_LABEL(blindLabel), "Blind"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(blindPix), blind_xpm); } else { gtk_label_set(GTK_LABEL(blindLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(blindPix), nothing_xpm); } } if (lastStun != Stunned) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(stunLabel, normalStyle, redStyle); } lastStun = Stunned; if (Stunned) { gtk_label_set(GTK_LABEL(stunLabel), "Stun"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(stunPix), stunned_xpm); } else { gtk_label_set(GTK_LABEL(stunLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(stunPix), nothing_xpm); } } if (lastHalu != Hallucination) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(halluLabel, normalStyle, redStyle); } lastHalu = Hallucination; if (Hallucination) { gtk_label_set(GTK_LABEL(halluLabel), "Hallu"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(halluPix), hallu_xpm); } else { gtk_label_set(GTK_LABEL(halluLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(halluPix), nothing_xpm); } } if (lastSick != Sick) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(sickLabel, normalStyle, redStyle); } lastSick = Sick; if (Sick) { if (u.usick_type & SICK_VOMITABLE) { gtk_label_set(GTK_LABEL(sickLabel), "FoodPois"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), sick_fp_xpm); } else if (u.usick_type & SICK_NONVOMITABLE) { gtk_label_set(GTK_LABEL(sickLabel), "Ill"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), sick_il_xpm); } else { gtk_label_set(GTK_LABEL(sickLabel), "FoodPois"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), sick_fp_xpm); } } else { gtk_label_set(GTK_LABEL(sickLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), nothing_xpm); } } enc = enc_stat[near_capacity()]; if (lastEncumb != near_capacity()) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(encumbLabel, normalStyle, redStyle); } lastEncumb = near_capacity(); switch (lastEncumb) { case 0: gtk_label_set(GTK_LABEL(encumbLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), nothing_xpm); break; case 1: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), slt_enc_xpm); break; case 2: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), mod_enc_xpm); break; case 3: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), hvy_enc_xpm); break; case 4: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), ext_enc_xpm); break; case 5: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), ovr_enc_xpm); } } firstTime = FALSE; }
static void dump_status(void) { int hp; char rngseedbuf[RNG_SEED_SIZE_BASE64]; fprintf(dumpfp, "%s the %s\n", u.uplname, rank_of(u.ulevel, Role_switch, u.ufemale)); fprintf(dumpfp, " Experience level: %d\n", u.ulevel); if (ACURR(A_STR) > 18) { if (ACURR(A_STR) < 118) fprintf(dumpfp, " Strength: 18/%02d\n", ACURR(A_STR) - 18); else if (ACURR(A_STR) == 118) fprintf(dumpfp, " Strength: 18/**\n"); else fprintf(dumpfp, " Strength: %-1d\n", ACURR(A_STR) - 100); } else fprintf(dumpfp, " Strength: %-1d\n", ACURR(A_STR)); fprintf(dumpfp, " Dexterity: %-1d\n Constitution: %-1d\n", ACURR(A_DEX), ACURR(A_CON)); fprintf(dumpfp, " Intelligence: %-1d\n Wisdom: %-1d\n Charisma: %-1d\n", ACURR(A_INT), ACURR(A_WIS), ACURR(A_CHA)); hp = Upolyd ? u.mh : u.uhp; fprintf(dumpfp, " Health: %d(%d)\n", hp < 0 ? 0 : hp, Upolyd ? u.mhmax : u.uhpmax); fprintf(dumpfp, " Energy: %d(%d)\n", u.uen, u.uenmax); fprintf(dumpfp, " Def: %d\n", 10 - get_player_ac()); fprintf(dumpfp, " Gold: %ld\n", money_cnt(invent)); fprintf(dumpfp, " Moves: %u\n\n", moves); get_initial_rng_seed(rngseedbuf); fprintf(dumpfp, "Dungeon seed: %.*s\n", RNG_SEED_SIZE_BASE64, rngseedbuf); fprintf(dumpfp, "Game ID: %s_%" PRIdLEAST64 "\n\n", u.uplname, (int_least64_t)u.ubirthday / 1000000L); }
static void make_player_info(struct nh_player_info *pi) { int cap, advskills, i; memset(pi, 0, sizeof (struct nh_player_info)); pi->moves = moves; strncpy(pi->plname, u.uplname, sizeof (pi->plname)); pi->align = u.ualign.type; /* This function could be called before the game is fully inited. Test youmonst.data as it is required for near_capacity(). program_state.game_running is no good, as we need this data before game_running is set. TODO: Wow this is hacky. */ if (!youmonst.data) return; API_ENTRY_CHECKPOINT_RETURN_VOID_ON_ERROR(); pi->x = youmonst.mx; pi->y = youmonst.my; pi->z = u.uz.dlevel; if (Upolyd) { strncpy(pi->rank, msgtitlecase(mons[u.umonnum].mname), sizeof (pi->rank)); } else strncpy(pi->rank, rank(), sizeof (pi->rank)); strncpy(pi->rolename, (u.ufemale && urole.name.f) ? urole.name.f : urole.name.m, sizeof (pi->rolename)); strncpy(pi->racename, urace.noun, sizeof (pi->racename)); strncpy(pi->gendername, genders[u.ufemale].adj, sizeof(pi->gendername)); pi->max_rank_sz = mrank_sz; /* abilities */ pi->st = ACURR(A_STR); pi->st_extra = 0; if (pi->st > 118) { pi->st = pi->st - 100; pi->st_extra = 0; } else if (pi->st > 18) { pi->st_extra = pi->st - 18; pi->st = 18; } pi->dx = ACURR(A_DEX); pi->co = ACURR(A_CON); pi->in = ACURR(A_INT); pi->wi = ACURR(A_WIS); pi->ch = ACURR(A_CHA); pi->score = botl_score(); /* hp and energy */ pi->hp = Upolyd ? u.mh : u.uhp; pi->hpmax = Upolyd ? u.mhmax : u.uhpmax; if (pi->hp < 0) pi->hp = 0; pi->en = u.uen; pi->enmax = u.uenmax; pi->ac = find_mac(&youmonst); pi->gold = money_cnt(invent); pi->coinsym = def_oc_syms[COIN_CLASS]; describe_level(pi->level_desc); pi->monnum = u.umonster; pi->cur_monnum = u.umonnum; /* level and exp points */ if (Upolyd) pi->level = mons[u.umonnum].mlevel; else pi->level = youmonst.m_lev; pi->xp = youmonst.exp; cap = near_capacity(); /* check if any skills could be anhanced */ advskills = 0; for (i = 0; i < P_NUM_SKILLS; i++) { if (P_RESTRICTED(i)) continue; if (can_advance(i, FALSE)) advskills++; } pi->can_enhance = advskills > 0; /* add status items for various problems there can be at most 24 items here at any one time or we overflow the buffer */ if (hu_stat[u.uhs]) /* 1 */ strncpy(pi->statusitems[pi->nr_items++], hu_stat[u.uhs], ITEMLEN); if (Confusion) /* 2 */ strncpy(pi->statusitems[pi->nr_items++], "Conf", ITEMLEN); if (sick(&youmonst)) { /* 3 */ if (u.usick_type & SICK_VOMITABLE) strncpy(pi->statusitems[pi->nr_items++], "FoodPois", ITEMLEN); if (u.usick_type & SICK_NONVOMITABLE) strncpy(pi->statusitems[pi->nr_items++], "Ill", ITEMLEN); } if (Blind) /* 4 */ strncpy(pi->statusitems[pi->nr_items++], "Blind", ITEMLEN); if (slippery_fingers(&youmonst)) /* 5 */ strncpy(pi->statusitems[pi->nr_items++], "Greasy", ITEMLEN); if (leg_hurt(&youmonst)) /* 6 */ strncpy(pi->statusitems[pi->nr_items++], "Lame", ITEMLEN); if (stunned(&youmonst)) /* 7 */ strncpy(pi->statusitems[pi->nr_items++], "Stun", ITEMLEN); if (hallucinating(&youmonst)) /* 8 */ strncpy(pi->statusitems[pi->nr_items++], "Hallu", ITEMLEN); if (strangled(&youmonst)) /* 9 */ strncpy(pi->statusitems[pi->nr_items++], "Strangle", ITEMLEN); if (sliming(&youmonst)) /* 10 */ strncpy(pi->statusitems[pi->nr_items++], "Slime", ITEMLEN); if (petrifying(&youmonst)) /* 11 */ strncpy(pi->statusitems[pi->nr_items++], "Petrify", ITEMLEN); if (u.ustuck && !Engulfed && !sticks(youmonst.data)) /* 12 */ strncpy(pi->statusitems[pi->nr_items++], "Held", ITEMLEN); if (enc_stat[cap] ) /* 13 */ strncpy(pi->statusitems[pi->nr_items++], enc_stat[cap], ITEMLEN); if (cancelled(&youmonst)) strncpy(pi->statusitems[pi->nr_items++], "Cancelled", ITEMLEN); if (slow(&youmonst)) strncpy(pi->statusitems[pi->nr_items++], "Slow", ITEMLEN); if (Levitation) /* 14 */ strncpy(pi->statusitems[pi->nr_items++], "Lev", ITEMLEN); else if (Flying) strncpy(pi->statusitems[pi->nr_items++], "Fly", ITEMLEN); if (uwep && is_pick(uwep)) /* 15 (first case) */ strncpy(pi->statusitems[pi->nr_items++], "Dig", ITEMLEN); else if (uwep && is_launcher(uwep)) strncpy(pi->statusitems[pi->nr_items++], "Ranged", ITEMLEN); else if (uwep && (uwep->otyp == CORPSE) && (touch_petrifies(&mons[uwep->corpsenm]))) strncpy(pi->statusitems[pi->nr_items++], "cWielded", ITEMLEN); else if (!uwep) strncpy(pi->statusitems[pi->nr_items++], "Unarmed", ITEMLEN); else if (!is_wep(uwep)) strncpy(pi->statusitems[pi->nr_items++], "NonWeap", ITEMLEN); else { /* strncpy(pi->statusitems[pi->nr_items++], "Melee", ITEMLEN); */ /* Don't show the default Melee status light, as that's the most common case. */ /* 15 (last case) */ } if (u.utrap) /* 16 */ strncpy(pi->statusitems[pi->nr_items++], trap_stat[u.utraptype], ITEMLEN); API_EXIT(); }
/* If dmg is zero, then the monster is not casting at you. If the monster is intentionally not casting at you, we have previously called spell_would_be_useless() and spellnum should always be a valid undirected spell. If you modify either of these, be sure to change is_undirected_spell() and spell_would_be_useless(). */ static void cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum) { if (dmg == 0 && !is_undirected_spell(AD_SPEL, spellnum)) { impossible("cast directed wizard spell (%d) with dmg=0?", spellnum); return; } switch (spellnum) { case MGC_DEATH_TOUCH: pline("Oh no, %s's using the touch of death!", mhe(mtmp)); if (nonliving(youmonst.data) || is_demon(youmonst.data)) { pline("You seem no deader than before."); } else if (!Antimagic && rn2(mtmp->m_lev) > 12) { if (Hallucination) { pline("You have an out of body experience."); } else { killer_format = KILLED_BY_AN; killer = "touch of death"; done(DIED); } } else { if (Antimagic) shieldeff(u.ux, u.uy); pline("Lucky for you, it didn't work!"); } dmg = 0; break; case MGC_CLONE_WIZ: if (mtmp->iswiz && flags.no_of_wizards == 1) { pline("Double Trouble..."); clonewiz(); dmg = 0; } else impossible("bad wizard cloning?"); break; case MGC_SUMMON_MONS: { int count; count = nasty(mtmp); /* summon something nasty */ if (mtmp->iswiz) verbalize("Destroy the thief, my pet%s!", plur(count)); else { const char *mappear = (count == 1) ? "A monster appears" : "Monsters appear"; /* messages not quite right if plural monsters created but only a single monster is seen */ if (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s around a spot near you!", mappear); else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s around your displaced image!", mappear); else pline("%s from nowhere!", mappear); } dmg = 0; break; } case MGC_AGGRAVATION: pline("You feel that monsters are aware of your presence."); aggravate(); dmg = 0; break; case MGC_CURSE_ITEMS: pline("You feel as if you need some help."); rndcurse(); dmg = 0; break; case MGC_DESTRY_ARMR: if (Antimagic) { shieldeff(u.ux, u.uy); pline("A field of force surrounds you!"); } else if (!destroy_arm(some_armor(&youmonst))) { pline("Your skin itches."); } dmg = 0; break; case MGC_WEAKEN_YOU: /* drain strength */ if (Antimagic) { shieldeff(u.ux, u.uy); pline("You feel momentarily weakened."); } else { pline("You suddenly feel weaker!"); dmg = mtmp->m_lev - 6; if (Half_spell_damage) dmg = (dmg + 1) / 2; losestr(rnd(dmg)); if (u.uhp < 1) done_in_by(mtmp); } dmg = 0; break; case MGC_DISAPPEAR: /* makes self invisible */ if (!mtmp->minvis && !mtmp->invis_blkd) { if (canseemon(mtmp)) pline("%s suddenly %s!", Monnam(mtmp), !See_invisible ? "disappears" : "becomes transparent"); mon_set_minvis(mtmp); dmg = 0; } else impossible("no reason for monster to cast disappear spell?"); break; case MGC_STUN_YOU: if (Antimagic || Free_action) { shieldeff(u.ux, u.uy); if (!Stunned) pline("You feel momentarily disoriented."); make_stunned(1L, FALSE); } else { pline(Stunned ? "You struggle to keep your balance." : "You reel..."); dmg = dice(ACURR(A_DEX) < 12 ? 6 : 4, 4); if (Half_spell_damage) dmg = (dmg + 1) / 2; make_stunned(HStun + dmg, FALSE); } dmg = 0; break; case MGC_HASTE_SELF: mon_adjust_speed(mtmp, 1, NULL); dmg = 0; break; case MGC_CURE_SELF: if (mtmp->mhp < mtmp->mhpmax) { if (canseemon(mtmp)) pline("%s looks better.", Monnam(mtmp)); /* note: player healing does 6d4; this used to do 1d8 */ if ((mtmp->mhp += dice(3,6)) > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; dmg = 0; } break; case MGC_PSI_BOLT: /* prior to 3.4.0 Antimagic was setting the damage to 1--this made the spell virtually harmless to players with magic res. */ if (Antimagic) { shieldeff(u.ux, u.uy); dmg = (dmg + 1) / 2; } if (dmg <= 5) pline("You get a slight %sache.", body_part(HEAD)); else if (dmg <= 10) pline("Your brain is on fire!"); else if (dmg <= 20) pline("Your %s suddenly aches painfully!", body_part(HEAD)); else pline("Your %s suddenly aches very painfully!", body_part(HEAD)); break; default: impossible("mcastu: invalid magic spell (%d)", spellnum); dmg = 0; break; } if (dmg) mdamageu(mtmp, dmg); }
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); } } }
/* Handles one turn of book reading. Returns 1 if unfinished, 0 if finshed. */ static int learn(void) { int i; short booktype; boolean costly = TRUE; boolean already_known = FALSE; int first_unknown = MAXSPELL; int known_spells = 0; const char *splname; /* JDS: lenses give 50% faster reading; 33% smaller read time */ if (u.uoccupation_progress[tos_book] && ublindf && ublindf->otyp == LENSES && rn2(2)) u.uoccupation_progress[tos_book]++; if (Confusion) { /* became confused while learning */ confused_book(u.utracked[tos_book]); u.utracked[tos_book] = 0; /* no longer studying */ helpless(-u.uoccupation_progress[tos_book], hr_busy, "absorbed in a spellbook", "You're finally able to put the book down."); u.uoccupation_progress[tos_book] = 0; return 0; } booktype = u.utracked[tos_book]->otyp; if (booktype == SPE_BOOK_OF_THE_DEAD) { deadbook(u.utracked[tos_book], FALSE); u.utracked[tos_book] = 0; u.uoccupation_progress[tos_book] = 0; return 0; } /* The book might get cursed while we're reading it. In this case, immediately stop reading it, cancel progress, and apply a few turns of helplessness. (3.4.3 applies negative spellbook effects but lets you memorize the spell anyway; this makes no sense. It destroys the spellbook on the "contact poison" result, which makes even less sense.) */ if (u.utracked[tos_book]->cursed) { pline("This book isn't making sense any more."); helpless(rn1(5,5), hr_busy, "making sense of a spellbook", "You give up trying to make sense of the spellbook."); u.uoccupation_progress[tos_book] = 0; u.utracked[tos_book] = 0; return 0; } if (++u.uoccupation_progress[tos_book] < 0) return 1; /* still busy */ if (ACURR(A_WIS) < 12) exercise(A_WIS, TRUE); /* you're studying. */ splname = msgprintf(objects[booktype].oc_name_known ? "\"%s\"" : "the \"%s\" spell", OBJ_NAME(objects[booktype])); for (i = 0; i < MAXSPELL; i++) { if (spellid(i) == booktype) { already_known = TRUE; if (u.utracked[tos_book]->spestudied > MAX_SPELL_STUDY) { pline("This spellbook is too faint to be read any more."); u.utracked[tos_book]->otyp = booktype = SPE_BLANK_PAPER; } else if (spellknow(i) <= 1000) { pline("Your knowledge of %s is keener.", splname); incrnknow(i); u.utracked[tos_book]->spestudied++; if (ACURR(A_WIS) < 12) exercise(A_WIS, TRUE); /* extra study */ } else { /* 1000 < spellknow(i) <= MAX_SPELL_STUDY */ pline("You know %s quite well already.", splname); if (yn("Do you want to read the book anyway?") == 'y') { pline("You refresh your knowledge of %s.", splname); incrnknow(i); u.utracked[tos_book]->spestudied++; } else costly = FALSE; } /* make book become known even when spell is already known, in case amnesia made you forget the book */ makeknown((int)booktype); break; } else if (spellid(i) == NO_SPELL && (i < first_unknown || i == spellno_from_let(objects[booktype].oc_defletter))) first_unknown = i; else known_spells++; } if (first_unknown == MAXSPELL && !already_known) panic("Too many spells memorized!"); if (!already_known) { spl_book[first_unknown].sp_id = booktype; spl_book[first_unknown].sp_lev = objects[booktype].oc_level; incrnknow(first_unknown); u.utracked[tos_book]->spestudied++; pline(known_spells > 0 ? "You add %s to your repertoire." : "You learn %s.", splname); makeknown((int)booktype); } if (costly) check_unpaid(u.utracked[tos_book]); u.utracked[tos_book] = 0; return 0; }
/* TODO: Perhaps work out some way to let controlled teleport in on a CMD_ARG_POS, but there are too many codeflow possibilities involved to make that easy. For now, if dotele turns into the spell, we copy the argument on to the spell-handling function (which currently ignores it), but the other possible codepaths just lose it. */ int dotele(const struct nh_cmd_arg *arg) { struct trap *trap; trap = t_at(level, u.ux, u.uy); if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP)) trap = 0; if (trap) { if (trap->once) { pline("This is a vault teleport, usable once only."); if (yn("Jump in?") == 'n') trap = 0; else { deltrap(level, trap); newsym(u.ux, u.uy); } } if (trap) pline("You %s onto the teleportation trap.", locomotion(youmonst.data, "jump")); } if (!trap) { boolean castit = FALSE; int sp_no = 0, energy = 0; if (!supernatural_ability_available(SPID_RLOC)) { /* Try to use teleport away spell. */ if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion) for (sp_no = 0; sp_no < MAXSPELL; sp_no++) if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) { castit = TRUE; break; } if (!castit) { if (!Teleportation) pline("You don't know that spell."); else pline("You are not able to teleport at will."); return 0; } } if (u.uhunger <= 100 || ACURR(A_STR) < 6) { pline("You lack the strength %s.", castit ? "for a teleport spell" : "to teleport"); return 1; } energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2; if (u.uen <= energy) { pline("You lack the energy %s.", castit ? "for a teleport spell" : "to teleport"); return 1; } if (check_capacity("Your concentration falters from carrying so much.")) return 1; if (castit) { exercise(A_WIS, TRUE); if (spelleffects(sp_no, TRUE, arg)) return 1; else return 0; } else u.uen -= energy; } if (trap && trap->once) { if (next_to_u()) vault_tele(); else pline("You shudder for a moment."); } else if (!tele_impl(FALSE, TRUE)) return 0; next_to_u(); if (!trap) morehungry(100); return 1; }
void statuswin::parse_statusline(std::string str) { int hp, hpmax, nconds; long val; std::string txt; int cap = near_capacity(); size_t pos; char buf[64]; /* get player name + title */ pos = str.find("St:", 0); if (pos != std::string::npos) tokenarray[0][0]->caption = str.substr(0, pos); /* strength needs special treatment */ if (ACURR(A_STR) > 18) { if (ACURR(A_STR) > STR18(100)) sprintf(buf,"St:%2d", ACURR(A_STR)-100); else if (ACURR(A_STR) < STR18(100)) sprintf(buf, "St:18/%02d", ACURR(A_STR)-18); else sprintf(buf,"St:18/**"); } else sprintf(buf, "St:%-1d", ACURR(A_STR)); tokenarray[0][1]->caption = buf; /* the other stats */ sprintf(buf, "Dx:%-1d", ACURR(A_DEX)); tokenarray[0][2]->caption = buf; sprintf(buf, "Co:%-1d", ACURR(A_CON)); tokenarray[0][3]->caption = buf; sprintf(buf, "In:%-1d", ACURR(A_INT)); tokenarray[1][1]->caption = buf; sprintf(buf, "Wi:%-1d", ACURR(A_WIS)); tokenarray[1][2]->caption = buf; sprintf(buf, "Ch:%-1d", ACURR(A_CHA)); tokenarray[1][3]->caption = buf; /* alignment */ tokenarray[4][0]->visible = 1; tokenarray[4][0]->caption = (u.ualign.type == A_CHAOTIC) ? "Chaotic" : (u.ualign.type == A_NEUTRAL) ? "Neutral" : "Lawful"; /* score */ #ifdef SCORE_ON_BOTL if (flags.showscore) { sprintf(buf, "S:%ld", botl_score()); tokenarray[3][4]->caption = buf; } else tokenarray[3][4]->caption.clear(); #endif /* money */ #ifndef GOLDOBJ val = u.ugold; #else val = money_cnt(invent); #endif if (val >= 100000) { sprintf(buf, "%c:%-2ldk", oc_syms[COIN_CLASS], val / 1000); tokenarray[3][2]->caption = buf; } else { sprintf(buf, "%c:%-2ld", oc_syms[COIN_CLASS], val); tokenarray[3][2]->caption = buf; } /* Experience */ if (Upolyd) { sprintf(buf, "HD:%d", mons[u.umonnum].mlevel); tokenarray[3][0]->caption = buf; } #ifdef EXP_ON_BOTL else if(flags.showexp) { Sprintf(buf, "Xp:%u/%-1ld", u.ulevel,u.uexp); tokenarray[3][0]->caption = buf; /* if the exp gets too long, suppress displaying the alignment */ if (tokenarray[3][0]->caption.length() > 10) tokenarray[4][0]->visible = 0; } #endif else { Sprintf(buf, "Exp:%u", u.ulevel); tokenarray[3][0]->caption = buf; } /* HP, energy, armor */ hp = Upolyd ? u.mh : u.uhp; hpmax = Upolyd ? u.mhmax : u.uhpmax; sprintf(buf, "HP:%d(%d)", hp, hpmax); tokenarray[2][1]->caption = buf; if (hp >= ((hpmax * 90) / 100)) tokenarray[2][1]->textcolor = warn_colors[V_WARN_NONE]; else if (hp >= ((hpmax * 70) / 100)) tokenarray[2][1]->textcolor = warn_colors[V_WARN_NORMAL]; else if (hp >= ((hpmax * 50) / 100)) tokenarray[2][1]->textcolor = warn_colors[V_WARN_MORE]; else if (hp >= ((hpmax * 25) / 100)) tokenarray[2][1]->textcolor = warn_colors[V_WARN_ALERT]; else tokenarray[2][1]->textcolor = warn_colors[V_WARN_CRITICAL]; sprintf(buf, "Pw:%d(%d)", u.uen, u.uenmax); tokenarray[2][2]->caption = buf; sprintf(buf, "AC:%-2d", u.uac); tokenarray[2][3]->caption = buf; /* time */ if(flags.time) { sprintf(buf, "T:%ld", moves); tokenarray[3][3]->caption = buf; } else tokenarray[3][3]->caption.clear(); /* depth again (numeric) */ sprintf(buf, "Dlvl:%-2d ", depth(&u.uz)); tokenarray[3][1]->caption = buf; /* conditions (hunger, confusion, etc) */ nconds = 0; if (u.uhs > 1) /* hunger */ add_cond(hu_stat[u.uhs], nconds++, u.uhs-1); else if (u.uhs < 1) /* satiated */ add_cond(hu_stat[u.uhs], nconds++, 0); if(Confusion) add_cond("Conf", nconds++, V_WARN_MORE); if(Sick) { if (u.usick_type & SICK_VOMITABLE) add_cond("FoodPois", nconds++, V_WARN_ALERT); if (u.usick_type & SICK_NONVOMITABLE) add_cond("Ill", nconds++, V_WARN_ALERT); } if(Blind) add_cond("Blind", nconds++, V_WARN_MORE); if(Stunned) add_cond("Stun", nconds++, V_WARN_MORE); if(Hallucination) add_cond("Hallu", nconds++, V_WARN_MORE); if(Slimed) add_cond("Slime", nconds++, V_WARN_ALERT); if(cap > UNENCUMBERED) add_cond(enc_stat[cap], nconds++, cap); /* reset the empty positions */ for ( ;nconds < 8; nconds++) add_cond("", nconds, 0); #ifdef SHOW_WEIGHT if (flags.showweight && !tokenarray[0][4]->caption[0]) { std::stringstream stream; stream << "Wt:" << static_cast<long>((inv_weight()+weight_cap())) << "/" << static_cast<long>(weight_cap()) ; tokenarray[0][4]->caption = stream.str(); } #endif }