Merge branch 'NetHack-3.6'

This commit is contained in:
nhmall
2019-07-02 22:46:53 -04:00
8 changed files with 175 additions and 30 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 botl.c $NHDT-Date: 1557094795 2019/05/05 22:19:55 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.145 $ */
/* NetHack 3.6 botl.c $NHDT-Date: 1562114350 2019/07/03 00:39:10 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.146 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2006. */
/* NetHack may be freely redistributed. See license for details. */
@@ -420,6 +420,7 @@ STATIC_DCL void NDECL(init_blstats);
STATIC_DCL int FDECL(compare_blstats, (struct istat_s *, struct istat_s *));
STATIC_DCL char *FDECL(anything_to_s, (char *, anything *, int));
STATIC_DCL int FDECL(percentage, (struct istat_s *, struct istat_s *));
STATIC_DCL int NDECL(exp_percentage);
#ifdef STATUS_HILITES
STATIC_DCL void FDECL(s_to_anything, (anything *, char *, int));
@@ -466,14 +467,18 @@ STATIC_DCL boolean FDECL(status_hilite_menu_add, (int));
#define INIT_THRESH /*empty*/
#endif
#define INIT_BLSTAT(name, fmtstr, anytyp, wid, fld) \
{ name, fmtstr, 0L, FALSE, anytyp, { (genericptr_t) 0 }, (char *) 0, \
#define INIT_BLSTAT(name, fmtstr, anytyp, wid, fld) \
{ name, fmtstr, 0L, FALSE, FALSE, 0, anytyp, \
{ (genericptr_t) 0 }, (char *) 0, \
wid, -1, fld INIT_THRESH }
#define INIT_BLSTATP(name, fmtstr, anytyp, wid, maxfld, fld) \
{ name, fmtstr, 0L, FALSE, anytyp, { (genericptr_t) 0 }, (char *) 0, \
#define INIT_BLSTATP(name, fmtstr, anytyp, wid, maxfld, fld) \
{ name, fmtstr, 0L, FALSE, TRUE, 0, anytyp, \
{ (genericptr_t) 0 }, (char *) 0, \
wid, maxfld, fld INIT_THRESH }
/* If entries are added to this, botl.h will require updating too */
/* If entries are added to this, botl.h will require updating too.
'max' value of BL_EXP gets special handling since the percentage
involved isn't a direct 100*current/maximum calculation. */
STATIC_VAR struct istat_s initblstats[MAXBLSTATS] = {
INIT_BLSTAT("title", "%s", ANY_STR, MAXVALWIDTH, BL_TITLE),
INIT_BLSTAT("strength", " St:%s", ANY_INT, 10, BL_STR),
@@ -488,7 +493,7 @@ STATIC_VAR struct istat_s initblstats[MAXBLSTATS] = {
INIT_BLSTAT("gold", " %s", ANY_LONG, 30, BL_GOLD),
INIT_BLSTATP("power", " Pw:%s", ANY_INT, 10, BL_ENEMAX, BL_ENE),
INIT_BLSTAT("power-max", "(%s)", ANY_INT, 10, BL_ENEMAX),
INIT_BLSTAT("experience-level", " Xp:%s", ANY_INT, 10, BL_XP),
INIT_BLSTATP("experience-level", " Xp:%s", ANY_INT, 10, BL_EXP, BL_XP),
INIT_BLSTAT("armor-class", " AC:%s", ANY_INT, 10, BL_AC),
INIT_BLSTAT("HD", " HD:%s", ANY_INT, 10, BL_HD),
INIT_BLSTAT("time", " T:%s", ANY_LONG, 20, BL_TIME),
@@ -497,7 +502,7 @@ STATIC_VAR struct istat_s initblstats[MAXBLSTATS] = {
INIT_BLSTATP("hitpoints", " HP:%s", ANY_INT, 10, BL_HPMAX, BL_HP),
INIT_BLSTAT("hitpoints-max", "(%s)", ANY_INT, 10, BL_HPMAX),
INIT_BLSTAT("dungeon-level", "%s", ANY_STR, MAXVALWIDTH, BL_LEVELDESC),
INIT_BLSTAT("experience", "/%s", ANY_LONG, 20, BL_EXP),
INIT_BLSTATP("experience", "/%s", ANY_LONG, 20, BL_EXP, BL_EXP),
INIT_BLSTAT("condition", "%s", ANY_MASK32, 0, BL_CONDITION)
};
@@ -724,8 +729,8 @@ boolean *valsetlist;
int pc, chg, color = NO_COLOR;
unsigned anytype;
boolean updated = FALSE, reset;
struct istat_s *curr = NULL, *prev = NULL;
enum statusfields idxmax;
struct istat_s *curr, *prev;
enum statusfields fldmax;
/*
* Now pass the changed values to window port.
@@ -736,6 +741,31 @@ boolean *valsetlist;
color = NO_COLOR;
chg = g.update_all ? 0 : compare_blstats(prev, curr);
/*
* TODO:
* Dynamically update 'percent_matters' as rules are added or
* removed to track whether any of them are precentage rules.
* Then there'll be no need to assume that non-Null 'thresholds'
* means that percentages need to be kept up to date.
* [Affects exp_percent_changing() too.]
*/
if (((chg || g.update_all || fld == BL_XP)
&& curr->percent_matters && curr->thresholds)
/* when 'hitpointbar' is On, percent matters even if HP
hasn't changed and has no percentage rules (in case HPmax
has changed when HP hasn't, where we ordinarily wouldn't
update HP so would miss an update of the hitpoint bar) */
|| (fld == BL_HP && iflags.wc2_hitpointbar)) {
fldmax = curr->idxmax;
pc = (fldmax == BL_EXP) ? exp_percentage()
: (fldmax >= 0) ? percentage(curr, &g.blstats[idx][fldmax])
: 0; /* bullet proofing; can't get here */
if (pc != prev->percent_value)
chg = 1;
curr->percent_value = pc;
} else {
pc = 0;
}
/* Temporary? hack: moveloop()'s prolog for a new game sets
* g.context.rndencode after the status window has been init'd,
@@ -753,7 +783,7 @@ boolean *valsetlist;
* 25 = the gold amount
*
* Setting 'chg = 2' is enough to render the field properly, but
* not to honor an initial highlight, so force 'update_all = TRUE'.
* not to honor an initial highlight, so force 'g.update_all = TRUE'.
*/
if (fld == BL_GOLD
&& (g.context.rndencode != oldrndencode
@@ -772,19 +802,7 @@ boolean *valsetlist;
}
#endif
/*
* TODO?
* It's possible for HPmax (or ENEmax) to change while current
* HP (or energy) stays the same. [Perhaps current and maximum
* both go up, then before the next status update takes place
* current goes down again.] If that happens with HPmax, we
* ought to force the windowport to treat current HP as changed
* if hitpointbar is On, in order for that to be re-rendered.
*/
if (g.update_all || chg || reset) {
idxmax = curr->idxmax;
pc = (idxmax >= 0) ? percentage(curr, &g.blstats[idx][idxmax]) : 0;
if (!valsetlist[fld])
(void) anything_to_s(curr->val, &curr->a, anytype);
@@ -904,6 +922,7 @@ boolean reassessment; /* TRUE: just recheck fields w/o other initialization */
status_enablefield(fld, fieldname, fieldfmt, fldenabl);
}
g.update_all = TRUE;
g.context.botlx = TRUE;
}
void
@@ -1221,6 +1240,75 @@ struct istat_s *bl, *maxbl;
return result;
}
/* percentage for both xp (level) and exp (points) is the percentage for
(curr_exp - this_level_start) in (next_level_start - this_level_start) */
STATIC_OVL int
exp_percentage()
{
int res = 0;
if (u.ulevel < 30) {
long exp_val, nxt_exp_val, curlvlstart;
curlvlstart = newuexp(u.ulevel - 1);
exp_val = u.uexp - curlvlstart;
nxt_exp_val = newuexp(u.ulevel) - curlvlstart;
if (exp_val == nxt_exp_val - 1L) {
/*
* Full 100% is unattainable since hero gains a level
* and the threshold for next level increases, but treat
* (next_level_start - 1 point) as a special case. It's a
* key value after being level drained so is something that
* some players would like to be able to highlight distinctly.
*/
res = 100;
} else {
struct istat_s curval, maxval;
curval.anytype = maxval.anytype = ANY_LONG;
curval.a = maxval.a = cg.zeroany;
curval.a.a_long = exp_val;
maxval.a.a_long = nxt_exp_val;
/* maximum delta between levels is 10000000; calculation of
100 * (10000000 - N) / 10000000 fits within 32-bit long */
res = percentage(&curval, &maxval);
}
}
return res;
}
/* experience points have changed but experience level hasn't; decide whether
botl update is needed for a different percentage highlight rule for Xp */
boolean
exp_percent_changing()
{
int pc, color_dummy;
anything a;
struct hilite_s *rule;
struct istat_s *curr;
/* if status update is already requested, skip this processing */
if (!g.context.botl) {
/*
* Status update is warranted iff percent integer changes and the new
* percentage results in a different highlighting rule being selected.
*/
curr = &g.blstats[g.now_or_before_idx][BL_XP];
/* TODO: [see eval_notify_windowport_field() about percent_matters
and the check against 'thresholds'] */
if (curr->percent_matters && curr->thresholds
&& (pc = exp_percentage()) != curr->percent_value) {
a = cg.zeroany;
a.a_int = (int) u.ulevel;
rule = get_hilite(g.now_or_before_idx, BL_XP,
(genericptr_t) &a, 0, pc, &color_dummy);
if (rule != curr->hilite_rule)
return TRUE; /* caller should set 'g.context.botl' to True */
}
}
return FALSE;
}
/* callback so that interface can get capacity index rather than trying
to reconstruct that from the encumbrance string or asking the general
core what the value is */

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 exper.c $NHDT-Date: 1553296396 2019/03/22 23:13:16 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.32 $ */
/* NetHack 3.6 exper.c $NHDT-Date: 1562114352 2019/07/03 00:39:12 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.33 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2007. */
/* NetHack may be freely redistributed. See license for details. */
@@ -14,6 +14,8 @@ long
newuexp(lev)
int lev;
{
if (lev < 1) /* for newuexp(u.ulevel - 1) when u.ulevel is 1 */
return 0L;
if (lev < 10)
return (10L * (1L << lev));
if (lev < 20)
@@ -177,6 +179,11 @@ register int exper, rexp;
u.uexp = newexp;
if (flags.showexp)
g.context.botl = TRUE;
/* even when experience points aren't being shown, experience level
might be highlighted with a percentage highlight rule and that
percentage depends upon experience points */
if (!g.context.botl && exp_percent_changing())
g.context.botl = TRUE;
}
/* newrexp will always differ from oldrexp unless they're LONG_MAX */
if (newrexp != oldrexp) {
@@ -303,7 +310,7 @@ boolean incr; /* true iff via incremental experience growth */
}
++u.ulevel;
pline("Welcome %sto experience level %d.",
u.ulevelmax < u.ulevel ? "" : "back ",
(u.ulevelmax < u.ulevel) ? "" : "back ",
u.ulevel);
if (u.ulevelmax < u.ulevel)
u.ulevelmax = u.ulevel;

View File

@@ -313,6 +313,15 @@ const char *str;
#endif
case '\\':
break;
case '\0':
/* String ended with '\\'. This can happen when someone
names an object with a name ending with '\\', drops the
named object on the floor nearby and does a look at all
nearby objects. */
/* brh - should we perhaps not allow things to have names
that contain '\\' */
str = save_str;
break;
}
}
*put++ = *str++;