1 /* NetHack 3.6 botl.c $NHDT-Date: 1447978683 2015/11/20 00:18:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.69 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
8 /* JNetHack may be freely redistributed. See license for details. */
13 extern const char *hu_stat[]; /* defined in eat.c */
16 const char *const enc_stat[] = { "", "Burdened", "Stressed",
17 "Strained", "Overtaxed", "Overloaded" };
19 const char *const enc_stat[] = { "", "
\82æ
\82ë
\82ß
\82«", "
\88³
\94\97",
20 "
\8cÀ
\8aE", "
\89×
\8fd", "
\92´
\89ß"};
23 STATIC_OVL NEARDATA int mrank_sz = 0; /* loaded by max_rank_sz (from u_init) */
24 STATIC_DCL const char *NDECL(rank);
26 #ifndef STATUS_VIA_WINDOWPORT
28 STATIC_DCL void NDECL(bot1);
29 STATIC_DCL void NDECL(bot2);
38 Strcpy(newbot1, plname);
39 if ('a' <= newbot1[0] && newbot1[0] <= 'z')
40 newbot1[0] += 'A' - 'a';
42 if(is_kanji1(newbot1, 9))
47 Sprintf(nb = eos(newbot1), " the ");
49 Sprintf(nb = eos(newbot1)," ");
55 Strcpy(mbot, mons[u.umonnum].mname);
56 while (mbot[k] != 0) {
57 if ((k == 0 || (k > 0 && mbot[k - 1] == ' ')) && 'a' <= mbot[k]
62 Strcpy(nb = eos(nb), mbot);
64 Strcpy(nb = eos(nb), rank());
66 Sprintf(nb = eos(nb), " ");
68 j = (int) ((nb + 2) - newbot1); /* strlen(newbot1) but less computation */
70 Sprintf(nb = eos(nb), "%*s", i - j, " "); /* pad with spaces */
71 if (ACURR(A_STR) > 18) {
72 if (ACURR(A_STR) > STR18(100))
74 Sprintf(nb = eos(nb), "St:%2d ", ACURR(A_STR) - 100);
76 Sprintf(nb = eos(nb), "
\8b:%2d ", ACURR(A_STR) - 100);
77 else if (ACURR(A_STR) < STR18(100))
79 Sprintf(nb = eos(nb), "St:18/%02d ", ACURR(A_STR) - 18);
81 Sprintf(nb = eos(nb), "
\8b:18/%02d ", ACURR(A_STR) - 18);
84 Sprintf(nb = eos(nb), "St:18/** ");
86 Sprintf(nb = eos(nb), "
\8b:18/** ");
89 Sprintf(nb = eos(nb), "St:%-1d ", ACURR(A_STR));
91 Sprintf(nb = eos(nb), "
\8b:%-1d ", ACURR(A_STR));
93 Sprintf(nb = eos(nb), "Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d",
95 Sprintf(nb = eos(nb), "
\91\81:%-1d
\91Ï:%-1d
\92m:%-1d
\8c«:%-1d
\96£:%-1d ",
96 ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS),
100 (u.ualign.type == A_CHAOTIC)
102 : (u.ualign.type == A_NEUTRAL) ? " Neutral" : " Lawful");
104 Sprintf(nb = eos(nb),
105 (u.ualign.type == A_CHAOTIC)
107 : (u.ualign.type == A_NEUTRAL) ? "
\92\86\97§" : "
\92\81\8f\98");
112 Sprintf(nb = eos(nb), " S:%ld", botl_score());
114 Sprintf(nb = eos(nb), "%ld
\93_", botl_score());
116 curs(WIN_STATUS, 1, 0);
117 putstr(WIN_STATUS, 0, newbot1);
126 int cap = near_capacity();
128 hp = Upolyd ? u.mh : u.uhp;
129 hpmax = Upolyd ? u.mhmax : u.uhpmax;
133 (void) describe_level(newbot2);
135 Sprintf(nb = eos(newbot2), "%s:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d",
137 Sprintf(nb = eos(newbot2), "%s:%-2ld
\91Ì:%d(%d)
\96\82:%d(%d)
\8aZ:%-2d",
138 encglyph(objnum_to_glyph(GOLD_PIECE)), money_cnt(invent), hp,
139 hpmax, u.uen, u.uenmax, u.uac);
142 Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel);
143 else if (flags.showexp)
145 Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel, u.uexp);
147 Sprintf(nb = eos(nb), "
\8co
\8c±:%u/%-1ld", u.ulevel,u.uexp);
150 Sprintf(nb = eos(nb), " Exp:%u", u.ulevel);
152 Sprintf(nb = eos(nb), "
\8co
\8c±:%u", u.ulevel);
156 Sprintf(nb = eos(nb), " T:%ld", moves);
158 Sprintf(nb = eos(nb), "
\95à:%ld", moves);
159 if (strcmp(hu_stat[u.uhs], " ")) {
160 Sprintf(nb = eos(nb), " ");
161 Strcat(newbot2, hu_stat[u.uhs]);
165 Sprintf(nb = eos(nb), " Conf");
167 Sprintf(nb = eos(nb), "
\8d¬
\97\90");
169 if (u.usick_type & SICK_VOMITABLE)
171 Sprintf(nb = eos(nb), " FoodPois");
173 Sprintf(nb = eos(nb), "
\90H
\93Å");
174 if (u.usick_type & SICK_NONVOMITABLE)
176 Sprintf(nb = eos(nb), " Ill");
178 Sprintf(nb = eos(nb), "
\95a
\8bC");
182 Sprintf(nb = eos(nb), " Blind");
184 Sprintf(nb = eos(nb), "
\96Ó
\96Ú");
187 Sprintf(nb = eos(nb), " Stun");
189 Sprintf(nb = eos(nb), " á¿
\9dò");
192 Sprintf(nb = eos(nb), " Hallu");
194 Sprintf(nb = eos(nb), "
\8c¶
\8ao");
197 Sprintf(nb = eos(nb), " Slime");
199 Sprintf(nb = eos(nb), "
\82Ç
\82ë
\82Ç
\82ë");
200 if (cap > UNENCUMBERED)
201 Sprintf(nb = eos(nb), " %s", enc_stat[cap]);
202 curs(WIN_STATUS, 1, 1);
203 putmixed(WIN_STATUS, 0, newbot2);
213 context.botl = context.botlx = 0;
216 #endif /* !STATUS_VIA_WINDOWPORT */
218 /* convert experience level (1..30) to rank index (0..8) */
223 return (xlev <= 2) ? 0 : (xlev <= 30) ? ((xlev + 2) / 4) : 8;
226 #if 0 /* not currently needed */
227 /* convert rank index (0..8) to experience level (1..30) */
232 return (rank <= 0) ? 1 : (rank <= 8) ? ((rank * 4) - 2) : 30;
237 rank_of(lev, monnum, female)
242 register const struct Role *role;
246 for (role = roles; role->name.m; role++)
247 if (monnum == role->malenum || monnum == role->femalenum)
253 for (i = xlev_to_rank((int) lev); i >= 0; i--) {
254 if (female && role->rank[i].f)
255 return role->rank[i].f;
257 return role->rank[i].m;
260 /* Try the role name, instead */
261 if (female && role->name.f)
263 else if (role->name.m)
268 return "
\83v
\83\8c\83C
\83\84\81[";
271 STATIC_OVL const char *
274 return rank_of(u.ulevel, Role_switch, flags.female);
278 title_to_mon(str, rank_indx, title_length)
280 int *rank_indx, *title_length;
284 /* Loop through each of the roles */
285 for (i = 0; roles[i].name.m; i++)
286 for (j = 0; j < 9; j++) {
287 if (roles[i].rank[j].m
288 && !strncmpi(str, roles[i].rank[j].m,
289 strlen(roles[i].rank[j].m))) {
293 *title_length = strlen(roles[i].rank[j].m);
294 return roles[i].malenum;
296 if (roles[i].rank[j].f
297 && !strncmpi(str, roles[i].rank[j].f,
298 strlen(roles[i].rank[j].f))) {
302 *title_length = strlen(roles[i].rank[j].f);
303 return (roles[i].femalenum != NON_PM) ? roles[i].femalenum
313 register int i, r, maxr = 0;
314 for (i = 0; i < 9; i++) {
315 if (urole.rank[i].m && (r = strlen(urole.rank[i].m)) > maxr)
317 if (urole.rank[i].f && (r = strlen(urole.rank[i].f)) > maxr)
328 long deepest = deepest_lev_reached(FALSE);
331 utotal = money_cnt(invent) + hidden_gold();
332 if ((utotal -= u.umoney0) < 0L)
334 utotal += u.urexp + (50 * (deepest - 1))
335 + (deepest > 30 ? 10000 : deepest > 20 ? 1000 * (deepest - 20) : 0);
336 if (utotal < u.urexp)
337 utotal = LONG_MAX; /* wrap around */
340 #endif /* SCORE_ON_BOTL */
342 /* provide the name of the current level for display by various ports */
349 /* TODO: Add in dungeon name */
351 Sprintf(buf, "%s ", dungeons[u.uz.dnum].dname);
352 else if (In_quest(&u.uz))
354 Sprintf(buf, "Home %d ", dunlev(&u.uz));
356 Sprintf(buf, "
\8cÌ
\8b½ %d ", dunlev(&u.uz));
357 else if (In_endgame(&u.uz))
359 Sprintf(buf, Is_astralevel(&u.uz) ? "Astral Plane " : "End Game ");
361 Sprintf(buf, Is_astralevel(&u.uz) ? "
\90¸
\97ì
\8aE " : "
\8dÅ
\8fI
\8e\8e\97û ");
363 /* ports with more room may expand this one */
365 Sprintf(buf, "Dlvl:%-2d ", depth(&u.uz));
367 Sprintf(buf, "
\92n
\89º:%-2d ", depth(&u.uz));
373 #ifdef STATUS_VIA_WINDOWPORT
374 /* =======================================================================*/
376 /* structure that tracks the status details in the core */
383 enum statusfields idxmax;
384 enum statusfields fld;
388 STATIC_DCL void NDECL(init_blstats);
389 STATIC_DCL char *FDECL(anything_to_s, (char *, anything *, int));
390 STATIC_DCL void FDECL(s_to_anything, (anything *, char *, int));
391 STATIC_OVL int FDECL(percentage, (struct istat_s *, struct istat_s *));
392 STATIC_OVL int FDECL(compare_blstats, (struct istat_s *, struct istat_s *));
394 #ifdef STATUS_HILITES
395 STATIC_DCL boolean FDECL(assign_hilite, (char *, char *, char *, char *,
397 STATIC_DCL const char *FDECL(clridx_to_s, (char *, int));
400 /* If entries are added to this, botl.h will require updating too */
401 STATIC_DCL struct istat_s initblstats[MAXBLSTATS] = {
402 { 0L, ANY_STR, { (genericptr_t) 0 }, (char *) 0, 80, 0, BL_TITLE},
403 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_STR},
404 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_DX},
405 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_CO},
406 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_IN},
407 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_WI},
408 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_CH},
409 { 0L, ANY_STR, { (genericptr_t) 0 }, (char *) 0, 40, 0, BL_ALIGN},
410 { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 20, 0, BL_SCORE},
411 { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 20, 0, BL_CAP},
412 { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 30, 0, BL_GOLD},
413 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, BL_ENEMAX, BL_ENE},
414 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_ENEMAX},
415 { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_XP},
416 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_AC},
417 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_HD},
418 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 20, 0, BL_TIME},
419 { 0L, ANY_UINT, { (genericptr_t) 0 }, (char *) 0, 40, 0, BL_HUNGER},
420 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, BL_HPMAX, BL_HP},
421 { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_HPMAX},
422 { 0L, ANY_STR, { (genericptr_t) 0 }, (char *) 0, 80, 0, BL_LEVELDESC},
423 { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 20, 0, BL_EXP},
425 { (genericptr_t) 0 }, (char *) 0, 0, 0, BL_CONDITION}
428 static struct fieldid_t {
429 const char *fieldname;
430 enum statusfields fldid;
433 {"strength", BL_STR},
434 {"dexterity", BL_DX},
435 {"constitution", BL_CO},
436 {"intelligence", BL_IN},
439 {"alignment", BL_ALIGN},
441 {"carrying-capacity", BL_CAP},
444 {"power-max", BL_ENEMAX},
445 {"experience-level", BL_XP},
446 {"armor-class", BL_AC},
449 {"hunger", BL_HUNGER},
450 {"hitpoints", BL_HP},
451 {"hitpoints-max", BL_HPMAX},
452 {"dungeon-level", BL_LEVELDESC},
453 {"experience", BL_EXP},
454 {"condition", BL_CONDITION},
457 struct istat_s blstats[2][MAXBLSTATS];
458 static boolean blinit = FALSE, update_all = FALSE;
465 static int idx = 0, idx_p, idxmax;
466 boolean updated = FALSE;
469 struct istat_s *curr, *prev;
470 boolean valset[MAXBLSTATS], chgval = FALSE;
473 panic("bot before init.");
474 if (!youmonst.data) {
475 context.botl = context.botlx = 0;
480 cap = near_capacity();
482 idx = 1 - idx; /* 0 -> 1, 1 -> 0 */
484 /* clear the "value set" indicators */
485 (void) memset((genericptr_t) valset, 0, MAXBLSTATS * sizeof(boolean));
488 * Player name and title.
492 if ('a' <= buf[0] && buf[0] <= 'z')
495 Sprintf(nb = eos(buf), " the ");
500 Strcpy(mbot, mons[u.umonnum].mname);
501 while (mbot[k] != 0) {
502 if ((k == 0 || (k > 0 && mbot[k - 1] == ' ')) && 'a' <= mbot[k]
504 mbot[k] += 'A' - 'a';
507 Sprintf1(nb = eos(nb), mbot);
509 Sprintf1(nb = eos(nb), rank());
510 Sprintf(blstats[idx][BL_TITLE].val, "%-29s", buf);
511 valset[BL_TITLE] = TRUE; /* indicate val already set */
516 blstats[idx][BL_STR].a.a_int = ACURR(A_STR);
517 if (ACURR(A_STR) > 18) {
518 if (ACURR(A_STR) > STR18(100))
519 Sprintf(buf, "%2d", ACURR(A_STR) - 100);
520 else if (ACURR(A_STR) < STR18(100))
521 Sprintf(buf, "18/%02d", ACURR(A_STR) - 18);
523 Sprintf(buf, "18/**");
525 Sprintf(buf, "%-1d", ACURR(A_STR));
526 Strcpy(blstats[idx][BL_STR].val, buf);
527 valset[BL_STR] = TRUE; /* indicate val already set */
529 /* Dexterity, constitution, intelligence, wisdom, charisma. */
531 blstats[idx][BL_DX].a.a_int = ACURR(A_DEX);
532 blstats[idx][BL_CO].a.a_int = ACURR(A_CON);
533 blstats[idx][BL_IN].a.a_int = ACURR(A_INT);
534 blstats[idx][BL_WI].a.a_int = ACURR(A_WIS);
535 blstats[idx][BL_CH].a.a_int = ACURR(A_CHA);
539 Strcpy(blstats[idx][BL_ALIGN].val,
540 (u.ualign.type == A_CHAOTIC)
542 : (u.ualign.type == A_NEUTRAL) ? "Neutral" : "Lawful");
546 blstats[idx][BL_SCORE].a.a_long =
554 blstats[idx][BL_HP].a.a_int = Upolyd ? u.mh : u.uhp;
555 blstats[idx][BL_HPMAX].a.a_int = Upolyd ? u.mhmax : u.uhpmax;
556 if (blstats[idx][BL_HP].a.a_int < 0)
557 blstats[idx][BL_HP].a.a_int = 0;
561 (void) describe_level(blstats[idx][BL_LEVELDESC].val);
562 valset[BL_LEVELDESC] = TRUE; /* indicate val already set */
566 blstats[idx][BL_GOLD].a.a_long = money_cnt(invent);
568 * The tty port needs to display the current symbol for gold
569 * as a field header, so to accommodate that we pass gold with
570 * that already included. If a window port needs to use the text
571 * gold amount without the leading "$:" the port will have to
572 * add 2 to the value pointer it was passed in status_update()
573 * for the BL_GOLD case.
575 * Another quirk of BL_GOLD is that the field display may have
576 * changed if a new symbol set was loaded, or we entered or left
580 Sprintf(blstats[idx][BL_GOLD].val, "%s:%ld",
581 encglyph(objnum_to_glyph(GOLD_PIECE)),
582 blstats[idx][BL_GOLD].a.a_long);
583 valset[BL_GOLD] = TRUE; /* indicate val already set */
585 /* Power (magical energy) */
587 blstats[idx][BL_ENE].a.a_int = u.uen;
588 blstats[idx][BL_ENEMAX].a.a_int = u.uenmax;
592 blstats[idx][BL_AC].a.a_int = u.uac;
594 /* Monster level (if Upolyd) */
597 blstats[idx][BL_HD].a.a_int = mons[u.umonnum].mlevel;
599 blstats[idx][BL_HD].a.a_int = 0;
603 blstats[idx][BL_XP].a.a_int = u.ulevel;
604 blstats[idx][BL_EXP].a.a_int = u.uexp;
608 blstats[idx][BL_TIME].a.a_long = moves;
612 blstats[idx][BL_HUNGER].a.a_uint = u.uhs;
613 *(blstats[idx][BL_HUNGER].val) = '\0';
614 if (strcmp(hu_stat[u.uhs], " ") != 0)
615 Strcpy(blstats[idx][BL_HUNGER].val, hu_stat[u.uhs]);
616 valset[BL_HUNGER] = TRUE;
618 /* Carrying capacity */
620 *(blstats[idx][BL_CAP].val) = '\0';
621 blstats[idx][BL_CAP].a.a_int = cap;
622 if (cap > UNENCUMBERED)
623 Strcpy(blstats[idx][BL_CAP].val, enc_stat[cap]);
624 valset[BL_CAP] = TRUE;
629 blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_BLIND;
631 blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_BLIND;
634 blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_CONF;
636 blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_CONF;
638 if (Sick && u.usick_type & SICK_VOMITABLE)
639 blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_FOODPOIS;
641 blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_FOODPOIS;
643 if (Sick && u.usick_type & SICK_NONVOMITABLE)
644 blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_ILL;
646 blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_ILL;
649 blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_HALLU;
651 blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_HALLU;
654 blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_STUNNED;
656 blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_STUNNED;
659 blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_SLIMED;
661 blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_SLIMED;
664 * Now pass the changed values to window port.
666 for (i = 0; i < MAXBLSTATS; i++) {
667 if (((i == BL_SCORE) && !flags.showscore)
668 || ((i == BL_EXP) && !flags.showexp)
669 || ((i == BL_TIME) && !flags.time)
670 || ((i == BL_HD) && !Upolyd)
671 || ((i == BL_XP || i == BL_EXP) && Upolyd))
673 anytype = blstats[idx][i].anytype;
674 curr = &blstats[idx][i];
675 prev = &blstats[idx_p][i];
677 if (update_all || ((chg = compare_blstats(prev, curr)) != 0)
678 || ((chgval = (valset[i] && strcmp(blstats[idx][i].val,
679 blstats[idx_p][i].val)))
681 idxmax = blstats[idx][i].idxmax;
682 pc = (idxmax) ? percentage(curr, &blstats[idx][idxmax]) : 0;
684 (void) anything_to_s(curr->val, &curr->a, anytype);
685 if (anytype != ANY_MASK32) {
686 status_update(i, (genericptr_t) curr->val,
687 valset[i] ? chgval : chg, pc);
690 /* send pointer to mask */
691 (genericptr_t) &curr->a.a_ulong, chg, 0);
697 * It is possible to get here, with nothing having been pushed
698 * to the window port, when none of the info has changed. In that
699 * case, we need to force a call to status_update() when
700 * context.botlx is set. The tty port in particular has a problem
701 * if that isn't done, since it sets context.botlx when a menu or
702 * text display obliterates the status line.
704 * To work around it, we call status_update() with fictitious
705 * index of BL_FLUSH (-1).
707 if (context.botlx && !updated)
708 status_update(BL_FLUSH, (genericptr_t) 0, 0, 0);
710 context.botl = context.botlx = 0;
715 status_initialize(reassessment)
717 reassessment; /* TRUE = just reassess fields w/o other initialization*/
720 const char *fieldfmt = (const char *)0;
721 const char *fieldname = (const char *)0;
725 (*windowprocs.win_status_init)();
727 #ifdef STATUS_HILITES
728 status_notify_windowport(TRUE);
731 for (i = 0; i < MAXBLSTATS; ++i) {
732 enum statusfields fld = initblstats[i].fld;
738 status_enablefield(fld, fieldname, fieldfmt, TRUE);
742 fieldname = "strength";
743 status_enablefield(fld, fieldname, fieldfmt, TRUE);
747 fieldname = "dexterity";
748 status_enablefield(fld, fieldname, fieldfmt, TRUE);
752 fieldname = "constitution";
753 status_enablefield(fld, fieldname, fieldfmt, TRUE);
757 fieldname = "intelligence";
758 status_enablefield(fld, fieldname, fieldfmt, TRUE);
762 fieldname = "wisdom";
763 status_enablefield(fld, fieldname, fieldfmt, TRUE);
767 fieldname = "charisma";
768 status_enablefield(fld, fieldname, fieldfmt, TRUE);
772 fieldname = "alignment";
773 status_enablefield(fld, fieldname, fieldfmt, TRUE);
778 status_enablefield(fld, fieldname, fieldfmt,
779 (!flags.showscore) ? FALSE : TRUE);
783 fieldname = "carrying-capacity";
784 status_enablefield(fld, fieldname, fieldfmt, TRUE);
789 status_enablefield(fld, fieldname, fieldfmt, TRUE);
794 status_enablefield(fld, fieldname, fieldfmt, TRUE);
798 fieldname = "power-max";
799 status_enablefield(fld, fieldname, fieldfmt, TRUE);
803 fieldname = "experience-level";
804 status_enablefield(fld, fieldname, fieldfmt,
805 (Upolyd) ? FALSE : TRUE);
809 fieldname = "armor-class";
810 status_enablefield(fld, fieldname, fieldfmt, TRUE);
815 status_enablefield(fld, fieldname, fieldfmt,
816 (!Upolyd) ? FALSE : TRUE);
821 status_enablefield(fld, fieldname, fieldfmt,
822 (!flags.time) ? FALSE : TRUE);
826 fieldname = "hunger";
827 status_enablefield(fld, fieldname, fieldfmt, TRUE);
831 fieldname = "hitpoints";
832 status_enablefield(fld, fieldname, fieldfmt, TRUE);
836 fieldname = "hitpoint-max";
837 status_enablefield(fld, fieldname, fieldfmt, TRUE);
841 fieldname = "dungeon-level";
842 status_enablefield(fld, fieldname, fieldfmt, TRUE);
846 fieldname = "experience";
847 status_enablefield(fld, fieldname, fieldfmt,
848 (!flags.showexp || Upolyd) ? FALSE : TRUE);
852 fieldname = "condition";
853 status_enablefield(fld, fieldname, fieldfmt, TRUE);
868 /* call the window port cleanup routine first */
869 (*windowprocs.win_status_finish)();
871 /* free memory that we alloc'd now */
872 for (i = 0; i < MAXBLSTATS; ++i) {
873 if (blstats[0][i].val)
874 free((genericptr_t) blstats[0][i].val);
875 if (blstats[1][i].val)
876 free((genericptr_t) blstats[1][i].val);
883 static boolean initalready = FALSE;
887 impossible("init_blstats called more than once.");
892 for (i = BEFORE; i <= NOW; ++i) {
893 for (j = 0; j < MAXBLSTATS; ++j) {
894 blstats[i][j] = initblstats[j];
895 blstats[i][j].a = zeroany;
896 if (blstats[i][j].valwidth) {
897 blstats[i][j].val = (char *) alloc(blstats[i][j].valwidth);
898 blstats[i][j].val[0] = '\0';
900 blstats[i][j].val = (char *) 0;
906 anything_to_s(buf, a, anytype)
916 Sprintf(buf, "%lu", a->a_ulong);
919 Sprintf(buf, "%lx", a->a_ulong);
922 Sprintf(buf, "%ld", a->a_long);
925 Sprintf(buf, "%d", a->a_int);
928 Sprintf(buf, "%u", a->a_uint);
931 Sprintf(buf, "%d", *a->a_iptr);
934 Sprintf(buf, "%ld", *a->a_lptr);
937 Sprintf(buf, "%lu", *a->a_ulptr);
940 Sprintf(buf, "%u", *a->a_uptr);
942 case ANY_STR: /* do nothing */
952 s_to_anything(a, buf, anytype)
962 a->a_long = atol(buf);
965 a->a_int = atoi(buf);
968 a->a_uint = (unsigned) atoi(buf);
971 a->a_ulong = (unsigned long) atol(buf);
975 *a->a_iptr = atoi(buf);
979 *a->a_uptr = (unsigned) atoi(buf);
983 *a->a_lptr = atol(buf);
987 *a->a_ulptr = (unsigned long) atol(buf);
990 a->a_ulong = (unsigned long) atol(buf);
1000 compare_blstats(bl1, bl2)
1001 struct istat_s *bl1, *bl2;
1003 int anytype, result = 0;
1006 panic("compare_blstat: bad istat pointer %s, %s",
1007 fmt_ptr((genericptr_t) bl1), fmt_ptr((genericptr_t) bl2));
1010 anytype = bl1->anytype;
1011 if ((!bl1->a.a_void || !bl2->a.a_void)
1012 && (anytype == ANY_IPTR || anytype == ANY_UPTR || anytype == ANY_LPTR
1013 || anytype == ANY_ULPTR)) {
1014 panic("compare_blstat: invalid pointer %s, %s",
1015 fmt_ptr((genericptr_t) bl1->a.a_void),
1016 fmt_ptr((genericptr_t) bl2->a.a_void));
1021 result = (bl1->a.a_int < bl2->a.a_int)
1023 : (bl1->a.a_int > bl2->a.a_int) ? -1 : 0;
1026 result = (*bl1->a.a_iptr < *bl2->a.a_iptr)
1028 : (*bl1->a.a_iptr > *bl2->a.a_iptr) ? -1 : 0;
1031 result = (bl1->a.a_long < bl2->a.a_long)
1033 : (bl1->a.a_long > bl2->a.a_long) ? -1 : 0;
1036 result = (*bl1->a.a_lptr < *bl2->a.a_lptr)
1038 : (*bl1->a.a_lptr > *bl2->a.a_lptr) ? -1 : 0;
1041 result = (bl1->a.a_uint < bl2->a.a_uint)
1043 : (bl1->a.a_uint > bl2->a.a_uint) ? -1 : 0;
1046 result = (*bl1->a.a_uptr < *bl2->a.a_uptr)
1048 : (*bl1->a.a_uptr > *bl2->a.a_uptr) ? -1 : 0;
1051 result = (bl1->a.a_ulong < bl2->a.a_ulong)
1053 : (bl1->a.a_ulong > bl2->a.a_ulong) ? -1 : 0;
1056 result = (*bl1->a.a_ulptr < *bl2->a.a_ulptr)
1058 : (*bl1->a.a_ulptr > *bl2->a.a_ulptr) ? -1 : 0;
1061 if (strcmp(bl1->val, bl2->val) == 0)
1067 if (bl1->a.a_ulong == bl2->a.a_ulong)
1079 percentage(bl, maxbl)
1080 struct istat_s *bl, *maxbl;
1085 if (!bl || !maxbl) {
1086 impossible("percentage: bad istat pointer %s, %s",
1087 fmt_ptr((genericptr_t) bl), fmt_ptr((genericptr_t) maxbl));
1091 anytype = bl->anytype;
1092 if (maxbl->a.a_void) {
1095 result = ((100 * bl->a.a_int) / maxbl->a.a_int);
1098 result = (int) ((100L * bl->a.a_long) / maxbl->a.a_long);
1101 result = (int) ((100U * bl->a.a_uint) / maxbl->a.a_uint);
1104 result = (int) ((100UL * bl->a.a_ulong) / maxbl->a.a_ulong);
1107 result = ((100 * (*bl->a.a_iptr)) / (*maxbl->a.a_iptr));
1110 result = (int) ((100L * (*bl->a.a_lptr)) / (*maxbl->a.a_lptr));
1113 result = (int) ((100U * (*bl->a.a_uptr)) / (*maxbl->a.a_uptr));
1116 result = (int) ((100UL * (*bl->a.a_ulptr)) / (*maxbl->a.a_ulptr));
1124 #ifdef STATUS_HILITES
1126 /****************************************************************************/
1127 /* Core status hiliting support */
1128 /****************************************************************************/
1138 struct hilite_s status_hilites[MAXBLSTATS];
1141 * This is the parser for the hilite options
1143 * OPTION=hilite_status: hitpoints/10%/red/normal
1145 * set_hilite_status() separates each hilite entry into its 4 component
1146 * strings, then calls assign_hilite() to make the adjustments.
1149 set_status_hilites(op, from_configfile)
1151 boolean from_configfile;
1153 char hsbuf[4][QBUFSZ];
1154 boolean rslt, badopt = FALSE;
1155 int fldnum, num = 0, ccount = 0;
1159 hsbuf[0][0] = hsbuf[1][0] = hsbuf[2][0] = hsbuf[3][0] = '\0';
1160 while (*op && fldnum < 4 && ccount < (QBUFSZ - 2)) {
1164 rslt = assign_hilite(&hsbuf[0][0], &hsbuf[1][0], &hsbuf[2][0],
1165 &hsbuf[3][0], from_configfile);
1171 hsbuf[0][0] = hsbuf[1][0] = '\0';
1172 hsbuf[2][0] = hsbuf[3][0] = '\0';
1175 } else if (c == '/') {
1179 hsbuf[fldnum][ccount++] = c;
1180 hsbuf[fldnum][ccount] = '\0';
1184 if (fldnum >= 2 && !badopt) {
1185 rslt = assign_hilite(&hsbuf[0][0], &hsbuf[1][0], &hsbuf[2][0],
1186 &hsbuf[3][0], from_configfile);
1196 clear_status_hilites(from_configfile)
1197 boolean from_configfile;
1202 for (i = 0; i < MAXBLSTATS; ++i) {
1203 (void) memset((genericptr_t) &status_hilites[i], 0,
1204 sizeof(struct hilite_s));
1205 /* notify window port */
1206 if (!from_configfile)
1207 status_threshold(i, blstats[0][i].anytype, it, 0, 0, 0);
1212 assign_hilite(sa, sb, sc, sd, from_configfile)
1213 char *sa, *sb, *sc, *sd;
1214 boolean from_configfile;
1217 int i = -1, dt = -1, idx = -1;
1218 int coloridx[2] = { -1, -1 };
1219 boolean inverse[2] = { FALSE, FALSE };
1220 boolean bold[2] = { FALSE, FALSE };
1221 boolean normal[2] = { 0, 0 };
1222 boolean percent = FALSE, down_up = FALSE, changed = FALSE;
1224 enum statusfields fld = BL_FLUSH;
1225 threshold.a_void = 0;
1228 * hilite_status: hitpoints/10%/red/normal
1231 /* field name to statusfield */
1232 for (i = 0; sa && i < SIZE(fieldids); ++i) {
1233 if (strcmpi(sa, fieldids[i].fieldname) == 0) {
1235 fld = fieldids[i].fldid;
1241 status_hilites[idx].set = FALSE; /* mark it "unset" */
1246 if ((strcmpi(sb, "updown") == 0) || (strcmpi(sb, "downup") == 0)
1247 || (strcmpi(sb, "up") == 0) || (strcmpi(sb, "down") == 0)) {
1249 } else if ((strcmpi(sb, "changed") == 0)
1250 && (fld == BL_TITLE || fld == BL_ALIGN || fld == BL_LEVELDESC
1251 || fld == BL_CONDITION)) {
1252 changed = TRUE; /* changed is only thing allowed */
1260 } else if (!index("0123456789", *tmp))
1264 if (strlen(sb) > 0) {
1265 dt = blstats[0][idx].anytype;
1268 (void) s_to_anything(&threshold, sb, dt);
1271 if (percent && (threshold.a_int < 1 || threshold.a_int > 100))
1273 if (!threshold.a_void && (strcmp(sb, "0") != 0))
1278 for (i = 0; i < 2; ++i) {
1287 break; /* sc is mandatory; sd is not */
1290 if (strcmpi(how, "bold") == 0) {
1292 } else if (strcmpi(how, "inverse") == 0) {
1294 } else if (strcmpi(how, "normal") == 0) {
1298 char colorname[BUFSZ];
1299 for (k = 0; k < CLR_MAX; ++k) {
1300 /* we have to make a copy to change space to dash */
1301 (void) strcpy(colorname, c_obj_colors[k]);
1302 for (tmp = index(colorname, ' '); tmp;
1303 tmp = index(colorname, ' '))
1305 if (strcmpi(how, colorname) == 0) {
1315 /* Assign the values */
1317 for (i = 0; i < 2; ++i) {
1319 status_hilites[idx].coloridx[i] = BL_HILITE_INVERSE;
1321 status_hilites[idx].coloridx[i] = BL_HILITE_BOLD;
1322 else if (coloridx[i])
1323 status_hilites[idx].coloridx[i] = coloridx[i];
1325 status_hilites[idx].coloridx[i] = BL_HILITE_NONE;
1329 status_hilites[idx].behavior = BL_TH_VAL_PERCENTAGE;
1331 status_hilites[idx].behavior = BL_TH_UPDOWN;
1332 else if (threshold.a_void)
1333 status_hilites[idx].behavior = BL_TH_VAL_ABSOLUTE;
1335 status_hilites[idx].behavior = BL_TH_NONE;
1337 if (status_hilites[idx].behavior != BL_TH_NONE) {
1338 status_hilites[idx].threshold = threshold;
1339 status_hilites[idx].set = TRUE;
1341 status_hilites[idx].anytype = dt;
1343 /* Now finally, we notify the window port */
1344 if (!from_configfile)
1345 status_threshold(idx, status_hilites[idx].anytype,
1346 status_hilites[idx].threshold,
1347 status_hilites[idx].behavior,
1348 status_hilites[idx].coloridx[0],
1349 status_hilites[idx].coloridx[1]);
1355 status_notify_windowport(all)
1362 for (idx = 0; idx < MAXBLSTATS; ++idx) {
1363 if (status_hilites[idx].set)
1364 status_threshold(idx, status_hilites[idx].anytype,
1365 status_hilites[idx].threshold,
1366 status_hilites[idx].behavior,
1367 status_hilites[idx].coloridx[0],
1368 status_hilites[idx].coloridx[1]);
1370 status_threshold(idx, blstats[0][idx].anytype, it, 0, 0, 0);
1376 * get_status_hilites
1378 * Returns a string containing all the status hilites in the
1379 * same format that is used to specify a status hilite preference
1380 * in the config file.
1383 get_status_hilites(buf, bufsiz)
1387 int i, j, k, coloridx;
1388 const char *text = (char *) 0;
1389 char tmp[BUFSZ], colorname[BUFSZ];
1390 boolean val_percentage, val_absolute, up_down;
1391 boolean added_one = FALSE;
1397 bufsiz--; /* required trailing null */
1398 for (i = 0; i < MAXBLSTATS; ++i) {
1399 val_percentage = val_absolute = up_down = FALSE;
1400 if (status_hilites[i].set) {
1407 k = strlen(fieldids[i].fieldname);
1409 Strcat(buf, fieldids[i].fieldname);
1416 if (status_hilites[i].behavior == BL_TH_VAL_PERCENTAGE) {
1417 val_percentage = TRUE;
1418 } else if (status_hilites[i].behavior == BL_TH_VAL_ABSOLUTE) {
1419 val_absolute = TRUE;
1420 } else if (status_hilites[i].behavior == BL_TH_UPDOWN) {
1425 if (status_hilites[i].behavior != BL_TH_UPDOWN) {
1426 anything_to_s(tmp, &status_hilites[i].threshold,
1427 blstats[0][i].anytype);
1431 if (k < (bufsiz - 1)) {
1434 Strcat(buf, "%"), k++;
1437 for (j = 0; j < 2; ++j) {
1442 coloridx = status_hilites[i].coloridx[j];
1444 if (coloridx == BL_HILITE_BOLD)
1446 else if (coloridx == BL_HILITE_INVERSE)
1452 (void) strcpy(colorname, c_obj_colors[coloridx]);
1453 for (blank = index(colorname, ' '); blank;
1454 blank = index(colorname, ' '))
1469 STATIC_OVL const char *
1470 clridx_to_s(buf, idx)
1474 static const char *a[] = { "bold", "inverse", "normal" };
1479 if (idx < 0 && idx >= BL_HILITE_BOLD)
1480 Strcpy(buf, a[idx + 3]);
1481 else if (idx >= 0 && idx < CLR_MAX)
1482 Strcpy(buf, c_obj_colors[idx]);
1483 /* replace spaces with - */
1484 for(p = buf; *p; p++)
1485 if(*p == ' ') *p = '-';
1491 status_hilite_menu()
1493 int i, j, k, pick_cnt, pick_idx, opt_idx;
1494 menu_item *statfield_picks = (menu_item *) 0;
1495 const char *fieldname;
1496 int field_picks[MAXBLSTATS], res;
1497 struct hilite_s hltemp[MAXBLSTATS];
1498 char buf[BUFSZ], thresholdbuf[BUFSZ], below[BUFSZ], above[BUFSZ];
1502 tmpwin = create_nhwindow(NHW_MENU);
1504 for (i = 0; i < MAXBLSTATS; i++) {
1505 (void) memset(&hltemp[i], 0, sizeof(struct hilite_s));
1506 fieldname = fieldids[i].fieldname;
1508 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, fieldname,
1512 end_menu(tmpwin, "Change hilite on which status field(s):");
1513 if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &statfield_picks)) > 0) {
1514 for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
1515 opt_idx = statfield_picks[pick_idx].item.a_int - 1;
1516 field_picks[opt_idx] = 1;
1518 free((genericptr_t) statfield_picks);
1519 statfield_picks = (menu_item *) 0;
1521 destroy_nhwindow(tmpwin);
1525 for (i = 0; i < MAXBLSTATS; i++) {
1526 if (field_picks[i]) {
1527 menu_item *pick = (menu_item *) 0;
1528 Sprintf(buf, "Threshold behavior options for %s:",
1529 fieldids[i].fieldname);
1530 tmpwin = create_nhwindow(NHW_MENU);
1532 if (i == BL_CONDITION) {
1534 any.a_int = BL_TH_CONDITION + 1;
1535 add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE,
1536 "Condition bitmask threshold.", MENU_UNSELECTED);
1539 any.a_int = BL_TH_NONE + 1;
1540 add_menu(tmpwin, NO_GLYPH, &any, 'n', 0, ATR_NONE, "None",
1542 if (i != BL_CONDITION) {
1543 if (blstats[0][i].idxmax > 0) {
1545 any.a_int = BL_TH_VAL_PERCENTAGE + 1;
1546 add_menu(tmpwin, NO_GLYPH, &any, 'p', 0, ATR_NONE,
1547 "Percentage threshold.", MENU_UNSELECTED);
1550 any.a_int = BL_TH_UPDOWN + 1;
1551 add_menu(tmpwin, NO_GLYPH, &any, 'u', 0, ATR_NONE,
1552 "UpDown threshold.", MENU_UNSELECTED);
1554 any.a_int = BL_TH_VAL_ABSOLUTE + 1;
1555 add_menu(tmpwin, NO_GLYPH, &any, 'v', 0, ATR_NONE,
1556 "Value threshold.", MENU_UNSELECTED);
1558 end_menu(tmpwin, buf);
1559 if ((res = select_menu(tmpwin, PICK_ONE, &pick)) > 0) {
1560 hltemp[i].behavior = pick->item.a_int - 1;
1561 free((genericptr_t) pick);
1563 destroy_nhwindow(tmpwin);
1567 if (hltemp[i].behavior == BL_TH_UPDOWN) {
1568 Sprintf(below, "%s decreases", fieldids[i].fieldname);
1569 Sprintf(above, "%s increases", fieldids[i].fieldname);
1570 } else if (hltemp[i].behavior) {
1571 /* Have them enter the threshold*/
1573 buf, "Set %s threshold to what%s?", fieldids[i].fieldname,
1574 (hltemp[i].behavior == BL_TH_VAL_PERCENTAGE)
1576 : (hltemp[i].behavior == BL_TH_CONDITION) ? " mask"
1578 getlin(buf, thresholdbuf);
1579 if (thresholdbuf[0] == '\033')
1581 (void) s_to_anything(&hltemp[i].threshold, thresholdbuf,
1582 blstats[0][i].anytype);
1583 if (!hltemp[i].threshold.a_void)
1586 Sprintf(below, "%s falls below %s%s", fieldids[i].fieldname,
1588 (hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ? "%"
1590 Sprintf(above, "%s rises above %s%s", fieldids[i].fieldname,
1592 (hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ? "%"
1595 for (j = 0; j < 2 && (hltemp[i].behavior != BL_TH_NONE); ++j) {
1596 char prompt[QBUFSZ];
1597 /* j == 0 below, j == 1 above */
1598 menu_item *pick2 = (menu_item *) 0;
1600 Sprintf(prompt, "Display how when %s?", j ? above : below);
1601 tmpwin = create_nhwindow(NHW_MENU);
1603 for (k = -3; k < CLR_MAX; ++k) {
1604 /* if (k == -1) continue; */
1606 any.a_int = (k >= 0) ? k + 1 : k;
1608 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1609 c_obj_colors[k], MENU_UNSELECTED);
1611 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1612 "normal", MENU_UNSELECTED);
1614 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1615 "inverse", MENU_UNSELECTED);
1617 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1618 "bold", MENU_UNSELECTED);
1620 end_menu(tmpwin, prompt);
1621 if ((res = select_menu(tmpwin, PICK_ONE, &pick2)) > 0) {
1622 hltemp[i].coloridx[j] = (pick2->item.a_char > 0)
1623 ? pick2->item.a_int - 1
1624 : pick2->item.a_int;
1625 free((genericptr_t) pick2);
1627 destroy_nhwindow(tmpwin);
1634 for (i = 0; i < MAXBLSTATS; i++) {
1635 if (field_picks[i]) {
1636 Sprintf(eos(buf), "%s/%s%s/", fieldids[i].fieldname,
1637 (hltemp[i].behavior == BL_TH_UPDOWN)
1639 : anything_to_s(thresholdbuf, &hltemp[i].threshold,
1640 blstats[0][i].anytype),
1641 (hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ? "%" : "");
1642 /* borrow thresholdbuf for use with these last two */
1643 Sprintf(eos(buf), "%s/",
1644 clridx_to_s(thresholdbuf, hltemp[i].coloridx[0]));
1645 Sprintf(eos(buf), "%s ",
1646 clridx_to_s(thresholdbuf, hltemp[i].coloridx[1]));
1649 return set_status_hilites(buf, FALSE);
1651 #endif /*STATUS_HILITES*/
1652 #endif /*STATUS_VIA_WINDOWPORT*/