-/* NetHack 3.6 windows.c $NHDT-Date: 1448013599 2015/11/20 09:59:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.35 $ */
+/* NetHack 3.6 windows.c $NHDT-Date: 1495232365 2017/05/19 22:19:25 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.41 $ */
/* Copyright (c) D. Cohrs, 1993. */
/* NetHack may be freely redistributed. See license for details. */
STATIC_DCL void FDECL(def_raw_print, (const char *s));
+#ifdef DUMPLOG
+STATIC_DCL winid FDECL(dump_create_nhwindow, (int));
+STATIC_DCL void FDECL(dump_clear_nhwindow, (winid));
+STATIC_DCL void FDECL(dump_display_nhwindow, (winid, BOOLEAN_P));
+STATIC_DCL void FDECL(dump_destroy_nhwindow, (winid));
+STATIC_DCL void FDECL(dump_start_menu, (winid));
+STATIC_DCL void FDECL(dump_add_menu, (winid, int, const ANY_P *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P));
+STATIC_DCL void FDECL(dump_end_menu, (winid, const char *));
+STATIC_DCL int FDECL(dump_select_menu, (winid, int, MENU_ITEM_P **));
+STATIC_DCL void FDECL(dump_putstr, (winid, int, const char *));
+#endif /* DUMPLOG */
+
#ifdef HANGUPHANDLING
volatile
#endif
exit(EXIT_FAILURE);
}
if (!winchoices[1].procs) {
- raw_printf("Window type %s not recognized. The only choice is: %s.",
+ config_error_add("Window type %s not recognized. The only choice is: %s",
s, winchoices[0].procs->name);
} else {
- raw_printf("Window type %s not recognized. Choices are:", s);
+ char buf[BUFSZ];
+ boolean first = TRUE;
+ buf[0] = '\0';
for (i = 0; winchoices[i].procs; i++) {
if ('+' == winchoices[i].procs->name[0])
continue;
if ('-' == winchoices[i].procs->name[0])
continue;
- raw_printf(" %s", winchoices[i].procs->name);
+ Sprintf(eos(buf), "%s%s", first ? "" : ",", winchoices[i].procs->name);
+ first = FALSE;
}
+ config_error_add("Window type %s not recognized. Choices are: %s", s, buf);
}
if (windowprocs.win_raw_print == def_raw_print)
- terminate(EXIT_SUCCESS);
- wait_synch();
+ nh_terminate(EXIT_SUCCESS);
}
#ifdef WINCHAIN
#endif
static char *NDECL(hup_get_color_string);
#endif /* CHANGE_COLOR */
-#ifdef STATUS_VIA_WINDOWPORT
-static void FDECL(hup_status_update, (int, genericptr_t, int, int));
-#endif
+static void FDECL(hup_status_update, (int, genericptr_t, int, int, int, unsigned long *));
static int NDECL(hup_int_ndecl);
static void NDECL(hup_void_ndecl);
hup_void_ndecl, /* end_screen */
hup_outrip, genl_preference_update, genl_getmsghistory,
genl_putmsghistory,
-#ifdef STATUS_VIA_WINDOWPORT
hup_void_ndecl, /* status_init */
hup_void_ndecl, /* status_finish */
genl_status_enablefield, hup_status_update,
-#ifdef STATUS_HILITES
- genl_status_threshold,
-#endif
-#endif /* STATUS_VIA_WINDOWPORT */
genl_can_suspend_no,
};
}
#endif /* CHANGE_COLOR */
-#ifdef STATUS_VIA_WINDOWPORT
/*ARGSUSED*/
static void
-hup_status_update(idx, ptr, chg, percent)
-int idx UNUSED, chg UNUSED, percent UNUSED;
+hup_status_update(idx, ptr, chg, pc, color, colormasks)
+int idx UNUSED;
genericptr_t ptr UNUSED;
+int chg UNUSED, pc UNUSED, color UNUSED;
+unsigned long *colormasks UNUSED;
+
{
return;
}
-#endif /* STATUS_VIA_WINDOWPORT */
/*
* Non-specific stubs.
#endif /* HANGUPHANDLING */
-#ifdef STATUS_VIA_WINDOWPORT
/****************************************************************************/
/* genl backward compat stuff */
genl_status_init()
{
int i;
+
for (i = 0; i < MAXBLSTATS; ++i) {
status_vals[i] = (char *) alloc(MAXCO);
*status_vals[i] = '\0';
/* free alloc'd memory here */
for (i = 0; i < MAXBLSTATS; ++i) {
if (status_vals[i])
- free((genericptr_t) status_vals[i]);
- status_vals[i] = (char *) 0;
+ free((genericptr_t) status_vals[i]), status_vals[i] = (char *) 0;
}
}
status_activefields[fieldidx] = enable;
}
+/* call once for each field, then call with BL_FLUSH to output the result */
void
-genl_status_update(idx, ptr, chg, percent)
-int idx, chg, percent;
+genl_status_update(idx, ptr, chg, percent, color, colormasks)
+int idx;
genericptr_t ptr;
+int chg UNUSED, percent UNUSED, color UNUSED;
+unsigned long *colormasks UNUSED;
{
char newbot1[MAXCO], newbot2[MAXCO];
long cond, *condptr = (long *) ptr;
register int i;
- char *text = (char *) ptr;
+ unsigned pass, lndelta;
+ enum statusfields idx1, idx2, *fieldlist;
+ char *nb, *text = (char *) ptr;
- enum statusfields fieldorder[2][15] = {
+ static enum statusfields fieldorder[][15] = {
+ /* line one */
{ BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH,
BL_FLUSH },
- { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
- BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER,
- BL_CAP, BL_CONDITION, BL_FLUSH }
+ /* line two, default order */
+ { BL_LEVELDESC, BL_GOLD,
+ BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
+ BL_XP, BL_EXP, BL_HD,
+ BL_TIME,
+ BL_HUNGER, BL_CAP, BL_CONDITION,
+ BL_FLUSH },
+ /* move time to the end */
+ { BL_LEVELDESC, BL_GOLD,
+ BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
+ BL_XP, BL_EXP, BL_HD,
+ BL_HUNGER, BL_CAP, BL_CONDITION,
+ BL_TIME, BL_FLUSH },
+ /* move experience and time to the end */
+ { BL_LEVELDESC, BL_GOLD,
+ BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
+ BL_HUNGER, BL_CAP, BL_CONDITION,
+ BL_XP, BL_EXP, BL_HD, BL_TIME, BL_FLUSH },
+ /* move level description plus gold and experience and time to end */
+ { BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC,
+ BL_HUNGER, BL_CAP, BL_CONDITION,
+ BL_LEVELDESC, BL_GOLD, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_FLUSH },
};
+ /* in case interface is using genl_status_update() but has not
+ specified WC2_FLUSH_STATUS (status_update() for field values
+ is buffered so final BL_FLUSH is needed to produce output) */
+ windowprocs.wincap2 |= WC2_FLUSH_STATUS;
+
if (idx != BL_FLUSH) {
if (!status_activefields[idx])
return;
switch (idx) {
case BL_CONDITION:
- cond = *condptr;
- *status_vals[idx] = '\0';
+ cond = condptr ? *condptr : 0L;
+ nb = status_vals[idx];
+ *nb = '\0';
+ if (cond & BL_MASK_STONE)
+ Strcpy(nb = eos(nb), " Stone");
+ if (cond & BL_MASK_SLIME)
+ Strcpy(nb = eos(nb), " Slime");
+ if (cond & BL_MASK_STRNGL)
+ Strcpy(nb = eos(nb), " Strngl");
+ if (cond & BL_MASK_FOODPOIS)
+ Strcpy(nb = eos(nb), " FoodPois");
+ if (cond & BL_MASK_TERMILL)
+ Strcpy(nb = eos(nb), " TermIll");
if (cond & BL_MASK_BLIND)
- Strcat(status_vals[idx], " Blind");
+ Strcpy(nb = eos(nb), " Blind");
+ if (cond & BL_MASK_DEAF)
+ Strcpy(nb = eos(nb), " Deaf");
+ if (cond & BL_MASK_STUN)
+ Strcpy(nb = eos(nb), " Stun");
if (cond & BL_MASK_CONF)
- Strcat(status_vals[idx], " Conf");
- if (cond & BL_MASK_FOODPOIS)
- Strcat(status_vals[idx], " FoodPois");
- if (cond & BL_MASK_ILL)
- Strcat(status_vals[idx], " Ill");
- if (cond & BL_MASK_STUNNED)
- Strcat(status_vals[idx], " Stun");
+ Strcpy(nb = eos(nb), " Conf");
if (cond & BL_MASK_HALLU)
- Strcat(status_vals[idx], " Hallu");
- if (cond & BL_MASK_SLIMED)
- Strcat(status_vals[idx], " Slime");
+ Strcpy(nb = eos(nb), " Hallu");
+ if (cond & BL_MASK_LEV)
+ Strcpy(nb = eos(nb), " Lev");
+ if (cond & BL_MASK_FLY)
+ Strcpy(nb = eos(nb), " Fly");
+ if (cond & BL_MASK_RIDE)
+ Strcpy(nb = eos(nb), " Ride");
break;
default:
Sprintf(status_vals[idx],
- status_fieldfmt[idx] ? status_fieldfmt[idx] : "%s", text);
+ status_fieldfmt[idx] ? status_fieldfmt[idx] : "%s",
+ text ? text : "");
break;
}
- }
+ return; /* processed one field other than BL_FLUSH */
+ } /* (idx != BL_FLUSH) */
- /* This genl version updates everything on the display, everytime */
- newbot1[0] = '\0';
- for (i = 0; fieldorder[0][i] != BL_FLUSH; ++i) {
- int idx1 = fieldorder[0][i];
+ /* We've received BL_FLUSH; time to output the gathered data */
+ nb = newbot1;
+ *nb = '\0';
+ for (i = 0; (idx1 = fieldorder[0][i]) != BL_FLUSH; ++i) {
if (status_activefields[idx1])
- Strcat(newbot1, status_vals[idx1]);
- }
- newbot2[0] = '\0';
- for (i = 0; fieldorder[1][i] != BL_FLUSH; ++i) {
- int idx2 = fieldorder[1][i];
- if (status_activefields[idx2])
- Strcat(newbot2, status_vals[idx2]);
+ Strcpy(nb = eos(nb), status_vals[idx1]);
}
+ /* if '$' is encoded, buffer length of \GXXXXNNNN is 9 greater than
+ single char; we want to subtract that 9 when checking display length */
+ lndelta = (status_activefields[BL_GOLD]
+ && strstr(status_vals[BL_GOLD], "\\G")) ? 9 : 0;
+ /* basic bot2 formats groups of second line fields into five buffers,
+ then decides how to order those buffers based on comparing lengths
+ of [sub]sets of them to the width of the map; we have more control
+ here but currently emulate that behavior */
+ for (pass = 1; pass <= 4; pass++) {
+ fieldlist = fieldorder[pass];
+ nb = newbot2;
+ *nb = '\0';
+ for (i = 0; (idx2 = fieldlist[i]) != BL_FLUSH; ++i) {
+ if (status_activefields[idx2]) {
+ const char *val = status_vals[idx2];
+
+ switch (idx2) {
+ case BL_HP: /* for pass 4, Hp comes first; mungspaces()
+ will strip the unwanted leading spaces */
+ case BL_XP: case BL_HD:
+ case BL_TIME:
+ Strcpy(nb = eos(nb), " ");
+ break;
+ case BL_LEVELDESC:
+ /* leveldesc has no leading space, so if we've moved
+ it past the first position, provide one */
+ if (i != 0)
+ Strcpy(nb = eos(nb), " ");
+ break;
+ /*
+ * We want " hunger encumbrance conditions"
+ * or " encumbrance conditions"
+ * or " hunger conditions"
+ * or " conditions"
+ * 'hunger' is either " " or " hunger_text";
+ * 'encumbrance' is either " " or " encumbrance_text";
+ * 'conditions' is either "" or " cond1 cond2...".
+ */
+ case BL_HUNGER:
+ /* hunger==" " - keep it, end up with " ";
+ hunger!=" " - insert space and get " hunger" */
+ if (strcmp(val, " "))
+ Strcpy(nb = eos(nb), " ");
+ break;
+ case BL_CAP:
+ /* cap==" " - suppress it, retain " hunger" or " ";
+ cap!=" " - use it, get " hunger cap" or " cap" */
+ if (!strcmp(val, " "))
+ ++val;
+ break;
+ default:
+ break;
+ }
+ Strcpy(nb = eos(nb), val); /* status_vals[idx2] */
+ } /* status_activefields[idx2] */
+
+ if (idx2 == BL_CONDITION && pass < 4
+ && strlen(newbot2) - lndelta > COLNO)
+ break; /* switch to next order */
+ } /* i */
+
+ if (idx2 == BL_FLUSH) { /* made it past BL_CONDITION */
+ if (pass > 1)
+ mungspaces(newbot2);
+ break;
+ }
+ } /* pass */
curs(WIN_STATUS, 1, 0);
putstr(WIN_STATUS, 0, newbot1);
curs(WIN_STATUS, 1, 1);
putmixed(WIN_STATUS, 0, newbot2); /* putmixed() due to GOLD glyph */
}
-#ifdef STATUS_HILITES
+STATIC_VAR struct window_procs dumplog_windowprocs_backup;
+STATIC_VAR FILE *dumplog_file;
+
+#ifdef DUMPLOG
+STATIC_VAR time_t dumplog_now;
+
+STATIC_DCL char *FDECL(dump_fmtstr, (const char *, char *));
+
+STATIC_OVL char *
+dump_fmtstr(fmt, buf)
+const char *fmt;
+char *buf;
+{
+ const char *fp = fmt;
+ char *bp = buf;
+ int slen, len = 0;
+ char tmpbuf[BUFSZ];
+ char verbuf[BUFSZ];
+ long uid;
+ time_t now;
+
+ now = dumplog_now;
+ uid = (long) getuid();
+
+ /*
+ * Note: %t and %T assume that time_t is a 'long int' number of
+ * seconds since some epoch value. That's quite iffy.... The
+ * unit of time might be different and the datum size might be
+ * some variant of 'long long int'. [Their main purpose is to
+ * construct a unique file name rather than record the date and
+ * time; violating the 'long seconds since base-date' assumption
+ * may or may not interfere with that usage.]
+ */
+
+ while (fp && *fp && len < BUFSZ-1) {
+ if (*fp == '%') {
+ fp++;
+ switch (*fp) {
+ default:
+ goto finish;
+ case '\0': /* fallthrough */
+ case '%': /* literal % */
+ Sprintf(tmpbuf, "%%");
+ break;
+ case 't': /* game start, timestamp */
+ Sprintf(tmpbuf, "%lu", (unsigned long) ubirthday);
+ break;
+ case 'T': /* current time, timestamp */
+ Sprintf(tmpbuf, "%lu", (unsigned long) now);
+ break;
+ case 'd': /* game start, YYYYMMDDhhmmss */
+ Sprintf(tmpbuf, "%08ld%06ld",
+ yyyymmdd(ubirthday), hhmmss(ubirthday));
+ break;
+ case 'D': /* current time, YYYYMMDDhhmmss */
+ Sprintf(tmpbuf, "%08ld%06ld", yyyymmdd(now), hhmmss(now));
+ break;
+ case 'v': /* version, eg. "3.6.1-0" */
+ Sprintf(tmpbuf, "%s", version_string(verbuf));
+ break;
+ case 'u': /* UID */
+ Sprintf(tmpbuf, "%ld", uid);
+ break;
+ case 'n': /* player name */
+ Sprintf(tmpbuf, "%s", *plname ? plname : "unknown");
+ break;
+ case 'N': /* first character of player name */
+ Sprintf(tmpbuf, "%c", *plname ? *plname : 'u');
+ break;
+ }
+
+ slen = strlen(tmpbuf);
+ if (len + slen < BUFSZ-1) {
+ len += slen;
+ Sprintf(bp, "%s", tmpbuf);
+ bp += slen;
+ if (*fp) fp++;
+ } else
+ break;
+ } else {
+ *bp = *fp;
+ bp++;
+ fp++;
+ len++;
+ }
+ }
+ finish:
+ *bp = '\0';
+ return buf;
+}
+#endif /* DUMPLOG */
+
+void
+dump_open_log(now)
+time_t now;
+{
+#ifdef DUMPLOG
+ char buf[BUFSZ];
+ char *fname;
+
+ dumplog_now = now;
+#ifdef SYSCF
+ if (!sysopt.dumplogfile)
+ return;
+ fname = dump_fmtstr(sysopt.dumplogfile, buf);
+#else
+ fname = dump_fmtstr(DUMPLOG_FILE, buf);
+#endif
+ dumplog_file = fopen(fname, "w");
+ dumplog_windowprocs_backup = windowprocs;
+
+#else /*!DUMPLOG*/
+ nhUse(now);
+#endif /*?DUMPLOG*/
+}
+
void
-genl_status_threshold(fldidx, thresholdtype, threshold, behavior, under, over)
-int fldidx, thresholdtype;
-int behavior, under, over;
-anything threshold;
+dump_close_log()
+{
+ if (dumplog_file) {
+ (void) fclose(dumplog_file);
+ dumplog_file = (FILE *) 0;
+ }
+}
+
+void
+dump_forward_putstr(win, attr, str, no_forward)
+winid win;
+int attr;
+const char *str;
+int no_forward;
+{
+ if (dumplog_file)
+ fprintf(dumplog_file, "%s\n", str);
+ if (!no_forward)
+ putstr(win, attr, str);
+}
+
+/*ARGSUSED*/
+STATIC_OVL void
+dump_putstr(win, attr, str)
+winid win UNUSED;
+int attr UNUSED;
+const char *str;
+{
+ if (dumplog_file)
+ fprintf(dumplog_file, "%s\n", str);
+}
+
+STATIC_OVL winid
+dump_create_nhwindow(dummy)
+int dummy;
+{
+ return dummy;
+}
+
+/*ARGUSED*/
+STATIC_OVL void
+dump_clear_nhwindow(win)
+winid win UNUSED;
+{
+ return;
+}
+
+/*ARGSUSED*/
+STATIC_OVL void
+dump_display_nhwindow(win, p)
+winid win UNUSED;
+boolean p UNUSED;
{
return;
}
-#endif /* STATUS_HILITES */
-#endif /* STATUS_VIA_WINDOWPORT */
+
+/*ARGUSED*/
+STATIC_OVL void
+dump_destroy_nhwindow(win)
+winid win UNUSED;
+{
+ return;
+}
+
+/*ARGUSED*/
+STATIC_OVL void
+dump_start_menu(win)
+winid win UNUSED;
+{
+ return;
+}
+
+/*ARGSUSED*/
+STATIC_OVL void
+dump_add_menu(win, glyph, identifier, ch, gch, attr, str, preselected)
+winid win UNUSED;
+int glyph UNUSED;
+const anything *identifier UNUSED;
+char ch;
+char gch UNUSED;
+int attr UNUSED;
+const char *str;
+boolean preselected UNUSED;
+{
+ if (dumplog_file) {
+ if (glyph == NO_GLYPH)
+ fprintf(dumplog_file, " %s\n", str);
+ else
+ fprintf(dumplog_file, " %c - %s\n", ch, str);
+ }
+}
+
+/*ARGSUSED*/
+STATIC_OVL void
+dump_end_menu(win, str)
+winid win UNUSED;
+const char *str;
+{
+ if (dumplog_file) {
+ if (str)
+ fprintf(dumplog_file, "%s\n", str);
+ else
+ fputs("\n", dumplog_file);
+ }
+}
+
+STATIC_OVL int
+dump_select_menu(win, how, item)
+winid win UNUSED;
+int how UNUSED;
+menu_item **item;
+{
+ *item = (menu_item *) 0;
+ return 0;
+}
+
+void
+dump_redirect(onoff_flag)
+boolean onoff_flag;
+{
+ if (dumplog_file) {
+ if (onoff_flag) {
+ windowprocs.win_create_nhwindow = dump_create_nhwindow;
+ windowprocs.win_clear_nhwindow = dump_clear_nhwindow;
+ windowprocs.win_display_nhwindow = dump_display_nhwindow;
+ windowprocs.win_destroy_nhwindow = dump_destroy_nhwindow;
+ windowprocs.win_start_menu = dump_start_menu;
+ windowprocs.win_add_menu = dump_add_menu;
+ windowprocs.win_end_menu = dump_end_menu;
+ windowprocs.win_select_menu = dump_select_menu;
+ windowprocs.win_putstr = dump_putstr;
+ } else {
+ windowprocs = dumplog_windowprocs_backup;
+ }
+ iflags.in_dumplog = onoff_flag;
+ } else {
+ iflags.in_dumplog = FALSE;
+ }
+}
/*windows.c*/