Files
nethack/src/pline.c
nethack.allison 7f0f43e6f9 add some unicode support (trunk only)
This patch attempts to add some levels of unicode support
to NetHack.

The master on/off switch for any Unicode support is
defining UNICODE_SUPPORT in config.h. Currently
there is code support for two subsets of unicode support:

UNICODE_DRAWING

If UNICODE_DRAWING is defined, then the data
structures used to house drawing symbols are expanded
to the size of wchar_t, big enough to hold unicode characters.
A typdef called `nhsym' is involved and if UNICODE_DRAWING
is defined, it is wchar_t, otherwise it is uchar.

UNICODE_WIDEWINPORT

If UNICODE_WIDEWINPORT is defined, then the data
structures inside the window port are expanded to the size of
wchar_t, big enough to hold unicode characters.  Both map
symbols and text within the window port are expanded, in order
for potential support for displaying multinational characters some
day, but this patch only provides viewing of map symbols.
A typdef called `nhwchar' is involved and if UNICODE_WIDEWINPORT
is defined, it is wchar_t, otherwise it is char.

The only window port with code support for UNICODE_WIDEWINPORT
currently is the TTY port.  Don't enable UNICODE_WIDEWINPORT
unless:
- it is a TTY port
- the underlying platform specific routines can
handle the larger data structures.

Don't enable UNICODE_SUPPORT unless:
- your compiler can handle wchar_t.
- your compiler can accept L'a' characters.
- your compiler can accept L"wide" strings.

Note that if your compiler can handle the above, you could
enable the larger data structures (currently if TTY) even if your
platform can't actually display unicode or UTF-8, by messing
with u_putch() in win/tty/wintty.c to only deal regular chars.
That should be the only function that actually pushes wide characters
out to the display.

If you enable UNICODE_SUPPORT, and your platform is capable
you will need to turn on the unicode run-time option to be able to
load unicode character sets from the symbol file, to be able to
push unicode characters to the display. You'll also want to load
a unicode symbol set once the unicode option is toggled on. In
a config file you would do that via these two lines:
OPTIONS=unicode
OPTIONS=symset:Unicode_non_US

The repository was stamped with NETHACK_PRE_UNICODE
prior to applying this patch, and stamped with
NETHACK_POST_UNICODE afterwards. The code differences
between those two tagged versions are this patch.
2006-10-17 23:55:42 +00:00

476 lines
11 KiB
C

/* SCCS Id: @(#)pline.c 3.5 2006/08/30 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers */
#include "hack.h"
static boolean no_repeat = FALSE;
static char *FDECL(You_buf, (int));
/*VARARGS1*/
/* Note that these declarations rely on knowledge of the internals
* of the variable argument handling stuff in "tradstdc.h"
*/
#if defined(USE_STDARG) || defined(USE_VARARGS)
static void FDECL(vpline, (const char *, va_list));
void
pline VA_DECL(const char *, line)
VA_START(line);
VA_INIT(line, char *);
vpline(line, VA_ARGS);
VA_END();
}
# ifdef USE_STDARG
static void
vpline(const char *line, va_list the_args) {
# else
static void
vpline(line, the_args) const char *line; va_list the_args; {
# endif
#else /* USE_STDARG | USE_VARARG */
#define vpline pline
void
pline VA_DECL(const char *, line)
#endif /* USE_STDARG | USE_VARARG */
char pbuf[BUFSZ];
/* Do NOT use VA_START and VA_END in here... see above */
if (!line || !*line) return;
#ifdef WIZARD
if (program_state.wizkit_wishing) return;
#endif
if (index(line, '%')) {
Vsprintf(pbuf,line,VA_ARGS);
line = pbuf;
}
if (!iflags.window_inited) {
raw_print(line);
return;
}
#ifndef MAC
# ifdef UNICODE_WIDEWINPORT
if (no_repeat && !nhwstrcmp(toplines, line))
# else
if (no_repeat && !strcmp(toplines, line))
# endif
return;
#endif /* MAC */
if (vision_full_recalc) vision_recalc(0);
if (u.ux) flush_screen(1); /* %% */
putstr(WIN_MESSAGE, 0, line);
}
/*VARARGS1*/
void
Norep VA_DECL(const char *, line)
VA_START(line);
VA_INIT(line, const char *);
no_repeat = TRUE;
vpline(line, VA_ARGS);
no_repeat = FALSE;
VA_END();
return;
}
/* work buffer for You(), &c and verbalize() */
static char *you_buf = 0;
static int you_buf_siz = 0;
static char *
You_buf(siz)
int siz;
{
if (siz > you_buf_siz) {
if (you_buf) free((genericptr_t) you_buf);
you_buf_siz = siz + 10;
you_buf = (char *) alloc((unsigned) you_buf_siz);
}
return you_buf;
}
void
free_youbuf()
{
if (you_buf) free((genericptr_t) you_buf), you_buf = (char *)0;
you_buf_siz = 0;
}
/* `prefix' must be a string literal, not a pointer */
#define YouPrefix(pointer,prefix,text) \
Strcpy((pointer = You_buf((int)(strlen(text) + sizeof prefix))), prefix)
#define YouMessage(pointer,prefix,text) \
strcat((YouPrefix(pointer, prefix, text), pointer), text)
/*VARARGS1*/
void
You VA_DECL(const char *, line)
char *tmp;
VA_START(line);
VA_INIT(line, const char *);
vpline(YouMessage(tmp, "You ", line), VA_ARGS);
VA_END();
}
/*VARARGS1*/
void
Your VA_DECL(const char *,line)
char *tmp;
VA_START(line);
VA_INIT(line, const char *);
vpline(YouMessage(tmp, "Your ", line), VA_ARGS);
VA_END();
}
/*VARARGS1*/
void
You_feel VA_DECL(const char *,line)
char *tmp;
VA_START(line);
VA_INIT(line, const char *);
if (Unaware)
YouPrefix(tmp, "You dream that you feel ", line);
else
YouPrefix(tmp, "You feel ", line);
vpline(strcat(tmp, line), VA_ARGS);
VA_END();
}
/*VARARGS1*/
void
You_cant VA_DECL(const char *,line)
char *tmp;
VA_START(line);
VA_INIT(line, const char *);
vpline(YouMessage(tmp, "You can't ", line), VA_ARGS);
VA_END();
}
/*VARARGS1*/
void
pline_The VA_DECL(const char *,line)
char *tmp;
VA_START(line);
VA_INIT(line, const char *);
vpline(YouMessage(tmp, "The ", line), VA_ARGS);
VA_END();
}
/*VARARGS1*/
void
There VA_DECL(const char *,line)
char *tmp;
VA_START(line);
VA_INIT(line, const char *);
vpline(YouMessage(tmp, "There ", line), VA_ARGS);
VA_END();
}
/*VARARGS1*/
void
You_hear VA_DECL(const char *,line)
char *tmp;
if (Deaf || !flags.acoustics) return;
VA_START(line);
VA_INIT(line, const char *);
if (Underwater)
YouPrefix(tmp, "You barely hear ", line);
else if (Unaware)
YouPrefix(tmp, "You dream that you hear ", line);
else
YouPrefix(tmp, "You hear ", line);
vpline(strcat(tmp, line), VA_ARGS);
VA_END();
}
/*VARARGS1*/
void
You_see VA_DECL(const char *,line)
char *tmp;
VA_START(line);
VA_INIT(line, const char *);
if (Unaware)
YouPrefix(tmp, "You dream that you see ", line);
else if (Blind) /* caller should have caught this... */
YouPrefix(tmp, "You sense ", line);
else
YouPrefix(tmp, "You see ", line);
vpline(strcat(tmp, line), VA_ARGS);
VA_END();
}
/* Print a message inside double-quotes.
* The caller is responsible for checking deafness.
* Gods can speak directly to you in spite of deafness.
*/
/*VARARGS1*/
void
verbalize VA_DECL(const char *,line)
char *tmp;
VA_START(line);
VA_INIT(line, const char *);
tmp = You_buf((int)strlen(line) + sizeof "\"\"");
Strcpy(tmp, "\"");
Strcat(tmp, line);
Strcat(tmp, "\"");
vpline(tmp, VA_ARGS);
VA_END();
}
/*VARARGS1*/
/* Note that these declarations rely on knowledge of the internals
* of the variable argument handling stuff in "tradstdc.h"
*/
#if defined(USE_STDARG) || defined(USE_VARARGS)
static void FDECL(vraw_printf,(const char *,va_list));
void
raw_printf VA_DECL(const char *, line)
VA_START(line);
VA_INIT(line, char *);
vraw_printf(line, VA_ARGS);
VA_END();
}
# ifdef USE_STDARG
static void
vraw_printf(const char *line, va_list the_args) {
# else
static void
vraw_printf(line, the_args) const char *line; va_list the_args; {
# endif
#else /* USE_STDARG | USE_VARARG */
void
raw_printf VA_DECL(const char *, line)
#endif
/* Do NOT use VA_START and VA_END in here... see above */
if(!index(line, '%'))
raw_print(line);
else {
char pbuf[BUFSZ];
Vsprintf(pbuf,line,VA_ARGS);
raw_print(pbuf);
}
}
/*VARARGS1*/
void
impossible VA_DECL(const char *, s)
VA_START(s);
VA_INIT(s, const char *);
if (program_state.in_impossible)
panic("impossible called impossible");
program_state.in_impossible = 1;
{
char pbuf[BUFSZ];
Vsprintf(pbuf,s,VA_ARGS);
paniclog("impossible", pbuf);
}
vpline(s,VA_ARGS);
pline("Program in disorder - perhaps you'd better #quit.");
program_state.in_impossible = 0;
VA_END();
}
const char *
align_str(alignment)
aligntyp alignment;
{
switch ((int)alignment) {
case A_CHAOTIC: return "chaotic";
case A_NEUTRAL: return "neutral";
case A_LAWFUL: return "lawful";
case A_NONE: return "unaligned";
}
return "unknown";
}
void
mstatusline(mtmp)
register struct monst *mtmp;
{
aligntyp alignment = mon_aligntyp(mtmp);
char info[BUFSZ], monnambuf[BUFSZ];
info[0] = 0;
if (mtmp->mtame) { Strcat(info, ", tame");
#ifdef WIZARD
if (wizard) {
Sprintf(eos(info), " (%d", mtmp->mtame);
if (!mtmp->isminion)
Sprintf(eos(info), "; hungry %ld; apport %d",
EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport);
Strcat(info, ")");
}
#endif
}
else if (mtmp->mpeaceful) Strcat(info, ", peaceful");
if (mtmp->meating) Strcat(info, ", eating");
if (mtmp->meating && (mtmp->cham == NON_PM) &&
mtmp->mappearance && mtmp->m_ap_type) {
Sprintf(eos(info), ", mimicing %s",
(mtmp->m_ap_type == M_AP_FURNITURE) ?
an(defsyms[mtmp->mappearance].explanation) :
(mtmp->m_ap_type == M_AP_OBJECT &&
OBJ_DESCR(objects[mtmp->mappearance])) ?
an(OBJ_DESCR(objects[mtmp->mappearance])) :
(mtmp->m_ap_type == M_AP_OBJECT &&
OBJ_NAME(objects[mtmp->mappearance])) ?
an(OBJ_NAME(objects[mtmp->mappearance])) :
(mtmp->m_ap_type == M_AP_MONSTER) ?
an(mons[mtmp->mappearance].mname) :
something);
}
if (mtmp->mcan) Strcat(info, ", cancelled");
if (mtmp->mconf) Strcat(info, ", confused");
if (mtmp->mblinded || !mtmp->mcansee)
Strcat(info, ", blind");
if (mtmp->mstun) Strcat(info, ", stunned");
if (mtmp->msleeping) Strcat(info, ", asleep");
#if 0 /* unfortunately mfrozen covers temporary sleep and being busy
(donning armor, for instance) as well as paralysis */
else if (mtmp->mfrozen) Strcat(info, ", paralyzed");
#else
else if (mtmp->mfrozen || !mtmp->mcanmove)
Strcat(info, ", can't move");
#endif
/* [arbitrary reason why it isn't moving] */
else if (mtmp->mstrategy & STRAT_WAITMASK)
Strcat(info, ", meditating");
else if (mtmp->mflee) Strcat(info, ", scared");
if (mtmp->mtrapped) Strcat(info, ", trapped");
if (mtmp->mspeed) Strcat(info,
mtmp->mspeed == MFAST ? ", fast" :
mtmp->mspeed == MSLOW ? ", slow" :
", ???? speed");
if (mtmp->mundetected) Strcat(info, ", concealed");
if (mtmp->minvis) Strcat(info, ", invisible");
if (mtmp == u.ustuck) Strcat(info,
sticks(youmonst.data) ? ", held by you" :
!u.uswallow ? ", holding you" :
attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_DGST) ?
", digesting you" :
is_animal(u.ustuck->data) ? ", swallowing you" :
", engulfing you");
#ifdef STEED
if (mtmp == u.usteed) Strcat(info, ", carrying you");
#endif
/* avoid "Status of the invisible newt ..., invisible" */
/* and unlike a normal mon_nam, use "saddled" even if it has a name */
Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *)0,
(SUPPRESS_IT|SUPPRESS_INVISIBLE), FALSE));
pline("Status of %s (%s): Level %d HP %d(%d) AC %d%s.",
monnambuf,
align_str(alignment),
mtmp->m_lev,
mtmp->mhp,
mtmp->mhpmax,
find_mac(mtmp),
info);
}
void
ustatusline()
{
char info[BUFSZ];
info[0] = '\0';
if (Sick) {
Strcat(info, ", dying from");
if (u.usick_type & SICK_VOMITABLE)
Strcat(info, " food poisoning");
if (u.usick_type & SICK_NONVOMITABLE) {
if (u.usick_type & SICK_VOMITABLE)
Strcat(info, " and");
Strcat(info, " illness");
}
}
if (Stoned) Strcat(info, ", solidifying");
if (Slimed) Strcat(info, ", becoming slimy");
if (Strangled) Strcat(info, ", being strangled");
if (Vomiting) Strcat(info, ", nauseated"); /* !"nauseous" */
if (Confusion) Strcat(info, ", confused");
if (Blind) {
Strcat(info, ", blind");
if (u.ucreamed) {
if ((long)u.ucreamed < Blinded || Blindfolded
|| !haseyes(youmonst.data))
Strcat(info, ", cover");
Strcat(info, "ed by sticky goop");
} /* note: "goop" == "glop"; variation is intentional */
}
if (Stunned) Strcat(info, ", stunned");
#ifdef STEED
if (!u.usteed)
#endif
if (Wounded_legs) {
const char *what = body_part(LEG);
if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
what = makeplural(what);
Sprintf(eos(info), ", injured %s", what);
}
if (Glib) Sprintf(eos(info), ", slippery %s",
makeplural(body_part(HAND)));
if (u.utrap) Strcat(info, ", trapped");
if (Fast) Strcat(info, Very_fast ?
", very fast" : ", fast");
if (u.uundetected) Strcat(info, ", concealed");
if (Invis) Strcat(info, ", invisible");
if (u.ustuck) {
if (sticks(youmonst.data))
Strcat(info, ", holding ");
else
Strcat(info, ", held by ");
Strcat(info, mon_nam(u.ustuck));
}
pline("Status of %s (%s%s): Level %d HP %d(%d) AC %d%s.",
plname,
(u.ualign.record >= 20) ? "piously " :
(u.ualign.record > 13) ? "devoutly " :
(u.ualign.record > 8) ? "fervently " :
(u.ualign.record > 3) ? "stridently " :
(u.ualign.record == 3) ? "" :
(u.ualign.record >= 1) ? "haltingly " :
(u.ualign.record == 0) ? "nominally " :
"insufficiently ",
align_str(u.ualign.type),
Upolyd ? mons[u.umonnum].mlevel : u.ulevel,
Upolyd ? u.mh : u.uhp,
Upolyd ? u.mhmax : u.uhpmax,
u.uac,
info);
}
void
self_invis_message()
{
pline("%s %s.",
Hallucination ? "Far out, man! You" : "Gee! All of a sudden, you",
See_invisible ? "can see right through yourself" :
"can't see yourself");
}
/*pline.c*/