mirror of
https://git.zap.org.au/git/trader.git
synced 2024-11-03 17:27:29 -05:00
Use wide-character functions for input routines and most strings
Convert all input routines, and most internal strings, to use wide-character functions. All extended characters are supported, including those having column widths of zero (eg, combining characters), one (eg, normal Western characters) and two (eg, many East Asian characters). This was quite a major undertaking!
This commit is contained in:
parent
b951b21894
commit
20473ae409
224
src/exch.c
224
src/exch.c
@ -97,7 +97,7 @@ void exchange_stock (void)
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1,
|
||||
_(" Interstellar Stock Exchange "));
|
||||
center(curwin, 2, 0, attr_normal, attr_highlight, 0, 1,
|
||||
_("Player: ^{%s^}"), player[current_player].name);
|
||||
_("Player: ^{%ls^}"), player[current_player].name);
|
||||
|
||||
all_off_map = true;
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
@ -143,19 +143,19 @@ void exchange_stock (void)
|
||||
- SHARE_RETURN_COLS, attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Price per share" is a two-line column
|
||||
label in a table containing the price per share in
|
||||
any given company. %s is the currency symbol in the
|
||||
current locale. The maximum column width is 12
|
||||
any given company. %ls is the currency symbol in
|
||||
the current locale. The maximum column width is 12
|
||||
characters INCLUDING the currency symbol (see
|
||||
SHARE_PRICE_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Price per\nshare (%s)"),
|
||||
lconvinfo.currency_symbol);
|
||||
pgettext("subtitle", "Price per\nshare (%ls)"),
|
||||
currency_symbol);
|
||||
|
||||
for (line = 6, i = 0; i < MAX_COMPANIES; i++) {
|
||||
if (company[i].on_map) {
|
||||
mvwaddch(curwin, line, 2, PRINTABLE_MAP_VAL(COMPANY_TO_MAP(i))
|
||||
| attr_choice);
|
||||
|
||||
left(curwin, line, 4, attr_normal, 0, 0, 1, "%s",
|
||||
left(curwin, line, 4, attr_normal, 0, 0, 1, "%ls",
|
||||
company[i].name);
|
||||
|
||||
right(curwin, line, w - 2, attr_normal, 0, 0, 1, "%'ld ",
|
||||
@ -196,48 +196,61 @@ void exchange_stock (void)
|
||||
|
||||
// Get the actual selection made by the player
|
||||
while (selection == SEL_NONE) {
|
||||
bool found;
|
||||
wint_t key;
|
||||
|
||||
int key = gettxchar(curwin);
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
bool found;
|
||||
|
||||
if (isupper(*keycode_company)) {
|
||||
key = toupper(key);
|
||||
} else if (islower(*keycode_company)) {
|
||||
key = tolower(key);
|
||||
}
|
||||
if (iswupper(*keycode_company)) {
|
||||
key = towupper(key);
|
||||
} else if (iswlower(*keycode_company)) {
|
||||
key = towlower(key);
|
||||
}
|
||||
|
||||
for (i = 0, found = false; keycode_company[i] != '\0'; i++) {
|
||||
if (keycode_company[i] == key) {
|
||||
found = true;
|
||||
if (company[i].on_map) {
|
||||
selection = i;
|
||||
} else {
|
||||
for (i = 0, found = false; keycode_company[i] != '\0'; i++) {
|
||||
if (keycode_company[i] == key) {
|
||||
found = true;
|
||||
if (company[i].on_map) {
|
||||
selection = i;
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found) {
|
||||
switch (key) {
|
||||
case '1':
|
||||
curs_set(CURS_OFF);
|
||||
show_status(current_player);
|
||||
curs_set(CURS_ON);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
curs_set(CURS_OFF);
|
||||
show_map(true);
|
||||
curs_set(CURS_ON);
|
||||
break;
|
||||
|
||||
case '3':
|
||||
selection = SEL_BANK;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
case ' ':
|
||||
selection = SEL_EXIT;
|
||||
break;
|
||||
|
||||
default:
|
||||
beep();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found) {
|
||||
} else {
|
||||
// Function or control key
|
||||
switch (key) {
|
||||
case '1':
|
||||
curs_set(CURS_OFF);
|
||||
show_status(current_player);
|
||||
curs_set(CURS_ON);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
curs_set(CURS_OFF);
|
||||
show_map(true);
|
||||
curs_set(CURS_ON);
|
||||
break;
|
||||
|
||||
case '3':
|
||||
selection = SEL_BANK;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
case ' ':
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
case KEY_EXIT:
|
||||
case KEY_CTRL('C'):
|
||||
@ -287,7 +300,7 @@ void visit_bank (void)
|
||||
{
|
||||
double credit_limit;
|
||||
double val, max;
|
||||
int key;
|
||||
wint_t key;
|
||||
bool done;
|
||||
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
@ -363,27 +376,41 @@ void visit_bank (void)
|
||||
|
||||
done = false;
|
||||
while (! done) {
|
||||
key = gettxchar(curwin);
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
switch (key) {
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
|
||||
0, 0, 1, "%lc", key);
|
||||
wrefresh(curwin);
|
||||
|
||||
switch (key) {
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
wechochar(curwin, key | A_BOLD);
|
||||
done = true;
|
||||
break;
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case KEY_CANCEL:
|
||||
case KEY_EXIT:
|
||||
case KEY_CTRL('C'):
|
||||
case KEY_CTRL('G'):
|
||||
case KEY_CTRL('\\'):
|
||||
done = true;
|
||||
break;
|
||||
case ' ':
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
beep();
|
||||
default:
|
||||
beep();
|
||||
}
|
||||
} else {
|
||||
// Function or control key
|
||||
switch (key) {
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
case KEY_EXIT:
|
||||
case KEY_CTRL('C'):
|
||||
case KEY_CTRL('G'):
|
||||
case KEY_CTRL('\\'):
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
beep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -410,8 +437,8 @@ void visit_bank (void)
|
||||
n = (lconvinfo.p_sep_by_space == 1) ? 1 : 0;
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, attr_normal | A_BOLD, 0, 1,
|
||||
getmaxx(curwin) / 2, &width_cursym, 1, "^{%s^}",
|
||||
lconvinfo.currency_symbol);
|
||||
getmaxx(curwin) / 2, &width_cursym, 1, "^{%ls^}",
|
||||
currency_symbol);
|
||||
chbuf_cursym = xchstrdup(chbuf);
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin)
|
||||
@ -468,8 +495,8 @@ void visit_bank (void)
|
||||
n = (lconvinfo.p_sep_by_space == 1) ? 1 : 0;
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, attr_normal | A_BOLD, 0, 1,
|
||||
getmaxx(curwin) / 2, &width_cursym, 1, "^{%s^}",
|
||||
lconvinfo.currency_symbol);
|
||||
getmaxx(curwin) / 2, &width_cursym, 1, "^{%ls^}",
|
||||
currency_symbol);
|
||||
chbuf_cursym = xchstrdup(chbuf);
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin)
|
||||
@ -527,11 +554,12 @@ void visit_bank (void)
|
||||
void trade_shares (int num, bool *bid_used)
|
||||
{
|
||||
bool done;
|
||||
int key, ret, w, x;
|
||||
int ret, w, x;
|
||||
long int maxshares, val;
|
||||
double ownership;
|
||||
chtype *chbuf;
|
||||
int width;
|
||||
wint_t key;
|
||||
|
||||
|
||||
assert(num >= 0 && num < MAX_COMPANIES);
|
||||
@ -548,8 +576,8 @@ void trade_shares (int num, bool *bid_used)
|
||||
w = getmaxx(curwin);
|
||||
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1,
|
||||
/* TRANSLATORS: %s represents the company name. */
|
||||
_(" Stock Transaction in %s "), company[num].name);
|
||||
/* TRANSLATORS: %ls represents the company name. */
|
||||
_(" Stock Transaction in %ls "), company[num].name);
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, w / 2, &width, 1,
|
||||
/* TRANSLATORS: "Shares issued" represents the number of
|
||||
@ -633,28 +661,42 @@ void trade_shares (int num, bool *bid_used)
|
||||
|
||||
done = false;
|
||||
while (! done) {
|
||||
key = gettxchar(curwin);
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
switch (key) {
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
|
||||
0, 0, 1, "%lc", key);
|
||||
wrefresh(curwin);
|
||||
|
||||
switch (key) {
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
wechochar(curwin, key | A_BOLD);
|
||||
done = true;
|
||||
break;
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case KEY_CANCEL:
|
||||
case KEY_EXIT:
|
||||
case KEY_CTRL('C'):
|
||||
case KEY_CTRL('G'):
|
||||
case KEY_CTRL('\\'):
|
||||
done = true;
|
||||
break;
|
||||
case ' ':
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
beep();
|
||||
default:
|
||||
beep();
|
||||
}
|
||||
} else {
|
||||
// Function or control key
|
||||
switch (key) {
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
case KEY_EXIT:
|
||||
case KEY_CTRL('C'):
|
||||
case KEY_CTRL('G'):
|
||||
case KEY_CTRL('\\'):
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
beep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -755,16 +797,16 @@ void trade_shares (int num, bool *bid_used)
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" No Shares Issued "),
|
||||
/* TRANSLATORS: %s represents the company name. */
|
||||
_("%s has refused\nto issue more shares."),
|
||||
/* TRANSLATORS: %ls represents the company name. */
|
||||
_("%ls has refused\nto issue more shares."),
|
||||
company[num].name);
|
||||
} else {
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_normal_window,
|
||||
attr_title, attr_normal, attr_highlight, 0,
|
||||
attr_waitforkey, _(" Shares Issued "),
|
||||
/* TRANSLATORS: %s represents the company name. */
|
||||
ngettext("%s has issued\n^{one^} more share.",
|
||||
"%s has issued\n^{%'ld^} more shares.",
|
||||
/* TRANSLATORS: %ls represents the company name. */
|
||||
ngettext("%ls has issued\n^{one^} more share.",
|
||||
"%ls has issued\n^{%'ld^} more shares.",
|
||||
maxshares), company[num].name, maxshares);
|
||||
}
|
||||
break;
|
||||
|
72
src/fileio.c
72
src/fileio.c
@ -83,7 +83,7 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
} while (0)
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
# define load_game_read_string(_var) \
|
||||
# define load_game_read_string(_var, _var_utf8) \
|
||||
do { \
|
||||
char *s; \
|
||||
int len; \
|
||||
@ -115,11 +115,14 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
s[len - 1] = '\0'; \
|
||||
} \
|
||||
\
|
||||
xmbstowcs(wcbuf, s, BUFSIZE); \
|
||||
(_var) = xwcsdup(wcbuf); \
|
||||
(_var_utf8) = s; \
|
||||
\
|
||||
lineno++; \
|
||||
(_var) = s; \
|
||||
} while (0)
|
||||
#else // ! USE_UTF8_GAME_FILE
|
||||
# define load_game_read_string(_var) \
|
||||
# define load_game_read_string(_var, _var_utf8) \
|
||||
do { \
|
||||
char *s; \
|
||||
int len; \
|
||||
@ -140,8 +143,11 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
s[len - 1] = '\0'; \
|
||||
} \
|
||||
\
|
||||
xmbstowcs(wcbuf, s, BUFSIZE); \
|
||||
(_var) = xwcsdup(wcbuf); \
|
||||
(_var_utf8) = s; \
|
||||
\
|
||||
lineno++; \
|
||||
(_var) = s; \
|
||||
} while (0)
|
||||
#endif // ! USE_UTF8_GAME_FILE
|
||||
|
||||
@ -165,27 +171,38 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
save_game_printf("%d", (int) _var)
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
# define save_game_write_string(_var) \
|
||||
# define save_game_write_string(_var, _var_utf8) \
|
||||
do { \
|
||||
if (need_icd) { \
|
||||
char *s = str_cd_iconv(_var, icd); \
|
||||
if (s == NULL) { \
|
||||
if (errno == EILSEQ) { \
|
||||
err_exit(_("%s: could not convert string"), \
|
||||
filename); \
|
||||
} else { \
|
||||
errno_exit("str_cd_iconv"); \
|
||||
} \
|
||||
} \
|
||||
save_game_printf("%s", s); \
|
||||
free(s); \
|
||||
if ((_var_utf8) != NULL) { \
|
||||
save_game_printf("%s", _var_utf8); \
|
||||
} else { \
|
||||
save_game_printf("%s", _var); \
|
||||
if (need_icd) { \
|
||||
snprintf(buf, BUFSIZE, "%ls", _var); \
|
||||
char *s = str_cd_iconv(buf, icd); \
|
||||
if (s == NULL) { \
|
||||
if (errno == EILSEQ) { \
|
||||
err_exit(_("%s: could not convert string"), \
|
||||
filename); \
|
||||
} else { \
|
||||
errno_exit("str_cd_iconv"); \
|
||||
} \
|
||||
} \
|
||||
save_game_printf("%s", s); \
|
||||
free(s); \
|
||||
} else { \
|
||||
save_game_printf("%ls", _var); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#else // ! USE_UTF8_GAME_FILE
|
||||
# define save_game_write_string(_var) \
|
||||
save_game_printf("%s", _var)
|
||||
# define save_game_write_string(_var, _var_utf8) \
|
||||
do { \
|
||||
if ((_var_utf8) != NULL) { \
|
||||
save_game_printf("%s", _var_utf8); \
|
||||
} else { \
|
||||
save_game_printf("%ls", _var); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif // ! USE_UTF8_GAME_FILE
|
||||
|
||||
|
||||
@ -201,12 +218,15 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
|
||||
bool load_game (int num)
|
||||
{
|
||||
char *buf, *filename;
|
||||
char *filename;
|
||||
FILE *file;
|
||||
char *codeset, *codeset_nl;
|
||||
int saved_errno, lineno;
|
||||
char *prev_locale;
|
||||
|
||||
char *buf;
|
||||
wchar_t *wcbuf;
|
||||
|
||||
int crypt_key;
|
||||
int n, i, j;
|
||||
|
||||
@ -219,6 +239,7 @@ bool load_game (int num)
|
||||
assert(num >= 1 && num <= 9);
|
||||
|
||||
buf = xmalloc(BUFSIZE);
|
||||
wcbuf = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||
|
||||
filename = game_filename(num);
|
||||
assert(filename != NULL);
|
||||
@ -246,6 +267,7 @@ bool load_game (int num)
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(wcbuf);
|
||||
free(filename);
|
||||
return false;
|
||||
}
|
||||
@ -332,7 +354,7 @@ bool load_game (int num)
|
||||
|
||||
// Read in player data
|
||||
for (i = 0; i < number_players; i++) {
|
||||
load_game_read_string(player[i].name);
|
||||
load_game_read_string(player[i].name, player[i].name_utf8);
|
||||
load_game_read_double(player[i].cash, player[i].cash >= 0.0);
|
||||
load_game_read_double(player[i].debt, player[i].debt >= 0.0);
|
||||
load_game_read_bool(player[i].in_game);
|
||||
@ -344,7 +366,8 @@ bool load_game (int num)
|
||||
|
||||
// Read in company data
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
company[i].name = xstrdup(gettext(company_name[i]));
|
||||
xmbstowcs(wcbuf, gettext(company_name[i]), BUFSIZE);
|
||||
company[i].name = xwcsdup(wcbuf);
|
||||
load_game_read_double(company[i].share_price, company[i].share_price >= 0.0);
|
||||
load_game_read_double(company[i].share_return, true);
|
||||
load_game_read_long(company[i].stock_issued, company[i].stock_issued >= 0);
|
||||
@ -391,6 +414,7 @@ bool load_game (int num)
|
||||
#endif
|
||||
|
||||
free(buf);
|
||||
free(wcbuf);
|
||||
free(filename);
|
||||
free(prev_locale);
|
||||
free(codeset_nl);
|
||||
@ -514,7 +538,7 @@ bool save_game (int num)
|
||||
|
||||
// Write out player data
|
||||
for (i = 0; i < number_players; i++) {
|
||||
save_game_write_string(player[i].name);
|
||||
save_game_write_string(player[i].name, player[i].name_utf8);
|
||||
save_game_write_double(player[i].cash);
|
||||
save_game_write_double(player[i].debt);
|
||||
save_game_write_bool(player[i].in_game);
|
||||
|
165
src/game.c
165
src/game.c
@ -108,48 +108,6 @@ static int cmp_player (const void *a, const void *b);
|
||||
|
||||
void init_game (void)
|
||||
{
|
||||
/* Initialise strings used for keycode input and map representations.
|
||||
|
||||
Each string must have an ASCII vertical line (U+007C) in the
|
||||
correct position, followed by context information (such as
|
||||
"input|Company" and "output|MapVals"). This is done to overcome a
|
||||
limitation of gettext_noop() and N_() that does NOT allow context
|
||||
IDs. This vertical line is replaced by a NUL character to
|
||||
terminate the resulting string. The vertical line MAY appear in
|
||||
other positions; if so, it is handled correctly. */
|
||||
|
||||
keycode_company = xstrdup(gettext(default_keycode_company));
|
||||
if (strlen(keycode_company) < MAX_COMPANIES + 1
|
||||
|| keycode_company[MAX_COMPANIES] != '|') {
|
||||
err_exit(_("keycode string for companies has incorrect format: `%s'"),
|
||||
keycode_company);
|
||||
}
|
||||
keycode_company[MAX_COMPANIES] = '\0';
|
||||
|
||||
keycode_game_move = xstrdup(gettext(default_keycode_game_move));
|
||||
if (strlen(keycode_game_move) < NUMBER_MOVES + 1
|
||||
|| keycode_game_move[NUMBER_MOVES] != '|') {
|
||||
err_exit(_("keycode string for game moves has incorrect format: `%s'"),
|
||||
keycode_game_move);
|
||||
}
|
||||
keycode_game_move[NUMBER_MOVES] = '\0';
|
||||
|
||||
printable_map_val = xstrdup(gettext(default_printable_map_val));
|
||||
if (strlen(printable_map_val) < MAX_COMPANIES + 4
|
||||
|| printable_map_val[MAX_COMPANIES + 3] != '|') {
|
||||
err_exit(_("output string for companies has incorrect format: `%s'"),
|
||||
printable_map_val);
|
||||
}
|
||||
printable_map_val[MAX_COMPANIES + 3] = '\0';
|
||||
|
||||
printable_game_move = xstrdup(gettext(default_printable_game_move));
|
||||
if (strlen(printable_game_move) < NUMBER_MOVES + 1
|
||||
|| printable_game_move[NUMBER_MOVES] != '|') {
|
||||
err_exit(_("output string for game moves has incorrect format: `%s'"),
|
||||
printable_game_move);
|
||||
}
|
||||
printable_game_move[NUMBER_MOVES] = '\0';
|
||||
|
||||
// Try to load an old game, if possible
|
||||
if (game_num != 0) {
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
@ -213,6 +171,8 @@ void init_game (void)
|
||||
}
|
||||
|
||||
if (! game_loaded) {
|
||||
wchar_t *buf = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||
|
||||
ask_player_names();
|
||||
|
||||
deltxwin(); // "Number of players" window
|
||||
@ -231,7 +191,8 @@ void init_game (void)
|
||||
|
||||
// Initialise company data
|
||||
for (int i = 0; i < MAX_COMPANIES; i++) {
|
||||
company[i].name = xstrdup(gettext(company_name[i]));
|
||||
xmbstowcs(buf, gettext(company_name[i]), BUFSIZE);
|
||||
company[i].name = xwcsdup(buf);
|
||||
company[i].share_price = 0.0;
|
||||
company[i].share_return = INITIAL_RETURN;
|
||||
company[i].stock_issued = 0;
|
||||
@ -263,10 +224,12 @@ void init_game (void)
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_normal_window,
|
||||
attr_title, attr_normal, attr_highlight, 0,
|
||||
attr_waitforkey, _(" First Player "),
|
||||
_("The first player to go is ^{%s^}."),
|
||||
_("The first player to go is ^{%ls^}."),
|
||||
player[first_player].name);
|
||||
txrefresh();
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,15 +243,14 @@ void init_game (void)
|
||||
|
||||
static int ask_number_players (void)
|
||||
{
|
||||
char *keycode_contgame;
|
||||
chtype *chbuf;
|
||||
wchar_t *keycode_contgame = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
int lines, maxwidth;
|
||||
int widthbuf[2];
|
||||
int key, ret;
|
||||
int ret;
|
||||
bool done;
|
||||
|
||||
|
||||
chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_keycode, 0, 2,
|
||||
WIN_COLS - 7, widthbuf, 2,
|
||||
/* TRANSLATORS: The keycode <C> should be modified to
|
||||
@ -311,21 +273,33 @@ static int ask_number_players (void)
|
||||
first character (keyboard input code) is used to print the user's
|
||||
response if one of those keys is pressed. Both upper and
|
||||
lower-case versions should be present. */
|
||||
keycode_contgame = xstrdup(pgettext("input|ContinueGame", "Cc"));
|
||||
xmbstowcs(keycode_contgame, pgettext("input|ContinueGame", "Cc"), BUFSIZE);
|
||||
|
||||
done = false;
|
||||
while (! done) {
|
||||
key = gettxchar(curwin);
|
||||
wint_t key;
|
||||
|
||||
if (key >= '1' && key <= MAX_PLAYERS + '0') {
|
||||
wechochar(curwin, key | A_BOLD);
|
||||
ret = key - '0';
|
||||
done = true;
|
||||
} else if (strchr(keycode_contgame, key) != NULL) {
|
||||
wechochar(curwin, ((unsigned char) *keycode_contgame) | A_BOLD);
|
||||
ret = 0;
|
||||
done = true;
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
if (key >= '1' && key <= MAX_PLAYERS + '0') {
|
||||
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
|
||||
0, 0, 1, "%lc", key);
|
||||
wrefresh(curwin);
|
||||
|
||||
ret = key - '0';
|
||||
done = true;
|
||||
} else if (wcschr(keycode_contgame, key) != NULL) {
|
||||
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
|
||||
0, 0, 1, "%lc", *keycode_contgame);
|
||||
wrefresh(curwin);
|
||||
|
||||
ret = 0;
|
||||
done = true;
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
} else {
|
||||
// Function or control key
|
||||
switch (key) {
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
@ -357,7 +331,7 @@ int ask_game_number (void)
|
||||
chtype *chbuf;
|
||||
int lines, maxwidth;
|
||||
int widthbuf[2];
|
||||
int key, ret;
|
||||
int ret;
|
||||
bool done;
|
||||
|
||||
|
||||
@ -378,13 +352,22 @@ int ask_game_number (void)
|
||||
|
||||
done = false;
|
||||
while (! done) {
|
||||
key = gettxchar(curwin);
|
||||
wint_t key;
|
||||
|
||||
if (key >= '1' && key <= '9') {
|
||||
wechochar(curwin, key | A_BOLD);
|
||||
ret = key - '0';
|
||||
done = true;
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
if (key >= '1' && key <= '9') {
|
||||
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
|
||||
0, 0, 1, "%lc", key);
|
||||
wrefresh(curwin);
|
||||
|
||||
ret = key - '0';
|
||||
done = true;
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
} else {
|
||||
// Function or control key
|
||||
switch (key) {
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
@ -426,10 +409,11 @@ void ask_player_names (void)
|
||||
int w = getmaxx(curwin) - x - 2;
|
||||
|
||||
player[0].name = NULL;
|
||||
player[0].name_utf8 = NULL;
|
||||
while (true) {
|
||||
int ret = gettxstr(curwin, &player[0].name, NULL, false,
|
||||
2, x, w, attr_input_field);
|
||||
if (ret == OK && strlen(player[0].name) != 0) {
|
||||
if (ret == OK && wcslen(player[0].name) != 0) {
|
||||
break;
|
||||
} else {
|
||||
beep();
|
||||
@ -460,6 +444,7 @@ void ask_player_names (void)
|
||||
|
||||
for (i = 0; i < number_players; i++) {
|
||||
player[i].name = NULL;
|
||||
player[i].name_utf8 = NULL;
|
||||
entered[i] = false;
|
||||
left(curwin, i + 3, 2, attr_normal, 0, 0, 1,
|
||||
/* xgettext:c-format, range: 1..8 */
|
||||
@ -478,7 +463,7 @@ void ask_player_names (void)
|
||||
switch (ret) {
|
||||
case OK:
|
||||
// Make sure name is not an empty string
|
||||
len = strlen(player[cur].name);
|
||||
len = wcslen(player[cur].name);
|
||||
entered[cur] = (len != 0);
|
||||
if (len == 0) {
|
||||
beep();
|
||||
@ -487,7 +472,7 @@ void ask_player_names (void)
|
||||
// Make sure name has not been entered already
|
||||
for (i = 0; i < number_players; i++) {
|
||||
if (i != cur && player[i].name != NULL
|
||||
&& strcmp(player[i].name, player[cur].name) == 0) {
|
||||
&& wcscmp(player[i].name, player[cur].name) == 0) {
|
||||
entered[cur] = false;
|
||||
beep();
|
||||
break;
|
||||
@ -601,10 +586,10 @@ void end_game (void)
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_highlight,
|
||||
attr_blink, 5, WIN_COLS - 8, widthbuf, 5,
|
||||
(player[0].sort_value == 0) ?
|
||||
_("The winner is ^{%s^}\n"
|
||||
_("The winner is ^{%ls^}\n"
|
||||
"who is ^[*** BANKRUPT ***^]") :
|
||||
/* xgettext:c-format */
|
||||
_("The winner is ^{%s^}\n"
|
||||
_("The winner is ^{%ls^}\n"
|
||||
"with a value of ^{%N^}."),
|
||||
player[0].name, player[0].sort_value);
|
||||
|
||||
@ -622,16 +607,15 @@ void end_game (void)
|
||||
pgettext("subtitle", "Player"));
|
||||
right(curwin, lines + 4, w - 4, attr_subtitle, 0, 0, 1,
|
||||
/* TRANSLATORS: "Total Value" refers to the total worth
|
||||
(shares, cash and debt) of any given player. %s is the
|
||||
(shares, cash and debt) of any given player. %ls is the
|
||||
currency symbol of the current locale. */
|
||||
pgettext("subtitle", "Total Value (%s)"),
|
||||
lconvinfo.currency_symbol);
|
||||
pgettext("subtitle", "Total Value (%ls)"), currency_symbol);
|
||||
|
||||
for (int i = 0; i < number_players; i++) {
|
||||
right(curwin, i + lines + 5, ORDINAL_COLS + 2, attr_normal, 0, 0,
|
||||
1, gettext(ordinal[i + 1]));
|
||||
left(curwin, i + lines + 5, ORDINAL_COLS + 4, attr_normal, 0, 0,
|
||||
1, "%s", player[i].name);
|
||||
1, "%ls", player[i].name);
|
||||
right(curwin, i + lines + 5, w - 2, attr_normal, 0, 0,
|
||||
1, " %!N ", player[i].sort_value);
|
||||
}
|
||||
@ -659,7 +643,7 @@ void show_map (bool closewin)
|
||||
|
||||
// Display current player and turn number
|
||||
left(curwin, 1, 4, attr_mapwin_title, attr_mapwin_highlight, 0, 1,
|
||||
_("Player: ^{%s^}"), player[current_player].name);
|
||||
_("Player: ^{%ls^}"), player[current_player].name);
|
||||
right(curwin, 1, getmaxx(curwin) - 2, attr_mapwin_title,
|
||||
attr_mapwin_highlight, attr_mapwin_blink, 1,
|
||||
(turn_number != max_turn) ? _(" Turn: ^{%d^} ") :
|
||||
@ -669,26 +653,11 @@ void show_map (bool closewin)
|
||||
for (int y = 0; y < MAX_Y; y++) {
|
||||
wmove(curwin, y + 3, 2);
|
||||
for (int x = 0; x < MAX_X; x++) {
|
||||
map_val_t m = galaxy_map[x][y];
|
||||
chtype *mapstr = CHTYPE_MAP_VAL(galaxy_map[x][y]);
|
||||
|
||||
switch (m) {
|
||||
case MAP_EMPTY:
|
||||
waddch(curwin, PRINTABLE_MAP_VAL(m) | attr_map_empty);
|
||||
break;
|
||||
|
||||
case MAP_OUTPOST:
|
||||
waddch(curwin, PRINTABLE_MAP_VAL(m) | attr_map_outpost);
|
||||
break;
|
||||
|
||||
case MAP_STAR:
|
||||
waddch(curwin, PRINTABLE_MAP_VAL(m) | attr_map_star);
|
||||
break;
|
||||
|
||||
default:
|
||||
waddch(curwin, PRINTABLE_MAP_VAL(m) | attr_map_company);
|
||||
break;
|
||||
while (*mapstr != '\0') {
|
||||
waddch(curwin, *mapstr++);
|
||||
}
|
||||
waddch(curwin, ' ' | attr_map_empty);
|
||||
}
|
||||
}
|
||||
|
||||
@ -724,7 +693,7 @@ void show_status (int num)
|
||||
attr_normal_window);
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1, _(" Stock Portfolio "));
|
||||
center(curwin, 2, 0, attr_normal, attr_highlight, 0, 1,
|
||||
_("Player: ^{%s^}"), player[num].name);
|
||||
_("Player: ^{%ls^}"), player[num].name);
|
||||
|
||||
val = total_value(num);
|
||||
if (val == 0.0) {
|
||||
@ -780,16 +749,16 @@ void show_status (int num)
|
||||
- SHARE_RETURN_COLS, attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Price per share" is a two-line column
|
||||
label in a table containing the price per share in
|
||||
any given company. %s is the currency symbol in the
|
||||
current locale. The maximum column width is 12
|
||||
any given company. %ls is the currency symbol in
|
||||
the current locale. The maximum column width is 12
|
||||
characters INCLUDING the currency symbol (see
|
||||
SHARE_PRICE_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Price per\nshare (%s)"),
|
||||
lconvinfo.currency_symbol);
|
||||
pgettext("subtitle", "Price per\nshare (%ls)"),
|
||||
currency_symbol);
|
||||
|
||||
for (line = 6, i = 0; i < MAX_COMPANIES; i++) {
|
||||
if (company[i].on_map) {
|
||||
left(curwin, line, 4, attr_normal, 0, 0, 1, "%s",
|
||||
left(curwin, line, 4, attr_normal, 0, 0, 1, "%ls",
|
||||
company[i].name);
|
||||
|
||||
right(curwin, line, w - 2, attr_normal, 0, 0, 1, "%.2f ",
|
||||
|
@ -128,10 +128,12 @@ player_info_t player[MAX_PLAYERS]; // Array of players
|
||||
map_val_t galaxy_map[MAX_X][MAX_Y]; // Map of the galaxy
|
||||
move_rec_t game_move[NUMBER_MOVES]; // Current moves
|
||||
|
||||
char *keycode_company; // Keycodes for each company
|
||||
char *keycode_game_move; // Keycodes for each game move
|
||||
char *printable_map_val; // Printable output for each map value
|
||||
char *printable_game_move; // Printable output for each game move
|
||||
wchar_t *keycode_company; // Keycodes for each company
|
||||
wchar_t *keycode_game_move; // Keycodes for each game move
|
||||
wchar_t *printable_map_val; // Printable output for each map value
|
||||
wchar_t *printable_game_move; // Printable output for each game move
|
||||
chtype *chtype_map_val[MAX_COMPANIES + 3]; // as chtype strings
|
||||
chtype *chtype_game_move[NUMBER_MOVES]; // as chtype strings
|
||||
|
||||
int max_turn; // Max. number of turns in game
|
||||
int turn_number; // Current turn (1 to max_turn)
|
||||
|
@ -32,7 +32,7 @@
|
||||
#define included_GLOBALS_H 1
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <system.h>
|
||||
|
||||
|
||||
/************************************************************************
|
||||
@ -97,7 +97,7 @@
|
||||
|
||||
// Information about each company
|
||||
typedef struct company_info {
|
||||
const char *name; // Company name
|
||||
wchar_t *name; // Company name
|
||||
double share_price; // Share price
|
||||
double share_return; // Return per share
|
||||
long int stock_issued; // Total stock sold to players
|
||||
@ -108,7 +108,8 @@ typedef struct company_info {
|
||||
|
||||
// Information about each player
|
||||
typedef struct player_info {
|
||||
char *name; // Player name
|
||||
wchar_t *name; // Player name
|
||||
char *name_utf8; // Player name (in UTF-8, for load/save)
|
||||
double cash; // Cash available
|
||||
double debt; // Amount of debt
|
||||
long int stock_owned[MAX_COMPANIES]; // How much stock is owned
|
||||
@ -130,11 +131,14 @@ typedef enum map_val {
|
||||
#define MAP_TO_COMPANY(m) ((m) - MAP_A)
|
||||
#define IS_MAP_COMPANY(m) ((m) >= MAP_A && (m) <= MAP_LAST)
|
||||
|
||||
#define PRINTABLE_MAP_VAL(m) \
|
||||
(((m) == MAP_EMPTY) ? printable_map_val[0] : \
|
||||
(((m) == MAP_OUTPOST) ? printable_map_val[1] : \
|
||||
(((m) == MAP_STAR) ? printable_map_val[2] : \
|
||||
printable_map_val[(m) - MAP_A + 3])))
|
||||
#define MAP_TO_INDEX(m) \
|
||||
(((m) == MAP_EMPTY) ? 0 : \
|
||||
(((m) == MAP_OUTPOST) ? 1 : \
|
||||
(((m) == MAP_STAR) ? 2 : \
|
||||
((m) - MAP_A + 3))))
|
||||
|
||||
#define PRINTABLE_MAP_VAL(m) printable_map_val[MAP_TO_INDEX(m)]
|
||||
#define CHTYPE_MAP_VAL(m) chtype_map_val[MAP_TO_INDEX(m)]
|
||||
|
||||
|
||||
// Information about a move
|
||||
@ -144,6 +148,7 @@ typedef struct move_rec {
|
||||
} move_rec_t;
|
||||
|
||||
#define PRINTABLE_GAME_MOVE(m) (printable_game_move[m])
|
||||
#define CHTYPE_GAME_MOVE(m) (chtype_game_move[m])
|
||||
|
||||
|
||||
// Player moves / selection values
|
||||
@ -193,10 +198,12 @@ extern player_info_t player[MAX_PLAYERS]; // Array of players
|
||||
extern map_val_t galaxy_map[MAX_X][MAX_Y]; // Map of the galaxy
|
||||
extern move_rec_t game_move[NUMBER_MOVES]; // Current moves
|
||||
|
||||
extern char *keycode_company; // Keycodes for each company
|
||||
extern char *keycode_game_move; // Keycodes for each game move
|
||||
extern char *printable_map_val; // Printable output for each map value
|
||||
extern char *printable_game_move; // Printable output for each game move
|
||||
extern wchar_t *keycode_company; // Keycodes for each company
|
||||
extern wchar_t *keycode_game_move; // Keycodes for each game move
|
||||
extern wchar_t *printable_map_val; // Printable output for each map value
|
||||
extern wchar_t *printable_game_move; // Printable output for each game move
|
||||
extern chtype *chtype_map_val[MAX_COMPANIES + 3]; // as chtype strings
|
||||
extern chtype *chtype_game_move[NUMBER_MOVES]; // as chtype strings
|
||||
|
||||
extern int max_turn; // Max. number of turns in game
|
||||
extern int turn_number; // Current turn (1 to max_turn)
|
||||
|
80
src/help.c
80
src/help.c
@ -279,7 +279,6 @@ void show_help (void)
|
||||
char *cp;
|
||||
mbstate_t mbstate;
|
||||
chtype *outp;
|
||||
wchar_t c;
|
||||
size_t i, n;
|
||||
|
||||
int count = BIGBUFSIZE;
|
||||
@ -387,36 +386,31 @@ void show_help (void)
|
||||
case '8':
|
||||
case '9':
|
||||
// N-th choice of move, as a key press
|
||||
c = btowc(PRINTABLE_GAME_MOVE(*htxt - L'1'));
|
||||
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
|
||||
wcbuf[0] = PRINTABLE_GAME_MOVE(*htxt - L'1');
|
||||
wcbuf[1] = '\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case 'M':
|
||||
// Last choice of move, as a key press
|
||||
c = btowc(PRINTABLE_GAME_MOVE(NUMBER_MOVES - 1));
|
||||
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
|
||||
wcbuf[0] = PRINTABLE_GAME_MOVE(NUMBER_MOVES - 1);
|
||||
wcbuf[1] = '\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case '.':
|
||||
// Map representation of empty space
|
||||
c = btowc(PRINTABLE_MAP_VAL(MAP_EMPTY));
|
||||
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
|
||||
wcbuf[0] = PRINTABLE_MAP_VAL(MAP_EMPTY);
|
||||
wcbuf[1] = '\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case '+':
|
||||
// Map representation of an outpost
|
||||
c = btowc(PRINTABLE_MAP_VAL(MAP_OUTPOST));
|
||||
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
|
||||
wcbuf[0] = PRINTABLE_MAP_VAL(MAP_OUTPOST);
|
||||
wcbuf[1] = '\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case '*':
|
||||
// Map representation of a star
|
||||
c = btowc(PRINTABLE_MAP_VAL(MAP_STAR));
|
||||
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
|
||||
wcbuf[0] = PRINTABLE_MAP_VAL(MAP_STAR);
|
||||
wcbuf[1] = '\0';
|
||||
goto addwcbuf;
|
||||
|
||||
@ -429,8 +423,8 @@ void show_help (void)
|
||||
case 'G':
|
||||
case 'H':
|
||||
// Map representation of company
|
||||
c = btowc(PRINTABLE_MAP_VAL(COMPANY_TO_MAP(*htxt - L'A')));
|
||||
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
|
||||
assert((*htxt - L'A') < MAX_COMPANIES);
|
||||
wcbuf[0] = PRINTABLE_MAP_VAL(COMPANY_TO_MAP(*htxt - L'A'));
|
||||
wcbuf[1] = '\0';
|
||||
goto addwcbuf;
|
||||
|
||||
@ -486,35 +480,41 @@ void show_help (void)
|
||||
"for the previous page ] "));
|
||||
wrefresh(curwin);
|
||||
|
||||
int key = gettxchar(curwin);
|
||||
|
||||
switch (key) {
|
||||
case KEY_BS:
|
||||
case KEY_BACKSPACE:
|
||||
case KEY_DEL:
|
||||
case KEY_PPAGE:
|
||||
case KEY_UP:
|
||||
case KEY_LEFT:
|
||||
case KEY_BTAB:
|
||||
if (curpage == 0) {
|
||||
beep();
|
||||
} else {
|
||||
curpage--;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
case KEY_EXIT:
|
||||
case KEY_CTRL('C'):
|
||||
case KEY_CTRL('G'):
|
||||
case KEY_CTRL('\\'):
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
wint_t key;
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
curpage++;
|
||||
done = (curpage == numpages);
|
||||
} else {
|
||||
// Function or control character
|
||||
switch (key) {
|
||||
case KEY_BS:
|
||||
case KEY_BACKSPACE:
|
||||
case KEY_DEL:
|
||||
case KEY_PPAGE:
|
||||
case KEY_UP:
|
||||
case KEY_LEFT:
|
||||
case KEY_BTAB:
|
||||
if (curpage == 0) {
|
||||
beep();
|
||||
} else {
|
||||
curpage--;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
case KEY_EXIT:
|
||||
case KEY_CTRL('C'):
|
||||
case KEY_CTRL('G'):
|
||||
case KEY_CTRL('\\'):
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
curpage++;
|
||||
done = (curpage == numpages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
1212
src/intf.c
1212
src/intf.c
File diff suppressed because it is too large
Load Diff
109
src/intf.h
109
src/intf.h
@ -105,8 +105,8 @@ typedef enum curs_type {
|
||||
#define KEY_CTRL(x) ((x) - 0100) // ASCII control character
|
||||
|
||||
// Keycodes for inserting the default value in input routines
|
||||
#define KEY_DEFAULTVAL1 '='
|
||||
#define KEY_DEFAULTVAL2 ';'
|
||||
#define CHAR_DEFVAL1 '='
|
||||
#define CHAR_DEFVAL2 ';'
|
||||
|
||||
// Control-arrow key combinations, as returned by Ncurses
|
||||
#ifndef KEY_CDOWN
|
||||
@ -116,6 +116,11 @@ typedef enum curs_type {
|
||||
# define KEY_CRIGHT 01052 // CTRL + Right Arrow
|
||||
#endif
|
||||
|
||||
// Function-key result, for Curses that do not define it
|
||||
#ifndef KEY_CODE_YES
|
||||
# define KEY_CODE_YES 0400
|
||||
#endif
|
||||
|
||||
// Timeout value (in ms) for Meta-X-style keyboard input
|
||||
#ifdef NCURSES_VERSION
|
||||
# define META_TIMEOUT ESCDELAY
|
||||
@ -321,7 +326,7 @@ extern int txdlgbox (int maxlines, int ncols, int begin_y, int begin_x,
|
||||
Returns: int - Number of lines actually used
|
||||
|
||||
This function converts the format string and following arguments into
|
||||
chbuf, a chtype buffer that can be used for calls to leftch(), centerch()
|
||||
chbuf, a chtype string that can be used for calls to leftch(), centerch()
|
||||
and rightch(). At most maxlines lines are used, each with a maximum
|
||||
width of maxwidth. The actual widths of each resulting line are stored
|
||||
in widthbuf (which must not be NULL). If maxlines is greater than 1,
|
||||
@ -534,26 +539,26 @@ extern int right (WINDOW *win, int y, int x, chtype attr_norm, chtype attr_alt1,
|
||||
|
||||
|
||||
/*
|
||||
Function: gettxchar - Read a character from the keyboard
|
||||
Function: gettxchar - Read a wide character from the keyboard
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
Returns: int - The keyboard character
|
||||
wch - Pointer to keyboard wide character
|
||||
Returns: int - OK or KEY_CODE_YES
|
||||
|
||||
This function reads a single character from the keyboard. The key is
|
||||
NOT echoed to the terminal display, nor is the cursor visibility
|
||||
affected.
|
||||
|
||||
This implementation does not handle multibyte characters correctly:
|
||||
each part of the multibyte character most likely appears as a separate
|
||||
keyboard press.
|
||||
This function waits until the user presses a key on the keyboard, then
|
||||
reads that key as a single wide character. If it is a function key or
|
||||
a control key, it is stored in wch and KEY_CODE_YES is returned.
|
||||
Otherwise, it is an ordinary key: it is also stored in wch and OK is
|
||||
returned. ERR is never returned. The key is NOT echoed to the
|
||||
terminal display, nor is the cursor visibility affected.
|
||||
*/
|
||||
extern int gettxchar (WINDOW *win);
|
||||
extern int gettxchar (WINDOW *win, wint_t *wch);
|
||||
|
||||
|
||||
/*
|
||||
Function: gettxline - Read a line from the keyboard (low-level)
|
||||
Function: gettxline - Read a line of input from the keyboard (low-level)
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
buf - Pointer to preallocated buffer
|
||||
bufsize - Size of buffer in bytes
|
||||
bufsize - Size of buffer (number of wchar_t elements)
|
||||
modified - Pointer to modified status (result)
|
||||
multifield - Allow <TAB>, etc, to exit this function
|
||||
emptyval - String used if input line is empty
|
||||
@ -561,14 +566,14 @@ extern int gettxchar (WINDOW *win);
|
||||
allowed - Characters allowed in the input line
|
||||
stripspc - True to strip leading/trailing spaces
|
||||
y, x - Start of the input field (line, column)
|
||||
width - Width of the input field
|
||||
width - Width of the input field (column spaces)
|
||||
attr - Character rendition to use for input field
|
||||
Returns: int - Status code: OK, ERR or KEY_ keycode
|
||||
|
||||
This low-level function draws an input field width characters long
|
||||
This low-level function shows an input field width column spaces long
|
||||
using attr as the character rendition, then reads a line of input from
|
||||
the keyboard and places it into the preallocated buffer buf[] of size
|
||||
bufsize. On entry, buf[] must contain a valid C string; this string is
|
||||
bufsize. On entry, buf[] must contain a valid string; this string is
|
||||
used as the initial contents of the input field. On exit, buf[]
|
||||
contains the final string as edited or input by the user. This string
|
||||
is printed in place of the input field using the original character
|
||||
@ -580,13 +585,13 @@ extern int gettxchar (WINDOW *win);
|
||||
empty string is entered, the string pointed to by emptyval (if not
|
||||
NULL) is stored in buf[].
|
||||
|
||||
If CANCEL, EXIT, ESC, ^C, ^\ or ^G is pressed, ERR is returned. In
|
||||
If ESC, CANCEL, EXIT, ^C, ^G or ^\ is pressed, ERR is returned. In
|
||||
this case, buf[] contains the string as left by the user: emptyval is
|
||||
NOT used, nor are leading and trailing spaces stripped.
|
||||
|
||||
If multifield is true, the UP and DOWN arrow keys, as well as TAB,
|
||||
Shift-TAB, ^P (Previous) and ^N (Next) return KEY_UP or KEY_DOWN as
|
||||
appropriate. As with CANCEL etc., emptyval is NOT used, nor are
|
||||
Shift-TAB, ^P (Previous) and ^N (Next) return either KEY_UP or KEY_DOWN
|
||||
as appropriate. As with ESC etc., emptyval is NOT used, nor are
|
||||
leading and trailing spaces stripped.
|
||||
|
||||
In all of these cases, the boolean variable *modified (if modified is
|
||||
@ -594,7 +599,7 @@ extern int gettxchar (WINDOW *win);
|
||||
way (including if the user made any changed, spaces were stripped or if
|
||||
emptyval was copied into buf[]).
|
||||
|
||||
If KEY_DEFAULTVAL1 or KEY_DEFAULTVAL2 is pressed when the input line is
|
||||
If either KEY_DEFVAL1 or KEY_DEFVAL2 is pressed when the input line is
|
||||
empty, the string pointed to by defaultval (if not NULL) is placed in
|
||||
the buffer as if typed by the user. Editing is NOT terminated in this
|
||||
case.
|
||||
@ -607,17 +612,12 @@ extern int gettxchar (WINDOW *win);
|
||||
Note that the character rendition (attributes) in attr may contain a
|
||||
printing character. For example, A_BOLD | '_' is a valid rendition
|
||||
that causes the input field to be a series of "_" characters in bold.
|
||||
|
||||
This implementation does not handle multibyte characters correctly:
|
||||
each part of the multibyte character most likely appears as a separate
|
||||
keyboard press and is handled as a separate character, causing the
|
||||
cursor position to be incorrect. In addition, allowed is compared on a
|
||||
byte-by-byte basis, not character-by-character.
|
||||
Note also that the cursor becomes invisible after calling this function.
|
||||
*/
|
||||
extern int gettxline (WINDOW *win, char *buf, int bufsize,
|
||||
extern int gettxline (WINDOW *win, wchar_t *restrict buf, int bufsize,
|
||||
bool *restrict modified, bool multifield,
|
||||
const char *emptyval, const char *defaultval,
|
||||
const char *allowed, bool stripspc, int y, int x,
|
||||
const wchar_t *emptyval, const wchar_t *defaultval,
|
||||
const wchar_t *allowed, bool stripspc, int y, int x,
|
||||
int width, chtype attr);
|
||||
|
||||
|
||||
@ -633,18 +633,19 @@ extern int gettxline (WINDOW *win, char *buf, int bufsize,
|
||||
Returns: int - Status code: OK, ERR or KEY_ keycode
|
||||
|
||||
This function calls gettxline() to allow the user to enter a string via
|
||||
the keyboard. On entry, bufptr must be the address of a char * pointer
|
||||
variable; that pointer (*bufptr) must either be NULL or contain the
|
||||
address of a buffer previously allocated with gettxstr(). If *bufptr
|
||||
is NULL, a buffer of BUFSIZE is automatically allocated using malloc();
|
||||
this buffer is used to store and return the input line.
|
||||
the keyboard. On entry, bufptr must be the address of a wchar_t *
|
||||
pointer variable; that pointer (*bufptr) must either be NULL or contain
|
||||
the address of a buffer previously allocated with gettxstr(). If
|
||||
*bufptr is NULL, a buffer of BUFSIZE is automatically allocated using
|
||||
malloc(); this buffer is used to store and return the input line.
|
||||
|
||||
Apart from bufptr, all parameters are as used for gettxline(). The
|
||||
gettxline() parameters emptyval and defaultval are passed as "",
|
||||
allowed is NULL and stripspc is true.
|
||||
*/
|
||||
extern int gettxstr (WINDOW *win, char **bufptr, bool *restrict modified,
|
||||
bool multifield, int y, int x, int width, chtype attr);
|
||||
extern int gettxstr (WINDOW *win, wchar_t *restrict *restrict bufptr,
|
||||
bool *restrict modified, bool multifield,
|
||||
int y, int x, int width, chtype attr);
|
||||
|
||||
|
||||
/*
|
||||
@ -656,7 +657,7 @@ extern int gettxstr (WINDOW *win, char **bufptr, bool *restrict modified,
|
||||
emptyval - Value to use for empty input
|
||||
defaultval - Value to use for default input
|
||||
y, x - Start of the input field (line, column)
|
||||
width - Width of the input field
|
||||
width - Width of the input field (column spaces)
|
||||
attr - Character rendition to use for input field
|
||||
Returns: int - Status code: OK, ERR or KEY_ keycode
|
||||
|
||||
@ -668,12 +669,11 @@ extern int gettxstr (WINDOW *win, char **bufptr, bool *restrict modified,
|
||||
result from gettxline() is passed back to the caller. Note that the
|
||||
low-level function gettxline() is called with multifield set to false.
|
||||
|
||||
This function is locale-aware, although multibyte strings are not
|
||||
handled correctly. In particular, the default value is formatted using
|
||||
strfmon() and uses the locale monetary default decimal places
|
||||
(frac_digits). In addition, the user is allowed to use the locale's
|
||||
radix character (decimal point) and the thousands separator, as well as
|
||||
the monetary versions of these.
|
||||
This function is locale-aware. In particular, the default value is
|
||||
formatted using strfmon() and uses the locale monetary default decimal
|
||||
places (frac_digits). In addition, the user is allowed to use the
|
||||
locale's radix character (decimal point) and the thousands separator,
|
||||
as well as the monetary versions of these.
|
||||
*/
|
||||
extern int gettxdouble (WINDOW *win, double *restrict result, double min,
|
||||
double max, double emptyval, double defaultval,
|
||||
@ -696,9 +696,9 @@ extern int gettxdouble (WINDOW *win, double *restrict result, double min,
|
||||
This function behaves almost exactly like gettxdouble(), except that
|
||||
only integer numbers are allowed to be entered.
|
||||
|
||||
This function is locale-aware, although multibyte strings are not
|
||||
handled correctly. In particular, the user is allowed to use the
|
||||
locale's thousands separator and the monetary thousands separator.
|
||||
This function is locale-aware. In particular, the user is allowed to
|
||||
use the locale's thousands separator and the monetary thousands
|
||||
separator.
|
||||
*/
|
||||
extern int gettxlong (WINDOW *win, long int *restrict result, long int min,
|
||||
long int max, long int emptyval, long int defaultval,
|
||||
@ -710,10 +710,11 @@ extern int gettxlong (WINDOW *win, long int *restrict result, long int min,
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
Returns: bool - True if Yes was selected, false if No
|
||||
|
||||
This function waits for the user to press either "Y" (for Yes) or "N"
|
||||
(for No) on the keyboard, then prints the answer using A_BOLD. True is
|
||||
returned if "Y" was selected, false if "N". Note that the cursor
|
||||
becomes invisible after calling this function.
|
||||
This function waits for the user to press either the locale-specific
|
||||
equivalent of "Y" (for Yes) or "N" (for No) on the keyboard, then
|
||||
prints the answer using A_BOLD. True is returned if "Y" was selected,
|
||||
false if "N". Note that the cursor becomes invisible after calling
|
||||
this function.
|
||||
*/
|
||||
extern bool answer_yesno (WINDOW *win);
|
||||
|
||||
@ -730,10 +731,6 @@ extern bool answer_yesno (WINDOW *win);
|
||||
|
||||
The reason the user is not asked "Press any key to continue" is
|
||||
historical: many, many people used to ask "where is the <ANY> key?" :-)
|
||||
|
||||
The current implementation does not handle multibyte characters
|
||||
correctly: only the first byte of the character is consumed, with
|
||||
further bytes left in the keyboard queue.
|
||||
*/
|
||||
extern void wait_for_key (WINDOW *win, int y, chtype attr);
|
||||
|
||||
|
163
src/move.c
163
src/move.c
@ -219,8 +219,8 @@ selection_t get_move (void)
|
||||
|
||||
// Display current move choices on the galaxy map
|
||||
for (int i = 0; i < NUMBER_MOVES; i++) {
|
||||
mvwaddch(curwin, game_move[i].y + 3, game_move[i].x * 2 + 2,
|
||||
PRINTABLE_GAME_MOVE(i) | attr_map_choice);
|
||||
mvwaddchstr(curwin, game_move[i].y + 3, game_move[i].x * 2 + 2,
|
||||
CHTYPE_GAME_MOVE(i));
|
||||
}
|
||||
wrefresh(curwin);
|
||||
|
||||
@ -242,7 +242,7 @@ selection_t get_move (void)
|
||||
|
||||
right(curwin, 1, getmaxx(curwin) / 2, attr_normal, attr_keycode,
|
||||
attr_choice, 1,
|
||||
_("Select move [^[%c^]-^[%c^]/^{1^}-^{3^}/^{<CTRL><C>^}]: "),
|
||||
_("Select move [^[%lc^]-^[%lc^]/^{1^}-^{3^}/^{<CTRL><C>^}]: "),
|
||||
PRINTABLE_GAME_MOVE(0), PRINTABLE_GAME_MOVE(NUMBER_MOVES - 1));
|
||||
|
||||
curs_set(CURS_ON);
|
||||
@ -250,60 +250,69 @@ selection_t get_move (void)
|
||||
|
||||
// Get the actual selection made by the player
|
||||
while (selection == SEL_NONE) {
|
||||
int i;
|
||||
bool found;
|
||||
wint_t key;
|
||||
|
||||
int key = gettxchar(curwin);
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
int i;
|
||||
bool found;
|
||||
|
||||
if (isupper(*keycode_game_move)) {
|
||||
key = toupper(key);
|
||||
} else if (islower(*keycode_game_move)) {
|
||||
key = tolower(key);
|
||||
}
|
||||
|
||||
for (i = 0, found = false; keycode_game_move[i] != '\0'; i++) {
|
||||
if (keycode_game_move[i] == key) {
|
||||
found = true;
|
||||
selection = i;
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
|
||||
attr_choice, 0, 1,
|
||||
/* TRANSLATORS: "Move" refers to the choice of
|
||||
moves made by the current player (out of a
|
||||
selection of 20 moves). */
|
||||
_("Move ^{%c^}"), PRINTABLE_GAME_MOVE(i));
|
||||
|
||||
break;
|
||||
if (iswupper(*keycode_game_move)) {
|
||||
key = towupper(key);
|
||||
} else if (iswlower(*keycode_game_move)) {
|
||||
key = towlower(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (! found) {
|
||||
for (i = 0, found = false; keycode_game_move[i] != '\0'; i++) {
|
||||
if (keycode_game_move[i] == key) {
|
||||
found = true;
|
||||
selection = i;
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
|
||||
attr_choice, 0, 1,
|
||||
/* TRANSLATORS: "Move" refers to the choice of
|
||||
moves made by the current player (out of a
|
||||
selection of 20 moves). */
|
||||
_("Move ^{%lc^}"), PRINTABLE_GAME_MOVE(i));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found) {
|
||||
switch (key) {
|
||||
case '1':
|
||||
curs_set(CURS_OFF);
|
||||
show_status(current_player);
|
||||
curs_set(CURS_ON);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
selection = SEL_BANKRUPT;
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
|
||||
attr_normal | A_BOLD, 0, 1,
|
||||
_("^{<2>^} (Declare bankruptcy)"));
|
||||
break;
|
||||
|
||||
case '3':
|
||||
selection = SEL_SAVE;
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
|
||||
attr_normal | A_BOLD, 0, 1,
|
||||
_("^{<3>^} (Save and end the game)"));
|
||||
break;
|
||||
|
||||
default:
|
||||
beep();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Function or control key
|
||||
switch (key) {
|
||||
case '1':
|
||||
curs_set(CURS_OFF);
|
||||
show_status(current_player);
|
||||
curs_set(CURS_ON);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
selection = SEL_BANKRUPT;
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
|
||||
attr_normal | A_BOLD, 0, 1,
|
||||
_("^{<2>^} (Declare bankruptcy)"));
|
||||
break;
|
||||
|
||||
case '3':
|
||||
selection = SEL_SAVE;
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
|
||||
attr_normal | A_BOLD, 0, 1,
|
||||
_("^{<3>^} (Save and end the game)"));
|
||||
break;
|
||||
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
case KEY_EXIT:
|
||||
@ -361,10 +370,10 @@ selection_t get_move (void)
|
||||
if (! saved) {
|
||||
// Ask which game to save
|
||||
|
||||
int key;
|
||||
bool done;
|
||||
int widthbuf[2];
|
||||
int lines, maxwidth;
|
||||
int choice;
|
||||
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_keycode, 0,
|
||||
2, WIN_COLS - 7, widthbuf, 2,
|
||||
@ -383,12 +392,22 @@ selection_t get_move (void)
|
||||
|
||||
done = false;
|
||||
while (! done) {
|
||||
key = gettxchar(curwin);
|
||||
wint_t key;
|
||||
|
||||
if (key >= '1' && key <= '9') {
|
||||
wechochar(curwin, key | A_BOLD);
|
||||
done = true;
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
if (key >= '1' && key <= '9') {
|
||||
left(curwin, getcury(curwin), getcurx(curwin),
|
||||
A_BOLD, 0, 0, 1, "%lc", key);
|
||||
wrefresh(curwin);
|
||||
|
||||
choice = key - '0';
|
||||
done = true;
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
} else {
|
||||
// Function or control key
|
||||
switch (key) {
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
@ -396,7 +415,7 @@ selection_t get_move (void)
|
||||
case KEY_CTRL('C'):
|
||||
case KEY_CTRL('G'):
|
||||
case KEY_CTRL('\\'):
|
||||
key = KEY_CANCEL;
|
||||
choice = ERR;
|
||||
done = true;
|
||||
break;
|
||||
|
||||
@ -408,9 +427,10 @@ selection_t get_move (void)
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
|
||||
if (key != KEY_CANCEL) {
|
||||
if (choice != ERR) {
|
||||
// Try to save the game, if possible
|
||||
game_num = key - '0';
|
||||
|
||||
game_num = choice;
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_status_window, 0, 0, 1,
|
||||
WIN_COLS - 7, &width, 1,
|
||||
@ -645,14 +665,14 @@ void bankrupt_player (bool forced)
|
||||
txdlgbox(MAX_DLG_LINES, 50, 7, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" Bankruptcy Court "),
|
||||
_("%s has been declared bankrupt "
|
||||
_("%ls has been declared bankrupt "
|
||||
"by the Interstellar Trading Bank."),
|
||||
player[current_player].name);
|
||||
} else {
|
||||
txdlgbox(MAX_DLG_LINES, 50, 7, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" Bankruptcy Court "),
|
||||
_("%s has declared bankruptcy."),
|
||||
_("%ls has declared bankruptcy."),
|
||||
player[current_player].name);
|
||||
}
|
||||
txrefresh();
|
||||
@ -721,7 +741,7 @@ void try_start_new_company (int x, int y)
|
||||
txdlgbox(MAX_DLG_LINES, 50, 7, WCENTER, attr_normal_window,
|
||||
attr_title, attr_normal, attr_highlight, 0, attr_waitforkey,
|
||||
_(" New Company "),
|
||||
_("A new company has been formed!\nIts name is ^{%s^}."),
|
||||
_("A new company has been formed!\nIts name is ^{%ls^}."),
|
||||
company[i].name);
|
||||
txrefresh();
|
||||
|
||||
@ -777,7 +797,7 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_highlight, 0, 4,
|
||||
WIN_COLS - 8, widthbuf, 4,
|
||||
_("^{%s^} has just merged into ^{%s^}.\n"
|
||||
_("^{%ls^} has just merged into ^{%ls^}.\n"
|
||||
"Please note the following transactions:\n"),
|
||||
company[bb].name, company[aa].name);
|
||||
|
||||
@ -787,11 +807,11 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
centerch(curwin, 3, 0, chbuf, lines, widthbuf);
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_highlight, 0, 0, 1, getmaxx(curwin) / 2,
|
||||
&width_aa, 1, "%s", company[aa].name);
|
||||
&width_aa, 1, "%ls", company[aa].name);
|
||||
chbuf_aa = xchstrdup(chbuf);
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_highlight, 0, 0, 1, getmaxx(curwin) / 2,
|
||||
&width_bb, 1, "%s", company[bb].name);
|
||||
&width_bb, 1, "%ls", company[bb].name);
|
||||
chbuf_bb = xchstrdup(chbuf);
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin) / 2,
|
||||
@ -824,12 +844,11 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
pgettext("subtitle", "Player"));
|
||||
right(curwin, lines + 6, w - 4, attr_subtitle, 0, 0, 1,
|
||||
/* TRANSLATORS: "Bonus" refers to the bonus cash amount paid to
|
||||
each player after two companies merge. %s is the currency
|
||||
each player after two companies merge. %ls is the currency
|
||||
symbol in the current locale. The maximum column width is
|
||||
12 characters INCLUDING the currency symbol (see
|
||||
MERGE_BONUS_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Bonus (%s)"),
|
||||
lconvinfo.currency_symbol);
|
||||
pgettext("subtitle", "Bonus (%ls)"), currency_symbol);
|
||||
right(curwin, lines + 6, w - 6 - MERGE_BONUS_COLS, attr_subtitle, 0, 0, 1,
|
||||
/* TRANSLATORS: "Total" refers to the total number of shares in
|
||||
the new company after a merger. The maximum column width is
|
||||
@ -868,7 +887,7 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, w - 12
|
||||
- MERGE_BONUS_COLS - MERGE_TOTAL_STOCK_COLS
|
||||
- MERGE_NEW_STOCK_COLS - MERGE_OLD_STOCK_COLS,
|
||||
&width, 1, "%s", player[i].name);
|
||||
&width, 1, "%ls", player[i].name);
|
||||
leftch(curwin, ln, 4, chbuf, 1, &width);
|
||||
|
||||
right(curwin, ln, w - 4, attr_normal, 0, 0, 1, "%!N", bonus);
|
||||
@ -994,7 +1013,7 @@ void adjust_values (void)
|
||||
attr_error_title, attr_error_highlight,
|
||||
attr_error_normal, 0, attr_error_waitforkey,
|
||||
_(" Bankruptcy Court "),
|
||||
_("%s has been declared bankrupt "
|
||||
_("%ls has been declared bankrupt "
|
||||
"by the Interstellar Trading Bank.\n\n"
|
||||
"^{All assets have been taken "
|
||||
"to repay outstanding loans.^}"),
|
||||
@ -1016,7 +1035,7 @@ void adjust_values (void)
|
||||
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_error_highlight,
|
||||
attr_error_normal, 0, 6, 60 - 4, widthbuf, 6,
|
||||
_("%s has been declared bankrupt by the "
|
||||
_("%ls has been declared bankrupt by the "
|
||||
"Interstellar Trading Bank.\n\n"
|
||||
"^{The Bank has agreed to pay stock holders ^}"
|
||||
"%.2f%%^{ of the share value on each share "
|
||||
|
Loading…
Reference in New Issue
Block a user