mirror of
https://git.zap.org.au/git/trader.git
synced 2025-01-03 14:57:41 -05:00
Merge branch master into with-autogenerated
This commit is contained in:
commit
b528bbc9f0
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,7 +1,9 @@
|
||||
*.o
|
||||
*.a
|
||||
*.gmo
|
||||
.deps/
|
||||
Makefile
|
||||
TAGS
|
||||
|
||||
/autom4te.cache
|
||||
/config.h
|
||||
@ -9,4 +11,9 @@ Makefile
|
||||
/config.status
|
||||
/stamp-h1
|
||||
|
||||
/po/POTFILES
|
||||
/po/en@quot.insert-header
|
||||
/po/messages.mo
|
||||
/po/remove-potcdate.sed
|
||||
|
||||
/src/trader
|
||||
|
32
INSTALL
32
INSTALL
@ -34,11 +34,22 @@ and installation:
|
||||
In actual fact, Star Traders uses the GNU Portability Library, so many
|
||||
older systems may also work without modification.
|
||||
|
||||
3. A working X/Open Curses-compatible library, such as NCurses.
|
||||
3. A working X/Open Curses-compatible library, such as Ncurses. Ncurses
|
||||
is preferred over system-native libraries, if present. Locales with
|
||||
multibyte character sequences (such as UTF-8) require a wide-character
|
||||
version of Curses, such as NcursesW, to work correctly.
|
||||
|
||||
4. Development libraries and header files for all of the above. On many
|
||||
4. The GNU Gettext library, version 0.18.1 or later, to allow the game to
|
||||
use languages other than English; this is also called Native Language
|
||||
Support. If you do not have this library (and do not wish to install
|
||||
it), you may pass "--disable-nls" to the configure script.
|
||||
|
||||
5. Development libraries and header files for all of the above. On many
|
||||
systems, these files are part of XXX-dev packages.
|
||||
|
||||
6. The GNU Perfect Hash Function Generator, gperf. This utility program
|
||||
is required for parts of the GNU Portability Library.
|
||||
|
||||
|
||||
Installation
|
||||
============
|
||||
@ -58,14 +69,15 @@ manual:
|
||||
This version of the configure script understands the following additional
|
||||
command line options:
|
||||
|
||||
--disable-nls Do not use Native Language Support
|
||||
--disable-assert Turn off all debugging assert() statements
|
||||
--with-ncurses Force the use of NCurses over the system's Curses
|
||||
--with-ncurses Force the use of Ncurses over the system's Curses
|
||||
library
|
||||
--with-ncursesw Force the use of the NCursesW library with wide-
|
||||
--with-ncursesw Force the use of the NcursesW library with wide-
|
||||
character support
|
||||
--without-ncursesw Don't use the NCursesW library with wide-character
|
||||
--without-ncursesw Don't use the NcursesW library with wide-character
|
||||
support
|
||||
--without-ncurses Don't use the NCurses library: use the system's
|
||||
--without-ncurses Don't use the Ncurses library: use the system's
|
||||
normal Curses library
|
||||
|
||||
By default, configure uses "/usr/local" as the top-level (prefix) install
|
||||
@ -90,12 +102,12 @@ You can also run configure in a separate build-only directory tree. This
|
||||
feature requires GNU Make and allows you to keep the source code tree from
|
||||
being modified by the compilation process. To use this option, create a
|
||||
separate build directory, then run configure. For example, if you placed
|
||||
the Star Traders source code tree in $HOME/src/trader-7.0, you could run
|
||||
the Star Traders source code tree in $HOME/src/trader-7.2, you could run
|
||||
something like:
|
||||
|
||||
mkdir /tmp/trader-build-7.0
|
||||
cd /tmp/trader-build-7.0
|
||||
$HOME/src/trader-7.0/configure
|
||||
mkdir $HOME/build/trader-build-7.2
|
||||
cd $HOME/build/trader-build-7.2
|
||||
$HOME/src/trader-7.2/configure
|
||||
|
||||
Once again, the Autoconf manual describes these options (and many others):
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
# Subdirectories to recurse into
|
||||
SUBDIRS = lib src doc m4
|
||||
SUBDIRS = lib src doc po m4
|
||||
|
||||
# Additional files to distribute
|
||||
EXTRA_DIST = build-aux/bootstrap
|
||||
|
25
NEWS
25
NEWS
@ -15,6 +15,25 @@ consult the Subversion repository for "trader" on The ZAP Group web server
|
||||
at http://www.zap.org.au/services/svn/.
|
||||
|
||||
|
||||
Version 7.2 (29th August, 2011)
|
||||
-------------------------------
|
||||
|
||||
Star Traders has been internationalised! As part of this update, all
|
||||
input and output routines have been rewritten to handle multibyte strings.
|
||||
English (Australian, British, Canadian and US) translations have been
|
||||
included. Translations for other languages (and corrections to existing
|
||||
languages) are more than welcome!
|
||||
|
||||
Game files are now stored in UTF-8 format (once decrypted!) and can be
|
||||
loaded under any locale with automatic character set translation. This
|
||||
does mean, however, that game files from versions 7.0 and 7.1 of Star
|
||||
Traders will not load under this release.
|
||||
|
||||
The program now better handles terminal resizing events (for versions of
|
||||
Curses supporting such events). It also tries to restore the terminal
|
||||
environment correctly when receiving a terminating signal.
|
||||
|
||||
|
||||
Version 7.1 (29th July, 2011)
|
||||
-----------------------------
|
||||
|
||||
@ -34,10 +53,10 @@ exercise for a number of software tools and libraries; the algorithms in
|
||||
the original Pascal and Visual Basic versions are reused for the game
|
||||
logic.
|
||||
|
||||
Note that the current version of Star Traders does NOT handle locales with
|
||||
Note that versions 7.0 and 7.1 of Star Traders did NOT handle locales with
|
||||
multibyte character sequences (such as UTF-8) correctly. Each byte in a
|
||||
multibyte sequence is treated as a separate character. Eight-bit locales
|
||||
(such as US-ASCII, ISO8859-1, etc.) work correctly.
|
||||
such a sequence was treated as a separate character. Eight-bit locales
|
||||
(such as US-ASCII, ISO8859-1, etc.) worked correctly.
|
||||
|
||||
|
||||
Early history
|
||||
|
@ -6,4 +6,4 @@
|
||||
set -e
|
||||
|
||||
gnulib-tool --update
|
||||
autoreconf --install --verbose
|
||||
env AUTOPOINT=true autoreconf --install --verbose
|
||||
|
@ -26,7 +26,7 @@ dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
|
||||
AC_INIT([Star Traders], [7.1], [J.Zaitseff@zap.org.au], [trader], [http://www.zap.org.au/software/trader/])
|
||||
AC_INIT([Star Traders], [7.2], [J.Zaitseff@zap.org.au], [trader], [http://www.zap.org.au/software/trader/])
|
||||
AC_DEFINE([PACKAGE_AUTHOR], ["John Zaitseff"], [Package author])
|
||||
|
||||
AC_PREREQ([2.67])
|
||||
@ -50,6 +50,9 @@ AX_C___ATTRIBUTE__
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
|
||||
AM_GNU_GETTEXT([external])
|
||||
AM_GNU_GETTEXT_VERSION([0.18.1])
|
||||
|
||||
gl_INIT
|
||||
|
||||
AX_WITH_CURSES
|
||||
@ -62,6 +65,7 @@ AC_CONFIG_FILES([
|
||||
lib/Makefile
|
||||
src/Makefile
|
||||
doc/Makefile
|
||||
po/Makefile.in
|
||||
m4/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
20
doc/trader.6
20
doc/trader.6
@ -41,7 +41,7 @@
|
||||
.if \n[.g] .mso www.tmac
|
||||
.\"
|
||||
.\" *********************************************************************
|
||||
.TH TRADER 6 "22nd July, 2011" "Unix-like systems"
|
||||
.TH TRADER 6 "29th August, 2011" "Unix-like systems"
|
||||
.SH NAME
|
||||
trader \- a game of interstellar trading
|
||||
.\" *********************************************************************
|
||||
@ -154,9 +154,11 @@ manual page for in-depth details). It requires a text console or window
|
||||
of at least 80\(mu24 in size.
|
||||
.TP
|
||||
.BR LANG ", " LC_ALL ", etc."
|
||||
This version of Star Traders has rudimentary support for locales and will
|
||||
use appropriate settings. In particular, numeric quantities will be
|
||||
displayed using \fBLC_NUMERIC\fR and monetary quantities will use
|
||||
This version of Star Traders has full support for locales and will use
|
||||
appropriate settings. In particular, messages will be displayed using
|
||||
\fBLC_MESSAGES\fR and \fBLANGUAGE\fR (if Star Traders has been translated
|
||||
into that language). In addition, numeric quantities will be displayed
|
||||
using \fBLC_NUMERIC\fR and monetary quantities will use
|
||||
\fBLC_MONETARY\fR. See the
|
||||
.BR locale (7)
|
||||
or
|
||||
@ -172,10 +174,7 @@ inclusive. The game file is scrambled to prevent you or others from
|
||||
casually cheating!
|
||||
.\" *********************************************************************
|
||||
.SH BUGS
|
||||
The current version of Star Traders does \fInot\fR handle locales with
|
||||
multibyte character sequences (such as UTF-8) correctly. Each byte in a
|
||||
multibyte sequence is treated as a separate character. Eight-bit locales
|
||||
(such as US-ASCII, ISO8859-1, etc.) work correctly.
|
||||
None yet known...
|
||||
.\" *********************************************************************
|
||||
.SH FEEDBACK
|
||||
Your comments, suggestions, corrections and enhancements are always
|
||||
@ -262,8 +261,9 @@ on 15th September, 1995.
|
||||
Star Traders was then to languish until almost 16 years later... when the
|
||||
game was rewritten once again, this time in the C programming language.
|
||||
Version 7.0 was released on 25th July, 2011 for Unix-like operating
|
||||
systems such as Linux. Now you, too, can run this small piece of
|
||||
computing history!
|
||||
systems such as Linux, with subsequent releases to add features and
|
||||
correct bugs. Now you, too, can run this small piece of computing
|
||||
history!
|
||||
.\" *********************************************************************
|
||||
.SH "SEE ALSO"
|
||||
.URL http://www.zap.org.au/software/trader/ "Star Traders home page"
|
||||
|
19
lib/.gitignore
vendored
19
lib/.gitignore
vendored
@ -1,15 +1,4 @@
|
||||
alloca.h
|
||||
arg-nonnull.h
|
||||
c++defs.h
|
||||
ctype.h
|
||||
getopt.h
|
||||
locale.h
|
||||
math.h
|
||||
stdio.h
|
||||
stdlib.h
|
||||
string.h
|
||||
sys/
|
||||
time.h
|
||||
unistd.h
|
||||
warn-on-use.h
|
||||
wchar.h
|
||||
unistr/.dirstamp
|
||||
unistr/u8-mbtoucr.c
|
||||
unistr/u8-uctomb-aux.c
|
||||
unistr/u8-uctomb.c
|
||||
|
1
m4/.gitignore
vendored
1
m4/.gitignore
vendored
@ -1 +0,0 @@
|
||||
largefile.m4
|
@ -15,33 +15,34 @@
|
||||
|
||||
|
||||
# Specification in the form of a command-line invocation:
|
||||
# gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl assert config-h ctype fprintf-posix getopt-gnu gettimeofday locale printf-posix snprintf-posix stat stdarg stdbool stdio strdup-posix string strncat strstr sys_stat sys_time unistd vfprintf-posix vsnprintf-posix
|
||||
# gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl assert btowc config-h getopt-gnu gettext gettext-h gettimeofday locale mbrtowc mbsrtowcs stdbool stdio striconv string strstr sys_stat sys_time unistd wchar wcrtomb wcsdup wctob wctype-h
|
||||
|
||||
# Specification in the form of a few gnulib-tool.m4 macro invocations:
|
||||
gl_LOCAL_DIR([])
|
||||
gl_MODULES([
|
||||
assert
|
||||
btowc
|
||||
config-h
|
||||
ctype
|
||||
fprintf-posix
|
||||
getopt-gnu
|
||||
gettext
|
||||
gettext-h
|
||||
gettimeofday
|
||||
locale
|
||||
printf-posix
|
||||
snprintf-posix
|
||||
stat
|
||||
stdarg
|
||||
mbrtowc
|
||||
mbsrtowcs
|
||||
stdbool
|
||||
stdio
|
||||
strdup-posix
|
||||
striconv
|
||||
string
|
||||
strncat
|
||||
strstr
|
||||
sys_stat
|
||||
sys_time
|
||||
unistd
|
||||
vfprintf-posix
|
||||
vsnprintf-posix
|
||||
wchar
|
||||
wcrtomb
|
||||
wcsdup
|
||||
wctob
|
||||
wctype-h
|
||||
])
|
||||
gl_AVOID([])
|
||||
gl_SOURCE_BASE([lib])
|
||||
|
33
po/LINGUAS
Normal file
33
po/LINGUAS
Normal file
@ -0,0 +1,33 @@
|
||||
#########################################################################
|
||||
# #
|
||||
# Star Traders: A Game of Interstellar Trading #
|
||||
# Copyright (C) 1990-2011, John Zaitseff #
|
||||
# #
|
||||
#########################################################################
|
||||
|
||||
# Author: John Zaitseff <J.Zaitseff@zap.org.au>
|
||||
# $Id$
|
||||
#
|
||||
# This file, po/LINGUAS, contains a list of the available languages in
|
||||
# the po directory.
|
||||
#
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
|
||||
en@quot
|
||||
en_AU
|
||||
en_CA
|
||||
en_GB
|
||||
en_US
|
444
po/Makefile.in.in
Normal file
444
po/Makefile.in.in
Normal file
@ -0,0 +1,444 @@
|
||||
# Makefile for PO directory in any package using GNU gettext.
|
||||
# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
|
||||
#
|
||||
# This file can be copied and used freely without restrictions. It can
|
||||
# be used in projects which are not available under the GNU General Public
|
||||
# License but which still want to provide support for the GNU gettext
|
||||
# functionality.
|
||||
# Please note that the actual code of GNU gettext is covered by the GNU
|
||||
# General Public License and is *not* in the public domain.
|
||||
#
|
||||
# Origin: gettext-0.18
|
||||
GETTEXT_MACRO_VERSION = 0.18
|
||||
|
||||
PACKAGE = @PACKAGE@
|
||||
VERSION = @VERSION@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
|
||||
SHELL = /bin/sh
|
||||
@SET_MAKE@
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
datarootdir = @datarootdir@
|
||||
datadir = @datadir@
|
||||
localedir = @localedir@
|
||||
gettextsrcdir = $(datadir)/gettext/po
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
||||
# We use $(mkdir_p).
|
||||
# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as
|
||||
# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions,
|
||||
# @install_sh@ does not start with $(SHELL), so we add it.
|
||||
# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined
|
||||
# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake
|
||||
# versions, $(mkinstalldirs) and $(install_sh) are unused.
|
||||
mkinstalldirs = $(SHELL) @install_sh@ -d
|
||||
install_sh = $(SHELL) @install_sh@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
mkdir_p = @mkdir_p@
|
||||
|
||||
GMSGFMT_ = @GMSGFMT@
|
||||
GMSGFMT_no = @GMSGFMT@
|
||||
GMSGFMT_yes = @GMSGFMT_015@
|
||||
GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT))
|
||||
MSGFMT_ = @MSGFMT@
|
||||
MSGFMT_no = @MSGFMT@
|
||||
MSGFMT_yes = @MSGFMT_015@
|
||||
MSGFMT = $(MSGFMT_$(USE_MSGCTXT))
|
||||
XGETTEXT_ = @XGETTEXT@
|
||||
XGETTEXT_no = @XGETTEXT@
|
||||
XGETTEXT_yes = @XGETTEXT_015@
|
||||
XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT))
|
||||
MSGMERGE = msgmerge
|
||||
MSGMERGE_UPDATE = @MSGMERGE@ --update
|
||||
MSGINIT = msginit
|
||||
MSGCONV = msgconv
|
||||
MSGFILTER = msgfilter
|
||||
|
||||
POFILES = @POFILES@
|
||||
GMOFILES = @GMOFILES@
|
||||
UPDATEPOFILES = @UPDATEPOFILES@
|
||||
DUMMYPOFILES = @DUMMYPOFILES@
|
||||
DISTFILES.common = Makefile.in.in remove-potcdate.sin \
|
||||
$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3)
|
||||
DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \
|
||||
$(POFILES) $(GMOFILES) \
|
||||
$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3)
|
||||
|
||||
POTFILES = \
|
||||
|
||||
CATALOGS = @CATALOGS@
|
||||
|
||||
# Makevars gets inserted here. (Don't remove this line!)
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update
|
||||
|
||||
.po.mo:
|
||||
@echo "$(MSGFMT) -c -o $@ $<"; \
|
||||
$(MSGFMT) -c -o t-$@ $< && mv t-$@ $@
|
||||
|
||||
.po.gmo:
|
||||
@lang=`echo $* | sed -e 's,.*/,,'`; \
|
||||
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
|
||||
echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \
|
||||
cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo
|
||||
|
||||
.sin.sed:
|
||||
sed -e '/^#/d' $< > t-$@
|
||||
mv t-$@ $@
|
||||
|
||||
|
||||
all: check-macro-version all-@USE_NLS@
|
||||
|
||||
all-yes: stamp-po
|
||||
all-no:
|
||||
|
||||
# Ensure that the gettext macros and this Makefile.in.in are in sync.
|
||||
check-macro-version:
|
||||
@test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \
|
||||
|| { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \
|
||||
exit 1; \
|
||||
}
|
||||
|
||||
# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no
|
||||
# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because
|
||||
# we don't want to bother translators with empty POT files). We assume that
|
||||
# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty.
|
||||
# In this case, stamp-po is a nop (i.e. a phony target).
|
||||
|
||||
# stamp-po is a timestamp denoting the last time at which the CATALOGS have
|
||||
# been loosely updated. Its purpose is that when a developer or translator
|
||||
# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS,
|
||||
# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent
|
||||
# invocations of "make" will do nothing. This timestamp would not be necessary
|
||||
# if updating the $(CATALOGS) would always touch them; however, the rule for
|
||||
# $(POFILES) has been designed to not touch files that don't need to be
|
||||
# changed.
|
||||
stamp-po: $(srcdir)/$(DOMAIN).pot
|
||||
test ! -f $(srcdir)/$(DOMAIN).pot || \
|
||||
test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES)
|
||||
@test ! -f $(srcdir)/$(DOMAIN).pot || { \
|
||||
echo "touch stamp-po" && \
|
||||
echo timestamp > stamp-poT && \
|
||||
mv stamp-poT stamp-po; \
|
||||
}
|
||||
|
||||
# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update',
|
||||
# otherwise packages like GCC can not be built if only parts of the source
|
||||
# have been downloaded.
|
||||
|
||||
# This target rebuilds $(DOMAIN).pot; it is an expensive operation.
|
||||
# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed.
|
||||
$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed
|
||||
if LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null | grep -v 'libtool:' >/dev/null; then \
|
||||
package_gnu='GNU '; \
|
||||
else \
|
||||
package_gnu=''; \
|
||||
fi; \
|
||||
if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \
|
||||
msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \
|
||||
else \
|
||||
msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \
|
||||
fi; \
|
||||
case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
|
||||
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \
|
||||
$(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
|
||||
--add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
|
||||
--files-from=$(srcdir)/POTFILES.in \
|
||||
--copyright-holder='$(COPYRIGHT_HOLDER)' \
|
||||
--msgid-bugs-address="$$msgid_bugs_address" \
|
||||
;; \
|
||||
*) \
|
||||
$(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
|
||||
--add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
|
||||
--files-from=$(srcdir)/POTFILES.in \
|
||||
--copyright-holder='$(COPYRIGHT_HOLDER)' \
|
||||
--package-name="$${package_gnu}@PACKAGE@" \
|
||||
--package-version='@VERSION@' \
|
||||
--msgid-bugs-address="$$msgid_bugs_address" \
|
||||
;; \
|
||||
esac
|
||||
test ! -f $(DOMAIN).po || { \
|
||||
if test -f $(srcdir)/$(DOMAIN).pot; then \
|
||||
sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \
|
||||
sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \
|
||||
if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \
|
||||
rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \
|
||||
else \
|
||||
rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \
|
||||
mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
|
||||
fi; \
|
||||
else \
|
||||
mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
|
||||
fi; \
|
||||
}
|
||||
|
||||
# This rule has no dependencies: we don't need to update $(DOMAIN).pot at
|
||||
# every "make" invocation, only create it when it is missing.
|
||||
# Only "make $(DOMAIN).pot-update" or "make dist" will force an update.
|
||||
$(srcdir)/$(DOMAIN).pot:
|
||||
$(MAKE) $(DOMAIN).pot-update
|
||||
|
||||
# This target rebuilds a PO file if $(DOMAIN).pot has changed.
|
||||
# Note that a PO file is not touched if it doesn't need to be changed.
|
||||
$(POFILES): $(srcdir)/$(DOMAIN).pot
|
||||
@lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
|
||||
if test -f "$(srcdir)/$${lang}.po"; then \
|
||||
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
|
||||
echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \
|
||||
cd $(srcdir) \
|
||||
&& { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
|
||||
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
|
||||
$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \
|
||||
*) \
|
||||
$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \
|
||||
esac; \
|
||||
}; \
|
||||
else \
|
||||
$(MAKE) $${lang}.po-create; \
|
||||
fi
|
||||
|
||||
|
||||
install: install-exec install-data
|
||||
install-exec:
|
||||
install-data: install-data-@USE_NLS@
|
||||
if test "$(PACKAGE)" = "gettext-tools"; then \
|
||||
$(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
|
||||
for file in $(DISTFILES.common) Makevars.template; do \
|
||||
$(INSTALL_DATA) $(srcdir)/$$file \
|
||||
$(DESTDIR)$(gettextsrcdir)/$$file; \
|
||||
done; \
|
||||
for file in Makevars; do \
|
||||
rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
|
||||
done; \
|
||||
else \
|
||||
: ; \
|
||||
fi
|
||||
install-data-no: all
|
||||
install-data-yes: all
|
||||
@catalogs='$(CATALOGS)'; \
|
||||
for cat in $$catalogs; do \
|
||||
cat=`basename $$cat`; \
|
||||
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
|
||||
dir=$(localedir)/$$lang/LC_MESSAGES; \
|
||||
$(mkdir_p) $(DESTDIR)$$dir; \
|
||||
if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \
|
||||
$(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \
|
||||
echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \
|
||||
for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
|
||||
if test -n "$$lc"; then \
|
||||
if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
|
||||
link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
|
||||
mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
|
||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
||||
(cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
|
||||
for file in *; do \
|
||||
if test -f $$file; then \
|
||||
ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
|
||||
fi; \
|
||||
done); \
|
||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
|
||||
else \
|
||||
if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
|
||||
:; \
|
||||
else \
|
||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
||||
fi; \
|
||||
fi; \
|
||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
|
||||
ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
|
||||
ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
|
||||
cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
|
||||
echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \
|
||||
fi; \
|
||||
done; \
|
||||
done
|
||||
|
||||
install-strip: install
|
||||
|
||||
installdirs: installdirs-exec installdirs-data
|
||||
installdirs-exec:
|
||||
installdirs-data: installdirs-data-@USE_NLS@
|
||||
if test "$(PACKAGE)" = "gettext-tools"; then \
|
||||
$(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
|
||||
else \
|
||||
: ; \
|
||||
fi
|
||||
installdirs-data-no:
|
||||
installdirs-data-yes:
|
||||
@catalogs='$(CATALOGS)'; \
|
||||
for cat in $$catalogs; do \
|
||||
cat=`basename $$cat`; \
|
||||
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
|
||||
dir=$(localedir)/$$lang/LC_MESSAGES; \
|
||||
$(mkdir_p) $(DESTDIR)$$dir; \
|
||||
for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
|
||||
if test -n "$$lc"; then \
|
||||
if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
|
||||
link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
|
||||
mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
|
||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
||||
(cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
|
||||
for file in *; do \
|
||||
if test -f $$file; then \
|
||||
ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
|
||||
fi; \
|
||||
done); \
|
||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
|
||||
else \
|
||||
if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
|
||||
:; \
|
||||
else \
|
||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
||||
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
|
||||
fi; \
|
||||
fi; \
|
||||
fi; \
|
||||
done; \
|
||||
done
|
||||
|
||||
# Define this as empty until I found a useful application.
|
||||
installcheck:
|
||||
|
||||
uninstall: uninstall-exec uninstall-data
|
||||
uninstall-exec:
|
||||
uninstall-data: uninstall-data-@USE_NLS@
|
||||
if test "$(PACKAGE)" = "gettext-tools"; then \
|
||||
for file in $(DISTFILES.common) Makevars.template; do \
|
||||
rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
|
||||
done; \
|
||||
else \
|
||||
: ; \
|
||||
fi
|
||||
uninstall-data-no:
|
||||
uninstall-data-yes:
|
||||
catalogs='$(CATALOGS)'; \
|
||||
for cat in $$catalogs; do \
|
||||
cat=`basename $$cat`; \
|
||||
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
|
||||
for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \
|
||||
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
|
||||
done; \
|
||||
done
|
||||
|
||||
check: all
|
||||
|
||||
info dvi ps pdf html tags TAGS ctags CTAGS ID:
|
||||
|
||||
mostlyclean:
|
||||
rm -f remove-potcdate.sed
|
||||
rm -f stamp-poT
|
||||
rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po
|
||||
rm -fr *.o
|
||||
|
||||
clean: mostlyclean
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile Makefile.in POTFILES *.mo
|
||||
|
||||
maintainer-clean: distclean
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
rm -f stamp-po $(GMOFILES)
|
||||
|
||||
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
|
||||
dist distdir:
|
||||
$(MAKE) update-po
|
||||
@$(MAKE) dist2
|
||||
# This is a separate target because 'update-po' must be executed before.
|
||||
dist2: stamp-po $(DISTFILES)
|
||||
dists="$(DISTFILES)"; \
|
||||
if test "$(PACKAGE)" = "gettext-tools"; then \
|
||||
dists="$$dists Makevars.template"; \
|
||||
fi; \
|
||||
if test -f $(srcdir)/$(DOMAIN).pot; then \
|
||||
dists="$$dists $(DOMAIN).pot stamp-po"; \
|
||||
fi; \
|
||||
if test -f $(srcdir)/ChangeLog; then \
|
||||
dists="$$dists ChangeLog"; \
|
||||
fi; \
|
||||
for i in 0 1 2 3 4 5 6 7 8 9; do \
|
||||
if test -f $(srcdir)/ChangeLog.$$i; then \
|
||||
dists="$$dists ChangeLog.$$i"; \
|
||||
fi; \
|
||||
done; \
|
||||
if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \
|
||||
for file in $$dists; do \
|
||||
if test -f $$file; then \
|
||||
cp -p $$file $(distdir) || exit 1; \
|
||||
else \
|
||||
cp -p $(srcdir)/$$file $(distdir) || exit 1; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
update-po: Makefile
|
||||
$(MAKE) $(DOMAIN).pot-update
|
||||
test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES)
|
||||
$(MAKE) update-gmo
|
||||
|
||||
# General rule for creating PO files.
|
||||
|
||||
.nop.po-create:
|
||||
@lang=`echo $@ | sed -e 's/\.po-create$$//'`; \
|
||||
echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \
|
||||
exit 1
|
||||
|
||||
# General rule for updating PO files.
|
||||
|
||||
.nop.po-update:
|
||||
@lang=`echo $@ | sed -e 's/\.po-update$$//'`; \
|
||||
if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \
|
||||
tmpdir=`pwd`; \
|
||||
echo "$$lang:"; \
|
||||
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
|
||||
echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \
|
||||
cd $(srcdir); \
|
||||
if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
|
||||
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
|
||||
$(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
|
||||
*) \
|
||||
$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
|
||||
esac; \
|
||||
}; then \
|
||||
if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
|
||||
rm -f $$tmpdir/$$lang.new.po; \
|
||||
else \
|
||||
if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
|
||||
:; \
|
||||
else \
|
||||
echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi; \
|
||||
else \
|
||||
echo "msgmerge for $$lang.po failed!" 1>&2; \
|
||||
rm -f $$tmpdir/$$lang.new.po; \
|
||||
fi
|
||||
|
||||
$(DUMMYPOFILES):
|
||||
|
||||
update-gmo: Makefile $(GMOFILES)
|
||||
@:
|
||||
|
||||
# Recreate Makefile by invoking config.status. Explicitly invoke the shell,
|
||||
# because execution permission bits may not work on the current file system.
|
||||
# Use @SHELL@, which is the shell determined by autoconf for the use by its
|
||||
# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient.
|
||||
Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@
|
||||
cd $(top_builddir) \
|
||||
&& @SHELL@ ./config.status $(subdir)/$@.in po-directories
|
||||
|
||||
force:
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make not to export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
55
po/Makevars
Normal file
55
po/Makevars
Normal file
@ -0,0 +1,55 @@
|
||||
#########################################################################
|
||||
# #
|
||||
# Star Traders: A Game of Interstellar Trading #
|
||||
# Copyright (C) 1990-2011, John Zaitseff #
|
||||
# #
|
||||
#########################################################################
|
||||
|
||||
# Author: John Zaitseff <J.Zaitseff@zap.org.au>
|
||||
# $Id$
|
||||
#
|
||||
# This file, po/Makevars, contains variables that are substituted into
|
||||
# po/Makefile for use with GNU gettext.
|
||||
#
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
|
||||
# The message domain is the same as the package name
|
||||
DOMAIN = $(PACKAGE)
|
||||
|
||||
# These two variables depend on the location of this directory
|
||||
subdir = po
|
||||
top_builddir = ..
|
||||
|
||||
# These options get passed to xgettext
|
||||
XGETTEXT_OPTIONS = --from-code=UTF-8 --keyword=_ --keyword=N_ --width=132
|
||||
|
||||
# These options get passed to msgmerge
|
||||
MSGMERGE_OPTIONS = --width=132
|
||||
|
||||
# Copyright holder that gets inserted into the header of the
|
||||
# $(DOMAIN).pot file.
|
||||
COPYRIGHT_HOLDER = John Zaitseff
|
||||
|
||||
# E-mail address or URL used by translators to report bugs in the
|
||||
# untranslated (original) strings
|
||||
MSGID_BUGS_ADDRESS = J.Zaitseff@zap.org.au
|
||||
|
||||
# List of locale categories, beyond LC_MESSAGES, for which the message
|
||||
# catalogs shall be used. It is usually empty.
|
||||
EXTRA_LOCALE_CATEGORIES =
|
||||
|
||||
# Additional files to distribute
|
||||
DISTFILES += README
|
42
po/POTFILES.in
Normal file
42
po/POTFILES.in
Normal file
@ -0,0 +1,42 @@
|
||||
#########################################################################
|
||||
# #
|
||||
# Star Traders: A Game of Interstellar Trading #
|
||||
# Copyright (C) 1990-2011, John Zaitseff #
|
||||
# #
|
||||
#########################################################################
|
||||
|
||||
# Author: John Zaitseff <J.Zaitseff@zap.org.au>
|
||||
# $Id$
|
||||
#
|
||||
# This file, po/POTFILES.in, contains a list of source files which
|
||||
# contain translatable strings.
|
||||
#
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
|
||||
# Source files from Star Traders
|
||||
src/trader.c
|
||||
src/globals.c
|
||||
src/game.c
|
||||
src/move.c
|
||||
src/exch.c
|
||||
src/fileio.c
|
||||
src/help.c
|
||||
src/intf.c
|
||||
src/utils.c
|
||||
|
||||
|
||||
# Source files from the Gnulib GNU Portability Library
|
||||
lib/getopt.c
|
9
po/README
Normal file
9
po/README
Normal file
@ -0,0 +1,9 @@
|
||||
**************************************************************************
|
||||
* *
|
||||
* Star Traders: A Game of Interstellar Trading *
|
||||
* Copyright (C) 1990-2011, John Zaitseff *
|
||||
* *
|
||||
**************************************************************************
|
||||
|
||||
This directory, po, contains translations for text strings used in Star
|
||||
Traders. The GNU Gettext project is used for this purpose.
|
47
po/Rules-quot
Normal file
47
po/Rules-quot
Normal file
@ -0,0 +1,47 @@
|
||||
# Special Makefile rules for English message catalogs with quotation marks.
|
||||
|
||||
DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot
|
||||
|
||||
.SUFFIXES: .insert-header .po-update-en
|
||||
|
||||
en@quot.po-create:
|
||||
$(MAKE) en@quot.po-update
|
||||
en@boldquot.po-create:
|
||||
$(MAKE) en@boldquot.po-update
|
||||
|
||||
en@quot.po-update: en@quot.po-update-en
|
||||
en@boldquot.po-update: en@boldquot.po-update-en
|
||||
|
||||
.insert-header.po-update-en:
|
||||
@lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \
|
||||
if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \
|
||||
tmpdir=`pwd`; \
|
||||
echo "$$lang:"; \
|
||||
ll=`echo $$lang | sed -e 's/@.*//'`; \
|
||||
LC_ALL=C; export LC_ALL; \
|
||||
cd $(srcdir); \
|
||||
if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$lang -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \
|
||||
if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
|
||||
rm -f $$tmpdir/$$lang.new.po; \
|
||||
else \
|
||||
if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
|
||||
:; \
|
||||
else \
|
||||
echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi; \
|
||||
else \
|
||||
echo "creation of $$lang.po failed!" 1>&2; \
|
||||
rm -f $$tmpdir/$$lang.new.po; \
|
||||
fi
|
||||
|
||||
en@quot.insert-header: insert-header.sin
|
||||
sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header
|
||||
|
||||
en@boldquot.insert-header: insert-header.sin
|
||||
sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header
|
||||
|
||||
mostlyclean: mostlyclean-quot
|
||||
mostlyclean-quot:
|
||||
rm -f *.insert-header
|
10
po/boldquot.sed
Normal file
10
po/boldquot.sed
Normal file
@ -0,0 +1,10 @@
|
||||
s/"\([^"]*\)"/“\1”/g
|
||||
s/`\([^`']*\)'/‘\1’/g
|
||||
s/ '\([^`']*\)' / ‘\1’ /g
|
||||
s/ '\([^`']*\)'$/ ‘\1’/g
|
||||
s/^'\([^`']*\)' /‘\1’ /g
|
||||
s/“”/""/g
|
||||
s/“/“[1m/g
|
||||
s/”/[0m”/g
|
||||
s/‘/‘[1m/g
|
||||
s/’/[0m’/g
|
25
po/en@boldquot.header
Normal file
25
po/en@boldquot.header
Normal file
@ -0,0 +1,25 @@
|
||||
# All this catalog "translates" are quotation characters.
|
||||
# The msgids must be ASCII and therefore cannot contain real quotation
|
||||
# characters, only substitutes like grave accent (0x60), apostrophe (0x27)
|
||||
# and double quote (0x22). These substitutes look strange; see
|
||||
# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html
|
||||
#
|
||||
# This catalog translates grave accent (0x60) and apostrophe (0x27) to
|
||||
# left single quotation mark (U+2018) and right single quotation mark (U+2019).
|
||||
# It also translates pairs of apostrophe (0x27) to
|
||||
# left single quotation mark (U+2018) and right single quotation mark (U+2019)
|
||||
# and pairs of quotation mark (0x22) to
|
||||
# left double quotation mark (U+201C) and right double quotation mark (U+201D).
|
||||
#
|
||||
# When output to an UTF-8 terminal, the quotation characters appear perfectly.
|
||||
# When output to an ISO-8859-1 terminal, the single quotation marks are
|
||||
# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to
|
||||
# grave/acute accent (by libiconv), and the double quotation marks are
|
||||
# transliterated to 0x22.
|
||||
# When output to an ASCII terminal, the single quotation marks are
|
||||
# transliterated to apostrophes, and the double quotation marks are
|
||||
# transliterated to 0x22.
|
||||
#
|
||||
# This catalog furthermore displays the text between the quotation marks in
|
||||
# bold face, assuming the VT100/XTerm escape sequences.
|
||||
#
|
22
po/en@quot.header
Normal file
22
po/en@quot.header
Normal file
@ -0,0 +1,22 @@
|
||||
# All this catalog "translates" are quotation characters.
|
||||
# The msgids must be ASCII and therefore cannot contain real quotation
|
||||
# characters, only substitutes like grave accent (0x60), apostrophe (0x27)
|
||||
# and double quote (0x22). These substitutes look strange; see
|
||||
# http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html
|
||||
#
|
||||
# This catalog translates grave accent (0x60) and apostrophe (0x27) to
|
||||
# left single quotation mark (U+2018) and right single quotation mark (U+2019).
|
||||
# It also translates pairs of apostrophe (0x27) to
|
||||
# left single quotation mark (U+2018) and right single quotation mark (U+2019)
|
||||
# and pairs of quotation mark (0x22) to
|
||||
# left double quotation mark (U+201C) and right double quotation mark (U+201D).
|
||||
#
|
||||
# When output to an UTF-8 terminal, the quotation characters appear perfectly.
|
||||
# When output to an ISO-8859-1 terminal, the single quotation marks are
|
||||
# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to
|
||||
# grave/acute accent (by libiconv), and the double quotation marks are
|
||||
# transliterated to 0x22.
|
||||
# When output to an ASCII terminal, the single quotation marks are
|
||||
# transliterated to apostrophes, and the double quotation marks are
|
||||
# transliterated to 0x22.
|
||||
#
|
1566
po/en_AU.po
Normal file
1566
po/en_AU.po
Normal file
File diff suppressed because it is too large
Load Diff
1566
po/en_CA.po
Normal file
1566
po/en_CA.po
Normal file
File diff suppressed because it is too large
Load Diff
1566
po/en_GB.po
Normal file
1566
po/en_GB.po
Normal file
File diff suppressed because it is too large
Load Diff
1566
po/en_US.po
Normal file
1566
po/en_US.po
Normal file
File diff suppressed because it is too large
Load Diff
23
po/insert-header.sin
Normal file
23
po/insert-header.sin
Normal file
@ -0,0 +1,23 @@
|
||||
# Sed script that inserts the file called HEADER before the header entry.
|
||||
#
|
||||
# At each occurrence of a line starting with "msgid ", we execute the following
|
||||
# commands. At the first occurrence, insert the file. At the following
|
||||
# occurrences, do nothing. The distinction between the first and the following
|
||||
# occurrences is achieved by looking at the hold space.
|
||||
/^msgid /{
|
||||
x
|
||||
# Test if the hold space is empty.
|
||||
s/m/m/
|
||||
ta
|
||||
# Yes it was empty. First occurrence. Read the file.
|
||||
r HEADER
|
||||
# Output the file's contents by reading the next line. But don't lose the
|
||||
# current line while doing this.
|
||||
g
|
||||
N
|
||||
bb
|
||||
:a
|
||||
# The hold space was nonempty. Following occurrences. Do nothing.
|
||||
x
|
||||
:b
|
||||
}
|
6
po/quot.sed
Normal file
6
po/quot.sed
Normal file
@ -0,0 +1,6 @@
|
||||
s/"\([^"]*\)"/“\1”/g
|
||||
s/`\([^`']*\)'/‘\1’/g
|
||||
s/ '\([^`']*\)' / ‘\1’ /g
|
||||
s/ '\([^`']*\)'$/ ‘\1’/g
|
||||
s/^'\([^`']*\)' /‘\1’ /g
|
||||
s/“”/""/g
|
19
po/remove-potcdate.sin
Normal file
19
po/remove-potcdate.sin
Normal file
@ -0,0 +1,19 @@
|
||||
# Sed script that remove the POT-Creation-Date line in the header entry
|
||||
# from a POT file.
|
||||
#
|
||||
# The distinction between the first and the following occurrences of the
|
||||
# pattern is achieved by looking at the hold space.
|
||||
/^"POT-Creation-Date: .*"$/{
|
||||
x
|
||||
# Test if the hold space is empty.
|
||||
s/P/P/
|
||||
ta
|
||||
# Yes it was empty. First occurrence. Remove the line.
|
||||
g
|
||||
d
|
||||
bb
|
||||
:a
|
||||
# The hold space was nonempty. Following occurrences. Do nothing.
|
||||
x
|
||||
:b
|
||||
}
|
@ -41,7 +41,8 @@ trader_SOURCES = \
|
||||
utils.c utils.h \
|
||||
system.h
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib
|
||||
trader_LDADD = @LIBINTL@ @CURSES_LIB@ $(top_builddir)/lib/libgnu.a
|
||||
trader_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib \
|
||||
-DLOCALEDIR=\"$(localedir)\"
|
||||
trader_LDADD = @CURSES_LIB@ @LIBICONV@ $(top_builddir)/lib/libgnu.a @LIBINTL@
|
||||
|
||||
EXTRA_DIST = README
|
||||
|
734
src/exch.c
734
src/exch.c
@ -76,7 +76,7 @@ void exchange_stock (void)
|
||||
selection_t selection = SEL_NONE;
|
||||
bool bid_used = false;
|
||||
bool all_off_map;
|
||||
int i, line;
|
||||
int w, i, line;
|
||||
|
||||
|
||||
if (quit_selected || abort_game || ! player[current_player].in_game) {
|
||||
@ -84,18 +84,20 @@ void exchange_stock (void)
|
||||
}
|
||||
|
||||
newtxwin(17, WIN_COLS, 1, WCENTER, false, 0);
|
||||
w = getmaxx(curwin);
|
||||
|
||||
while (selection != SEL_EXIT) {
|
||||
selection = SEL_NONE;
|
||||
|
||||
// Display (or refresh) the Stock Exchange window
|
||||
wbkgd(curwin, attr_normal_window);
|
||||
wbkgdset(curwin, attr_normal_window);
|
||||
werase(curwin);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center(curwin, 1, attr_title, " Interstellar Stock Exchange ");
|
||||
center2(curwin, 2, attr_normal, attr_highlight, "Player: ", "%s",
|
||||
player[current_player].name);
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1,
|
||||
_(" Interstellar Stock Exchange "));
|
||||
center(curwin, 2, 0, attr_normal, attr_highlight, 0, 1,
|
||||
_("Player: ^{%ls^}"), player[current_player].name);
|
||||
|
||||
all_off_map = true;
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
@ -106,37 +108,70 @@ void exchange_stock (void)
|
||||
}
|
||||
|
||||
if (all_off_map) {
|
||||
center(curwin, 8, attr_normal, "No companies on the map");
|
||||
center(curwin, 8, 0, attr_normal, attr_highlight, 0, 1,
|
||||
_("No companies on the map"));
|
||||
} else {
|
||||
char *buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
mvwhline(curwin, 4, 2, ' ' | attr_subtitle, w - 4);
|
||||
mvwhline(curwin, 5, 2, ' ' | attr_subtitle, w - 4);
|
||||
|
||||
// Handle the locale's currency symbol
|
||||
snprintf(buf, BUFSIZE, "share (%s)", lconvinfo.currency_symbol);
|
||||
|
||||
wattrset(curwin, attr_subtitle);
|
||||
mvwprintw(curwin, 4, 2, " %-22s %12s %10s %10s %10s ",
|
||||
"", "Price per", "", "Shares", "Shares");
|
||||
mvwprintw(curwin, 5, 2, " %-22s %12s %10s %10s %10s ",
|
||||
"Company", buf, "Return (%)", "issued", "left");
|
||||
wattrset(curwin, attr_normal);
|
||||
left(curwin, 4, 4, attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Company" is a two-line column label in
|
||||
a table containing a list of companies. */
|
||||
pgettext("subtitle", "\nCompany"));
|
||||
right(curwin, 4, w - 4, attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Shares left" is a two-line column
|
||||
label in a table containing the number of shares
|
||||
left to be purchased in any given company. The
|
||||
maximum column width is 10 characters (see
|
||||
STOCK_LEFT_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Shares\nleft"));
|
||||
right(curwin, 4, w - 6 - STOCK_LEFT_COLS, attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Shares issued" is a two-line column
|
||||
label in a table containing the number of shares
|
||||
already sold (ie, bought by all players) in any
|
||||
given company. The maximum column width is 10
|
||||
characters (see STOCK_ISSUED_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Shares\nissued"));
|
||||
right(curwin, 4, w - 8 - STOCK_LEFT_COLS - STOCK_ISSUED_COLS,
|
||||
attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Return" is a two-line column label in
|
||||
a table containing the share return as a percentage
|
||||
in any given company. The maximum column width is
|
||||
10 characters (see SHARE_RETURN_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Return\n(%%)"));
|
||||
right(curwin, 4, w - 10 - STOCK_LEFT_COLS - STOCK_ISSUED_COLS
|
||||
- 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. %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 (%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);
|
||||
l_strfmon(buf, BUFSIZE, "%!12n", company[i].share_price);
|
||||
mvwprintw(curwin, line, 4, "%-22s %12s %10.2f %'10ld %'10ld ",
|
||||
company[i].name, buf, company[i].share_return
|
||||
* 100.0, company[i].stock_issued,
|
||||
company[i].max_stock - company[i].stock_issued);
|
||||
|
||||
left(curwin, line, 4, attr_normal, 0, 0, 1, "%ls",
|
||||
company[i].name);
|
||||
|
||||
right(curwin, line, w - 2, attr_normal, 0, 0, 1, "%'ld ",
|
||||
company[i].max_stock - company[i].stock_issued);
|
||||
right(curwin, line, w - 4 - STOCK_LEFT_COLS, attr_normal,
|
||||
0, 0, 1, "%'ld ", company[i].stock_issued);
|
||||
right(curwin, line, w - 6 - STOCK_LEFT_COLS
|
||||
- STOCK_ISSUED_COLS, attr_normal, 0, 0, 1, "%.2f ",
|
||||
company[i].share_return * 100.0);
|
||||
right(curwin, line, w - 8 - STOCK_LEFT_COLS
|
||||
- STOCK_ISSUED_COLS - SHARE_RETURN_COLS, attr_normal,
|
||||
0, 0, 1, " %!N ", company[i].share_price);
|
||||
|
||||
line++;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
wrefresh(curwin);
|
||||
@ -144,64 +179,78 @@ void exchange_stock (void)
|
||||
// Show menu of choices for the player
|
||||
newtxwin(6, WIN_COLS, 18, WCENTER, true, attr_normal_window);
|
||||
|
||||
wmove(curwin, 3, 2);
|
||||
attrpr(curwin, attr_keycode, "<1>");
|
||||
waddstr(curwin, " Display stock portfolio");
|
||||
left(curwin, 3, 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<1>^} Display stock portfolio"));
|
||||
left(curwin, 4, 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<2>^} Display galaxy map"));
|
||||
left(curwin, 3, getmaxx(curwin) / 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<3>^} Visit the Trading Bank"));
|
||||
left(curwin, 4, getmaxx(curwin) / 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<4>^} Exit the Stock Exchange"));
|
||||
|
||||
wmove(curwin, 4, 2);
|
||||
attrpr(curwin, attr_keycode, "<2>");
|
||||
waddstr(curwin, " Display galaxy map");
|
||||
|
||||
wmove(curwin, 3, 40);
|
||||
attrpr(curwin, attr_keycode, "<3>");
|
||||
waddstr(curwin, " Visit the Trading Bank");
|
||||
|
||||
wmove(curwin, 4, 40);
|
||||
attrpr(curwin, attr_keycode, "<4>");
|
||||
waddstr(curwin, " Exit the Stock Exchange");
|
||||
|
||||
mvwaddstr(curwin, 1, 18, "Enter selection ");
|
||||
waddstr(curwin, "[");
|
||||
attrpr(curwin, attr_highlight, "Company letter");
|
||||
waddstr(curwin, "/");
|
||||
attrpr(curwin, attr_keycode, "1");
|
||||
waddstr(curwin, "-");
|
||||
attrpr(curwin, attr_keycode, "4");
|
||||
waddstr(curwin, "]: ");
|
||||
center(curwin, 1, -1, attr_normal, attr_keycode, attr_highlight, 1,
|
||||
_("Enter selection [^[Company letter^]/^{1^}-^{4^}]: "));
|
||||
|
||||
curs_set(CURS_ON);
|
||||
wrefresh(curwin);
|
||||
|
||||
// Get the actual selection made by the player
|
||||
while (selection == SEL_NONE) {
|
||||
int key = toupper(gettxchar(curwin));
|
||||
wint_t key;
|
||||
|
||||
if (IS_COMPANY_KEY(key)) {
|
||||
if (company[KEY_TO_COMPANY(key)].on_map) {
|
||||
selection = KEY_TO_COMPANY(key);
|
||||
} else {
|
||||
beep();
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
bool found;
|
||||
|
||||
if (iswupper(*keycode_company)) {
|
||||
key = towupper(key);
|
||||
} else if (iswlower(*keycode_company)) {
|
||||
key = towlower(key);
|
||||
}
|
||||
|
||||
for (i = 0, found = false; keycode_company[i] != L'\0'; i++) {
|
||||
if (keycode_company[i] == key) {
|
||||
found = true;
|
||||
if (company[i].on_map) {
|
||||
selection = i;
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found) {
|
||||
switch (key) {
|
||||
case L'1':
|
||||
curs_set(CURS_OFF);
|
||||
show_status(current_player);
|
||||
curs_set(CURS_ON);
|
||||
break;
|
||||
|
||||
case L'2':
|
||||
curs_set(CURS_OFF);
|
||||
show_map(true);
|
||||
curs_set(CURS_ON);
|
||||
break;
|
||||
|
||||
case L'3':
|
||||
selection = SEL_BANK;
|
||||
break;
|
||||
|
||||
case L'4':
|
||||
case L' ':
|
||||
selection = SEL_EXIT;
|
||||
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':
|
||||
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'):
|
||||
@ -251,15 +300,12 @@ void visit_bank (void)
|
||||
{
|
||||
double credit_limit;
|
||||
double val, max;
|
||||
int key;
|
||||
wint_t key;
|
||||
bool done;
|
||||
char *buf;
|
||||
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
int x, width;
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
|
||||
credit_limit = (total_value(current_player) - player[current_player].debt)
|
||||
* CREDIT_LIMIT_RATE;
|
||||
@ -270,179 +316,209 @@ void visit_bank (void)
|
||||
// Show the informational part of the Bank
|
||||
newtxwin(10, WIN_COLS - 4, 5, WCENTER, true, attr_normal_window);
|
||||
|
||||
center(curwin, 1, attr_title, " Interstellar Trading Bank ");
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1,
|
||||
_(" Interstellar Trading Bank "));
|
||||
|
||||
l_strfmon(buf, BUFSIZE, "%18n", player[current_player].cash);
|
||||
center2(curwin, 3, attr_normal, attr_highlight, "Current cash: ",
|
||||
" %s ", buf);
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin) - 4, &width,
|
||||
1, pgettext("label", "Current cash: "));
|
||||
x = (getmaxx(curwin) + width - (BANK_VALUE_COLS + 2)) / 2;
|
||||
|
||||
l_strfmon(buf, BUFSIZE, "%18n", player[current_player].debt);
|
||||
center2(curwin, 4, attr_normal, attr_highlight, "Current debt: ",
|
||||
" %s ", buf);
|
||||
rightch(curwin, 3, x, chbuf, 1, &width);
|
||||
right(curwin, 3, x + BANK_VALUE_COLS + 2, attr_normal, attr_highlight, 0,
|
||||
1, " ^{%N^} ", player[current_player].cash);
|
||||
|
||||
center2(curwin, 5, attr_normal, attr_highlight, "Interest rate: ",
|
||||
" %17.2f%% ", interest_rate * 100.0);
|
||||
right(curwin, 4, x, attr_normal, 0, 0, 1,
|
||||
pgettext("label", "Current debt: "));
|
||||
right(curwin, 4, x + BANK_VALUE_COLS + 2, attr_normal, attr_highlight, 0,
|
||||
1, " ^{%N^} ", player[current_player].debt);
|
||||
|
||||
l_strfmon(buf, BUFSIZE, "%18n", credit_limit);
|
||||
center2(curwin, 7, attr_highlight, attr_title, "Credit limit: ",
|
||||
" %s ", buf);
|
||||
right(curwin, 5, x, attr_normal, 0, 0, 1,
|
||||
pgettext("label", "Interest rate: "));
|
||||
right(curwin, 5, x + BANK_VALUE_COLS + 2, attr_normal, attr_highlight, 0,
|
||||
1, " ^{%.2f%%^} ", interest_rate * 100.0);
|
||||
|
||||
right(curwin, 7, x, attr_highlight, 0, 0, 1,
|
||||
/* TRANSLATORS: The "Total value", "Current cash", "Current
|
||||
debt", "Interest rate" and "Credit limit" labels MUST all be
|
||||
the same length (ie, right-padded with spaces as needed) and
|
||||
must have at least one trailing space so that the display
|
||||
routines work correctly. The maximum length of each label
|
||||
is 36 characters.
|
||||
|
||||
Note that some of these labels are used for both the Player
|
||||
Status window and the Trading Bank window. */
|
||||
pgettext("label", "Credit limit: "));
|
||||
whline(curwin, ' ' | attr_title, BANK_VALUE_COLS + 2);
|
||||
right(curwin, 7, x + BANK_VALUE_COLS + 2, attr_title, 0, 0, 1,
|
||||
" %N ", credit_limit);
|
||||
|
||||
wrefresh(curwin);
|
||||
|
||||
// Show menu of choices for the player
|
||||
newtxwin(7, WIN_COLS - 4, 15, WCENTER, true, attr_normal_window);
|
||||
|
||||
center2(curwin, 3, attr_keycode, attr_normal, "<1>", " Borrow money ");
|
||||
center2(curwin, 4, attr_keycode, attr_normal, "<2>", " Repay debt ");
|
||||
center2(curwin, 5, attr_keycode, attr_normal, "<3>", " Exit from the Bank");
|
||||
center(curwin, 3, 0, attr_normal, attr_keycode, 0, 1,
|
||||
/* TRANSLATORS: The "Borrow money", "Repay debt" and "Exit
|
||||
from the Bank" menu options must all be the same length
|
||||
(ie, padded with trailing spaces as required). The maximum
|
||||
length is 72 characters. */
|
||||
_("^{<1>^} Borrow money "));
|
||||
center(curwin, 4, 0, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<2>^} Repay debt "));
|
||||
center(curwin, 5, 0, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<3>^} Exit from the Bank"));
|
||||
|
||||
mvwaddstr(curwin, 1, 24, "Enter selection ");
|
||||
waddstr(curwin, "[");
|
||||
attrpr(curwin, attr_keycode, "1");
|
||||
waddstr(curwin, "-");
|
||||
attrpr(curwin, attr_keycode, "3");
|
||||
waddstr(curwin, "]: ");
|
||||
center(curwin, 1, 0, attr_normal, attr_keycode, 0, 1,
|
||||
_("Enter selection [^{1^}-^{3^}]: "));
|
||||
|
||||
curs_set(CURS_ON);
|
||||
wrefresh(curwin);
|
||||
|
||||
done = false;
|
||||
while (! done) {
|
||||
key = gettxchar(curwin);
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
switch (key) {
|
||||
case L'1':
|
||||
case L'2':
|
||||
case L'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 L' ':
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
|
||||
switch (key) {
|
||||
case '1':
|
||||
case L'1':
|
||||
// Borrow money from the Bank
|
||||
if (credit_limit == 0.0) {
|
||||
newtxwin(7, 50, 8, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " Insufficient Credit Limit ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"The Bank will not lend you any more money");
|
||||
|
||||
wait_for_key(curwin, 5, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" Insufficient Credit Limit "),
|
||||
_("The Bank will not lend you any more money."));
|
||||
} else {
|
||||
int x, y, n;
|
||||
int ret;
|
||||
chtype *chbuf_cursym;
|
||||
int width_cursym;
|
||||
int n, ret;
|
||||
|
||||
|
||||
wbkgd(curwin, attr_normal_window);
|
||||
wbkgdset(curwin, attr_normal_window);
|
||||
werase(curwin);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
mvwprintw(curwin, 3, 10, "How much do you wish to borrow? ");
|
||||
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, "^{%ls^}",
|
||||
currency_symbol);
|
||||
chbuf_cursym = xchstrdup(chbuf);
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin)
|
||||
- BANK_INPUT_COLS - width_cursym - 6, &width, 1,
|
||||
_("How much do you wish to borrow? "));
|
||||
x = (getmaxx(curwin) + width - BANK_INPUT_COLS - width_cursym
|
||||
- n) / 2;
|
||||
rightch(curwin, 3, x, chbuf, 1, &width);
|
||||
|
||||
// Show the currency symbol before or after the input field
|
||||
wattron(curwin, A_BOLD);
|
||||
if (lconvinfo.p_cs_precedes == 1) {
|
||||
wprintw(curwin, "%s%s", lconvinfo.currency_symbol,
|
||||
(lconvinfo.p_sep_by_space == 1) ? " " : "");
|
||||
n = 10;
|
||||
leftch(curwin, 3, x, chbuf_cursym, 1, &width_cursym);
|
||||
x += width_cursym + n;
|
||||
} else {
|
||||
getyx(curwin, y, x);
|
||||
n = strlen(lconvinfo.currency_symbol) + 10
|
||||
+ (lconvinfo.p_sep_by_space == 1);
|
||||
mvwprintw(curwin, y, getmaxx(curwin) - n, "%s%s",
|
||||
(lconvinfo.p_sep_by_space == 1) ? " " : "",
|
||||
lconvinfo.currency_symbol);
|
||||
wmove(curwin, y, x);
|
||||
leftch(curwin, 3, x + BANK_INPUT_COLS + n, chbuf_cursym, 1,
|
||||
&width_cursym);
|
||||
}
|
||||
wattroff(curwin, A_BOLD);
|
||||
x = getcurx(curwin);
|
||||
|
||||
ret = gettxdouble(curwin, &val, 0.0, credit_limit + ROUNDING_AMOUNT,
|
||||
0.0, credit_limit, 3, x, getmaxx(curwin) - x - n,
|
||||
0.0, credit_limit, 3, x, BANK_INPUT_COLS,
|
||||
attr_input_field);
|
||||
|
||||
if (ret == OK && val > ROUNDING_AMOUNT) {
|
||||
player[current_player].cash += val;
|
||||
player[current_player].debt += val * (interest_rate + 1.0);
|
||||
}
|
||||
|
||||
free(chbuf_cursym);
|
||||
}
|
||||
break;
|
||||
|
||||
case '2':
|
||||
case L'2':
|
||||
// Repay a debt
|
||||
if (player[current_player].debt == 0.0) {
|
||||
newtxwin(7, 50, 8, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " No Debt ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"You have no debt to repay");
|
||||
|
||||
wait_for_key(curwin, 5, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" No Debt "),
|
||||
_("You have no debt to repay."));
|
||||
} else if (player[current_player].cash == 0.0) {
|
||||
newtxwin(7, 60, 8, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " No Cash ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"You have no cash with which to repay the debt!");
|
||||
|
||||
wait_for_key(curwin, 5, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" No Cash "),
|
||||
_("You have no cash with which to repay the debt!"));
|
||||
} else {
|
||||
int x, y, n;
|
||||
int ret;
|
||||
chtype *chbuf_cursym;
|
||||
int width_cursym;
|
||||
int n, ret;
|
||||
|
||||
|
||||
wbkgd(curwin, attr_normal_window);
|
||||
wbkgdset(curwin, attr_normal_window);
|
||||
werase(curwin);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
mvwprintw(curwin, 3, 10, "How much do you wish to repay? ");
|
||||
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, "^{%ls^}",
|
||||
currency_symbol);
|
||||
chbuf_cursym = xchstrdup(chbuf);
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin)
|
||||
- BANK_INPUT_COLS - width_cursym - 6, &width, 1,
|
||||
_("How much do you wish to repay? "));
|
||||
x = (getmaxx(curwin) + width - BANK_INPUT_COLS - width_cursym
|
||||
- n) / 2;
|
||||
rightch(curwin, 3, x, chbuf, 1, &width);
|
||||
|
||||
// Show the currency symbol before or after the input field
|
||||
wattron(curwin, A_BOLD);
|
||||
if (lconvinfo.p_cs_precedes == 1) {
|
||||
wprintw(curwin, "%s%s", lconvinfo.currency_symbol,
|
||||
(lconvinfo.p_sep_by_space == 1) ? " " : "");
|
||||
n = 10;
|
||||
leftch(curwin, 3, x, chbuf_cursym, 1, &width_cursym);
|
||||
x += width_cursym + n;
|
||||
} else {
|
||||
getyx(curwin, y, x);
|
||||
n = strlen(lconvinfo.currency_symbol) + 10
|
||||
+ (lconvinfo.p_sep_by_space == 1);
|
||||
mvwprintw(curwin, y, getmaxx(curwin) - n, "%s%s",
|
||||
(lconvinfo.p_sep_by_space == 1) ? " " : "",
|
||||
lconvinfo.currency_symbol);
|
||||
wmove(curwin, y, x);
|
||||
leftch(curwin, 3, x + BANK_INPUT_COLS + n, chbuf_cursym, 1,
|
||||
&width_cursym);
|
||||
}
|
||||
wattroff(curwin, A_BOLD);
|
||||
x = getcurx(curwin);
|
||||
|
||||
max = MIN(player[current_player].cash, player[current_player].debt);
|
||||
|
||||
ret = gettxdouble(curwin, &val, 0.0, max + ROUNDING_AMOUNT, 0.0,
|
||||
max, 3, x, getmaxx(curwin) - x - n,
|
||||
attr_input_field);
|
||||
max, 3, x, BANK_INPUT_COLS, attr_input_field);
|
||||
|
||||
if (ret == OK) {
|
||||
player[current_player].cash -= val;
|
||||
@ -455,6 +531,8 @@ void visit_bank (void)
|
||||
player[current_player].debt = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
free(chbuf_cursym);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -466,7 +544,7 @@ void visit_bank (void)
|
||||
deltxwin(); // Trading Bank window
|
||||
txrefresh();
|
||||
|
||||
free(buf);
|
||||
free(chbuf);
|
||||
}
|
||||
|
||||
|
||||
@ -476,19 +554,18 @@ void visit_bank (void)
|
||||
void trade_shares (int num, bool *bid_used)
|
||||
{
|
||||
bool done;
|
||||
int key, ret, x;
|
||||
int ret, w, x;
|
||||
long int maxshares, val;
|
||||
double ownership;
|
||||
char *buf;
|
||||
chtype *chbuf;
|
||||
int width;
|
||||
wint_t key;
|
||||
|
||||
|
||||
assert(num >= 0 && num < MAX_COMPANIES);
|
||||
assert(company[num].on_map);
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
|
||||
ownership = (company[num].stock_issued == 0) ? 0.0 :
|
||||
((double) player[current_player].stock_owned[num]
|
||||
@ -496,138 +573,172 @@ void trade_shares (int num, bool *bid_used)
|
||||
|
||||
// Show the informational part of the trade window
|
||||
newtxwin(9, WIN_COLS - 4, 5, WCENTER, true, attr_normal_window);
|
||||
w = getmaxx(curwin);
|
||||
|
||||
center(curwin, 1, attr_title, " Stock Transaction in %s ",
|
||||
company[num].name);
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1,
|
||||
/* TRANSLATORS: %ls represents the company name. */
|
||||
_(" Stock Transaction in %ls "), company[num].name);
|
||||
|
||||
mvwaddstr(curwin, 3, 2, "Shares issued: ");
|
||||
attrpr(curwin, attr_highlight, "%'12ld", company[num].stock_issued);
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, w / 2, &width, 1,
|
||||
/* TRANSLATORS: "Shares issued" represents the number of
|
||||
shares already sold by the company to all players.
|
||||
|
||||
mvwaddstr(curwin, 4, 2, "Shares left: ");
|
||||
attrpr(curwin, attr_highlight, "%'12ld",
|
||||
company[num].max_stock - company[num].stock_issued);
|
||||
Note that the labels "Shares issued", "Shares left",
|
||||
"Price per share" and "Return" must all be the same length
|
||||
and must have at least one trailing space for the output
|
||||
routines to work correctly. The maximum length of each
|
||||
label is 22 characters. */
|
||||
pgettext("label|Stock A", "Shares issued: "));
|
||||
leftch(curwin, 3, 2, chbuf, 1, &width);
|
||||
right(curwin, 3, width + SHARE_PRICE_COLS + 2, attr_normal, attr_highlight,
|
||||
0, 1, "^{%'ld^}", company[num].stock_issued);
|
||||
|
||||
mvwaddstr(curwin, 5, 2, "Price per share: ");
|
||||
l_strfmon(buf, BUFSIZE, "%12n", company[num].share_price);
|
||||
attrpr(curwin, attr_highlight, "%12s", buf);
|
||||
left(curwin, 4, 2, attr_normal, 0, 0, 1,
|
||||
/* TRANSLATORS: "Shares left" is the number of shares that are
|
||||
left to be purchased in the current company. */
|
||||
pgettext("label|Stock A", "Shares left: "));
|
||||
right(curwin, 4, width + SHARE_PRICE_COLS + 2, attr_normal, attr_highlight,
|
||||
0, 1, "^{%'ld^}", company[num].max_stock - company[num].stock_issued);
|
||||
|
||||
mvwaddstr(curwin, 6, 2, "Return: ");
|
||||
attrpr(curwin, attr_highlight, "%11.2f%%",
|
||||
company[num].share_return * 100.0);
|
||||
left(curwin, 5, 2, attr_normal, 0, 0, 1,
|
||||
/* TRANSLATORS: "Price per share" is the cost of each share in
|
||||
the current company. */
|
||||
pgettext("label|Stock A", "Price per share: "));
|
||||
right(curwin, 5, width + SHARE_PRICE_COLS + 2, attr_normal, attr_highlight,
|
||||
0, 1, "^{%N^}", company[num].share_price);
|
||||
|
||||
mvwaddstr(curwin, 3, 38, "Current holdings: ");
|
||||
attrpr(curwin, attr_highlight, " %'16ld ",
|
||||
player[current_player].stock_owned[num]);
|
||||
left(curwin, 6, 2, attr_normal, 0, 0, 1,
|
||||
/* TRANSLATORS: "Return" is the share return as a percentage. */
|
||||
pgettext("label|Stock A", "Return: "));
|
||||
right(curwin, 6, width + SHARE_PRICE_COLS + 2, attr_normal, attr_highlight,
|
||||
0, 1, "^{%.2f%%^}", company[num].share_return * 100.0);
|
||||
|
||||
mvwaddstr(curwin, 4, 38, "Percentage owned: ");
|
||||
attrpr(curwin, attr_highlight, " %'15.2f%% ", ownership * 100.0);
|
||||
left(curwin, 3, w / 2, attr_normal, 0, 0, 1,
|
||||
/* TRANSLATORS: "Current holdings" is the number of shares the
|
||||
current player owns in this particular company.
|
||||
|
||||
wmove(curwin, 6, 38);
|
||||
attrpr(curwin, attr_highlight, "Current cash: ");
|
||||
l_strfmon(buf, BUFSIZE, "%16n", player[current_player].cash);
|
||||
attrpr(curwin, attr_title, " %16s ", buf);
|
||||
Note that the labels "Current holdings", "Percentage owned"
|
||||
and "Current cash" MUST all be the same length and contain at
|
||||
least one trailing space for the display routines to work
|
||||
correctly. The maximum length of each label is 18
|
||||
characters. */
|
||||
pgettext("label|Stock B", "Current holdings: "));
|
||||
right(curwin, 3, w - 2, attr_normal, attr_highlight, 0, 1, " ^{%'ld^} ",
|
||||
player[current_player].stock_owned[num]);
|
||||
|
||||
left(curwin, 4, w / 2, attr_normal, 0, 0, 1,
|
||||
/* TRANSLATORS: "Percentage owned" is the current player's
|
||||
percentage ownership in this particular company. */
|
||||
pgettext("label|Stock B", "Percentage owned: "));
|
||||
right(curwin, 4, w - 2, attr_normal, attr_highlight, 0, 1, " ^{%.2f%%^} ",
|
||||
ownership * 100.0);
|
||||
|
||||
left(curwin, 6, w / 2, attr_highlight, 0, 0, 1,
|
||||
pgettext("label|Stock B", "Current cash: "));
|
||||
whline(curwin, ' ' | attr_title, TRADE_VALUE_COLS + 2);
|
||||
right(curwin, 6, w - 2, attr_title, 0, 0, 1, " %N ",
|
||||
player[current_player].cash);
|
||||
|
||||
wrefresh(curwin);
|
||||
|
||||
// Show menu of choices for the player
|
||||
newtxwin(7, WIN_COLS - 4, 14, WCENTER, true, attr_normal_window);
|
||||
|
||||
wmove(curwin, 3, 2);
|
||||
attrpr(curwin, attr_keycode, "<1>");
|
||||
waddstr(curwin, " Buy stock from company");
|
||||
left(curwin, 3, 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<1>^} Buy stock from company"));
|
||||
left(curwin, 4, 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<2>^} Sell stock back to company"));
|
||||
left(curwin, 3, getmaxx(curwin) / 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<3>^} Bid company to issue more shares"));
|
||||
left(curwin, 4, getmaxx(curwin) / 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<4>^} Exit to the Stock Exchange"));
|
||||
|
||||
wmove(curwin, 4, 2);
|
||||
attrpr(curwin, attr_keycode, "<2>");
|
||||
waddstr(curwin, " Sell stock back to company");
|
||||
|
||||
wmove(curwin, 3, 38);
|
||||
attrpr(curwin, attr_keycode, "<3>");
|
||||
waddstr(curwin, " Bid company to issue more shares");
|
||||
|
||||
wmove(curwin, 4, 38);
|
||||
attrpr(curwin, attr_keycode, "<4>");
|
||||
waddstr(curwin, " Exit to the Stock Exchange");
|
||||
|
||||
mvwaddstr(curwin, 1, 24, "Enter selection ");
|
||||
waddstr(curwin, "[");
|
||||
attrpr(curwin, attr_keycode, "1");
|
||||
waddstr(curwin, "-");
|
||||
attrpr(curwin, attr_keycode, "4");
|
||||
waddstr(curwin, "]: ");
|
||||
center(curwin, 1, 0, attr_normal, attr_keycode, 0, 1,
|
||||
_("Enter selection [^{1^}-^{4^}]: "));
|
||||
|
||||
curs_set(CURS_ON);
|
||||
wrefresh(curwin);
|
||||
|
||||
done = false;
|
||||
while (! done) {
|
||||
key = gettxchar(curwin);
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
switch (key) {
|
||||
case L'1':
|
||||
case L'2':
|
||||
case L'3':
|
||||
case L'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 L' ':
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
|
||||
switch (key) {
|
||||
case '1':
|
||||
case L'1':
|
||||
// Buy stock in company
|
||||
maxshares = player[current_player].cash / company[num].share_price;
|
||||
|
||||
if (company[num].max_stock - company[num].stock_issued == 0) {
|
||||
newtxwin(7, 50, 8, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " No Shares Available ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"No more shares are available for purchase");
|
||||
|
||||
wait_for_key(curwin, 5, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" No Shares Available "),
|
||||
_("No more shares are available for purchase."));
|
||||
} else if (maxshares <= 0) {
|
||||
newtxwin(7, 50, 8, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " Insufficient Cash ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"Not enough cash to purchase shares");
|
||||
|
||||
wait_for_key(curwin, 5, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" Insufficient Cash "),
|
||||
_("You do not have enough cash\n"
|
||||
"to purchase additional shares."));
|
||||
} else {
|
||||
maxshares = MIN(maxshares, company[num].max_stock -
|
||||
company[num].stock_issued);
|
||||
|
||||
wbkgd(curwin, attr_normal_window);
|
||||
wbkgdset(curwin, attr_normal_window);
|
||||
werase(curwin);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center3(curwin, 2, attr_normal, attr_normal, attr_highlight,
|
||||
"You can purchase up to ", " shares.", "%'ld", maxshares);
|
||||
center(curwin, 2, 0, attr_normal, attr_highlight, 0, 1,
|
||||
ngettext("You can purchase ^{one^} share.",
|
||||
"You can purchase up to ^{%'ld^} shares.",
|
||||
maxshares), maxshares);
|
||||
|
||||
mvwprintw(curwin, 4, 10, "How many shares do you wish to purchase? ");
|
||||
x = getcurx(curwin);
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1,
|
||||
getmaxx(curwin) - TRADE_INPUT_COLS - 4, &width, 1,
|
||||
_("How many shares do you wish to purchase? "));
|
||||
x = (getmaxx(curwin) + width - TRADE_INPUT_COLS) / 2;
|
||||
rightch(curwin, 4, x, chbuf, 1, &width);
|
||||
|
||||
ret = gettxlong(curwin, &val, 0, maxshares, 0, maxshares, 4, x,
|
||||
getmaxx(curwin) - x - 10, attr_input_field);
|
||||
TRADE_INPUT_COLS, attr_input_field);
|
||||
|
||||
if (ret == OK) {
|
||||
player[current_player].cash -= val * company[num].share_price;
|
||||
@ -637,32 +748,32 @@ void trade_shares (int num, bool *bid_used)
|
||||
}
|
||||
break;
|
||||
|
||||
case '2':
|
||||
case L'2':
|
||||
// Sell stock back to company
|
||||
maxshares = player[current_player].stock_owned[num];
|
||||
if (maxshares == 0) {
|
||||
newtxwin(7, 50, 8, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " No Shares ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"You do not have any shares to sell");
|
||||
|
||||
wait_for_key(curwin, 5, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" No Shares "),
|
||||
_("You do not have any shares to sell."));
|
||||
} else {
|
||||
wbkgd(curwin, attr_normal_window);
|
||||
wbkgdset(curwin, attr_normal_window);
|
||||
werase(curwin);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center3(curwin, 2, attr_normal, attr_normal, attr_highlight,
|
||||
"You can sell up to ", " shares.", "%'ld", maxshares);
|
||||
center(curwin, 2, 0, attr_normal, attr_highlight, 0, 1,
|
||||
ngettext("You can sell ^{one^} share.",
|
||||
"You can sell up to ^{%'ld^} shares.",
|
||||
maxshares), maxshares);
|
||||
|
||||
mvwprintw(curwin, 4, 10, "How many shares do you wish to sell? ");
|
||||
x = getcurx(curwin);
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1,
|
||||
getmaxx(curwin) - TRADE_INPUT_COLS - 4, &width, 1,
|
||||
_("How many shares do you wish to sell? "));
|
||||
x = (getmaxx(curwin) + width - TRADE_INPUT_COLS) / 2;
|
||||
rightch(curwin, 4, x, chbuf, 1, &width);
|
||||
|
||||
ret = gettxlong(curwin, &val, 0, maxshares, 0, maxshares, 4, x,
|
||||
getmaxx(curwin) - x - 10, attr_input_field);
|
||||
TRADE_INPUT_COLS, attr_input_field);
|
||||
|
||||
if (ret == OK) {
|
||||
company[num].stock_issued -= val;
|
||||
@ -672,7 +783,7 @@ void trade_shares (int num, bool *bid_used)
|
||||
}
|
||||
break;
|
||||
|
||||
case '3':
|
||||
case L'3':
|
||||
// Bid company to issue more shares
|
||||
maxshares = 0;
|
||||
if (! *bid_used && randf() < ownership && randf() < BID_CHANCE) {
|
||||
@ -683,25 +794,20 @@ void trade_shares (int num, bool *bid_used)
|
||||
*bid_used = true;
|
||||
|
||||
if (maxshares == 0) {
|
||||
newtxwin(8, 50, 8, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " No Shares Issued ");
|
||||
center(curwin, 3, attr_error_highlight, "%s", company[num].name);
|
||||
center(curwin, 4, attr_error_highlight,
|
||||
"has refused to issue more shares");
|
||||
|
||||
wait_for_key(curwin, 6, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
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: %ls represents the company name. */
|
||||
_("%ls has refused\nto issue more shares."),
|
||||
company[num].name);
|
||||
} else {
|
||||
newtxwin(8, 50, 8, WCENTER, true, attr_normal_window);
|
||||
|
||||
center(curwin, 1, attr_title, " Shares Issued ");
|
||||
center(curwin, 3, attr_highlight, "%s", company[num].name);
|
||||
center(curwin, 4, attr_highlight, "has issued %'ld more shares",
|
||||
maxshares);
|
||||
|
||||
wait_for_key(curwin, 6, attr_waitforkey);
|
||||
deltxwin();
|
||||
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_normal_window,
|
||||
attr_title, attr_normal, attr_highlight, 0,
|
||||
attr_waitforkey, _(" Shares Issued "),
|
||||
/* 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;
|
||||
|
||||
@ -713,7 +819,7 @@ void trade_shares (int num, bool *bid_used)
|
||||
deltxwin(); // Stock Transaction window
|
||||
txrefresh();
|
||||
|
||||
free(buf);
|
||||
free(chbuf);
|
||||
}
|
||||
|
||||
|
||||
|
317
src/fileio.c
317
src/fileio.c
@ -52,15 +52,16 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
#define load_game_scanf(_fmt, _var, _cond) \
|
||||
do { \
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) { \
|
||||
err_exit("%s: missing field on line %d", filename, lineno); \
|
||||
err_exit(_("%s: missing field on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
if (sscanf(unscramble(crypt_key, buf, BUFSIZE), _fmt "\n", \
|
||||
&(_var)) != 1) { \
|
||||
err_exit("%s: illegal field on line %d: `%s'", \
|
||||
err_exit(_("%s: illegal field on line %d: `%s'"), \
|
||||
filename, lineno, buf); \
|
||||
} \
|
||||
if (! (_cond)) { \
|
||||
err_exit("%s: illegal value on line %d: `%s'", \
|
||||
err_exit(_("%s: illegal value on line %d: `%s'"), \
|
||||
filename, lineno, buf); \
|
||||
} \
|
||||
lineno++; \
|
||||
@ -81,32 +82,74 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
(_var) = b; \
|
||||
} while (0)
|
||||
|
||||
#define load_game_read_string(_var) \
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
# define load_game_read_string(_var, _var_utf8) \
|
||||
do { \
|
||||
char *s; \
|
||||
int len; \
|
||||
\
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) { \
|
||||
err_exit("%s: missing field on line %d", filename, lineno); \
|
||||
err_exit(_("%s: missing field on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
if (strlen(unscramble(crypt_key, buf, BUFSIZE)) == 0) { \
|
||||
err_exit("%s: illegal value on line %d", filename, lineno); \
|
||||
err_exit(_("%s: illegal value on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
lineno++; \
|
||||
\
|
||||
s = malloc(strlen(buf) + 1); \
|
||||
if (s == NULL) { \
|
||||
err_exit_nomem(); \
|
||||
if (need_icd) { \
|
||||
s = str_cd_iconv(buf, icd); \
|
||||
if (s == NULL) { \
|
||||
if (errno == EILSEQ) { \
|
||||
err_exit(_("%s: illegal characters on line %d"), \
|
||||
filename, lineno); \
|
||||
} else { \
|
||||
errno_exit("str_cd_iconv"); \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
s = xstrdup(buf); \
|
||||
} \
|
||||
\
|
||||
strcpy(s, buf); \
|
||||
len = strlen(s); \
|
||||
if (len > 0 && s[len - 1] == '\n') { \
|
||||
s[len - 1] = '\0'; \
|
||||
} \
|
||||
\
|
||||
(_var) = s; \
|
||||
xmbstowcs(wcbuf, s, BUFSIZE); \
|
||||
(_var) = xwcsdup(wcbuf); \
|
||||
(_var_utf8) = s; \
|
||||
\
|
||||
lineno++; \
|
||||
} while (0)
|
||||
#else // ! USE_UTF8_GAME_FILE
|
||||
# define load_game_read_string(_var, _var_utf8) \
|
||||
do { \
|
||||
char *s; \
|
||||
int len; \
|
||||
\
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) { \
|
||||
err_exit(_("%s: missing field on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
if (strlen(unscramble(crypt_key, buf, BUFSIZE)) == 0) { \
|
||||
err_exit(_("%s: illegal value on line %d"), \
|
||||
filename, lineno); \
|
||||
} \
|
||||
\
|
||||
s = xstrdup(buf); \
|
||||
\
|
||||
len = strlen(s); \
|
||||
if (len > 0 && s[len - 1] == '\n') { \
|
||||
s[len - 1] = '\0'; \
|
||||
} \
|
||||
\
|
||||
xmbstowcs(wcbuf, s, BUFSIZE); \
|
||||
(_var) = xwcsdup(wcbuf); \
|
||||
(_var_utf8) = s; \
|
||||
\
|
||||
lineno++; \
|
||||
} while (0)
|
||||
#endif // ! USE_UTF8_GAME_FILE
|
||||
|
||||
|
||||
// Macros used in save_game()
|
||||
@ -126,8 +169,41 @@ static const unsigned char game_file_crypt_key[] = {
|
||||
save_game_printf("%2.20e", _var)
|
||||
#define save_game_write_bool(_var) \
|
||||
save_game_printf("%d", (int) _var)
|
||||
#define save_game_write_string(_var) \
|
||||
save_game_printf("%s", _var)
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
# define save_game_write_string(_var, _var_utf8) \
|
||||
do { \
|
||||
if ((_var_utf8) != NULL) { \
|
||||
save_game_printf("%s", _var_utf8); \
|
||||
} else { \
|
||||
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, _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
|
||||
|
||||
|
||||
/************************************************************************
|
||||
@ -142,21 +218,28 @@ 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;
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
iconv_t icd;
|
||||
bool need_icd;
|
||||
#endif
|
||||
|
||||
|
||||
assert(num >= 1 && num <= 9);
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
buf = xmalloc(BUFSIZE);
|
||||
wcbuf = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||
|
||||
filename = game_filename(num);
|
||||
assert(filename != NULL);
|
||||
@ -167,62 +250,94 @@ bool load_game (int num)
|
||||
|
||||
if (errno == ENOENT) {
|
||||
// File not found
|
||||
newtxwin(7, 40, 9, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " Game Not Found ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"Game %d has not been saved to disk", num);
|
||||
|
||||
wait_for_key(curwin, 5, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
txdlgbox(MAX_DLG_LINES, 50, 9, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" Game Not Found "),
|
||||
_("Game %d has not been saved to disk."), num);
|
||||
} else {
|
||||
// Some other file error
|
||||
saved_errno = errno;
|
||||
|
||||
newtxwin(9, 70, 9, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " Game Not Loaded ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"Game %d could not be loaded from disk", num);
|
||||
center(curwin, 5, attr_error_normal, "File %s: %s", filename,
|
||||
strerror(saved_errno));
|
||||
|
||||
wait_for_key(curwin, 7, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
txdlgbox(MAX_DLG_LINES, 60, 9, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight,
|
||||
attr_error_normal, 0, attr_error_waitforkey,
|
||||
_(" Game Not Loaded "),
|
||||
_("Game %d could not be loaded from disk.\n\n"
|
||||
"^{File %s: %s^}"), num, filename,
|
||||
strerror(saved_errno));
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(wcbuf);
|
||||
free(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Change the formatting of numbers to the POSIX locale for consistency
|
||||
prev_locale = strdup(setlocale(LC_NUMERIC, NULL));
|
||||
if (prev_locale == NULL) {
|
||||
err_exit_nomem();
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
// Make sure all strings are read in UTF-8 format for consistency
|
||||
codeset = nl_langinfo(CODESET);
|
||||
if (codeset == NULL) {
|
||||
errno_exit("nl_langinfo(CODESET)");
|
||||
}
|
||||
need_icd = (strcmp(codeset, GAME_FILE_CHARSET) != 0);
|
||||
if (need_icd) {
|
||||
// Try using the GNU libiconv "//TRANSLIT" option
|
||||
strcpy(buf, codeset);
|
||||
strcat(buf, GAME_FILE_TRANSLIT);
|
||||
|
||||
icd = iconv_open(buf, GAME_FILE_CHARSET);
|
||||
if (icd == (iconv_t) -1) {
|
||||
// Try iconv_open() without "//TRANSLIT"
|
||||
icd = iconv_open(codeset, GAME_FILE_CHARSET);
|
||||
if (icd == (iconv_t) -1) {
|
||||
errno_exit("iconv_open");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
icd = (iconv_t) -1;
|
||||
}
|
||||
codeset_nl = xstrdup(GAME_FILE_CHARSET "\n");
|
||||
#else // ! USE_UTF8_GAME_FILE
|
||||
// Make sure all strings are read in the correct codeset
|
||||
codeset = nl_langinfo(CODESET);
|
||||
if (codeset == NULL) {
|
||||
errno_exit("nl_langinfo(CODESET)");
|
||||
}
|
||||
codeset_nl = xmalloc(strlen(codeset) + 2);
|
||||
strcpy(codeset_nl, codeset);
|
||||
strcat(codeset_nl, "\n");
|
||||
#endif // ! USE_UTF8_GAME_FILE
|
||||
|
||||
// Change the formatting of numbers to the POSIX locale for consistency
|
||||
prev_locale = xstrdup(setlocale(LC_NUMERIC, NULL));
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
|
||||
// Read the game file header
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit("%s: missing header in game file", filename);
|
||||
err_exit(_("%s: missing header in game file"), filename);
|
||||
}
|
||||
if (strcmp(buf, GAME_FILE_HEADER "\n") != 0) {
|
||||
err_exit("%s: not a valid game file", filename);
|
||||
err_exit(_("%s: not a valid game file"), filename);
|
||||
}
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit("%s: missing subheader in game file", filename);
|
||||
err_exit(_("%s: missing subheader in game file"), filename);
|
||||
}
|
||||
if (strcmp(buf, GAME_FILE_API_VERSION "\n") != 0) {
|
||||
err_exit("%s: saved under a different version of Star Traders",
|
||||
err_exit(_("%s: saved under a different version of Star Traders"),
|
||||
filename);
|
||||
}
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit(_("%s: missing subheader in game file"), filename);
|
||||
}
|
||||
if (strcmp(buf, codeset_nl) != 0) {
|
||||
err_exit(_("%s: saved under an incompatible character encoding"),
|
||||
filename);
|
||||
}
|
||||
|
||||
lineno = 3;
|
||||
lineno = 4;
|
||||
|
||||
// Read in the game file encryption key
|
||||
if (fscanf(file, "%i\n", &crypt_key) != 1) {
|
||||
err_exit("%s: illegal or missing field on line %d", filename, lineno);
|
||||
err_exit(_("%s: illegal or missing field on line %d"), filename, lineno);
|
||||
}
|
||||
lineno++;
|
||||
|
||||
@ -239,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);
|
||||
@ -251,7 +366,8 @@ bool load_game (int num)
|
||||
|
||||
// Read in company data
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
company[i].name = 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);
|
||||
@ -262,10 +378,10 @@ bool load_game (int num)
|
||||
// Read in galaxy map
|
||||
for (int x = 0; x < MAX_X; x++) {
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit("%s: missing field on line %d", filename, lineno);
|
||||
err_exit(_("%s: missing field on line %d"), filename, lineno);
|
||||
}
|
||||
if (strlen(unscramble(crypt_key, buf, BUFSIZE)) != MAX_Y + 1) {
|
||||
err_exit("%s: illegal field on line %d", filename, lineno);
|
||||
err_exit(_("%s: illegal field on line %d"), filename, lineno);
|
||||
}
|
||||
|
||||
for (int y = 0; y < MAX_Y; y++) {
|
||||
@ -274,7 +390,7 @@ bool load_game (int num)
|
||||
|| (c >= MAP_A && c <= MAP_LAST)) {
|
||||
galaxy_map[x][y] = (map_val_t) c;
|
||||
} else {
|
||||
err_exit("%s: illegal value on line %d", filename, lineno);
|
||||
err_exit(_("%s: illegal value on line %d"), filename, lineno);
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,9 +407,17 @@ bool load_game (int num)
|
||||
// Change the formatting of numbers back to the user-supplied locale
|
||||
setlocale(LC_NUMERIC, prev_locale);
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
if (need_icd) {
|
||||
iconv_close(icd);
|
||||
}
|
||||
#endif
|
||||
|
||||
free(buf);
|
||||
free(wcbuf);
|
||||
free(filename);
|
||||
free(prev_locale);
|
||||
free(codeset_nl);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -306,19 +430,22 @@ bool save_game (int num)
|
||||
const char *data_dir;
|
||||
char *buf, *filename;
|
||||
FILE *file;
|
||||
char *codeset;
|
||||
int saved_errno;
|
||||
char *prev_locale;
|
||||
struct stat statbuf;
|
||||
int crypt_key;
|
||||
int i, j, x, y;
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
iconv_t icd;
|
||||
bool need_icd;
|
||||
#endif
|
||||
|
||||
|
||||
assert(num >= 1 && num <= 9);
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
buf = xmalloc(BUFSIZE);
|
||||
|
||||
crypt_key = option_dont_encrypt ? 0 :
|
||||
game_file_crypt_key[randi(GAME_FILE_CRYPT_KEY_SIZE)];
|
||||
@ -333,17 +460,13 @@ bool save_game (int num)
|
||||
; // Do nothing: directory already exists
|
||||
} else {
|
||||
// Data directory could not be created
|
||||
|
||||
newtxwin(9, 70, 7, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " Game Not Saved ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"Game %d could not be saved to disk", num);
|
||||
center(curwin, 5, attr_error_normal, "Directory %s: %s",
|
||||
data_dir, strerror(saved_errno));
|
||||
|
||||
wait_for_key(curwin, 7, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
txdlgbox(MAX_DLG_LINES, 60, 7, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight,
|
||||
attr_error_normal, 0, attr_error_waitforkey,
|
||||
_(" Game Not Saved "),
|
||||
_("Game %d could not be saved to disk.\n\n"
|
||||
"^{Directory %s: %s^}"), num, data_dir,
|
||||
strerror(saved_errno));
|
||||
|
||||
free(buf);
|
||||
return false;
|
||||
@ -358,33 +481,49 @@ bool save_game (int num)
|
||||
if (file == NULL) {
|
||||
// File could not be opened for writing
|
||||
saved_errno = errno;
|
||||
|
||||
newtxwin(9, 70, 7, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " Game Not Saved ");
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"Game %d could not be saved to disk", num);
|
||||
center(curwin, 5, attr_error_normal, "File %s: %s", filename,
|
||||
strerror(saved_errno));
|
||||
|
||||
wait_for_key(curwin, 7, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
txdlgbox(MAX_DLG_LINES, 60, 7, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight,
|
||||
attr_error_normal, 0, attr_error_waitforkey,
|
||||
_(" Game Not Saved "),
|
||||
_("Game %d could not be saved to disk.\n\n"
|
||||
"^{File %s: %s^}"), num, filename, strerror(saved_errno));
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Change the formatting of numbers to the POSIX locale for consistency
|
||||
prev_locale = strdup(setlocale(LC_NUMERIC, NULL));
|
||||
if (prev_locale == NULL) {
|
||||
err_exit_nomem();
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
// Make sure all strings are output in UTF-8 format for consistency
|
||||
codeset = nl_langinfo(CODESET);
|
||||
if (codeset == NULL) {
|
||||
errno_exit("nl_langinfo(CODESET)");
|
||||
}
|
||||
need_icd = (strcmp(codeset, GAME_FILE_CHARSET) != 0);
|
||||
if (need_icd) {
|
||||
icd = iconv_open(GAME_FILE_CHARSET, codeset);
|
||||
if (icd == (iconv_t) -1) {
|
||||
errno_exit("iconv_open");
|
||||
}
|
||||
} else {
|
||||
icd = (iconv_t) -1;
|
||||
}
|
||||
codeset = GAME_FILE_CHARSET; // Now contains output codeset
|
||||
#else // ! USE_UTF8_GAME_FILE
|
||||
// Make sure all strings are output in the correct codeset
|
||||
codeset = nl_langinfo(CODESET);
|
||||
if (codeset == NULL) {
|
||||
errno_exit("nl_langinfo(CODESET)");
|
||||
}
|
||||
#endif // ! USE_UTF8_GAME_FILE
|
||||
|
||||
// Change the formatting of numbers to the POSIX locale for consistency
|
||||
prev_locale = xstrdup(setlocale(LC_NUMERIC, NULL));
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
|
||||
// Write out the game file header and encryption key
|
||||
fprintf(file, "%s\n" "%s\n", GAME_FILE_HEADER, GAME_FILE_API_VERSION);
|
||||
fprintf(file, "%d\n", crypt_key);
|
||||
fprintf(file, "%s\n" "%d\n", codeset, crypt_key);
|
||||
|
||||
// Write out various game variables
|
||||
save_game_write_int(MAX_X);
|
||||
@ -399,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);
|
||||
@ -443,6 +582,12 @@ bool save_game (int num)
|
||||
// Change the formatting of numbers back to the user-supplied locale
|
||||
setlocale(LC_NUMERIC, prev_locale);
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
if (need_icd) {
|
||||
iconv_close(icd);
|
||||
}
|
||||
#endif
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
free(prev_locale);
|
||||
|
535
src/game.c
535
src/game.c
@ -110,14 +110,20 @@ void init_game (void)
|
||||
{
|
||||
// Try to load an old game, if possible
|
||||
if (game_num != 0) {
|
||||
newtxwin(5, 30, 6, WCENTER, true, attr_status_window);
|
||||
center(curwin, 2, attr_status_window, "Loading game %d... ", game_num);
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
int width;
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_status_window, 0, 0, 1, WIN_COLS - 7,
|
||||
&width, 1, _("Loading game %d... "), game_num);
|
||||
newtxwin(5, width + 5, 6, WCENTER, true, attr_status_window);
|
||||
centerch(curwin, 2, 0, chbuf, 1, &width);
|
||||
wrefresh(curwin);
|
||||
|
||||
game_loaded = load_game(game_num);
|
||||
|
||||
deltxwin();
|
||||
txrefresh();
|
||||
free(chbuf);
|
||||
}
|
||||
|
||||
// Initialise game data, if not already loaded
|
||||
@ -134,18 +140,25 @@ void init_game (void)
|
||||
choice = ask_game_number();
|
||||
|
||||
if (choice != ERR) {
|
||||
// Try to load the game, if possible
|
||||
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
int width;
|
||||
|
||||
game_num = choice;
|
||||
|
||||
// Try to load the game, if possible
|
||||
newtxwin(5, 30, 9, WCENTER, true, attr_status_window);
|
||||
center(curwin, 2, attr_status_window,
|
||||
"Loading game %d... ", game_num);
|
||||
mkchstr(chbuf, BUFSIZE, attr_status_window, 0, 0, 1,
|
||||
WIN_COLS - 7, &width, 1,
|
||||
_("Loading game %d... "), game_num);
|
||||
newtxwin(5, width + 5, 9, WCENTER, true, attr_status_window);
|
||||
centerch(curwin, 2, 0, chbuf, 1, &width);
|
||||
wrefresh(curwin);
|
||||
|
||||
game_loaded = load_game(game_num);
|
||||
|
||||
deltxwin();
|
||||
txrefresh();
|
||||
free(chbuf);
|
||||
}
|
||||
|
||||
deltxwin(); // "Enter game number" window
|
||||
@ -158,7 +171,7 @@ void init_game (void)
|
||||
}
|
||||
|
||||
if (! game_loaded) {
|
||||
int i, j, x, y;
|
||||
wchar_t *buf = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||
|
||||
ask_player_names();
|
||||
|
||||
@ -166,19 +179,20 @@ void init_game (void)
|
||||
txrefresh();
|
||||
|
||||
// Initialise player data (other than names)
|
||||
for (i = 0; i < number_players; i++) {
|
||||
for (int i = 0; i < number_players; i++) {
|
||||
player[i].cash = INITIAL_CASH;
|
||||
player[i].debt = 0.0;
|
||||
player[i].in_game = true;
|
||||
|
||||
for (j = 0; j < MAX_COMPANIES; j++) {
|
||||
for (int j = 0; j < MAX_COMPANIES; j++) {
|
||||
player[i].stock_owned[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise company data
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
company[i].name = company_name[i];
|
||||
for (int i = 0; i < MAX_COMPANIES; 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;
|
||||
@ -187,8 +201,8 @@ void init_game (void)
|
||||
}
|
||||
|
||||
// Initialise galaxy map
|
||||
for (x = 0; x < MAX_X; x++) {
|
||||
for (y = 0; y < MAX_Y; y++) {
|
||||
for (int x = 0; x < MAX_X; x++) {
|
||||
for (int y = 0; y < MAX_Y; y++) {
|
||||
galaxy_map[x][y] = (randf() < STAR_RATIO) ?
|
||||
MAP_STAR : MAP_EMPTY;
|
||||
}
|
||||
@ -207,16 +221,15 @@ void init_game (void)
|
||||
first_player = randi(number_players);
|
||||
current_player = first_player;
|
||||
|
||||
newtxwin(7, 50, 8, WCENTER, true, attr_normal_window);
|
||||
|
||||
center(curwin, 2, attr_normal, "The first player to go is");
|
||||
center(curwin, 3, attr_highlight, "%s",
|
||||
player[first_player].name);
|
||||
|
||||
wait_for_key(curwin, 5, attr_waitforkey);
|
||||
deltxwin();
|
||||
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 ^{%ls^}."),
|
||||
player[first_player].name);
|
||||
txrefresh();
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,35 +243,63 @@ void init_game (void)
|
||||
|
||||
static int ask_number_players (void)
|
||||
{
|
||||
int key, ret;
|
||||
wchar_t *keycode_contgame = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
int lines, maxwidth;
|
||||
int widthbuf[2];
|
||||
int ret;
|
||||
bool done;
|
||||
|
||||
|
||||
// Ask for the number of players
|
||||
newtxwin(5, 62, 3, WCENTER, true, attr_normal_window);
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_keycode, 0, 2,
|
||||
WIN_COLS - 7, widthbuf, 2,
|
||||
/* TRANSLATORS: The keycode <C> should be modified to
|
||||
match that (or those) specified with msgctxt
|
||||
"input|ContinueGame". */
|
||||
_("Enter number of players [^{1^}-^{%d^}] "
|
||||
"or ^{<C>^} to continue a game: "), MAX_PLAYERS);
|
||||
assert(lines == 1 || lines == 2);
|
||||
maxwidth = (lines == 1 ? widthbuf[0] : MAX(widthbuf[0], widthbuf[1])) + 5;
|
||||
|
||||
mvwaddstr(curwin, 2, 2, "Enter number of players ");
|
||||
waddstr(curwin, "[");
|
||||
attrpr(curwin, attr_keycode, "1");
|
||||
waddstr(curwin, "-");
|
||||
attrpr(curwin, attr_keycode, "%d", MAX_PLAYERS);
|
||||
waddstr(curwin, "]");
|
||||
waddstr(curwin, " or ");
|
||||
attrpr(curwin, attr_keycode, "<C>");
|
||||
waddstr(curwin, " to continue a game: ");
|
||||
newtxwin(lines + 4, maxwidth, 3, WCENTER, true, attr_normal_window);
|
||||
leftch(curwin, 2, 2, chbuf, lines, widthbuf);
|
||||
free(chbuf);
|
||||
|
||||
curs_set(CURS_ON);
|
||||
wrefresh(curwin);
|
||||
|
||||
/* TRANSLATORS: This string specifies the keycodes used to continue a
|
||||
game; these must NOT contain any numeric digit from 1 to 9. The
|
||||
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. */
|
||||
xmbstowcs(keycode_contgame, pgettext("input|ContinueGame", "Cc"), BUFSIZE);
|
||||
|
||||
done = false;
|
||||
while (! done) {
|
||||
key = toupper(gettxchar(curwin));
|
||||
wint_t key;
|
||||
|
||||
if (key >= '1' && key <= MAX_PLAYERS + '0') {
|
||||
wechochar(curwin, key | A_BOLD);
|
||||
ret = key - '0';
|
||||
done = true;
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
if (key >= L'1' && key <= MAX_PLAYERS + L'0') {
|
||||
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
|
||||
0, 0, 1, "%lc", key);
|
||||
wrefresh(curwin);
|
||||
|
||||
ret = key - L'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:
|
||||
@ -270,12 +311,6 @@ static int ask_number_players (void)
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
wechochar(curwin, key | A_BOLD);
|
||||
ret = 0;
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
beep();
|
||||
}
|
||||
@ -283,6 +318,7 @@ static int ask_number_players (void)
|
||||
}
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
free(keycode_contgame);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -292,35 +328,46 @@ static int ask_number_players (void)
|
||||
|
||||
int ask_game_number (void)
|
||||
{
|
||||
int key, ret;
|
||||
chtype *chbuf;
|
||||
int lines, maxwidth;
|
||||
int widthbuf[2];
|
||||
int ret;
|
||||
bool done;
|
||||
|
||||
|
||||
// Ask which game to load
|
||||
newtxwin(5, 54, 6, WCENTER, true, attr_normal_window);
|
||||
chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_keycode, 0, 2,
|
||||
WIN_COLS - 7, widthbuf, 2,
|
||||
_("Enter game number [^{1^}-^{9^}] "
|
||||
"or ^{<CTRL><C>^} to cancel: "));
|
||||
assert(lines == 1 || lines == 2);
|
||||
maxwidth = (lines == 1 ? widthbuf[0] : MAX(widthbuf[0], widthbuf[1])) + 5;
|
||||
|
||||
mvwaddstr(curwin, 2, 2, "Enter game number ");
|
||||
waddstr(curwin, "[");
|
||||
attrpr(curwin, attr_keycode, "1");
|
||||
waddstr(curwin, "-");
|
||||
attrpr(curwin, attr_keycode, "9");
|
||||
waddstr(curwin, "]");
|
||||
waddstr(curwin, " or ");
|
||||
attrpr(curwin, attr_keycode, "<CTRL><C>");
|
||||
waddstr(curwin, " to cancel: ");
|
||||
newtxwin(lines + 4, maxwidth, 6, WCENTER, true, attr_normal_window);
|
||||
leftch(curwin, 2, 2, chbuf, lines, widthbuf);
|
||||
free(chbuf);
|
||||
|
||||
curs_set(CURS_ON);
|
||||
wrefresh(curwin);
|
||||
|
||||
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 >= L'1' && key <= L'9') {
|
||||
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
|
||||
0, 0, 1, "%lc", key);
|
||||
wrefresh(curwin);
|
||||
|
||||
ret = key - L'0';
|
||||
done = true;
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
} else {
|
||||
// Function or control key
|
||||
switch (key) {
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
@ -348,30 +395,39 @@ int ask_game_number (void)
|
||||
|
||||
void ask_player_names (void)
|
||||
{
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
int width;
|
||||
|
||||
|
||||
if (number_players == 1) {
|
||||
// Ask for the player's name
|
||||
|
||||
newtxwin(5, WIN_COLS - 4, 9, WCENTER, true, attr_normal_window);
|
||||
|
||||
mvwaddstr(curwin, 2, 2, "Please enter your name: ");
|
||||
left(curwin, 2, 2, attr_normal, 0, 0, 1, _("Please enter your name: "));
|
||||
|
||||
int x = getcurx(curwin);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
newtxwin(5, 44, 6, WCENTER, true, attr_normal_window);
|
||||
mvwaddstr(curwin, 2, 2, "Do you need any instructions?");
|
||||
if (answer_yesno(curwin, attr_keycode)) {
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, attr_keycode, 0, 1,
|
||||
WIN_COLS - YESNO_COLS - 6, &width, 1,
|
||||
_("Do you need any instructions? [^{Y^}/^{N^}] "));
|
||||
newtxwin(5, width + YESNO_COLS + 4, 6, WCENTER, true,
|
||||
attr_normal_window);
|
||||
leftch(curwin, 2, 2, chbuf, 1, &width);
|
||||
|
||||
if (answer_yesno(curwin)) {
|
||||
show_help();
|
||||
}
|
||||
|
||||
@ -384,16 +440,18 @@ void ask_player_names (void)
|
||||
|
||||
newtxwin(number_players + 5, WIN_COLS - 4, 9, WCENTER,
|
||||
true, attr_normal_window);
|
||||
|
||||
center(curwin, 1, attr_title, " Enter Player Names ");
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1, _(" Enter Player Names "));
|
||||
|
||||
for (i = 0; i < number_players; i++) {
|
||||
player[i].name = NULL;
|
||||
player[i].name_utf8 = NULL;
|
||||
entered[i] = false;
|
||||
mvwprintw(curwin, i + 3, 2, "Player %d:", i + 1);
|
||||
left(curwin, i + 3, 2, attr_normal, 0, 0, 1,
|
||||
/* xgettext:c-format, range: 1..8 */
|
||||
_("Player %d: "), i + 1);
|
||||
}
|
||||
|
||||
int x = getcurx(curwin) + 1;
|
||||
int x = getcurx(curwin);
|
||||
int w = getmaxx(curwin) - x - 2;
|
||||
|
||||
cur = 0;
|
||||
@ -405,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();
|
||||
@ -414,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;
|
||||
@ -466,15 +524,21 @@ void ask_player_names (void)
|
||||
}
|
||||
}
|
||||
|
||||
newtxwin(5, 50, 6, WCENTER, true, attr_normal_window);
|
||||
mvwaddstr(curwin, 2, 2, "Does any player need instructions?");
|
||||
if (answer_yesno(curwin, attr_keycode)) {
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, attr_keycode, 0, 1,
|
||||
WIN_COLS - YESNO_COLS - 6, &width, 1,
|
||||
_("Does any player need instructions? [^{Y^}/^{N^}] "));
|
||||
newtxwin(5, width + YESNO_COLS + 4, 6, WCENTER, true,
|
||||
attr_normal_window);
|
||||
leftch(curwin, 2, 2, chbuf, 1, &width);
|
||||
|
||||
if (answer_yesno(curwin)) {
|
||||
show_help();
|
||||
}
|
||||
}
|
||||
|
||||
deltxwin(); // "Need instructions?" window
|
||||
deltxwin(); // "Enter player names" window
|
||||
free(chbuf);
|
||||
}
|
||||
|
||||
|
||||
@ -483,8 +547,8 @@ void ask_player_names (void)
|
||||
|
||||
void end_game (void)
|
||||
{
|
||||
int i;
|
||||
char *buf;
|
||||
chtype *chbuf;
|
||||
int lines, widthbuf[5];
|
||||
|
||||
|
||||
if (abort_game) {
|
||||
@ -492,74 +556,74 @@ void end_game (void)
|
||||
return;
|
||||
}
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
|
||||
newtxwin(7, 40, 9, WCENTER, true, attr_error_window);
|
||||
txdlgbox(MAX_DLG_LINES, 50, 9, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" Game Over "),
|
||||
ngettext("The game is over after one turn.",
|
||||
"The game is over after %d turns.",
|
||||
turn_number - 1), turn_number - 1);
|
||||
|
||||
center(curwin, 1, attr_error_title, " Game Over ");
|
||||
center(curwin, 3, attr_error_highlight, "The game is over after %d turns",
|
||||
turn_number - 1);
|
||||
|
||||
wait_for_key(curwin, 5, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
|
||||
for (i = 0; i < number_players; i++) {
|
||||
for (int i = 0; i < number_players; i++) {
|
||||
show_status(i);
|
||||
}
|
||||
|
||||
if (number_players == 1) {
|
||||
l_strfmon(buf, BUFSIZE, "%1n", total_value(0));
|
||||
|
||||
newtxwin(9, 60, 8, WCENTER, true, attr_normal_window);
|
||||
|
||||
center(curwin, 1, attr_title, " Total Value ");
|
||||
center2(curwin, 4, attr_normal, attr_highlight,
|
||||
"Your total value was ", "%s", buf);
|
||||
|
||||
wait_for_key(curwin, 7, attr_waitforkey);
|
||||
deltxwin();
|
||||
txdlgbox(MAX_DLG_LINES, 60, 8, WCENTER, attr_normal_window,
|
||||
attr_title, attr_normal, attr_highlight, 0, attr_waitforkey,
|
||||
_(" Total Value "),
|
||||
/* xgettext:c-format */
|
||||
_("Your total value was ^{%N^}."), total_value(0));
|
||||
} else {
|
||||
// Sort players on the basis of total value
|
||||
for (i = 0; i < number_players; i++) {
|
||||
for (int i = 0; i < number_players; i++) {
|
||||
player[i].sort_value = total_value(i);
|
||||
}
|
||||
qsort(player, number_players, sizeof(player_info_t), cmp_player);
|
||||
|
||||
newtxwin(number_players + 10, WIN_COLS - 4, 3, WCENTER,
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_highlight,
|
||||
attr_blink, 5, WIN_COLS - 8, widthbuf, 5,
|
||||
(player[0].sort_value == 0) ?
|
||||
_("The winner is ^{%ls^}\n"
|
||||
"who is ^[*** BANKRUPT ***^]") :
|
||||
/* xgettext:c-format */
|
||||
_("The winner is ^{%ls^}\n"
|
||||
"with a value of ^{%N^}."),
|
||||
player[0].name, player[0].sort_value);
|
||||
|
||||
newtxwin(number_players + lines + 8, WIN_COLS - 4, 3, WCENTER,
|
||||
true, attr_normal_window);
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1, _(" Game Winner "));
|
||||
centerch(curwin, 3, 0, chbuf, lines, widthbuf);
|
||||
|
||||
center(curwin, 1, attr_title, " Game Winner ");
|
||||
center2(curwin, 3, attr_normal, attr_highlight, "The winner is ",
|
||||
"%s", player[0].name);
|
||||
if (player[0].sort_value == 0.0) {
|
||||
center2(curwin, 4, attr_normal, attr_blink, "who is ",
|
||||
"*** BANKRUPT ***");
|
||||
} else {
|
||||
l_strfmon(buf, BUFSIZE, "%1n", player[0].sort_value);
|
||||
center2(curwin, 4, attr_normal, attr_highlight,
|
||||
"with a value of ", "%s", buf);
|
||||
}
|
||||
int w = getmaxx(curwin);
|
||||
|
||||
int w = getmaxx(curwin) - 33;
|
||||
wattrset(curwin, attr_subtitle);
|
||||
snprintf(buf, BUFSIZE, "Total Value (%s)", lconvinfo.currency_symbol);
|
||||
mvwprintw(curwin, 6, 2, "%5s %-*.*s %18s ", "", w, w, "Player", buf);
|
||||
wattrset(curwin, attr_normal);
|
||||
mvwhline(curwin, lines + 4, 2, ' ' | attr_subtitle, w - 4);
|
||||
left(curwin, lines + 4, ORDINAL_COLS + 4, attr_subtitle, 0, 0, 1,
|
||||
/* TRANSLATORS: "Player" is used as a column title in a
|
||||
table containing all player names. */
|
||||
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. %ls is the
|
||||
currency symbol of the current locale. */
|
||||
pgettext("subtitle", "Total Value (%ls)"), currency_symbol);
|
||||
|
||||
for (i = 0; i < number_players; i++) {
|
||||
l_strfmon(buf, BUFSIZE, "%!18n", player[i].sort_value);
|
||||
mvwprintw(curwin, i + 7, 2, "%5s %-*.*s %18s ",
|
||||
ordinal[i + 1], w, w, player[i].name, buf);
|
||||
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, "%ls", player[i].name);
|
||||
right(curwin, i + lines + 5, w - 2, attr_normal, 0, 0,
|
||||
1, " %!N ", player[i].sort_value);
|
||||
}
|
||||
|
||||
wait_for_key(curwin, getmaxy(curwin) - 2, attr_waitforkey);
|
||||
deltxwin();
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(chbuf);
|
||||
}
|
||||
|
||||
|
||||
@ -568,79 +632,31 @@ void end_game (void)
|
||||
|
||||
void show_map (bool closewin)
|
||||
{
|
||||
int n, x, y;
|
||||
|
||||
|
||||
newtxwin(MAX_Y + 4, WIN_COLS, 1, WCENTER, true, attr_map_window);
|
||||
|
||||
// Draw various borders
|
||||
// Draw various borders and highlights
|
||||
mvwaddch(curwin, 2, 0, ACS_LTEE);
|
||||
whline(curwin, ACS_HLINE, getmaxx(curwin) - 2);
|
||||
mvwaddch(curwin, 2, getmaxx(curwin) - 1, ACS_RTEE);
|
||||
mvwhline(curwin, 1, 2, ' ' | attr_mapwin_title, getmaxx(curwin) - 4);
|
||||
|
||||
// Display current player and turn number
|
||||
wattrset(curwin, attr_mapwin_title);
|
||||
mvwaddstr(curwin, 1, 2, " ");
|
||||
waddstr(curwin, "Player: ");
|
||||
n = getmaxx(curwin) - getcurx(curwin) - 4;
|
||||
wattrset(curwin, attr_mapwin_highlight);
|
||||
wprintw(curwin, "%-*.*s", n, n, player[current_player].name);
|
||||
wattrset(curwin, attr_mapwin_title);
|
||||
waddstr(curwin, " ");
|
||||
|
||||
if (turn_number != max_turn) {
|
||||
const char *initial = "Turn: ";
|
||||
|
||||
char *buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
|
||||
int len1 = strlen(initial);
|
||||
int len2 = snprintf(buf, BUFSIZE, "%d", turn_number);
|
||||
|
||||
mvwaddstr(curwin, 1, getmaxx(curwin) - (len1 + len2) - 6, " ");
|
||||
waddstr(curwin, initial);
|
||||
attrpr(curwin, attr_mapwin_highlight, "%s", buf);
|
||||
waddstr(curwin, " ");
|
||||
|
||||
free(buf);
|
||||
|
||||
} else {
|
||||
const char *buf = "*** Last Turn ***";
|
||||
int len = strlen(buf);
|
||||
|
||||
mvwaddstr(curwin, 1, getmaxx(curwin) - len - 6, " ");
|
||||
attrpr(curwin, attr_mapwin_blink, "%s", buf);
|
||||
waddstr(curwin, " ");
|
||||
}
|
||||
|
||||
wattrset(curwin, attr_map_window);
|
||||
left(curwin, 1, 4, attr_mapwin_title, attr_mapwin_highlight, 0, 1,
|
||||
_("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^} ") :
|
||||
_(" ^[*** Last Turn ***^] "), turn_number);
|
||||
|
||||
// Display the actual map
|
||||
for (y = 0; y < MAX_Y; y++) {
|
||||
for (int y = 0; y < MAX_Y; y++) {
|
||||
wmove(curwin, y + 3, 2);
|
||||
for (x = 0; x < MAX_X; x++) {
|
||||
map_val_t m = galaxy_map[x][y];
|
||||
for (int x = 0; x < MAX_X; x++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -667,27 +683,25 @@ void show_map (bool closewin)
|
||||
void show_status (int num)
|
||||
{
|
||||
double val;
|
||||
int i, line;
|
||||
int w, i, line;
|
||||
|
||||
|
||||
assert(num >= 0 && num < number_players);
|
||||
|
||||
newtxwin(MAX_COMPANIES + 15, WIN_COLS, 1, WCENTER, true,
|
||||
attr_normal_window);
|
||||
|
||||
center(curwin, 1, attr_title, " Stock Portfolio ");
|
||||
center2(curwin, 2, attr_normal, attr_highlight, "Player: ", "%s",
|
||||
player[num].name);
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1, _(" Stock Portfolio "));
|
||||
center(curwin, 2, 0, attr_normal, attr_highlight, 0, 1,
|
||||
_("Player: ^{%ls^}"), player[num].name);
|
||||
|
||||
val = total_value(num);
|
||||
if (val == 0.0) {
|
||||
center(curwin, 11, attr_blink, "* * * B A N K R U P T * * *");
|
||||
|
||||
center(curwin, 11, 0, attr_normal, attr_highlight, attr_blink, 1,
|
||||
/* TRANSLATORS: The current player is bankrupt (has no
|
||||
shares or cash, ie, whose total value is zero) */
|
||||
_("^[* * * B A N K R U P T * * *^]"));
|
||||
} else {
|
||||
char *buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
w = getmaxx(curwin);
|
||||
|
||||
// Check to see if any companies are on the map
|
||||
bool none = true;
|
||||
@ -699,51 +713,115 @@ void show_status (int num)
|
||||
}
|
||||
|
||||
if (none) {
|
||||
center(curwin, 8, attr_normal, "No companies on the map");
|
||||
center(curwin, 8, 0, attr_normal, attr_highlight, 0, 1,
|
||||
_("No companies on the map"));
|
||||
} else {
|
||||
// Handle the locale's currency symbol
|
||||
snprintf(buf, BUFSIZE, "share (%s)", lconvinfo.currency_symbol);
|
||||
mvwhline(curwin, 4, 2, ' ' | attr_subtitle, w - 4);
|
||||
mvwhline(curwin, 5, 2, ' ' | attr_subtitle, w - 4);
|
||||
|
||||
wattrset(curwin, attr_subtitle);
|
||||
mvwprintw(curwin, 4, 2, " %-22s %12s %10s %10s %10s ",
|
||||
"", "Price per", "", "Holdings", "Company");
|
||||
mvwprintw(curwin, 5, 2, " %-22s %12s %10s %10s %10s ",
|
||||
"Company", buf, "Return (%)", "(shares)", "owner (%)");
|
||||
wattrset(curwin, attr_normal);
|
||||
left(curwin, 4, 4, attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Company" is a two-line column label in
|
||||
a table containing a list of companies. */
|
||||
pgettext("subtitle", "\nCompany"));
|
||||
right(curwin, 4, w - 4, attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Ownership" is a two-line column label
|
||||
in a table containing the current player's
|
||||
percentage ownership in any given company. The
|
||||
maximum column width is 10 characters (see
|
||||
OWNERSHIP_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Ownership\n(%%)"));
|
||||
right(curwin, 4, w - 6 - OWNERSHIP_COLS, attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Holdings" is a two-line column label
|
||||
in a table containing the number of shares the
|
||||
current player owns in any given company. The
|
||||
maximum column width is 10 characters (see
|
||||
STOCK_OWNED_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Holdings\n(shares)"));
|
||||
right(curwin, 4, w - 8 - OWNERSHIP_COLS - STOCK_OWNED_COLS,
|
||||
attr_subtitle, 0, 0, 2,
|
||||
/* TRANSLATORS: "Return" is a two-line column label in
|
||||
a table containing the share return as a percentage
|
||||
in any given company. The maximum column width is
|
||||
10 characters (see SHARE_RETURN_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Return\n(%%)"));
|
||||
right(curwin, 4, w - 10 - OWNERSHIP_COLS - STOCK_OWNED_COLS
|
||||
- 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. %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 (%ls)"),
|
||||
currency_symbol);
|
||||
|
||||
for (line = 6, i = 0; i < MAX_COMPANIES; i++) {
|
||||
if (company[i].on_map) {
|
||||
l_strfmon(buf, BUFSIZE, "%!12n", company[i].share_price);
|
||||
mvwprintw(curwin, line, 2,
|
||||
" %-22s %10s %10.2f %'10ld %10.2f ",
|
||||
company[i].name, buf,
|
||||
company[i].share_return * 100.0,
|
||||
player[num].stock_owned[i],
|
||||
(company[i].stock_issued == 0) ? 0.0 :
|
||||
((double) player[num].stock_owned[i] * 100.0)
|
||||
/ company[i].stock_issued);
|
||||
left(curwin, line, 4, attr_normal, 0, 0, 1, "%ls",
|
||||
company[i].name);
|
||||
|
||||
right(curwin, line, w - 2, attr_normal, 0, 0, 1, "%.2f ",
|
||||
(company[i].stock_issued == 0) ? 0.0 :
|
||||
((double) player[num].stock_owned[i] * 100.0)
|
||||
/ company[i].stock_issued);
|
||||
right(curwin, line, w - 4 - OWNERSHIP_COLS, attr_normal,
|
||||
0, 0, 1, "%'ld ", player[num].stock_owned[i]);
|
||||
right(curwin, line, w - 6 - OWNERSHIP_COLS
|
||||
- STOCK_OWNED_COLS, attr_normal, 0, 0, 1, "%.2f ",
|
||||
company[i].share_return * 100.0);
|
||||
right(curwin, line, w - 8 - OWNERSHIP_COLS
|
||||
- STOCK_OWNED_COLS - SHARE_RETURN_COLS, attr_normal,
|
||||
0, 0, 1, " %!N ", company[i].share_price);
|
||||
|
||||
line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line = 15;
|
||||
l_strfmon(buf, BUFSIZE, "%18n", player[num].cash);
|
||||
center2(curwin, line++, attr_normal, attr_highlight, "Current cash: ",
|
||||
" %s ", buf);
|
||||
line = MAX_COMPANIES + 7;
|
||||
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
int width, x;
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_highlight, 0, 0, 1, w / 2, &width, 1,
|
||||
/* TRANSLATORS: The "Total value", "Current cash",
|
||||
"Current debt" and "Interest rate" labels MUST all be
|
||||
the same length (ie, right-padded with spaces as
|
||||
needed) and must have at least one trailing space so
|
||||
that the display routines work correctly. The maximum
|
||||
length of each label is 36 characters.
|
||||
|
||||
Note that some of these labels are used for both the
|
||||
Player Status window and the Trading Bank window. */
|
||||
pgettext("label", "Total value: "));
|
||||
x = (w + width - (TOTAL_VALUE_COLS + 2)) / 2;
|
||||
|
||||
right(curwin, line, x, attr_normal, attr_highlight, 0, 1,
|
||||
pgettext("label", "Current cash: "));
|
||||
right(curwin, line, x + TOTAL_VALUE_COLS + 2, attr_normal,
|
||||
attr_highlight, 0, 1, " ^{%N^} ", player[num].cash);
|
||||
line++;
|
||||
|
||||
if (player[num].debt != 0.0) {
|
||||
l_strfmon(buf, BUFSIZE, "%18n", player[num].debt);
|
||||
center2(curwin, line++, attr_normal, attr_highlight,
|
||||
"Current debt: ", " %s ", buf);
|
||||
center2(curwin, line++, attr_normal, attr_highlight,
|
||||
"Interest rate: ", " %17.2f%% ", interest_rate * 100.0);
|
||||
right(curwin, line, x, attr_normal, attr_highlight, 0, 1,
|
||||
pgettext("label", "Current debt: "));
|
||||
right(curwin, line, x + TOTAL_VALUE_COLS + 2, attr_normal,
|
||||
attr_highlight, 0, 1, " ^{%N^} ", player[num].debt);
|
||||
line++;
|
||||
|
||||
right(curwin, line, x, attr_normal, attr_highlight, 0, 1,
|
||||
pgettext("label", "Interest rate: "));
|
||||
right(curwin, line, x + TOTAL_VALUE_COLS + 2, attr_normal,
|
||||
attr_highlight, 0, 1, " ^{%.2f%%^} ", interest_rate * 100.0);
|
||||
line++;
|
||||
}
|
||||
|
||||
l_strfmon(buf, BUFSIZE, "%18n", val);
|
||||
center2(curwin, line + 1, attr_highlight, attr_title,
|
||||
"Total value: ", " %s ", buf);
|
||||
rightch(curwin, line + 1, x, chbuf, 1, &width);
|
||||
whline(curwin, ' ' | attr_title, TOTAL_VALUE_COLS + 2);
|
||||
right(curwin, line + 1, x + TOTAL_VALUE_COLS + 2, attr_title, 0, 0, 1,
|
||||
" %N ", val);
|
||||
|
||||
free(buf);
|
||||
free(chbuf);
|
||||
}
|
||||
|
||||
wait_for_key(curwin, getmaxy(curwin) - 2, attr_waitforkey);
|
||||
@ -758,13 +836,12 @@ void show_status (int num)
|
||||
double total_value (int num)
|
||||
{
|
||||
double val;
|
||||
int i;
|
||||
|
||||
|
||||
assert(num >= 0 && num < number_players);
|
||||
|
||||
val = player[num].cash - player[num].debt;
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
for (int i = 0; i < MAX_COMPANIES; i++) {
|
||||
if (company[i].on_map) {
|
||||
val += player[num].stock_owned[i] * company[i].share_price;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "system.h"
|
||||
#include "globals.h"
|
||||
|
||||
|
||||
@ -37,28 +38,84 @@
|
||||
|
||||
// Company names
|
||||
const char *company_name[MAX_COMPANIES] = {
|
||||
"Altair Starways",
|
||||
"Betelgeuse, Ltd",
|
||||
"Capella Freight Co",
|
||||
"Denebola Shippers",
|
||||
"Eridani Expediters",
|
||||
"Fornax Express",
|
||||
"Gemeni Inc",
|
||||
"Hercules and Co"
|
||||
/* TRANSLATORS: The eight company names do NOT have to be literal
|
||||
translations of the English names. In fact, if possible, the
|
||||
names should start with successive letters of your alphabet (in
|
||||
English, for example, "A" to "H"). No company name should be more
|
||||
than 24 characters (column positions, to be precise) long. */
|
||||
N_("Altair Starways"),
|
||||
N_("Betelgeuse, Ltd"),
|
||||
N_("Capella Freight Co"),
|
||||
N_("Denebola Shippers"),
|
||||
N_("Eridani Expediters"),
|
||||
N_("Fornax Express"),
|
||||
N_("Gemeni Inc"),
|
||||
N_("Hercules and Co")
|
||||
};
|
||||
|
||||
|
||||
// Default keycodes (keyboard input characters) for each company
|
||||
const char *default_keycode_company =
|
||||
/* TRANSLATORS: This string specifies the keycodes (keyboard input
|
||||
codes) used to enter the Stock Transaction window for each
|
||||
company. There must be exactly eight characters, one for each
|
||||
company in order, before the ASCII vertical line "|"; these must
|
||||
be EITHER all in upper-case or all in lower-case. If at all
|
||||
possible, these should be successive letters in your alphabet (in
|
||||
English, "A" to "H"). Do NOT use digits or control characters.
|
||||
Do not change or translate anything after the vertical line. */
|
||||
N_("ABCDEFGH|input|Companies");
|
||||
|
||||
|
||||
// Default keycodes (keyboard input characters) for each move
|
||||
const char *default_keycode_game_move =
|
||||
/* TRANSLATORS: This string specifies the keycodes used to select a
|
||||
game move. There must be exactly 20 characters, one for each
|
||||
move, before the ASCII vertical line "|"; these must be EITHER all
|
||||
in upper-case or all in lower-case. If at all possible, these
|
||||
should be successive letters in your alphabet. Do NOT use digits
|
||||
or control characters. Do not change or translate anything after
|
||||
the vertical line. */
|
||||
N_("ABCDEFGHIJKLMNOPQRST|input|GameMoves");
|
||||
|
||||
|
||||
// Default printable output representations for each map element
|
||||
const char *default_printable_map_val =
|
||||
/* TRANSLATORS: This string is used to display the galaxy map to
|
||||
screen. There must be exactly 11 characters before the ASCII
|
||||
vertical line. The first ("." in English) is used for empty
|
||||
space, the second ("+") for outposts, the third ("*") for stars,
|
||||
the remaining for the eight companies. Do not change or translate
|
||||
anything after the vertical line. */
|
||||
N_(".+*ABCDEFGH|output|MapVals");
|
||||
|
||||
|
||||
// Default printable output representations for each move
|
||||
const char *default_printable_game_move =
|
||||
/* TRANSLATORS: This string is used to display the game moves
|
||||
(choices). There must be exactly 20 characters (NUMBER_MOVES)
|
||||
before the ASCII vertical line. The first character corresponds
|
||||
to the first character in the "input|GameMoves" string, and so on.
|
||||
Do not change or translate anything after the vertical line. */
|
||||
N_("abcdefghijklmnopqrst|output|GameMoves");
|
||||
|
||||
|
||||
// Ordinal strings
|
||||
const char *ordinal[MAX_PLAYERS + 1] = {
|
||||
"0th",
|
||||
"1st",
|
||||
"2nd",
|
||||
"3rd",
|
||||
"4th",
|
||||
"5th",
|
||||
"6th",
|
||||
"7th",
|
||||
"8th"
|
||||
"",
|
||||
/* TRANSLATORS: The ordinal strings "1st" to "8th" are used in the
|
||||
Game Winner dialog box at the end of the game. If ordinals depend
|
||||
on the gender of the player, it may be simpler to list cardinal
|
||||
numbers instead (eg, "No. 1"). Up to five characters are allowed
|
||||
(see ORDINAL_COLS in src/intf.h). */
|
||||
N_("1st"),
|
||||
N_("2nd"),
|
||||
N_("3rd"),
|
||||
N_("4th"),
|
||||
N_("5th"),
|
||||
N_("6th"),
|
||||
N_("7th"),
|
||||
N_("8th")
|
||||
};
|
||||
|
||||
|
||||
|
@ -32,9 +32,6 @@
|
||||
#define included_GLOBALS_H 1
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Game constants *
|
||||
************************************************************************/
|
||||
@ -97,7 +94,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 +105,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,12 +128,6 @@ 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) ((char) (m))
|
||||
|
||||
#define COMPANY_TO_KEY(i) ((i) + 'A')
|
||||
#define KEY_TO_COMPANY(k) ((k) - 'A')
|
||||
#define IS_COMPANY_KEY(k) ((k) >= 'A' && (k) < COMPANY_TO_KEY(MAX_COMPANIES))
|
||||
|
||||
|
||||
// Information about a move
|
||||
typedef struct move_rec {
|
||||
@ -143,10 +135,6 @@ typedef struct move_rec {
|
||||
int y;
|
||||
} move_rec_t;
|
||||
|
||||
#define MOVE_TO_KEY(m) ((m) + 'a')
|
||||
#define KEY_TO_MOVE(k) ((k) - 'a')
|
||||
#define IS_MOVE_KEY(k) ((k) >= 'a' && (k) < MOVE_TO_KEY(NUMBER_MOVES))
|
||||
|
||||
|
||||
// Player moves / selection values
|
||||
typedef enum selection {
|
||||
@ -170,6 +158,18 @@ typedef enum selection {
|
||||
// Company names
|
||||
extern const char *company_name[MAX_COMPANIES];
|
||||
|
||||
// Default keycodes (keyboard input characters) for each company
|
||||
extern const char *default_keycode_company;
|
||||
|
||||
// Default keycodes (keyboard input characters) for each move
|
||||
extern const char *default_keycode_game_move;
|
||||
|
||||
// Default printable output representations for each map element
|
||||
extern const char *default_printable_map_val;
|
||||
|
||||
// Default printable output representations for each move
|
||||
extern const char *default_printable_game_move;
|
||||
|
||||
// Ordinal strings
|
||||
extern const char *ordinal[MAX_PLAYERS + 1];
|
||||
|
||||
|
604
src/help.c
604
src/help.c
@ -35,113 +35,188 @@
|
||||
* Help text definition *
|
||||
************************************************************************/
|
||||
|
||||
static const char *help_text[] = {
|
||||
"^BStar Traders^N is a simple game of interstellar trading. The object of the\n"
|
||||
"game is to amass the greatest amount of wealth possible. This is done by\n"
|
||||
"creating interstellar shipping lanes, expanding them and buying shares in\n"
|
||||
"the companies controlling them. Shares appreciate in value as company\n"
|
||||
"operations expand. In addition, the return on each share (as a percentage)\n"
|
||||
"also changes. Players may also borrow from the Interstellar Trading Bank to\n"
|
||||
"finance additional purchases on the Stock Exchange.\n"
|
||||
"\n"
|
||||
"The map of the galaxy is represented by a ^B~x^N x ^B~y^N grid. A typical section\n"
|
||||
"of it may be:\n"
|
||||
"\n"
|
||||
" ^e . . ^s*^e . . . ^s*^e ^s*^e . ^N\n"
|
||||
" ^e . . . . . . . . . ^N ^e . ^N represents ^Bempty space^N,\n"
|
||||
" ^e . ^s*^e . . . . . . . ^N ^s * ^N represents a ^Bstar^N.\n"
|
||||
" ^e . . . . . . . ^s*^e . ^N\n"
|
||||
" ^e . . . . ^s*^e . . . . ^N\n"
|
||||
,
|
||||
#define HELP_TEXT_PAGES 10
|
||||
|
||||
"The computer selects ^B~m^N moves (labeled ^k~1^N to ^k~M^N) at random, and places these\n"
|
||||
"on the map. To select any of the highlighted positions, press that letter.\n"
|
||||
"As an example, some of the moves on the map may be:\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" ^e ^k~1^e . ^s*^e . . . ^s*^e ^s*^e . ^N\n"
|
||||
" ^e . . . ^k~3^e . . . . . ^N\n"
|
||||
" ^e . ^s*^e . . . . ^k~5^e . . ^N Moves ^k~1^N to ^k~5^N shown.\n"
|
||||
" ^e . ^k~2^e . . ^k~4^e . . ^s*^e . ^N\n"
|
||||
" ^e . . . . ^s*^e . . . . ^N\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Selecting a position that is ^Bnot^N next to a star (such as moves ^k~1^N, ^k~3^N or ^k~5^N)\n"
|
||||
"will set up an ^Boutpost^N, not belonging to any company. Thus, if move ^k~3^N was\n"
|
||||
"selected on the above map, a ^o + ^N would be placed at that position.\n"
|
||||
,
|
||||
static const char *help_text[HELP_TEXT_PAGES] = {
|
||||
|
||||
"If, on the other hand, a position next to a star (or another outpost) is\n"
|
||||
"selected, a ^Bcompany^N would be formed and its first letter would appear on the\n"
|
||||
"map. As a reward for creating the company, you are granted the first five\n"
|
||||
"shares. Up to ^B~c^N companies can be created in this way.\n"
|
||||
"\n"
|
||||
"If a position next to an existing company is selected, the company would\n"
|
||||
"expand its operations by one square. This increases the cost of its shares\n"
|
||||
"and hence your return. Thus, if the map was as shown below, selecting ^k~6^N\n"
|
||||
"or ^k~8^N increases Company ^B~B^N's shipping lane:\n"
|
||||
"\n"
|
||||
" ^e ^k~1^e . ^s*^e . . . ^s*^e ^s*^e . ^N\n"
|
||||
" ^e . . . ^o+^e . . ^k~6^e . . ^N\n"
|
||||
" ^e . ^s*^e . . . . ^c~B^e ^c~B^e ^c~B^e ^N Move ^k~6^N or ^k~8^N increases Company ^B~B^N.\n"
|
||||
" ^e . ^k~2^e . . ^k~4^e . . ^s*^e ^c~B^e ^N\n"
|
||||
" ^e . . . . ^s*^e . . . ^k~8^e ^N\n"
|
||||
,
|
||||
/*
|
||||
TRANSLATORS: The help text for Star Traders is marked up using a
|
||||
custom mark-up format NOT used anywhere else in the source code.
|
||||
|
||||
"Selecting positions next to stars increases the value of your stock by about\n"
|
||||
"five times as much as an extension not next to a star. Thus move ^k~6^N should\n"
|
||||
"be preferred to move ^k~8^N.\n"
|
||||
"\n"
|
||||
" ^e ^c~C^e . ^s*^e . . . ^s*^e ^s*^e . ^N\n"
|
||||
" ^e ^k~1^e ^o+^e . ^o+^e . . ^k~6^e . . ^N\n"
|
||||
" ^e . ^s*^e . . . . ^c~B^e ^c~B^e ^c~B^e ^N Move ^k~6^N is preferred to ^k~8^N.\n"
|
||||
" ^e . ^k~2^e . . ^k~4^e . . ^s*^e ^c~B^e ^N\n"
|
||||
" ^e . . . . ^s*^e . . . ^k~8^e ^N\n"
|
||||
"\n"
|
||||
"You can also expand any company by selecting positions next to outposts.\n"
|
||||
"Such outposts will be swallowed up by that company. Thus, move ^k~1^N will\n"
|
||||
"extend Company ^BC^N by ^Btwo^N squares. As a bonus, outposts next to stars are\n"
|
||||
"more valuable: the company's share price will increase by a greater amount\n"
|
||||
"than it would for outposts not next to stars.\n"
|
||||
,
|
||||
Each string is a single page of text that is displayed in an area 76
|
||||
columns wide by 16 lines high. Each line is delimited by "\n". NO
|
||||
word-wrapping is performed: you must place the "\n" characters in the
|
||||
appropriate place. Ideally, each line within the string should be
|
||||
also (manually) space-justified or centred. TAB characters and other
|
||||
control codes must NOT be used. If a string starts with "@" as the
|
||||
very first character, that string is ignored (as are all strings
|
||||
following): this allows a variable number of help text pages (from
|
||||
one to ten). Multibyte strings are handled correctly (even those
|
||||
requiring shift sequences!).
|
||||
|
||||
"If two companies are separated on the map by only one square, then they can\n"
|
||||
"be ^Bmerged^N into one company by selecting that position (if available). For\n"
|
||||
"example, on the map below, companies ^B~A^N and ^B~B^N can be merged by selecting ^k~5^N.\n"
|
||||
"When this occurs, the company with the greater assets value takes over the\n"
|
||||
"other one. Here, Company ^B~B^N might take over Company ^B~A^N. Company ^B~A^N ceases to\n"
|
||||
"exist, although it may reappear as an entirely new company at a later stage.\n"
|
||||
"\n"
|
||||
" ^e ^k~1^e . ^s*^e . . . ^s*^e ^s*^e . ^N\n"
|
||||
" ^e . . . ^c~A^e ^c~A^e ^k~5^e ^c~B^e . . ^N\n"
|
||||
" ^e . ^s*^e . . ^c~A^e . ^c~B^e ^c~B^e ^c~B^e ^N Move ^k~5^N merges companies ^B~A^N and ^B~B^N.\n"
|
||||
" ^e . ^k~2^e . . . . . ^s*^e ^c~B^e ^N\n"
|
||||
" ^e . . . . ^s*^e . ^o+^e . . ^N\n"
|
||||
"\n"
|
||||
"When companies merge, players are granted shares in the dominant company\n"
|
||||
"proportional to the amount owned in the old company. As well, a cash bonus\n"
|
||||
"is also paid, proportional to the percentage of the old company owned.\n"
|
||||
,
|
||||
The ASCII circumflex accent character "^" switches to a different
|
||||
character rendition (also called attributes), depending on the
|
||||
character following the "^":
|
||||
|
||||
"Once you select your move, you enter the ^BInterstellar Stock Exchange^N. Here\n"
|
||||
"you can purchase shares, sell them, borrow from the Trading Bank or repay\n"
|
||||
"some of your debt (if applicable). Note that each company issues a limited\n"
|
||||
"number of shares --- you cannot go on buying for ever! You can, however,\n"
|
||||
"bid for more shares to be issued. You have a better chance of succeeding if\n"
|
||||
"you own a larger proportion of the company.\n"
|
||||
"\n"
|
||||
"The game usually ends after ^B~t^N turns. However, you can end the game sooner\n"
|
||||
"by pressing ^K<CTRL><C>^N when asked to select a move. As well, individual\n"
|
||||
"players can declare themselves bankrupt at any time. If your debt is large\n"
|
||||
"enough, the Bank may do this for you! If you do not complete your game in\n"
|
||||
"the time you have available, you may save the game and continue it later.\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The ^Bwinner of the game^N is the person with the greatest net worth (total\n"
|
||||
"value of cash, stock and debt). ^HGood luck^N and may the best person win!\n"
|
||||
,
|
||||
^^ - Print the circumflex accent (ASCII code U+005E)
|
||||
^N - Switch to using the normal character rendition
|
||||
^B - Switch to using the bold character rendition
|
||||
^H - Switch to using the highlight character rendition
|
||||
^K - Switch to using the keycode character rendition (such as used for "<CTRL><C>")
|
||||
^e - Switch to using the character rendition used for empty space
|
||||
^o - Switch to using the character rendition used for outposts
|
||||
^s - Switch to using the character rendition used for stars
|
||||
^c - Switch to using the character rendition used for companies
|
||||
^k - Switch to using the character rendition used for keyboard choices on the galaxy map
|
||||
|
||||
NULL
|
||||
The help text parsing routines also understand the following "value
|
||||
escapes" introduced by the ASCII tilde character "~"; these act like
|
||||
"%" conversion specifiers in printf():
|
||||
|
||||
~~ - Print the tilde character (ASCII code U+007E) [*]
|
||||
~x - Print the width of the galaxy map (MAX_X) [**]
|
||||
~y - Print the height of the galaxy map (MAX_Y) [**]
|
||||
~m - Print the number of moves available (NUMBER_MOVES) [**]
|
||||
~c - Print the maximum number of companies that can be formed (MAX_COMPANIES) [*]
|
||||
~t - Prints the default number of turns in the game (DEFAULT_MAX_TURN) [**]
|
||||
~1 to ~9 - Print the keycode for the N-th choice of move [***]
|
||||
~M - Print the keycode for the last choice of move [***]
|
||||
~A to ~H - Print the character used to represent the company on the galaxy map [***]
|
||||
~. - Print the character used to represent empty space on the map [***]
|
||||
~+ - Print the character used to represent outposts on the map [***]
|
||||
~* - Print the character used to represent stars on the map [***]
|
||||
|
||||
[*] Takes one character space (column space) in the output
|
||||
[**] Takes two column spaces in the output
|
||||
[***] Takes one or two column spaces in the output, depending on the
|
||||
appropriate strings in the current PO file.
|
||||
|
||||
Note that all keycodes and map representation characters use locale-
|
||||
specific characters; double-width characters ARE supported. Note
|
||||
also that the tilde value escapes do NOT change the current character
|
||||
rendition: a circumflex accent escape is needed for that. For
|
||||
example, to display the first choice of move as it would be shown on
|
||||
the galaxy map, use something like "^k~1^N" (a six-character sequence
|
||||
that would translate to just one character (or maybe two) in the
|
||||
output text).
|
||||
*/
|
||||
N_( ""
|
||||
"^BStar Traders^N is a simple game of interstellar trading. The object of the\n"
|
||||
"game is to amass the greatest amount of wealth possible. This is done by\n"
|
||||
"creating interstellar shipping lanes, expanding them and buying shares in\n"
|
||||
"the companies controlling them. Shares appreciate in value as company\n"
|
||||
"operations expand. In addition, the return on each share (as a percentage)\n"
|
||||
"also changes. Players may also borrow from the Interstellar Trading Bank to\n"
|
||||
"finance additional purchases on the Stock Exchange.\n"
|
||||
"\n"
|
||||
"The map of the galaxy is represented by a ^B~x^N x ^B~y^N grid. A typical section\n"
|
||||
"of it may be:\n"
|
||||
"\n"
|
||||
" ^e ~. ~. ^s~*^e ~. ~. ~. ^s~*^e ^s~*^e ~. ^N\n"
|
||||
" ^e ~. ~. ~. ~. ~. ~. ~. ~. ~. ^N ^e ~. ^N represents ^Bempty space^N,\n"
|
||||
" ^e ~. ^s~*^e ~. ~. ~. ~. ~. ~. ~. ^N ^s ~* ^N represents a ^Bstar^N.\n"
|
||||
" ^e ~. ~. ~. ~. ~. ~. ~. ^s~*^e ~. ^N\n"
|
||||
" ^e ~. ~. ~. ~. ^s~*^e ~. ~. ~. ~. ^N\n"
|
||||
""),
|
||||
|
||||
N_( ""
|
||||
"The computer selects ^B~m^N moves (labeled ^k~1^N to ^k~M^N) at random, and places these\n"
|
||||
"on the map. To select any of the highlighted positions, press that letter.\n"
|
||||
"For example, some of the moves on the map may be:\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" ^e ^k~1^e ~. ^s~*^e ~. ~. ~. ^s~*^e ^s~*^e ~. ^N\n"
|
||||
" ^e ~. ~. ~. ^k~3^e ~. ~. ~. ~. ~. ^N\n"
|
||||
" ^e ~. ^s~*^e ~. ~. ~. ~. ^k~5^e ~. ~. ^N Moves ^k~1^N to ^k~5^N shown.\n"
|
||||
" ^e ~. ^k~2^e ~. ~. ^k~4^e ~. ~. ^s~*^e ~. ^N\n"
|
||||
" ^e ~. ~. ~. ~. ^s~*^e ~. ~. ~. ~. ^N\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Selecting a position that is ^Bnot^N next to a star (such as moves ^k~1^N, ^k~3^N or ^k~5^N)\n"
|
||||
"will set up an ^Boutpost^N, not belonging to any company. Thus, if move ^k~3^N is\n"
|
||||
"selected on the above map, a ^o ~+ ^N would be placed at that position.\n"
|
||||
""),
|
||||
|
||||
N_( ""
|
||||
"If, on the other hand, a position next to a star (or another outpost) is\n"
|
||||
"selected, a ^Bcompany^N would be formed and its letter would appear on the map.\n"
|
||||
"As a reward for creating the company, you are granted the first five shares.\n"
|
||||
"Up to ^B~c^N companies can be created in this way.\n"
|
||||
"\n"
|
||||
"If a position next to an existing company is selected, the company would\n"
|
||||
"expand its operations by one square. This increases the cost of its shares\n"
|
||||
"and hence your return. Thus, if the map was as shown below, selecting ^k~6^N\n"
|
||||
"or ^k~8^N increases Company ^B~B^N's shipping lane:\n"
|
||||
"\n"
|
||||
" ^e ^k~1^e ~. ^s~*^e ~. ~. ~. ^s~*^e ^s~*^e ~. ^N\n"
|
||||
" ^e ~. ~. ~. ^o~+^e ~. ~. ^k~6^e ~. ~. ^N\n"
|
||||
" ^e ~. ^s~*^e ~. ~. ~. ~. ^c~B^e ^c~B^e ^c~B^e ^N Move ^k~6^N or ^k~8^N increases Company ^B~B^N.\n"
|
||||
" ^e ~. ^k~2^e ~. ~. ^k~4^e ~. ~. ^s~*^e ^c~B^e ^N\n"
|
||||
" ^e ~. ~. ~. ~. ^s~*^e ~. ~. ~. ^k~8^e ^N\n"
|
||||
""),
|
||||
|
||||
N_( ""
|
||||
"Selecting positions next to stars increases the value of your stock by about\n"
|
||||
"five times as much as an extension not next to a star. Thus move ^k~6^N should\n"
|
||||
"be preferred to move ^k~8^N.\n"
|
||||
"\n"
|
||||
" ^e ^c~C^e ~. ^s~*^e ~. ~. ~. ^s~*^e ^s~*^e ~. ^N\n"
|
||||
" ^e ^k~1^e ^o~+^e ~. ^o~+^e ~. ~. ^k~6^e ~. ~. ^N\n"
|
||||
" ^e ~. ^s~*^e ~. ~. ~. ~. ^c~B^e ^c~B^e ^c~B^e ^N Move ^k~6^N is preferred to ^k~8^N.\n"
|
||||
" ^e ~. ^k~2^e ~. ~. ^k~4^e ~. ~. ^s~*^e ^c~B^e ^N\n"
|
||||
" ^e ~. ~. ~. ~. ^s~*^e ~. ~. ~. ^k~8^e ^N\n"
|
||||
"\n"
|
||||
"You may also expand any company by selecting positions next to outposts.\n"
|
||||
"Such outposts will be swallowed up by that company. Thus, move ^k~1^N will\n"
|
||||
"extend Company ^B~C^N by ^Btwo^N squares. As a bonus, outposts next to stars are\n"
|
||||
"more valuable: the company's share price will increase by a greater amount\n"
|
||||
"than it would for outposts not next to stars.\n"
|
||||
""),
|
||||
|
||||
N_( ""
|
||||
"If two companies are separated on the map by only one square, then they can\n"
|
||||
"be ^Bmerged^N into one company by selecting that position (if available). For\n"
|
||||
"example, on the map below, companies ^B~A^N and ^B~B^N can be merged by selecting ^k~5^N.\n"
|
||||
"When this occurs, the company with the greater assets value takes over the\n"
|
||||
"other one. Here, Company ^B~B^N might take over Company ^B~A^N. Company ^B~A^N ceases to\n"
|
||||
"exist, although it may reappear as an entirely new company at a later stage.\n"
|
||||
"\n"
|
||||
" ^e ^k~1^e ~. ^s~*^e ~. ~. ~. ^s~*^e ^s~*^e ~. ^N\n"
|
||||
" ^e ~. ~. ~. ^c~A^e ^c~A^e ^k~5^e ^c~B^e ~. ~. ^N\n"
|
||||
" ^e ~. ^s~*^e ~. ~. ^c~A^e ~. ^c~B^e ^c~B^e ^c~B^e ^N Move ^k~5^N merges companies ^B~A^N and ^B~B^N.\n"
|
||||
" ^e ~. ^k~2^e ~. ~. ~. ~. ~. ^s~*^e ^c~B^e ^N\n"
|
||||
" ^e ~. ~. ~. ~. ^s~*^e ~. ^o~+^e ~. ~. ^N\n"
|
||||
"\n"
|
||||
"When companies merge, players are granted shares in the dominant company\n"
|
||||
"proportional to the amount owned in the old company. As well, a cash bonus\n"
|
||||
"is also paid, proportional to the percentage of the old company owned.\n"
|
||||
""),
|
||||
|
||||
N_( ""
|
||||
"Once you select your move, you enter the ^BInterstellar Stock Exchange^N. Here\n"
|
||||
"you may purchase shares, sell them, borrow from the Trading Bank or repay\n"
|
||||
"some of your debt (if applicable). Note that each company issues a limited\n"
|
||||
"number of shares -- you cannot go on buying for ever! You may, however, bid\n"
|
||||
"for more shares to be issued. You have a better chance of succeeding if you\n"
|
||||
"own a larger proportion of the company.\n"
|
||||
"\n"
|
||||
"The game usually ends after ^B~t^N turns. However, you may end the game sooner\n"
|
||||
"by pressing ^K<CTRL><C>^N when asked to select a move. As well, individual\n"
|
||||
"players can declare themselves bankrupt at any time. If your debt is large\n"
|
||||
"enough, the Bank may do this for you! If you do not complete your game in\n"
|
||||
"the time you have available, you may save the game and continue it later.\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The ^Bwinner of the game^N is the person with the greatest net worth (total\n"
|
||||
"value of cash, stock and debt). ^HGood luck^N and may the best person win!\n"
|
||||
"")
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
, N_("@ Help text, page 7")
|
||||
, N_("@ Help text, page 8")
|
||||
, N_("@ Help text, page 9")
|
||||
, N_("@ Help text, page 10")
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -157,210 +232,299 @@ static const char *help_text[] = {
|
||||
|
||||
void show_help (void)
|
||||
{
|
||||
wchar_t *wchelp_text[HELP_TEXT_PAGES];
|
||||
wchar_t *wcbuf = xmalloc(BIGBUFSIZE * sizeof(wchar_t));
|
||||
chtype *outbuf = xmalloc(BIGBUFSIZE * sizeof(chtype));
|
||||
|
||||
int curpage = 0;
|
||||
int numpages;
|
||||
int numpages = 0;
|
||||
bool done = false;
|
||||
|
||||
|
||||
// Count how many pages appear in the help text
|
||||
for (numpages = 0; help_text[numpages] != NULL; numpages++)
|
||||
;
|
||||
// Count how many pages appear in the (translated) help text
|
||||
while (numpages < HELP_TEXT_PAGES) {
|
||||
const char *s = gettext(help_text[numpages]);
|
||||
if (s == NULL || *s == '\0' || *s == '@')
|
||||
break;
|
||||
|
||||
if (numpages == 0)
|
||||
xmbstowcs(wcbuf, s, BIGBUFSIZE);
|
||||
wchelp_text[numpages] = xwcsdup(wcbuf);
|
||||
numpages++;
|
||||
}
|
||||
|
||||
if (numpages == 0) {
|
||||
free(outbuf);
|
||||
free(wcbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
newtxwin(WIN_LINES - 1, WIN_COLS, 1, WCENTER, false, 0);
|
||||
|
||||
while (! done) {
|
||||
// Display a page of instructions
|
||||
|
||||
wbkgdset(curwin, attr_normal_window);
|
||||
werase(curwin);
|
||||
wbkgd(curwin, attr_normal_window);
|
||||
box(curwin, 0, 0);
|
||||
center(curwin, 1, attr_title, " How to Play ");
|
||||
center(curwin, 2, attr_normal, "Page %d of %d", curpage + 1, numpages);
|
||||
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1, _(" How to Play "));
|
||||
center(curwin, 2, 0, attr_normal, attr_highlight, 0, 1,
|
||||
_("Page %d of %d"), curpage + 1, numpages);
|
||||
wmove(curwin, 4, 2);
|
||||
|
||||
// Process the help text string
|
||||
|
||||
const char *s = help_text[curpage];
|
||||
const wchar_t *htxt = wchelp_text[curpage];
|
||||
char convbuf[MB_LEN_MAX + 1];
|
||||
char *cp;
|
||||
mbstate_t mbstate;
|
||||
chtype *outp;
|
||||
size_t i, n;
|
||||
|
||||
int count = BIGBUFSIZE;
|
||||
int maxchar = MB_CUR_MAX;
|
||||
int curattr = attr_normal;
|
||||
|
||||
while (*s != '\0') {
|
||||
switch (*s) {
|
||||
case '\n':
|
||||
// Start a new line, suitably indented
|
||||
wmove(curwin, getcury(curwin) + 1, 2);
|
||||
memset(&mbstate, 0, sizeof(mbstate));
|
||||
outp = outbuf;
|
||||
|
||||
while (*htxt != L'\0' && count > maxchar * 2) {
|
||||
switch (*htxt) {
|
||||
case L'\n':
|
||||
// Start a new line
|
||||
*outp++ = '\n';
|
||||
count--;
|
||||
break;
|
||||
|
||||
case '^':
|
||||
// Set the current attribute
|
||||
switch (*++s) {
|
||||
case '^':
|
||||
waddch(curwin, *s | curattr);
|
||||
break;
|
||||
case L'^':
|
||||
// Switch to a different character rendition
|
||||
switch (*++htxt) {
|
||||
case L'^':
|
||||
wcbuf[0] = *htxt;
|
||||
wcbuf[1] = L'\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case 'N':
|
||||
case L'N':
|
||||
curattr = attr_normal;
|
||||
wattrset(curwin, curattr);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
case L'B':
|
||||
curattr = attr_normal | A_BOLD;
|
||||
wattrset(curwin, curattr);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
case L'H':
|
||||
curattr = attr_highlight;
|
||||
wattrset(curwin, curattr);
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
case L'K':
|
||||
curattr = attr_keycode;
|
||||
wattrset(curwin, curattr);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
case L'e':
|
||||
curattr = attr_map_empty;
|
||||
wattrset(curwin, curattr);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
case L'o':
|
||||
curattr = attr_map_outpost;
|
||||
wattrset(curwin, curattr);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case L's':
|
||||
curattr = attr_map_star;
|
||||
wattrset(curwin, curattr);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case L'c':
|
||||
curattr = attr_map_company;
|
||||
wattrset(curwin, curattr);
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
case L'k':
|
||||
curattr = attr_map_choice;
|
||||
wattrset(curwin, curattr);
|
||||
break;
|
||||
|
||||
default:
|
||||
waddch(curwin, '^' | curattr);
|
||||
waddch(curwin, *s | curattr);
|
||||
wcbuf[0] = L'^';
|
||||
wcbuf[1] = *htxt;
|
||||
wcbuf[2] = L'\0';
|
||||
goto addwcbuf;
|
||||
}
|
||||
break;
|
||||
|
||||
case '~':
|
||||
case L'~':
|
||||
// Print a global constant
|
||||
switch (*++s) {
|
||||
case '~':
|
||||
waddch(curwin, *s | curattr);
|
||||
break;
|
||||
switch (*++htxt) {
|
||||
case L'~':
|
||||
wcbuf[0] = *htxt;
|
||||
wcbuf[1] = L'\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case 'x':
|
||||
wprintw(curwin, "%2d", MAX_X);
|
||||
break;
|
||||
case L'x':
|
||||
swprintf(wcbuf, BIGBUFSIZE, L"%2d", MAX_X);
|
||||
goto addwcbuf;
|
||||
|
||||
case 'y':
|
||||
wprintw(curwin, "%2d", MAX_Y);
|
||||
break;
|
||||
case L'y':
|
||||
swprintf(wcbuf, BIGBUFSIZE, L"%2d", MAX_Y);
|
||||
goto addwcbuf;
|
||||
|
||||
case 'm':
|
||||
wprintw(curwin, "%2d", NUMBER_MOVES);
|
||||
break;
|
||||
case L'm':
|
||||
swprintf(wcbuf, BIGBUFSIZE, L"%2d", NUMBER_MOVES);
|
||||
goto addwcbuf;
|
||||
|
||||
case 'c':
|
||||
wprintw(curwin, "%d", MAX_COMPANIES);
|
||||
break;
|
||||
case L'c':
|
||||
swprintf(wcbuf, BIGBUFSIZE, L"%d", MAX_COMPANIES);
|
||||
goto addwcbuf;
|
||||
|
||||
case 't':
|
||||
wprintw(curwin, "%2d", DEFAULT_MAX_TURN);
|
||||
break;
|
||||
case L't':
|
||||
swprintf(wcbuf, BIGBUFSIZE, L"%2d", DEFAULT_MAX_TURN);
|
||||
goto addwcbuf;
|
||||
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case L'1':
|
||||
case L'2':
|
||||
case L'3':
|
||||
case L'4':
|
||||
case L'5':
|
||||
case L'6':
|
||||
case L'7':
|
||||
case L'8':
|
||||
case L'9':
|
||||
// N-th choice of move, as a key press
|
||||
wprintw(curwin, "%c", MOVE_TO_KEY(*s - '1'));
|
||||
break;
|
||||
wcbuf[0] = PRINTABLE_GAME_MOVE(*htxt - L'1');
|
||||
wcbuf[1] = L'\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case 'M':
|
||||
case L'M':
|
||||
// Last choice of move, as a key press
|
||||
wprintw(curwin, "%c", MOVE_TO_KEY(NUMBER_MOVES - 1));
|
||||
break;
|
||||
wcbuf[0] = PRINTABLE_GAME_MOVE(NUMBER_MOVES - 1);
|
||||
wcbuf[1] = L'\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case L'.':
|
||||
// Map representation of empty space
|
||||
wcbuf[0] = PRINTABLE_MAP_VAL(MAP_EMPTY);
|
||||
wcbuf[1] = L'\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case L'+':
|
||||
// Map representation of an outpost
|
||||
wcbuf[0] = PRINTABLE_MAP_VAL(MAP_OUTPOST);
|
||||
wcbuf[1] = L'\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case L'*':
|
||||
// Map representation of a star
|
||||
wcbuf[0] = PRINTABLE_MAP_VAL(MAP_STAR);
|
||||
wcbuf[1] = L'\0';
|
||||
goto addwcbuf;
|
||||
|
||||
case L'A':
|
||||
case L'B':
|
||||
case L'C':
|
||||
case L'D':
|
||||
case L'E':
|
||||
case L'F':
|
||||
case L'G':
|
||||
case L'H':
|
||||
// Map representation of company
|
||||
wprintw(curwin, "%c",
|
||||
PRINTABLE_MAP_VAL(COMPANY_TO_MAP(*s - 'A')));
|
||||
break;
|
||||
assert((*htxt - L'A') < MAX_COMPANIES);
|
||||
wcbuf[0] = PRINTABLE_MAP_VAL(COMPANY_TO_MAP(*htxt - L'A'));
|
||||
wcbuf[1] = L'\0';
|
||||
goto addwcbuf;
|
||||
|
||||
default:
|
||||
waddch(curwin, '~' | curattr);
|
||||
waddch(curwin, *s | curattr);
|
||||
wcbuf[0] = L'~';
|
||||
wcbuf[1] = *htxt;
|
||||
wcbuf[2] = L'\0';
|
||||
goto addwcbuf;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Print the character
|
||||
waddch(curwin, *s | curattr);
|
||||
wcbuf[0] = *htxt;
|
||||
wcbuf[1] = L'\0';
|
||||
|
||||
addwcbuf:
|
||||
for (wchar_t *p = wcbuf; *p != L'\0' && count > maxchar * 2; p++) {
|
||||
n = xwcrtomb(convbuf, *p, &mbstate);
|
||||
for (i = 0, cp = convbuf; i < n; i++, cp++, outp++, count--) {
|
||||
*outp = (unsigned char) *cp | curattr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s++;
|
||||
htxt++;
|
||||
}
|
||||
|
||||
center(curwin, 21, attr_waitforkey, (curpage == 0) ?
|
||||
"[ Press <SPACE> to continue ] " :
|
||||
"[ Press <SPACE> to continue or <BACKSPACE> for the previous page ] ");
|
||||
// Add the terminating NUL (possibly with a preceding shift sequence)
|
||||
n = xwcrtomb(convbuf, L'\0', &mbstate);
|
||||
for (i = 0, cp = convbuf; i < n; i++, cp++, outp++, count--) {
|
||||
*outp = (unsigned char) *cp;
|
||||
}
|
||||
assert(count >= 0);
|
||||
|
||||
// Display the formatted text in outbuf
|
||||
for (outp = outbuf; *outp != 0; outp++) {
|
||||
if (*outp == '\n') {
|
||||
wmove(curwin, getcury(curwin) + 1, 2);
|
||||
} else {
|
||||
waddch(curwin, *outp);
|
||||
}
|
||||
}
|
||||
|
||||
center(curwin, getmaxy(curwin) - 2, 0, attr_waitforkey, 0, 0, 1,
|
||||
(curpage == 0) ? _("[ Press <SPACE> to continue ] ") :
|
||||
/* TRANSLATORS: The specific use of <SPACE> and
|
||||
<BACKSPACE> is not essential: you can use <DEL>,
|
||||
<PAGE-UP>, <UP>, <LEFT> or <BACK-TAB> instead of
|
||||
<BACKSPACE>, and almost any other key instead of
|
||||
<SPACE> (other than <ESC>, <CANCEL>, <EXIT>, <CTRL><C>,
|
||||
<CTRL><G> or <CTRL><\>). */
|
||||
_("[ Press <SPACE> to continue or <BACKSPACE> "
|
||||
"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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deltxwin();
|
||||
txrefresh();
|
||||
|
||||
for (curpage = 0; curpage < numpages; curpage++) {
|
||||
free(wchelp_text[curpage]);
|
||||
}
|
||||
free(outbuf);
|
||||
free(wcbuf);
|
||||
}
|
||||
|
@ -42,8 +42,9 @@
|
||||
Returns: (nothing)
|
||||
|
||||
This function displays instructions on how to play Star Traders in a
|
||||
Curses window. It does not depend on any global game variable. On
|
||||
exit, the previous screen is restored and refreshed.
|
||||
Curses window. It does not depend on any global game variables other
|
||||
than printable_map_val[] and printable_game_move[]. On exit, the
|
||||
previous screen is restored and refreshed.
|
||||
*/
|
||||
extern void show_help (void);
|
||||
|
||||
|
2739
src/intf.c
2739
src/intf.c
File diff suppressed because it is too large
Load Diff
520
src/intf.h
520
src/intf.h
@ -33,9 +33,6 @@
|
||||
#define included_INTF_H 1
|
||||
|
||||
|
||||
#include "system.h"
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Constants and type declarations *
|
||||
************************************************************************/
|
||||
@ -43,18 +40,45 @@
|
||||
/*
|
||||
This version of Star Traders only utilises WIN_COLS x WIN_LINES of a
|
||||
terminal screen; this terminal must be at least MIN_COLS x MIN_LINES in
|
||||
size; the newtxwin() function automatically places a new window in the
|
||||
centre-top of the terminal screen. The program does not yet handle
|
||||
terminal resizing events.
|
||||
size. Windows are placed in the centre-top of the terminal screen.
|
||||
*/
|
||||
|
||||
#define MIN_LINES 24 // Minimum number of lines in terminal
|
||||
#define MIN_COLS 80 // Minimum number of columns in terminal
|
||||
|
||||
#define WIN_LINES MIN_LINES // Number of lines in main window
|
||||
#define WIN_COLS MIN_COLS // Number of columns in main window
|
||||
#define WIN_LINES MIN_LINES // Number of lines used in main window
|
||||
#define WIN_COLS MIN_COLS // Number of columns used in main window
|
||||
|
||||
#define WCENTER -1 // Centre the new window
|
||||
#define WCENTER -1 // Centre the new window
|
||||
|
||||
#define MAX_DLG_LINES 10 // Default maximum lines of text in dialog box
|
||||
|
||||
// Space (number of terminal columns) to allow for various fields
|
||||
#define YESNO_COLS 4 // Space to allow for "Yes" or "No" response
|
||||
#define ORDINAL_COLS 5 // Space for ordinals (1st, 2nd, etc)
|
||||
#define TOTAL_VALUE_COLS 18 // Space for total value (monetary)
|
||||
#define SHARE_PRICE_COLS 12 // Space for "Price per share"
|
||||
#define SHARE_RETURN_COLS 10 // Space for "Return per share"
|
||||
#define STOCK_OWNED_COLS 10 // Space for "Holdings (shares)"
|
||||
#define OWNERSHIP_COLS 10 // Space for "Company ownership (%)"
|
||||
#define STOCK_ISSUED_COLS 10 // Space for "Shares issued"
|
||||
#define STOCK_LEFT_COLS 10 // Space for "Shares left"
|
||||
#define BANK_VALUE_COLS 18 // Space for amounts in bank window
|
||||
#define BANK_INPUT_COLS 16 // Space for input text box in bank
|
||||
#define TRADE_VALUE_COLS 16 // Space for amounts in trade window
|
||||
#define TRADE_INPUT_COLS 10 // Space for input text box in trade window
|
||||
#define MERGE_BONUS_COLS 12 // Space for "Bonus" (company merger)
|
||||
#define MERGE_OLD_STOCK_COLS 8 // Space for "Old stocks" (company merger)
|
||||
#define MERGE_NEW_STOCK_COLS 8 // Space for "New stocks" (company merger)
|
||||
#define MERGE_TOTAL_STOCK_COLS 8 // Space for "Total stocks" (company merger)
|
||||
|
||||
|
||||
// Check if resizing events are supported
|
||||
#ifdef KEY_RESIZE
|
||||
# define HANDLE_RESIZE_EVENTS 1
|
||||
#else
|
||||
# undef HANDLE_RESIZE_EVENTS
|
||||
#endif
|
||||
|
||||
|
||||
// Visibility of the cursor in Curses (for curs_set())
|
||||
@ -77,13 +101,11 @@ typedef enum curs_type {
|
||||
|
||||
#define KEY_CTRL(x) ((x) - 0100) // ASCII control character
|
||||
|
||||
#define KEY_ILLEGAL 077777 // No key should ever return this!
|
||||
|
||||
// Keycodes for inserting the default value in input routines
|
||||
#define KEY_DEFAULTVAL1 '='
|
||||
#define KEY_DEFAULTVAL2 ';'
|
||||
#define CHAR_DEFVAL1 L'='
|
||||
#define CHAR_DEFVAL2 L';'
|
||||
|
||||
// Control-arrow key combinations, as returned by NCurses
|
||||
// Control-arrow key combinations, as returned by Ncurses
|
||||
#ifndef KEY_CDOWN
|
||||
# define KEY_CDOWN 01007 // CTRL + Down Arrow
|
||||
# define KEY_CUP 01060 // CTRL + Up Arrow
|
||||
@ -91,15 +113,9 @@ typedef enum curs_type {
|
||||
# define KEY_CRIGHT 01052 // CTRL + Right Arrow
|
||||
#endif
|
||||
|
||||
// Keycodes only defined by NCurses
|
||||
#ifndef KEY_RESIZE
|
||||
# define KEY_RESIZE KEY_ILLEGAL
|
||||
#endif
|
||||
#ifndef KEY_EVENT
|
||||
# define KEY_EVENT KEY_ILLEGAL
|
||||
#endif
|
||||
#ifndef KEY_MOUSE
|
||||
# define KEY_MOUSE KEY_ILLEGAL
|
||||
// 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
|
||||
@ -115,6 +131,7 @@ typedef enum curs_type {
|
||||
************************************************************************/
|
||||
|
||||
extern WINDOW *curwin; // Top-most (current) window
|
||||
extern bool use_color; // True to use colour
|
||||
|
||||
|
||||
// Character renditions (attributes) used by Star Traders
|
||||
@ -152,6 +169,36 @@ extern chtype attr_error_highlight; // Error window highlighted string
|
||||
extern chtype attr_error_waitforkey; // "Press any key", error window
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Game printing macros and global variable declarations *
|
||||
************************************************************************/
|
||||
|
||||
// Macros and variables for printing the galaxy map
|
||||
|
||||
#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)]
|
||||
|
||||
extern wchar_t *keycode_company; // Keycodes for each company
|
||||
extern wchar_t *printable_map_val; // Printable output for each map value
|
||||
extern chtype *chtype_map_val[MAX_COMPANIES + 3]; // as chtype strings
|
||||
|
||||
|
||||
// Macros and variables for printing the current game moves
|
||||
|
||||
#define PRINTABLE_GAME_MOVE(m) (printable_game_move[m])
|
||||
#define CHTYPE_GAME_MOVE(m) (chtype_game_move[m])
|
||||
|
||||
extern wchar_t *keycode_game_move; // Keycodes for each game move
|
||||
extern wchar_t *printable_game_move; // Printable output for each game move
|
||||
extern chtype *chtype_game_move[NUMBER_MOVES]; // as chtype strings
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Basic text input/output function prototypes *
|
||||
************************************************************************/
|
||||
@ -191,10 +238,10 @@ extern void end_screen (void);
|
||||
Function: newtxwin - Create a new window, inserted into window stack
|
||||
Parameters: nlines - Number of lines in new window
|
||||
ncols - Number of columns in new window
|
||||
begin_y - Starting line number (0 to LINES-1)
|
||||
begin_x - Starting column number (0 to COLS-1)
|
||||
begin_y - Starting line number (0 to LINES-1) or WCENTER
|
||||
begin_x - Starting column number (0 to COLS-1) or WCENTER
|
||||
dofill - True to draw background and box frame
|
||||
bkgd_attr - Background attribute
|
||||
bkgd_attr - Background character rendition
|
||||
Returns: WINDOW * - Pointer to new window
|
||||
|
||||
This function creates a window using the Curses newwin() function and
|
||||
@ -261,124 +308,284 @@ extern int txrefresh (void);
|
||||
|
||||
|
||||
/*
|
||||
Function: attrpr - Print a string with a particular character rendition
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
attr - Character rendition to use for the string
|
||||
format - printf()-like format string
|
||||
... - printf()-like arguments
|
||||
Returns: int - Return code from wprintw(): OK or ERR
|
||||
Function: txdlgbox - Display a dialog box and wait for any key
|
||||
Parameters: maxlines - Maximum number of lines of text in window
|
||||
ncols - Number of columns in dialog box window
|
||||
begin_y - Starting line number (0 to LINES-1) or WCENTER
|
||||
begin_x - Starting column number (0 to COLS-1) or WCENTER
|
||||
bkgd_attr - Background character rendition
|
||||
title_attr - Character rendition to use for dialog box title
|
||||
norm_attr - Normal character rendition in box
|
||||
alt1_attr - Alternate character rendition 1 (highlight)
|
||||
alt2_attr - Alternate character rendition 2 (more highlighted)
|
||||
keywait_attr - "Press any key" character rendition
|
||||
boxtitle - Dialog box title (may be NULL)
|
||||
format - Dialog box text, as passed to mkchstr()
|
||||
... - Dialog box text format parameters
|
||||
Returns: int - OK is always returned
|
||||
|
||||
This function sets the character rendition (attributes) to attr, prints
|
||||
the string using wprintw(), then restores the previous character
|
||||
rendition. The return code is as returned from wprintw(). Note that
|
||||
wrefresh() is NOT called.
|
||||
This function creates a dialog box window using newtxwin(), displays
|
||||
boxtitle centred on the first line (if boxtitle is not NULL), displays
|
||||
format (and associated parameters) centred using mkchstr(), then waits
|
||||
for the user to press any key before closing the dialog box window.
|
||||
Note that txrefresh() is NOT called once the window is closed.
|
||||
*/
|
||||
extern int attrpr (WINDOW *win, chtype attr, const char *restrict format, ...)
|
||||
__attribute__((format (printf, 3, 4)));
|
||||
extern int txdlgbox (int maxlines, int ncols, int begin_y, int begin_x,
|
||||
chtype bkgd_attr, chtype title_attr, chtype norm_attr,
|
||||
chtype alt1_attr, chtype alt2_attr, chtype keywait_attr,
|
||||
const char *restrict boxtitle,
|
||||
const char *restrict format, ...);
|
||||
|
||||
|
||||
/*
|
||||
Function: center - Centre a string in a given window
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
y - Line on which to centre the string
|
||||
attr - Character rendition to use for the string
|
||||
format - printf()-like format string
|
||||
... - printf()-like arguments
|
||||
Returns: int - Return code from wprintw(): OK or ERR
|
||||
Function: mkchstr - Prepare a string for printing to screen
|
||||
Parameters: chbuf - Pointer to chtype buffer in which to store string
|
||||
chbufsize - Number of chtype elements in chbuf
|
||||
attr_norm - Normal character rendition to use
|
||||
attr_alt1 - First alternate character rendition to use
|
||||
attr_alt2 - Second alternate character rendition to use
|
||||
maxlines - Maximum number of screen lines to use
|
||||
maxwidth - Maximum width of each line, in chars
|
||||
widthbuf - Pointer to buffer to store widths of each line
|
||||
widthbufsize - Number of int elements in widthbuf
|
||||
format - Format string as described below
|
||||
... - Arguments for the format string
|
||||
Returns: int - Number of lines actually used
|
||||
|
||||
This function prints a string formatted with wprintw() in the centre of
|
||||
line y in the window win, using the character rendition (attributes) in
|
||||
attr. If the string is too long to fit the window, it is truncated.
|
||||
Please note that wrefresh() is NOT called.
|
||||
This function converts the format string and following arguments into
|
||||
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,
|
||||
lines are wrapped as needed.
|
||||
|
||||
At the current time, the implementation of this function does NOT
|
||||
handle multibyte strings correctly: strlen() is used to determine the
|
||||
printing width of the string.
|
||||
The format string is similar to but more limited than printf(). In
|
||||
particular, only the following conversion specifiers are understood:
|
||||
|
||||
%% - Insert the ASCII percent sign (ASCII code U+0025)
|
||||
|
||||
%c - Insert the next parameter as a character (type char)
|
||||
%lc - Insert the next parameter as a wide char (type wchar_t)
|
||||
%s - Insert the next parameter as a string (type char *)
|
||||
%ls - Insert the next parameter as a wide string (type wchar_t *)
|
||||
%d - Insert the next parameter as an integer (type int)
|
||||
%'d - As above, using the locale's thousands group separator
|
||||
%ld - Insert the next parameter as a long int
|
||||
%'ld - As above, using the locale's thousands group separator
|
||||
%f - Insert the next parameter as a floating point number (double)
|
||||
%.mf - As above, with precision "m" (a positive integer > 0)
|
||||
%'.mf - As above, using the locale's thousands group separator
|
||||
%N - Insert the next parameter as a double, using the locale's
|
||||
national currency format (extension to printf())
|
||||
%!N - As above, using the locale's national currency format without
|
||||
the actual currency symbol (extension to printf())
|
||||
|
||||
Instead of using "%" to convert the next parameter, "%m$" can be used
|
||||
to indicate fixed parameter m (where m is an integer from 1 to 8). For
|
||||
example, "%4$s" inserts the fourth parameter after "format" as a string
|
||||
into chbuf. As with printf(), using "%m$" together with ordinary "%"
|
||||
forms is undefined. If "%m$" is used, no parameter m can be skipped.
|
||||
|
||||
Note that no other flag, field width, precision or length modifier
|
||||
characters are recognised: if needed, these should be formatted FIRST
|
||||
with snprintf(), then inserted using %s as appropriate.
|
||||
|
||||
In addition to the conversion specifiers, the following character
|
||||
rendition flags are understood, where the "^" character is a literal
|
||||
ASCII circumflex accent:
|
||||
|
||||
^^ - Insert the circumflex accent (ASCII code U+005E)
|
||||
^{ - Switch to using attr_alt1 character rendition (alternate mode 1)
|
||||
^} - Switch to using attr_norm character rendition
|
||||
^[ - Switch to using attr_alt2 character rendition (alternate mode 2)
|
||||
^] - Switch to using attr_norm character rendition
|
||||
|
||||
Printable characters other than these are inserted as literals. The
|
||||
character '\n' will force the start of a new line; no other control (or
|
||||
non-printable) characters are allowed. By default, attr_norm is used
|
||||
as the character rendition (attributes).
|
||||
|
||||
This function returns the actual number of lines used (from 0 to
|
||||
maxlines). If an error is detected, the application terminates.
|
||||
*/
|
||||
extern int center (WINDOW *win, int y, chtype attr,
|
||||
const char *restrict format, ...)
|
||||
__attribute__((format (printf, 4, 5)));
|
||||
extern int mkchstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
||||
chtype attr_alt1, chtype attr_alt2, int maxlines,
|
||||
int maxwidth, int *restrict widthbuf, int widthbufsize,
|
||||
const char *restrict format, ...);
|
||||
|
||||
|
||||
/*
|
||||
Function: center2 - Centre two strings in a given window
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
y - Line on which to centre the strings
|
||||
attr1 - Character rendition to use for initial string
|
||||
attr2 - Character rendition to use for main string
|
||||
initial - Initial string (no printf() formatting)
|
||||
format - printf()-like format string for main string
|
||||
... - printf()-like arguments
|
||||
Returns: int - Return code from wprintw(): OK or ERR
|
||||
Function: vmkchstr - Prepare a string for printing to screen
|
||||
Parameters: chbuf - Pointer to chtype buffer in which to store string
|
||||
chbufsize - Number of chtype elements in chbuf
|
||||
attr_norm - Normal character rendition to use
|
||||
attr_alt1 - First alternate character rendition to use
|
||||
attr_alt2 - Second alternate character rendition to use
|
||||
maxlines - Maximum number of screen lines to use
|
||||
maxwidth - Maximum width of each line, in chars
|
||||
widthbuf - Pointer to buffer to store widths of each line
|
||||
widthbufsize - Number of int elements in widthbuf
|
||||
format - Format string as described for mkchstr()
|
||||
args - Variable argument list
|
||||
Returns: int - Number of lines actually used
|
||||
|
||||
This function prints two strings side-by-side on line y in the centre
|
||||
of window win. The first (initial) string is printed with character
|
||||
rendition (attributes) attr1 using waddstr(). The second (main) string
|
||||
uses wprintw(format, ...) with rendition attr2. If the main string is
|
||||
too long to fit in the window alongside the initial string, the main
|
||||
string is truncated to fit. Please note that wrefresh() is NOT called.
|
||||
|
||||
As with center(), the current implementation does NOT handle multibyte
|
||||
strings correctly.
|
||||
This function is exactly the same as mkchstr(), except that it is
|
||||
called with a va_list parameter args instead of a variable number of
|
||||
arguments. Note that va_end() is NOT called on args, and that args is
|
||||
undefined after this function.
|
||||
*/
|
||||
extern int center2 (WINDOW *win, int y, chtype attr1, chtype attr2,
|
||||
const char *initial, const char *restrict format, ...)
|
||||
__attribute__((format (printf, 6, 7)));
|
||||
extern int vmkchstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
||||
chtype attr_alt1, chtype attr_alt2, int maxlines,
|
||||
int maxwidth, int *restrict widthbuf, int widthbufsize,
|
||||
const char *restrict format, va_list args);
|
||||
|
||||
|
||||
/*
|
||||
Function: center3 - Centre three strings in a given window
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
y - Line on which to centre the strings
|
||||
attr1 - Character rendition to use for initial string
|
||||
attr3 - Character rendition to use for final string
|
||||
attr2 - Character rendition to use for main string
|
||||
initial - Initial string (no printf() formatting)
|
||||
final - Final string (no printf() formatting)
|
||||
format - printf()-like format string for main string
|
||||
... - printf()-like arguments
|
||||
Returns: int - Return code from wprintw(): OK or ERR
|
||||
Function: leftch - Print strings in chstr left-aligned
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
y - Line on which to print first string
|
||||
x - Starting column number for each line
|
||||
chstr - chtype string as returned from mkchstr()
|
||||
lines - Number of lines in chstr as returned from mkchstr()
|
||||
widthbuf - Widths of each line as returned from mkchstr()
|
||||
Returns: int - Always returns OK
|
||||
|
||||
This function prints three strings side-by-side on line y in the centre
|
||||
of window win. The first (initial) string is printed with character
|
||||
rendition (attributes) attr1 using waddstr(). The second (main) string
|
||||
uses wprintw(format, ...) with rendition attr2. The third (final)
|
||||
string is then printed with rendition attr3 using waddstr(). If the
|
||||
strings are too long to fit the window width, the main (centre) string
|
||||
is truncated. Please note that wrefresh() is NOT called. Also note
|
||||
the order of rendition values: 1, 3, 2, NOT 1, 2, 3!
|
||||
|
||||
As with center(), the current implementation does NOT handle multibyte
|
||||
strings correctly.
|
||||
This function takes the strings in the chtype array chstr and prints
|
||||
them left-aligned in the window win. Note that wrefresh() is NOT
|
||||
called.
|
||||
*/
|
||||
|
||||
extern int center3 (WINDOW *win, int y, chtype attr1, chtype attr3,
|
||||
chtype attr2, const char *initial, const char *final,
|
||||
const char *restrict format, ...)
|
||||
__attribute__((format (printf, 8, 9)));
|
||||
extern int leftch (WINDOW *win, int y, int x, const chtype *restrict chstr,
|
||||
int lines, const int *restrict widthbuf);
|
||||
|
||||
|
||||
/*
|
||||
Function: gettxchar - Read a character from the keyboard
|
||||
Function: centerch - Print strings in chstr centred in window
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
y - Line on which to print first string
|
||||
offset - Column offset to add to position for each line
|
||||
chstr - chtype string as returned from mkchstr()
|
||||
lines - Number of lines in chstr as returned from mkchstr()
|
||||
widthbuf - Widths of each line as returned from mkchstr()
|
||||
Returns: int - ERR if more lines in chstr[] than lines, else OK
|
||||
|
||||
This function takes the strings in the chtype array chstr and prints
|
||||
them centred in the window win, offset by the parameter offset. Note
|
||||
that wrefresh() is NOT called. ERR is returned if there are more lines
|
||||
in chstr[] than are passed in the parameter lines.
|
||||
*/
|
||||
extern int centerch (WINDOW *win, int y, int offset,
|
||||
const chtype *restrict chstr, int lines,
|
||||
const int *restrict widthbuf);
|
||||
|
||||
|
||||
/*
|
||||
Function: rightch - Print strings in chstr right-aligned
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
y - Line on which to print first string
|
||||
x - Ending column number for each line
|
||||
chstr - chtype string as returned from mkchstr()
|
||||
lines - Number of lines in chstr as returned from mkchstr()
|
||||
widthbuf - Widths of each line as returned from mkchstr()
|
||||
Returns: int - ERR if more lines in chstr[] than lines, else OK
|
||||
|
||||
This function takes the strings in the chtype array chstr and prints
|
||||
them right-aligned in the window win, with each line ending just before
|
||||
column x. Note that wrefresh() is NOT called. ERR is returned if
|
||||
there are more lines in chstr[] than are passed in the parameter lines.
|
||||
*/
|
||||
extern int rightch (WINDOW *win, int y, int x, const chtype *restrict chstr,
|
||||
int lines, const int *restrict widthbuf);
|
||||
|
||||
|
||||
/*
|
||||
Function: left - Print strings left-aligned
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
Returns: int - The keyboard character
|
||||
y - Line on which to print first string
|
||||
x - Starting column number for each line
|
||||
attr_norm - Normal character rendition to use
|
||||
attr_alt1 - First alternate character rendition to use
|
||||
attr_alt2 - Second alternate character rendition to use
|
||||
maxlines - Maximum number of screen lines to use
|
||||
format - Format string as described for mkchstr()
|
||||
... - Arguments for the format string
|
||||
Returns: int - Number of lines actually used
|
||||
|
||||
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 shortcut function prepares a chtype string using mkchstr(), then
|
||||
prints the string using leftch(). At most MAX_DLG_LINES are printed,
|
||||
with the maximum width being that of the window win - x - 2 (the "2" is
|
||||
for the right-hand border).
|
||||
*/
|
||||
extern int gettxchar (WINDOW *win);
|
||||
extern int left (WINDOW *win, int y, int x, chtype attr_norm, chtype attr_alt1,
|
||||
chtype attr_alt2, int maxlines, const char *restrict format,
|
||||
...);
|
||||
|
||||
|
||||
/*
|
||||
Function: gettxline - Read a line from the keyboard (low-level)
|
||||
Function: center - Print strings centred in window
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
y - Line on which to print first string
|
||||
offset - Column offset to add to position for each line
|
||||
attr_norm - Normal character rendition to use
|
||||
attr_alt1 - First alternate character rendition to use
|
||||
attr_alt2 - Second alternate character rendition to use
|
||||
maxlines - Maximum number of screen lines to use
|
||||
format - Format string as described for mkchstr()
|
||||
... - Arguments for the format string
|
||||
Returns: int - Number of lines actually used
|
||||
|
||||
This shortcut function prepares a chtype string using mkchstr(), then
|
||||
prints the string using centerch(). At most MAX_DLG_LINES are printed,
|
||||
with the maximum width being that of the window win - 4 (for borders).
|
||||
*/
|
||||
extern int center (WINDOW *win, int y, int offset, chtype attr_norm,
|
||||
chtype attr_alt1, chtype attr_alt2, int maxlines,
|
||||
const char *restrict format, ...);
|
||||
|
||||
|
||||
/*
|
||||
Function: right - Print strings right-aligned
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
y - Line on which to print first string
|
||||
x - Ending column number for each line
|
||||
attr_norm - Normal character rendition to use
|
||||
attr_alt1 - First alternate character rendition to use
|
||||
attr_alt2 - Second alternate character rendition to use
|
||||
maxlines - Maximum number of screen lines to use
|
||||
format - Format string as described for mkchstr()
|
||||
... - Arguments for the format string
|
||||
Returns: int - Number of lines actually used
|
||||
|
||||
This shortcut function prepares a chtype string using mkchstr(), then
|
||||
prints the string using rightch(). At most MAX_DLG_LINES are printed,
|
||||
with the maximum width being that of x - 2 (the "2" is for the
|
||||
left-hand border).
|
||||
*/
|
||||
extern int right (WINDOW *win, int y, int x, chtype attr_norm, chtype attr_alt1,
|
||||
chtype attr_alt2, int maxlines, const char *restrict format,
|
||||
...);
|
||||
|
||||
|
||||
/*
|
||||
Function: gettxchar - Read a wide character from the keyboard
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
wch - Pointer to keyboard wide character
|
||||
Returns: int - OK or KEY_CODE_YES
|
||||
|
||||
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, wint_t *restrict wch);
|
||||
|
||||
|
||||
/*
|
||||
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
|
||||
@ -386,14 +593,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
|
||||
@ -405,13 +612,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
|
||||
@ -419,30 +626,25 @@ 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.
|
||||
|
||||
If allowed is not NULL, only characters in that string are allowed to
|
||||
be entered into the input line. For example, if allowed points to
|
||||
"0123456789abcdefABCDEF", only those characters would be allowed (in
|
||||
L"0123456789abcdefABCDEF", only those characters would be allowed (in
|
||||
this instance, allowing the user to type in a hexadecimal number).
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@ -458,18 +660,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 "",
|
||||
gettxline() parameters emptyval and defaultval are passed as L"",
|
||||
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);
|
||||
|
||||
|
||||
/*
|
||||
@ -481,7 +684,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
|
||||
|
||||
@ -493,12 +696,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,
|
||||
@ -521,9 +723,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,
|
||||
@ -533,17 +735,15 @@ extern int gettxlong (WINDOW *win, long int *restrict result, long int min,
|
||||
/*
|
||||
Function: answer_yesno - Wait for a Yes/No answer
|
||||
Parameters: win - Window to use (should be curwin)
|
||||
attr_keys - Window rendition to use for key choices
|
||||
Returns: bool - True if Yes was selected, false if No
|
||||
|
||||
This function prompts the user by printing " [Y/N] " using appropriate
|
||||
character renditions ("Y" and "N" in attr_keys, the rest in the current
|
||||
rendition), then 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, chtype attr_keys);
|
||||
extern bool answer_yesno (WINDOW *win);
|
||||
|
||||
|
||||
/*
|
||||
@ -558,10 +758,6 @@ extern bool answer_yesno (WINDOW *win, chtype attr_keys);
|
||||
|
||||
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);
|
||||
|
||||
|
593
src/move.c
593
src/move.c
@ -207,7 +207,6 @@ void select_moves (void)
|
||||
|
||||
selection_t get_move (void)
|
||||
{
|
||||
int i, x, y;
|
||||
selection_t selection = SEL_NONE;
|
||||
|
||||
|
||||
@ -219,89 +218,101 @@ selection_t get_move (void)
|
||||
show_map(false);
|
||||
|
||||
// Display current move choices on the galaxy map
|
||||
for (i = 0; i < NUMBER_MOVES; i++) {
|
||||
mvwaddch(curwin, game_move[i].y + 3, game_move[i].x * 2 + 2,
|
||||
MOVE_TO_KEY(i) | attr_map_choice);
|
||||
for (int i = 0; i < NUMBER_MOVES; i++) {
|
||||
mvwaddchstr(curwin, game_move[i].y + 3, game_move[i].x * 2 + 2,
|
||||
CHTYPE_GAME_MOVE(i));
|
||||
}
|
||||
wrefresh(curwin);
|
||||
|
||||
// Show menu of choices for the player
|
||||
newtxwin(5, WIN_COLS, 19, WCENTER, false, 0);
|
||||
while (selection == SEL_NONE) {
|
||||
wbkgd(curwin, attr_normal_window);
|
||||
wbkgdset(curwin, attr_normal_window);
|
||||
werase(curwin);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
wmove(curwin, 2, 2);
|
||||
attrpr(curwin, attr_keycode, "<1>");
|
||||
waddstr(curwin, " Display stock portfolio");
|
||||
left(curwin, 2, 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<1>^} Display stock portfolio"));
|
||||
left(curwin, 3, 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<2>^} Declare bankruptcy"));
|
||||
left(curwin, 2, getmaxx(curwin) / 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<3>^} Save and end the game"));
|
||||
left(curwin, 3, getmaxx(curwin) / 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("^{<CTRL><C>^} Quit the game"));
|
||||
|
||||
wmove(curwin, 3, 2);
|
||||
attrpr(curwin, attr_keycode, "<2>");
|
||||
waddstr(curwin, " Declare bankruptcy");
|
||||
|
||||
wmove(curwin, 2, 42);
|
||||
attrpr(curwin, attr_keycode, "<3>");
|
||||
waddstr(curwin, " Save and end the game");
|
||||
|
||||
wmove(curwin, 3, 42);
|
||||
attrpr(curwin, attr_keycode, "<CTRL><C>");
|
||||
waddstr(curwin, " Quit the game");
|
||||
|
||||
mvwaddstr(curwin, 1, 9, "Select move ");
|
||||
waddstr(curwin, "[");
|
||||
attrpr(curwin, attr_choice, "%c", MOVE_TO_KEY(0));
|
||||
waddstr(curwin, "-");
|
||||
attrpr(curwin, attr_choice, "%c", MOVE_TO_KEY(NUMBER_MOVES - 1));
|
||||
waddstr(curwin, "/");
|
||||
attrpr(curwin, attr_keycode, "1");
|
||||
waddstr(curwin, "-");
|
||||
attrpr(curwin, attr_keycode, "3");
|
||||
waddstr(curwin, "/");
|
||||
attrpr(curwin, attr_keycode, "<CTRL><C>");
|
||||
waddstr(curwin, "]: ");
|
||||
right(curwin, 1, getmaxx(curwin) / 2, attr_normal, attr_keycode,
|
||||
attr_choice, 1,
|
||||
_("Select move [^[%lc^]-^[%lc^]/^{1^}-^{3^}/^{<CTRL><C>^}]: "),
|
||||
PRINTABLE_GAME_MOVE(0), PRINTABLE_GAME_MOVE(NUMBER_MOVES - 1));
|
||||
|
||||
curs_set(CURS_ON);
|
||||
wrefresh(curwin);
|
||||
|
||||
// Get the actual selection made by the player
|
||||
while (selection == SEL_NONE) {
|
||||
int key = tolower(gettxchar(curwin));
|
||||
wint_t key;
|
||||
|
||||
if (IS_MOVE_KEY(key)) {
|
||||
selection = KEY_TO_MOVE(key);
|
||||
if (gettxchar(curwin, &key) == OK) {
|
||||
// Ordinary wide character
|
||||
int i;
|
||||
bool found;
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
waddstr(curwin, "Move ");
|
||||
attrpr(curwin, attr_choice, "%c", key);
|
||||
if (iswupper(*keycode_game_move)) {
|
||||
key = towupper(key);
|
||||
} else if (iswlower(*keycode_game_move)) {
|
||||
key = towlower(key);
|
||||
}
|
||||
|
||||
for (i = 0, found = false; keycode_game_move[i] != L'\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 L'1':
|
||||
curs_set(CURS_OFF);
|
||||
show_status(current_player);
|
||||
curs_set(CURS_ON);
|
||||
break;
|
||||
|
||||
case L'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 L'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);
|
||||
wattron(curwin, A_BOLD);
|
||||
waddstr(curwin, "<2>");
|
||||
wattroff(curwin, A_BOLD);
|
||||
waddstr(curwin, " (Declare bankruptcy)");
|
||||
break;
|
||||
|
||||
case '3':
|
||||
selection = SEL_SAVE;
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
wattron(curwin, A_BOLD);
|
||||
waddstr(curwin, "<3>");
|
||||
wattroff(curwin, A_BOLD);
|
||||
waddstr(curwin, " (Save and end the game)");
|
||||
break;
|
||||
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
case KEY_EXIT:
|
||||
@ -311,10 +322,9 @@ selection_t get_move (void)
|
||||
selection = SEL_QUIT;
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
wattron(curwin, A_BOLD);
|
||||
waddstr(curwin, "<CTRL><C>");
|
||||
wattroff(curwin, A_BOLD);
|
||||
waddstr(curwin, " (Quit the game)");
|
||||
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
|
||||
attr_normal | A_BOLD, 0, 1,
|
||||
_("^{<CTRL><C>^} (Quit the game)"));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -324,30 +334,31 @@ selection_t get_move (void)
|
||||
}
|
||||
|
||||
// Clear the menu choices (but not the prompt!)
|
||||
wattrset(curwin, attr_normal);
|
||||
for (y = 2; y < 4; y++) {
|
||||
wmove(curwin, y, 2);
|
||||
for (x = 2; x < getmaxx(curwin) - 2; x++) {
|
||||
waddch(curwin, ' ' | attr_normal);
|
||||
}
|
||||
}
|
||||
wrefresh(curwin);
|
||||
mvwhline(curwin, 2, 2, ' ' | attr_normal, getmaxx(curwin) - 4);
|
||||
mvwhline(curwin, 3, 2, ' ' | attr_normal, getmaxx(curwin) - 4);
|
||||
|
||||
// Ask the player to confirm their choice
|
||||
mvwaddstr(curwin, 2, 22, "Are you sure?");
|
||||
if (! answer_yesno(curwin, attr_keycode)) {
|
||||
right(curwin, 2, getmaxx(curwin) / 2, attr_normal, attr_keycode, 0, 1,
|
||||
_("Are you sure? [^{Y^}/^{N^}] "));
|
||||
wrefresh(curwin);
|
||||
|
||||
if (! answer_yesno(curwin)) {
|
||||
selection = SEL_NONE;
|
||||
}
|
||||
|
||||
// Save the game if required
|
||||
if (selection == SEL_SAVE) {
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
int width;
|
||||
|
||||
bool saved = false;
|
||||
|
||||
if (game_loaded) {
|
||||
// Save the game to the same game number
|
||||
newtxwin(5, 30, 7, WCENTER, true, attr_status_window);
|
||||
center(curwin, 2, attr_status_window,
|
||||
"Saving game %d... ", game_num);
|
||||
mkchstr(chbuf, BUFSIZE, attr_status_window, 0, 0, 1, WIN_COLS
|
||||
- 7, &width, 1, _("Saving game %d... "), game_num);
|
||||
newtxwin(5, width + 5, 7, WCENTER, true, attr_status_window);
|
||||
centerch(curwin, 2, 0, chbuf, 1, &width);
|
||||
wrefresh(curwin);
|
||||
|
||||
saved = save_game(game_num);
|
||||
@ -357,34 +368,46 @@ selection_t get_move (void)
|
||||
}
|
||||
|
||||
if (! saved) {
|
||||
int key;
|
||||
bool done;
|
||||
|
||||
// Ask which game to save
|
||||
newtxwin(6, 54, 8, WCENTER, true, attr_normal_window);
|
||||
|
||||
center(curwin, 1, attr_title, " Save Game ");
|
||||
mvwaddstr(curwin, 3, 2, "Enter game number ");
|
||||
waddstr(curwin, "[");
|
||||
attrpr(curwin, attr_keycode, "1");
|
||||
waddstr(curwin, "-");
|
||||
attrpr(curwin, attr_keycode, "9");
|
||||
waddstr(curwin, "]");
|
||||
waddstr(curwin, " or ");
|
||||
attrpr(curwin, attr_keycode, "<CTRL><C>");
|
||||
waddstr(curwin, " to cancel: ");
|
||||
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,
|
||||
_("Enter game number [^{1^}-^{9^}] "
|
||||
"or ^{<CTRL><C>^} to cancel: "));
|
||||
assert(lines == 1 || lines == 2);
|
||||
maxwidth = ((lines == 1) ? widthbuf[0] :
|
||||
MAX(widthbuf[0], widthbuf[1])) + 5;
|
||||
|
||||
newtxwin(lines + 4, maxwidth, 8, WCENTER, true,
|
||||
attr_normal_window);
|
||||
leftch(curwin, 2, 2, chbuf, lines, widthbuf);
|
||||
|
||||
curs_set(CURS_ON);
|
||||
wrefresh(curwin);
|
||||
|
||||
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 >= L'1' && key <= L'9') {
|
||||
left(curwin, getcury(curwin), getcurx(curwin),
|
||||
A_BOLD, 0, 0, 1, "%lc", key);
|
||||
wrefresh(curwin);
|
||||
|
||||
choice = key - L'0';
|
||||
done = true;
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
} else {
|
||||
// Function or control key
|
||||
switch (key) {
|
||||
case KEY_ESC:
|
||||
case KEY_CANCEL:
|
||||
@ -392,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;
|
||||
|
||||
@ -404,13 +427,17 @@ selection_t get_move (void)
|
||||
|
||||
curs_set(CURS_OFF);
|
||||
|
||||
if (key != KEY_CANCEL) {
|
||||
game_num = key - '0';
|
||||
|
||||
if (choice != ERR) {
|
||||
// Try to save the game, if possible
|
||||
newtxwin(5, 30, 7, WCENTER, true, attr_status_window);
|
||||
center(curwin, 2, attr_status_window,
|
||||
"Saving game %d... ", game_num);
|
||||
|
||||
game_num = choice;
|
||||
|
||||
mkchstr(chbuf, BUFSIZE, attr_status_window, 0, 0, 1,
|
||||
WIN_COLS - 7, &width, 1,
|
||||
_("Saving game %d... "), game_num);
|
||||
newtxwin(5, width + 5, 7, WCENTER, true,
|
||||
attr_status_window);
|
||||
centerch(curwin, 2, 0, chbuf, 1, &width);
|
||||
wrefresh(curwin);
|
||||
|
||||
saved = save_game(game_num);
|
||||
@ -432,6 +459,8 @@ selection_t get_move (void)
|
||||
|
||||
selection = SEL_NONE;
|
||||
}
|
||||
|
||||
free(chbuf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,13 +504,13 @@ void process_move (selection_t selection)
|
||||
|
||||
assign_vals(x, y, left, right, up, down);
|
||||
|
||||
if (left == MAP_EMPTY && right == MAP_EMPTY &&
|
||||
up == MAP_EMPTY && down == MAP_EMPTY) {
|
||||
if ( left == MAP_EMPTY && right == MAP_EMPTY
|
||||
&& up == MAP_EMPTY && down == MAP_EMPTY) {
|
||||
// The position is out in the middle of nowhere...
|
||||
galaxy_map[x][y] = MAP_OUTPOST;
|
||||
|
||||
} else if (! IS_MAP_COMPANY(left) && ! IS_MAP_COMPANY(right)
|
||||
&& ! IS_MAP_COMPANY(up) && ! IS_MAP_COMPANY(down)) {
|
||||
} else if ( ! IS_MAP_COMPANY(left) && ! IS_MAP_COMPANY(right)
|
||||
&& ! IS_MAP_COMPANY(up) && ! IS_MAP_COMPANY(down)) {
|
||||
// See if a company can be established
|
||||
try_start_new_company(x, y);
|
||||
|
||||
@ -632,58 +661,25 @@ void next_player (void)
|
||||
|
||||
void bankrupt_player (bool forced)
|
||||
{
|
||||
bool longname;
|
||||
int i;
|
||||
|
||||
|
||||
/* It would be nice if we had functions that would do word-wrapping
|
||||
for us automatically! */
|
||||
|
||||
longname = (strlen(player[current_player].name) > 20);
|
||||
if (forced) {
|
||||
newtxwin(longname ? 9 : 8, 54, 7, WCENTER, true, attr_error_window);
|
||||
txdlgbox(MAX_DLG_LINES, 50, 7, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" Bankruptcy Court "),
|
||||
_("%ls has been declared bankrupt "
|
||||
"by the Interstellar Trading Bank."),
|
||||
player[current_player].name);
|
||||
} else {
|
||||
newtxwin(longname ? 8 : 7, 50, 7, WCENTER, true, attr_error_window);
|
||||
txdlgbox(MAX_DLG_LINES, 50, 7, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, 0, 0,
|
||||
attr_error_waitforkey, _(" Bankruptcy Court "),
|
||||
_("%ls has declared bankruptcy."),
|
||||
player[current_player].name);
|
||||
}
|
||||
|
||||
center(curwin, 1, attr_error_title, " Bankruptcy Court ");
|
||||
|
||||
if (forced) {
|
||||
if (longname) {
|
||||
center(curwin, 3, attr_error_highlight, "%s",
|
||||
player[current_player].name);
|
||||
center(curwin, 4, attr_error_highlight,
|
||||
"has been declared bankrupt by the");
|
||||
center(curwin, 5, attr_error_highlight,
|
||||
"Interstellar Trading Bank");
|
||||
} else {
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"%s has been declared bankrupt",
|
||||
player[current_player].name);
|
||||
center(curwin, 4, attr_error_highlight,
|
||||
"by the Interstellar Trading Bank");
|
||||
}
|
||||
} else {
|
||||
if (longname) {
|
||||
center(curwin, 3, attr_error_highlight, "%s",
|
||||
player[current_player].name);
|
||||
center(curwin, 4, attr_error_highlight,
|
||||
"has declared bankruptcy");
|
||||
} else {
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"%s has declared bankruptcy",
|
||||
player[current_player].name);
|
||||
}
|
||||
}
|
||||
|
||||
wait_for_key(curwin, getmaxy(curwin) - 2, attr_error_waitforkey);
|
||||
|
||||
deltxwin();
|
||||
txrefresh();
|
||||
|
||||
// Confiscate all assets belonging to player
|
||||
player[current_player].in_game = false;
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
for (int i = 0; i < MAX_COMPANIES; i++) {
|
||||
company[i].stock_issued -= player[current_player].stock_owned[i];
|
||||
player[current_player].stock_owned[i] = 0;
|
||||
}
|
||||
@ -692,7 +688,7 @@ void bankrupt_player (bool forced)
|
||||
|
||||
// Is anyone still left in the game?
|
||||
bool all_out = true;
|
||||
for (i = 0; i < number_players; i++) {
|
||||
for (int i = 0; i < number_players; i++) {
|
||||
if (player[i].in_game) {
|
||||
all_out = false;
|
||||
break;
|
||||
@ -742,16 +738,11 @@ void try_start_new_company (int x, int y)
|
||||
} else {
|
||||
// Create the new company
|
||||
|
||||
newtxwin(8, 50, 7, WCENTER, true, attr_normal_window);
|
||||
|
||||
center(curwin, 1, attr_title, " New Company ");
|
||||
center(curwin, 3, attr_normal, "A new company has been formed!");
|
||||
center2(curwin, 4, attr_normal, attr_highlight, "Its name is ",
|
||||
"%s", company[i].name);
|
||||
|
||||
wait_for_key(curwin, 6, attr_waitforkey);
|
||||
|
||||
deltxwin();
|
||||
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 ^{%ls^}."),
|
||||
company[i].name);
|
||||
txrefresh();
|
||||
|
||||
galaxy_map[x][y] = COMPANY_TO_MAP(i);
|
||||
@ -779,22 +770,23 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
int aa = MAP_TO_COMPANY(a);
|
||||
int bb = MAP_TO_COMPANY(b);
|
||||
|
||||
assert(aa >= 0 && aa < MAX_COMPANIES);
|
||||
assert(bb >= 0 && bb < MAX_COMPANIES);
|
||||
|
||||
double val_aa = company[aa].share_price * company[aa].stock_issued *
|
||||
company[aa].share_return;
|
||||
double val_bb = company[bb].share_price * company[bb].stock_issued *
|
||||
company[bb].share_return;
|
||||
|
||||
long int old_stock, new_stock, total_new;
|
||||
int x, y, i, line;
|
||||
double bonus;
|
||||
char *buf;
|
||||
long int old_stock, new_stock, total_new;
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
int lines, width, widthbuf[4];
|
||||
chtype *chbuf_aa, *chbuf_bb;
|
||||
int width_aa, width_bb;
|
||||
int x, y, w, i, ln;
|
||||
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
|
||||
if (val_aa < val_bb) {
|
||||
// Make sure aa is the dominant company
|
||||
map_val_t t;
|
||||
@ -806,31 +798,81 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
|
||||
// Display information about the merger
|
||||
|
||||
newtxwin(number_players + 14, WIN_COLS - 4, 9 - number_players,
|
||||
WCENTER, true, attr_normal_window);
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_highlight, 0, 4,
|
||||
WIN_COLS - 8, widthbuf, 4,
|
||||
_("^{%ls^} has just merged into ^{%ls^}.\n"
|
||||
"Please note the following transactions:\n"),
|
||||
company[bb].name, company[aa].name);
|
||||
|
||||
center(curwin, 1, attr_title, " Company Merger ");
|
||||
center3(curwin, 3, attr_highlight, attr_highlight, attr_normal,
|
||||
company[bb].name, company[aa].name, " has just merged into ");
|
||||
newtxwin(number_players + lines + 10, WIN_COLS - 4, lines + 6
|
||||
- number_players, WCENTER, true, attr_normal_window);
|
||||
center(curwin, 1, 0, attr_title, 0, 0, 1, _(" Company Merger "));
|
||||
centerch(curwin, 3, 0, chbuf, lines, widthbuf);
|
||||
|
||||
center(curwin, 5, attr_normal, "Please note the following transactions:");
|
||||
mkchstr(chbuf, BUFSIZE, attr_highlight, 0, 0, 1, getmaxx(curwin) / 2,
|
||||
&width_aa, 1, "%ls", company[aa].name);
|
||||
chbuf_aa = xchstrdup(chbuf);
|
||||
|
||||
center2(curwin, 7, attr_normal, attr_highlight, " Old stock: ",
|
||||
"%-20s", company[bb].name);
|
||||
center2(curwin, 8, attr_normal, attr_highlight, " New stock: ",
|
||||
"%-20s", company[aa].name);
|
||||
mkchstr(chbuf, BUFSIZE, attr_highlight, 0, 0, 1, getmaxx(curwin) / 2,
|
||||
&width_bb, 1, "%ls", company[bb].name);
|
||||
chbuf_bb = xchstrdup(chbuf);
|
||||
|
||||
// Handle the locale's currency symbol
|
||||
snprintf(buf, BUFSIZE, "Bonus (%s)", lconvinfo.currency_symbol);
|
||||
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin) / 2,
|
||||
&width, 1,
|
||||
/* TRANSLATORS: "Old stock" refers to the company that has
|
||||
just ceased existence due to a merger.
|
||||
|
||||
int w = getmaxx(curwin) - 52;
|
||||
wattrset(curwin, attr_subtitle);
|
||||
mvwprintw(curwin, 10, 2, " %-*.*s %8s %8s %8s %12s ", w, w,
|
||||
"Player", "Old", "New", "Total", buf);
|
||||
wattrset(curwin, attr_normal);
|
||||
Note that the "Old stock" and "New stock" labels MUST be
|
||||
the same length and must contain a trailing space for the
|
||||
display routines to work correctly. The maximum length of
|
||||
each label is 36 characters. */
|
||||
pgettext("label", "Old stock: "));
|
||||
|
||||
w = getmaxx(curwin);
|
||||
x = (w + width - MAX(width_aa, width_bb)) / 2;
|
||||
|
||||
rightch(curwin, lines + 3, x, chbuf, 1, &width);
|
||||
leftch(curwin, lines + 3, x, chbuf_bb, 1, &width_bb);
|
||||
|
||||
right(curwin, lines + 4, x, attr_normal, 0, 0, 1,
|
||||
/* TRANSLATORS: "New stock" refers to the company that has
|
||||
absorbed another due to a merger. */
|
||||
pgettext("label", "New Stock: "));
|
||||
leftch(curwin, lines + 4, x, chbuf_aa, 1, &width_aa);
|
||||
|
||||
mvwhline(curwin, lines + 6, 2, ' ' | attr_subtitle, w - 4);
|
||||
left(curwin, lines + 6, 4, attr_subtitle, 0, 0, 1,
|
||||
/* TRANSLATORS: "Player" is used as a column title in a
|
||||
table containing all player names. */
|
||||
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. %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 (%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
|
||||
8 characters (see MERGE_TOTAL_STOCK_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Total"));
|
||||
right(curwin, lines + 6, w - 8 - MERGE_BONUS_COLS - MERGE_TOTAL_STOCK_COLS,
|
||||
attr_subtitle, 0, 0, 1,
|
||||
/* TRANSLATORS: "New" refers to how many (new) shares each
|
||||
player receives in the surviving company after a merger.
|
||||
The maximum column width is 8 characters (see
|
||||
MERGE_NEW_STOCK_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "New"));
|
||||
right(curwin, lines + 6, w - 10 - MERGE_BONUS_COLS - MERGE_TOTAL_STOCK_COLS
|
||||
- MERGE_NEW_STOCK_COLS, attr_subtitle, 0, 0, 1,
|
||||
/* TRANSLATORS: "Old" refers to how many shares each player had
|
||||
in the company ceasing existence. The maximum column width
|
||||
is 8 characters (see MERGE_OLD_STOCK_COLS in src/intf.h). */
|
||||
pgettext("subtitle", "Old"));
|
||||
|
||||
total_new = 0;
|
||||
for (line = 11, i = 0; i < number_players; i++) {
|
||||
for (ln = lines + 7, i = 0; i < number_players; i++) {
|
||||
if (player[i].in_game) {
|
||||
// Calculate new stock and any bonus
|
||||
old_stock = player[i].stock_owned[bb];
|
||||
@ -845,11 +887,22 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
player[i].stock_owned[bb] = 0;
|
||||
player[i].cash += bonus;
|
||||
|
||||
l_strfmon(buf, BUFSIZE, "%!12n", bonus);
|
||||
mvwprintw(curwin, line, 2, " %-*.*s %'8ld %'8ld %'8ld %12s ",
|
||||
w, w, player[i].name, old_stock, new_stock,
|
||||
player[i].stock_owned[aa], buf);
|
||||
line++;
|
||||
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, "%ls", player[i].name);
|
||||
leftch(curwin, ln, 4, chbuf, 1, &width);
|
||||
|
||||
right(curwin, ln, w - 4, attr_normal, 0, 0, 1, "%!N", bonus);
|
||||
right(curwin, ln, w - 6 - MERGE_BONUS_COLS, attr_normal, 0, 0, 1,
|
||||
"%'ld", player[i].stock_owned[aa]);
|
||||
right(curwin, ln, w - 8 - MERGE_BONUS_COLS - MERGE_TOTAL_STOCK_COLS,
|
||||
attr_normal, 0, 0, 1, "%'ld", new_stock);
|
||||
right(curwin, ln, w - 10 - MERGE_BONUS_COLS - MERGE_TOTAL_STOCK_COLS
|
||||
- MERGE_NEW_STOCK_COLS, attr_normal, 0, 0, 1, "%'ld",
|
||||
old_stock);
|
||||
|
||||
ln++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -876,7 +929,9 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
deltxwin(); // "Company merger" window
|
||||
txrefresh();
|
||||
|
||||
free(buf);
|
||||
free(chbuf_bb);
|
||||
free(chbuf_aa);
|
||||
free(chbuf);
|
||||
}
|
||||
|
||||
|
||||
@ -948,7 +1003,6 @@ void inc_share_price (int num, double inc)
|
||||
|
||||
void adjust_values (void)
|
||||
{
|
||||
int i, x, y;
|
||||
int which;
|
||||
|
||||
|
||||
@ -958,67 +1012,84 @@ void adjust_values (void)
|
||||
|
||||
if (company[which].on_map) {
|
||||
if (randf() < ALL_ASSETS_TAKEN) {
|
||||
newtxwin(10, 60, 6, WCENTER, true, attr_error_window);
|
||||
|
||||
center(curwin, 1, attr_error_title, " Bankruptcy Court ");
|
||||
center(curwin, 3, attr_error_highlight, "%s has been declared",
|
||||
company[which].name);
|
||||
center(curwin, 4, attr_error_highlight,
|
||||
"bankrupt by the Interstellar Trading Bank.");
|
||||
|
||||
center(curwin, 6, attr_error_window,
|
||||
"All assets have been taken to repay outstanding loans.");
|
||||
|
||||
wait_for_key(curwin, 8, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
txdlgbox(MAX_DLG_LINES, 60, 6, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight,
|
||||
attr_error_normal, 0, attr_error_waitforkey,
|
||||
_(" Bankruptcy Court "),
|
||||
_("%ls has been declared bankrupt "
|
||||
"by the Interstellar Trading Bank.\n\n"
|
||||
"^{All assets have been taken "
|
||||
"to repay outstanding loans.^}"),
|
||||
company[which].name);
|
||||
txrefresh();
|
||||
|
||||
} else {
|
||||
double rate = randf();
|
||||
char *buf;
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||
chtype *chbuf_amt;
|
||||
int w, x, lines, width, width_amt, widthbuf[6];
|
||||
|
||||
for (i = 0; i < number_players; i++) {
|
||||
for (int i = 0; i < number_players; i++) {
|
||||
if (player[i].in_game) {
|
||||
player[i].cash += player[i].stock_owned[which] * rate;
|
||||
}
|
||||
}
|
||||
|
||||
newtxwin(14, 60, 4, WCENTER, true, attr_error_window);
|
||||
lines = mkchstr(chbuf, BUFSIZE, attr_error_highlight,
|
||||
attr_error_normal, 0, 6, 60 - 4, widthbuf, 6,
|
||||
_("%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 "
|
||||
"owned.^}"),
|
||||
company[which].name, rate * 100.0);
|
||||
|
||||
center(curwin, 1, attr_error_title, " Bankruptcy Court ");
|
||||
center(curwin, 3, attr_error_highlight, "%s has been declared",
|
||||
company[which].name);
|
||||
center(curwin, 4, attr_error_highlight,
|
||||
"bankrupt by the Interstellar Trading Bank.");
|
||||
newtxwin(9 + lines, 60, 4, WCENTER, true, attr_error_window);
|
||||
w = getmaxx(curwin);
|
||||
|
||||
center2(curwin, 6, attr_error_normal, attr_error_highlight,
|
||||
"The Bank has agreed to pay stock holders ",
|
||||
"%4.2f%%", rate * 100.0);
|
||||
center(curwin, 7, attr_error_normal,
|
||||
"of the share value on each share owned.");
|
||||
center(curwin, 1, 0, attr_error_title, 0, 0, 1,
|
||||
_(" Bankruptcy Court "));
|
||||
centerch(curwin, 3, 0, chbuf, lines, widthbuf);
|
||||
|
||||
l_strfmon(buf, BUFSIZE, "%12n", company[which].share_price);
|
||||
center2(curwin, 9, attr_error_normal, attr_error_highlight,
|
||||
"Old share value: ", "%s", buf);
|
||||
mkchstr(chbuf, BUFSIZE, attr_error_highlight, 0, 0, 1, w / 2,
|
||||
&width_amt, 1, "%N", company[which].share_price);
|
||||
chbuf_amt = xchstrdup(chbuf);
|
||||
|
||||
l_strfmon(buf, BUFSIZE, "%12n", company[which].share_price
|
||||
* rate);
|
||||
center2(curwin, 10, attr_error_normal, attr_error_highlight,
|
||||
"Amount paid per share: ", "%s", buf);
|
||||
mkchstr(chbuf, BUFSIZE, attr_error_normal, 0, 0, 1, w / 2,
|
||||
&width, 1,
|
||||
/* TRANSLATORS: The label "Amount paid per share"
|
||||
refers to payment made by the Interstellar
|
||||
Trading Bank to each player upon company
|
||||
bankruptcy. This label MUST be the same
|
||||
length as "Old share value" and MUST have at
|
||||
least one trailing space for the display
|
||||
routines to work correctly. The maximum
|
||||
length is 28 characters. */
|
||||
pgettext("label", "Amount paid per share: "));
|
||||
x = (w + width - width_amt) / 2;
|
||||
|
||||
wait_for_key(curwin, 12, attr_error_waitforkey);
|
||||
right(curwin, lines + 4, x, attr_error_normal, 0, 0, 1,
|
||||
/* TRANSLATORS: "Old share value" refers to the
|
||||
share price of a company before it was forced
|
||||
into bankruptcy by the Bank. This label must be
|
||||
the same width as "Amount paid per share". */
|
||||
pgettext("label", "Old share value: "));
|
||||
leftch(curwin, lines + 4, x, chbuf_amt, 1, &width_amt);
|
||||
|
||||
rightch(curwin, lines + 5, x, chbuf, 1, &width);
|
||||
left(curwin, lines + 5, x, attr_error_highlight, 0, 0, 1,
|
||||
"%N", company[which].share_price * rate);
|
||||
|
||||
wait_for_key(curwin, getmaxy(curwin) - 2, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
txrefresh();
|
||||
|
||||
free(buf);
|
||||
free(chbuf_amt);
|
||||
free(chbuf);
|
||||
}
|
||||
|
||||
for (i = 0; i < number_players; i++) {
|
||||
for (int i = 0; i < number_players; i++) {
|
||||
player[i].stock_owned[which] = 0;
|
||||
}
|
||||
|
||||
@ -1028,8 +1099,8 @@ void adjust_values (void)
|
||||
company[which].max_stock = 0;
|
||||
company[which].on_map = false;
|
||||
|
||||
for (x = 0; x < MAX_X; x++) {
|
||||
for (y = 0; y < MAX_Y; y++) {
|
||||
for (int x = 0; x < MAX_X; x++) {
|
||||
for (int y = 0; y < MAX_Y; y++) {
|
||||
if (galaxy_map[x][y] == COMPANY_TO_MAP((unsigned int) which)) {
|
||||
galaxy_map[x][y] = MAP_EMPTY;
|
||||
}
|
||||
@ -1047,7 +1118,7 @@ void adjust_values (void)
|
||||
}
|
||||
|
||||
// Make sure that a company's return is not too large
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
for (int i = 0; i < MAX_COMPANIES; i++) {
|
||||
if (company[i].on_map && company[i].share_return > MAX_COMPANY_RETURN) {
|
||||
company[i].share_return /= randf() + RETURN_DIVIDER;
|
||||
}
|
||||
@ -1067,9 +1138,10 @@ void adjust_values (void)
|
||||
}
|
||||
|
||||
// Give the current player the companies' dividends
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
for (int i = 0; i < MAX_COMPANIES; i++) {
|
||||
if (company[i].on_map && company[i].stock_issued != 0) {
|
||||
player[current_player].cash += player[current_player].stock_owned[i]
|
||||
player[current_player].cash +=
|
||||
player[current_player].stock_owned[i]
|
||||
* company[i].share_price * company[i].share_return
|
||||
+ ((double) player[current_player].stock_owned[i]
|
||||
/ company[i].stock_issued) * company[i].share_price
|
||||
@ -1090,31 +1162,16 @@ void adjust_values (void)
|
||||
|
||||
// Check if a player's debt is too large
|
||||
if (total_value(current_player) <= -MAX_OVERDRAFT) {
|
||||
double impounded;
|
||||
char *buf;
|
||||
double impounded = MIN(player[current_player].cash,
|
||||
player[current_player].debt);
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
|
||||
impounded = MIN(player[current_player].cash,
|
||||
player[current_player].debt);
|
||||
|
||||
newtxwin(8, 60, 7, WCENTER, true, attr_error_window);
|
||||
center(curwin, 1, attr_error_title, " Interstellar Trading Bank ");
|
||||
|
||||
l_strfmon(buf, BUFSIZE, "%1n", player[current_player].debt);
|
||||
center(curwin, 3, attr_error_highlight,
|
||||
"Your debt has amounted to %s", buf);
|
||||
|
||||
l_strfmon(buf, BUFSIZE, "%1n", impounded);
|
||||
center3(curwin, 4, attr_error_normal, attr_error_normal,
|
||||
attr_error_highlight, "The Bank has impounded ",
|
||||
" from your cash", "%s", buf);
|
||||
|
||||
wait_for_key(curwin, 6, attr_error_waitforkey);
|
||||
deltxwin();
|
||||
txdlgbox(MAX_DLG_LINES, 60, 7, WCENTER, attr_error_window,
|
||||
attr_error_title, attr_error_highlight, attr_error_normal,
|
||||
0, attr_error_waitforkey, _(" Interstellar Trading Bank "),
|
||||
/* xgettext:c-format */
|
||||
_("Your debt has amounted to %N!\n"
|
||||
"^{The Bank has impounded ^}%N^{ from your cash.^}"),
|
||||
player[current_player].debt, impounded);
|
||||
txrefresh();
|
||||
|
||||
player[current_player].cash -= impounded;
|
||||
|
26
src/system.h
26
src/system.h
@ -55,18 +55,22 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
|
||||
|
||||
// Headers defined by X/Open Single Unix Specification v4
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <monetary.h>
|
||||
#include <langinfo.h>
|
||||
|
||||
|
||||
// Headers defined by the GNU C Library
|
||||
@ -74,8 +78,28 @@
|
||||
#include <getopt.h>
|
||||
|
||||
|
||||
// Internationalisation using GNU gettext
|
||||
|
||||
#include "gettext.h" // This handles ENABLE_NLS correctly
|
||||
|
||||
#define _(string) gettext(string)
|
||||
#define N_(string) gettext_noop(string)
|
||||
|
||||
|
||||
// Character set conversion for game files
|
||||
|
||||
#ifdef HAVE_ICONV
|
||||
# define USE_UTF8_GAME_FILE 1
|
||||
# include "striconv.h"
|
||||
#else
|
||||
# undef USE_UTF8_GAME_FILE
|
||||
#endif
|
||||
|
||||
|
||||
// X/Open-compatible Curses library
|
||||
|
||||
#define _XOPEN_SOURCE_EXTENDED 1 // Required by old versions of NcursesW
|
||||
|
||||
#if defined(HAVE_NCURSESW_CURSES_H)
|
||||
# include <ncursesw/curses.h>
|
||||
#elif defined(HAVE_NCURSESW_H)
|
||||
|
75
src/trader.c
75
src/trader.c
@ -147,7 +147,7 @@ static void end_program (void);
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// Strip off leading pathname components from program name
|
||||
init_program_name(argv);
|
||||
init_program_name(argv[0]);
|
||||
|
||||
// Initialise the locale
|
||||
if (setlocale(LC_ALL, "") == NULL) {
|
||||
@ -155,6 +155,10 @@ int main (int argc, char *argv[])
|
||||
"(check LANG, LC_ALL and LANGUAGE in environment)");
|
||||
}
|
||||
|
||||
// Use correct message catalogs for the locale
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
// Process command line arguments
|
||||
process_cmdline(argc, argv);
|
||||
|
||||
@ -228,8 +232,8 @@ void process_cmdline (int argc, char *argv[])
|
||||
option_max_turn = strtol(optarg, &p, 10);
|
||||
|
||||
if (option_max_turn < MIN_MAX_TURN || p == NULL || *p != '\0') {
|
||||
fprintf(stderr, "%s: invalid value for --max-turn: `%s'\n",
|
||||
program_name(), optarg);
|
||||
fprintf(stderr, _("%s: invalid value for --max-turn: `%s'\n"),
|
||||
program_name, optarg);
|
||||
show_usage(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
@ -244,8 +248,8 @@ void process_cmdline (int argc, char *argv[])
|
||||
|
||||
if (optind < argc && argv[optind] != NULL) {
|
||||
if (*argv[optind] == '-') {
|
||||
fprintf(stderr, "%s: invalid operand `%s'\n", program_name(),
|
||||
argv[optind]);
|
||||
fprintf(stderr, _("%s: invalid operand `%s'\n"),
|
||||
program_name, argv[optind]);
|
||||
show_usage(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -253,8 +257,8 @@ void process_cmdline (int argc, char *argv[])
|
||||
&& *argv[optind] >= '1' && *argv[optind] <= '9') {
|
||||
game_num = *argv[optind] - '0';
|
||||
} else {
|
||||
fprintf(stderr, "%s: invalid game number `%s'\n",
|
||||
program_name(), argv[optind]);
|
||||
fprintf(stderr, _("%s: invalid game number `%s'\n"),
|
||||
program_name, argv[optind]);
|
||||
show_usage(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -262,8 +266,8 @@ void process_cmdline (int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (optind < argc && argv[optind] != NULL) {
|
||||
fprintf(stderr, "%s: extra operand `%s'\n", program_name(),
|
||||
argv[optind]);
|
||||
fprintf(stderr, _("%s: extra operand `%s'\n"),
|
||||
program_name, argv[optind]);
|
||||
show_usage(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
@ -274,8 +278,11 @@ void process_cmdline (int argc, char *argv[])
|
||||
|
||||
void show_version (void)
|
||||
{
|
||||
printf("\
|
||||
" PACKAGE_NAME " (%s) %s\n\
|
||||
/* TRANSLATORS: "John Zaitseff" [IPA d͡ʒɒn ˈzaɪ̯t͡səf] is the proper
|
||||
name of the author. The IPA pronunciation in this comment is in
|
||||
UTF-8 encoding. */
|
||||
printf(_("\
|
||||
Star Traders (%s) %s\n\
|
||||
Copyright (C) %s, John Zaitseff.\n\
|
||||
\n\
|
||||
Star Traders is a simple game of interstellar trading, where the object\n\
|
||||
@ -286,7 +293,7 @@ This program is free software that is distributed under the terms of the\n\
|
||||
GNU General Public License, version 3 or later. You are welcome to\n\
|
||||
modify and/or distribute it under certain conditions. This program has\n\
|
||||
NO WARRANTY, to the extent permitted by law; see the License for details.\n\
|
||||
", program_name(), PACKAGE_VERSION, "1990-2011");
|
||||
"), program_name, PACKAGE_VERSION, "1990-2011");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@ -297,39 +304,49 @@ NO WARRANTY, to the extent permitted by law; see the License for details.\n\
|
||||
|
||||
void show_usage (int status)
|
||||
{
|
||||
const char *pn = program_name();
|
||||
|
||||
|
||||
if (status != EXIT_SUCCESS) {
|
||||
fprintf(stderr, "%s: Try `%s --help' for more information.\n",
|
||||
pn, pn);
|
||||
fprintf(stderr, _("%s: Try `%s --help' for more information.\n"),
|
||||
program_name, program_name);
|
||||
} else {
|
||||
printf("Usage: %s [OPTION ...] [GAME]\n", pn);
|
||||
printf("\
|
||||
printf(_("Usage: %s [OPTION ...] [GAME]\n"), program_name);
|
||||
printf(_("\
|
||||
Play Star Traders, a simple game of interstellar trading.\n\n\
|
||||
");
|
||||
printf("\
|
||||
"));
|
||||
printf(_("\
|
||||
Options:\n\
|
||||
-V, --version output version information and exit\n\
|
||||
-h, --help display this help and exit\n\
|
||||
--no-color don't use colour for displaying text\n\
|
||||
--no-color don't use color for displaying text\n\
|
||||
--max-turn=NUM set the number of turns to NUM\n\n\
|
||||
");
|
||||
printf("\
|
||||
"));
|
||||
printf(_("\
|
||||
If GAME is specified as a number between 1 and 9, load and continue\n\
|
||||
playing that game. If GAME is not specified, start a new game.\n\n\
|
||||
");
|
||||
"));
|
||||
|
||||
#ifdef PACKAGE_AUTHOR
|
||||
printf("Report bugs to %s <%s>.\n", PACKAGE_AUTHOR, PACKAGE_BUGREPORT);
|
||||
/* TRANSLATORS: The first %s is the proper name of the package
|
||||
author, John Zaitseff [IPA d͡ʒɒn ˈzaɪ̯t͡səf]; the second %s is
|
||||
the e-mail address for reporting bugs. Please add ANOTHER
|
||||
line with the (translated) text "Report translation bugs to
|
||||
<ADDRESS>\n", with ADDRESS replaced with either an e-mail
|
||||
address or web URL for reporting bugs in your translation. */
|
||||
printf(_("Report bugs to %s <%s>.\n"), PACKAGE_AUTHOR, PACKAGE_BUGREPORT);
|
||||
#else
|
||||
printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
|
||||
/* TRANSLATORS: %s is the e-mail address for reporting bugs. As
|
||||
with the previous string, please add ANOTHER line with the
|
||||
(translated) text "Report translation bugs to <ADDRESS>\n",
|
||||
with ADDRESS replaced with either an e-mail address or web URL
|
||||
for reporting bugs in your translation. */
|
||||
printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
|
||||
#endif
|
||||
#ifdef PACKAGE_PACKAGER_BUG_REPORTS
|
||||
printf("Report %s bugs to <%s>.\n", PACKAGE_PACKAGER, PACKAGE_PACKAGER_BUG_REPORTS);
|
||||
/* TRANSLATORS: The first %s is for packagers and may be
|
||||
something like "Debian". */
|
||||
printf(_("Report %s bugs to <%s>.\n"), PACKAGE_PACKAGER, PACKAGE_PACKAGER_BUG_REPORTS);
|
||||
#endif
|
||||
#ifdef PACKAGE_URL
|
||||
printf(PACKAGE_NAME " home page: <%s>.\n", PACKAGE_URL);
|
||||
printf(_("Star Traders home page: <%s>.\n"), PACKAGE_URL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
12
src/trader.h
12
src/trader.h
@ -52,11 +52,17 @@
|
||||
* Global definitions *
|
||||
************************************************************************/
|
||||
|
||||
#define GAME_FILE_HEADER PACKAGE_NAME " Saved Game"
|
||||
#define GAME_FILE_API_VERSION "7.0" // For game loads and saves
|
||||
#define GAME_FILE_SENTINEL 42 // End of game file sentinel
|
||||
#define GAME_FILE_HEADER "Star Traders Saved Game"
|
||||
#define GAME_FILE_API_VERSION "File API 7.2" // For game loads and saves
|
||||
#define GAME_FILE_SENTINEL 42 // End of game file sentinel
|
||||
|
||||
#ifdef USE_UTF8_GAME_FILE
|
||||
# define GAME_FILE_CHARSET "UTF-8" // For strings in game file
|
||||
# define GAME_FILE_TRANSLIT "//TRANSLIT" // Transliterate (GNU libiconv)
|
||||
#endif
|
||||
|
||||
#define BUFSIZE 1024 // For various string buffers
|
||||
#define BIGBUFSIZE 2048 // For buffers known to be larger
|
||||
|
||||
|
||||
#endif /* included_TRADER_H */
|
||||
|
327
src/utils.c
327
src/utils.c
@ -35,9 +35,19 @@
|
||||
* Global variable definitions *
|
||||
************************************************************************/
|
||||
|
||||
const char *program_name = NULL; // Canonical program name
|
||||
|
||||
|
||||
// Global copy, suitably modified, of localeconv() information
|
||||
struct lconv lconvinfo;
|
||||
|
||||
// localeconv() information, converted to wide strings
|
||||
wchar_t *decimal_point; // Locale's radix character
|
||||
wchar_t *thousands_sep; // Locale's thousands separator
|
||||
wchar_t *currency_symbol; // Local currency symbol
|
||||
wchar_t *mon_decimal_point; // Local monetary radix character
|
||||
wchar_t *mon_thousands_sep; // Local monetary thousands separator
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Module-specific constants and variable definitions *
|
||||
@ -57,11 +67,9 @@ struct lconv lconvinfo;
|
||||
* Module-specific variables *
|
||||
************************************************************************/
|
||||
|
||||
static char *program_name_str = NULL; // Canonical program name
|
||||
static char *home_directory_str = NULL; // Full pathname to home
|
||||
static char *data_directory_str = NULL; // Writable data dir pathname
|
||||
|
||||
static char *current_mon_locale; // As returned by setlocale()
|
||||
static bool add_currency_symbol = false; // Do we need to add "$"?
|
||||
|
||||
|
||||
@ -73,37 +81,27 @@ static bool add_currency_symbol = false; // Do we need to add "$"?
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// init_program_name: Make the program name "canonical"
|
||||
// init_program_name: Make the program name canonical
|
||||
|
||||
void init_program_name (char *argv[])
|
||||
void init_program_name (const char *argv0)
|
||||
{
|
||||
if (argv == NULL || argv[0] == NULL || *argv[0] == '\0') {
|
||||
program_name_str = PACKAGE;
|
||||
/* This implementation assumes a POSIX environment with an ASCII-safe
|
||||
character encoding (such as ASCII or UTF-8). */
|
||||
|
||||
if (argv0 == NULL || *argv0 == '\0') {
|
||||
program_name = PACKAGE;
|
||||
} else {
|
||||
char *p = strrchr(argv[0], '/');
|
||||
char *p = strrchr(argv0, '/');
|
||||
|
||||
if (p != NULL && *++p != '\0') {
|
||||
argv[0] = p;
|
||||
program_name = xstrdup(p);
|
||||
} else {
|
||||
program_name = xstrdup(argv0);
|
||||
}
|
||||
|
||||
program_name_str = argv[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// program_name: Return the canonical program name
|
||||
|
||||
const char *program_name (void)
|
||||
{
|
||||
if (program_name_str == NULL) {
|
||||
init_program_name(NULL);
|
||||
}
|
||||
|
||||
return program_name_str;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// home_directory: Return home directory pathname
|
||||
|
||||
@ -111,10 +109,10 @@ const char *home_directory (void)
|
||||
{
|
||||
if (home_directory_str == NULL) {
|
||||
// Use the HOME environment variable where possible
|
||||
char *home = getenv("HOME");
|
||||
const char *home = getenv("HOME");
|
||||
|
||||
if (home != NULL && *home != '\0') {
|
||||
home_directory_str = strdup(home);
|
||||
home_directory_str = xstrdup(home);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,20 +127,19 @@ const char *data_directory (void)
|
||||
{
|
||||
/* This implementation assumes a POSIX environment by using "/" as
|
||||
the directory separator. It also assumes a dot-starting directory
|
||||
name is permissible (again, true on POSIX systems) */
|
||||
name is permissible (again, true on POSIX systems) and that the
|
||||
character encoding is ASCII-safe. */
|
||||
|
||||
if (data_directory_str == NULL) {
|
||||
const char *name = program_name();
|
||||
const char *home = home_directory();
|
||||
|
||||
if (name != NULL && home != NULL) {
|
||||
char *p = malloc(strlen(home) + strlen(name) + 3);
|
||||
if (p != NULL) {
|
||||
strcpy(p, home);
|
||||
strcat(p, "/.");
|
||||
strcat(p, name);
|
||||
data_directory_str = p;
|
||||
}
|
||||
if (program_name != NULL && home != NULL) {
|
||||
char *p = xmalloc(strlen(home) + strlen(program_name) + 3);
|
||||
|
||||
strcpy(p, home);
|
||||
strcat(p, "/.");
|
||||
strcat(p, program_name);
|
||||
data_directory_str = p;
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,8 +152,8 @@ const char *data_directory (void)
|
||||
|
||||
char *game_filename (int gamenum)
|
||||
{
|
||||
/* This implementation assumes a POSIX environment by using "/" as
|
||||
the directory separator */
|
||||
/* This implementation assumes a POSIX environment and an ASCII-safe
|
||||
character encoding. */
|
||||
|
||||
char buf[GAME_FILENAME_BUFSIZE]; // Buffer for part of filename
|
||||
const char *dd; // Data directory
|
||||
@ -170,20 +167,13 @@ char *game_filename (int gamenum)
|
||||
snprintf(buf, GAME_FILENAME_BUFSIZE, GAME_FILENAME_PROTO, gamenum);
|
||||
|
||||
if (dd == NULL) {
|
||||
char *p = malloc(strlen(buf) + 1);
|
||||
|
||||
if (p != NULL) {
|
||||
strcpy(p, buf);
|
||||
}
|
||||
return p;
|
||||
return xstrdup(buf);
|
||||
} else {
|
||||
char *p = malloc(strlen(dd) + strlen(buf) + 2);
|
||||
char *p = xmalloc(strlen(dd) + strlen(buf) + 2);
|
||||
|
||||
if (p != NULL) {
|
||||
strcpy(p, dd);
|
||||
strcat(p, "/");
|
||||
strcat(p, buf);
|
||||
}
|
||||
strcpy(p, dd);
|
||||
strcat(p, "/");
|
||||
strcat(p, buf);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@ -206,7 +196,7 @@ void err_exit (const char *restrict format, ...)
|
||||
|
||||
end_screen();
|
||||
|
||||
fprintf(stderr, "%s: ", program_name());
|
||||
fprintf(stderr, _("%s: "), program_name);
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
@ -227,12 +217,12 @@ void errno_exit (const char *restrict format, ...)
|
||||
|
||||
end_screen();
|
||||
|
||||
fprintf(stderr, "%s: ", program_name());
|
||||
fprintf(stderr, _("%s: "), program_name);
|
||||
if (format != NULL) {
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
fputs(": ", stderr);
|
||||
fputs(_(": "), stderr);
|
||||
}
|
||||
fprintf(stderr, "%s\n", strerror(saved_errno));
|
||||
|
||||
@ -245,7 +235,7 @@ void errno_exit (const char *restrict format, ...)
|
||||
|
||||
void err_exit_nomem (void)
|
||||
{
|
||||
err_exit("out of memory");
|
||||
err_exit(_("out of memory"));
|
||||
}
|
||||
|
||||
|
||||
@ -306,22 +296,27 @@ extern int randi (int limit)
|
||||
|
||||
void init_locale (void)
|
||||
{
|
||||
char *cur, *cloc;
|
||||
struct lconv *lc;
|
||||
wchar_t *buf;
|
||||
|
||||
|
||||
current_mon_locale = setlocale(LC_MONETARY, NULL);
|
||||
cur = xstrdup(setlocale(LC_MONETARY, NULL));
|
||||
lc = localeconv();
|
||||
|
||||
assert(current_mon_locale != NULL);
|
||||
assert(lc != NULL);
|
||||
|
||||
lconvinfo = *lc;
|
||||
|
||||
/* Are we in the POSIX locale? This test may not be portable as the
|
||||
string returned by setlocale() is supposed to be opaque. */
|
||||
add_currency_symbol = false;
|
||||
if (strcmp(current_mon_locale, "POSIX") == 0
|
||||
|| strcmp(current_mon_locale, "C") == 0) {
|
||||
|
||||
/* Are we in the POSIX locale? The string returned by setlocale() is
|
||||
supposed to be opaque, but in practise is not. To be on the safe
|
||||
side, we explicitly set the locale to "C", then test the returned
|
||||
value of that, too. */
|
||||
cloc = setlocale(LC_MONETARY, "C");
|
||||
if ( strcmp(cur, cloc) == 0
|
||||
|| strcmp(cur, "POSIX") == 0 || strcmp(cur, "C") == 0
|
||||
|| strcmp(cur, "C.UTF-8") == 0 || strcmp(cur, "C.utf8") == 0) {
|
||||
|
||||
add_currency_symbol = true;
|
||||
lconvinfo.currency_symbol = MOD_POSIX_CURRENCY_SYMBOL;
|
||||
@ -329,31 +324,56 @@ void init_locale (void)
|
||||
lconvinfo.p_cs_precedes = MOD_POSIX_P_CS_PRECEDES;
|
||||
lconvinfo.p_sep_by_space = MOD_POSIX_P_SEP_BY_SPACE;
|
||||
}
|
||||
|
||||
// Convert localeconv() information to wide strings
|
||||
|
||||
buf = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||
|
||||
xmbstowcs(buf, lconvinfo.decimal_point, BUFSIZE);
|
||||
decimal_point = xwcsdup(buf);
|
||||
|
||||
xmbstowcs(buf, lconvinfo.thousands_sep, BUFSIZE);
|
||||
thousands_sep = xwcsdup(buf);
|
||||
|
||||
xmbstowcs(buf, lconvinfo.currency_symbol, BUFSIZE);
|
||||
currency_symbol = xwcsdup(buf);
|
||||
|
||||
xmbstowcs(buf, lconvinfo.mon_decimal_point, BUFSIZE);
|
||||
mon_decimal_point = xwcsdup(buf);
|
||||
|
||||
xmbstowcs(buf, lconvinfo.mon_thousands_sep, BUFSIZE);
|
||||
mon_thousands_sep = xwcsdup(buf);
|
||||
|
||||
free(buf);
|
||||
|
||||
setlocale(LC_MONETARY, cur);
|
||||
free(cur);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// l_strfmon: Convert monetary value to a string
|
||||
|
||||
ssize_t l_strfmon (char *restrict s, size_t maxsize,
|
||||
ssize_t l_strfmon (char *restrict buf, size_t maxsize,
|
||||
const char *restrict format, double val)
|
||||
{
|
||||
/* The current implementation assumes MOD_POSIX_P_CS_PRECEDES is 1
|
||||
(currency symbol precedes value) and that MOD_POSIX_P_SEP_BY_SPACE
|
||||
is 0 (no space separates currency symbol and value). It does,
|
||||
however, handle currency symbols of length > 1 */
|
||||
however, handle currency symbols of length > 1. */
|
||||
|
||||
assert(MOD_POSIX_P_CS_PRECEDES == 1);
|
||||
assert(MOD_POSIX_P_SEP_BY_SPACE == 0);
|
||||
|
||||
ssize_t ret = strfmon(s, maxsize, format, val);
|
||||
ssize_t ret = strfmon(buf, maxsize, format, val);
|
||||
|
||||
if (ret > 0 && add_currency_symbol) {
|
||||
if (strstr(format, "!") == NULL) {
|
||||
/* Insert lconvinfo.currency_symbol to s.
|
||||
|
||||
NB: add_currecy_symbol == true assumes POSIX locale:
|
||||
single-byte strings are in effect, so strlen(), etc, work
|
||||
correctly. */
|
||||
NB: add_currecy_symbol == true assumes a POSIX locale and
|
||||
that the character encoding is ASCII-safe (such as by
|
||||
being ASCII itself, or UTF-8). */
|
||||
const char *sym = lconvinfo.currency_symbol;
|
||||
int symlen = strlen(sym);
|
||||
char *p;
|
||||
@ -362,7 +382,7 @@ ssize_t l_strfmon (char *restrict s, size_t maxsize,
|
||||
assert(maxsize > (unsigned int) symlen);
|
||||
|
||||
// Count number of leading spaces
|
||||
for (p = s, spc = 0; *p == ' '; p++, spc++)
|
||||
for (p = buf, spc = 0; *p == ' '; p++, spc++)
|
||||
;
|
||||
|
||||
if (symlen <= spc) {
|
||||
@ -374,12 +394,12 @@ ssize_t l_strfmon (char *restrict s, size_t maxsize,
|
||||
} else {
|
||||
// Make space for currency symbol, then copy it
|
||||
|
||||
memmove(s + symlen - spc, s, maxsize - (symlen - spc));
|
||||
s[maxsize - 1] = '\0';
|
||||
memmove(buf + symlen - spc, buf, maxsize - (symlen - spc));
|
||||
buf[maxsize - 1] = '\0';
|
||||
|
||||
for ( ; *sym != '\0'; sym++, s++) {
|
||||
for ( ; *sym != '\0'; sym++, buf++) {
|
||||
// Make sure terminating NUL character is NOT copied!
|
||||
*s = *sym;
|
||||
*buf = *sym;
|
||||
}
|
||||
|
||||
ret = MIN((unsigned int) ret + symlen - spc, maxsize - 1);
|
||||
@ -437,5 +457,170 @@ char *unscramble (int key, char *restrict buf, int bufsize)
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Miscellaneous function definitions *
|
||||
************************************************************************/
|
||||
|
||||
// These functions are documented in the file "utils.h"
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// xmalloc: Allocate a new block of memory, with checking
|
||||
|
||||
void *xmalloc (size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
|
||||
if (size < 1)
|
||||
size = 1;
|
||||
|
||||
p = malloc(size);
|
||||
if (p == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// xstrdup: Duplicate a string, with checking
|
||||
|
||||
char *xstrdup (const char *str)
|
||||
{
|
||||
char *s;
|
||||
|
||||
|
||||
if (str == NULL)
|
||||
str = "";
|
||||
|
||||
s = strdup(str);
|
||||
if (s == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// chstrdup: Duplicate a chtype buffer
|
||||
|
||||
chtype *xchstrdup (const chtype *restrict chstr)
|
||||
{
|
||||
const chtype *p;
|
||||
int len;
|
||||
chtype *ret;
|
||||
|
||||
|
||||
// Determine chstr length, including ending NUL
|
||||
for (len = 1, p = chstr; *p != '\0'; p++, len++)
|
||||
;
|
||||
|
||||
ret = xmalloc(len * sizeof(chtype));
|
||||
memcpy(ret, chstr, len * sizeof(chtype));
|
||||
ret[len - 1] = '\0'; // Terminating NUL, just in case not present
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// xwcsdup: Duplicate a wide-character string, with checking
|
||||
|
||||
wchar_t *xwcsdup (const wchar_t *str)
|
||||
{
|
||||
wchar_t *s;
|
||||
|
||||
|
||||
if (str == NULL)
|
||||
str = L"";
|
||||
|
||||
s = wcsdup(str);
|
||||
if (s == NULL) {
|
||||
err_exit_nomem();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// xmbstowcs: Convert a multibyte string to a wide-character string
|
||||
|
||||
size_t xmbstowcs (wchar_t *restrict dest, const char *restrict src, size_t len)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(len > 0);
|
||||
|
||||
char *s = xstrdup(src);
|
||||
size_t n;
|
||||
|
||||
while (true) {
|
||||
mbstate_t mbstate;
|
||||
char *p = s;
|
||||
|
||||
memset(&mbstate, 0, sizeof(mbstate));
|
||||
if ((n = mbsrtowcs(dest, (const char **) &p, len, &mbstate))
|
||||
== (size_t) -1) {
|
||||
if (errno == EILSEQ) {
|
||||
// Illegal sequence detected: replace it and try again
|
||||
*p = EILSEQ_REPL;
|
||||
} else {
|
||||
errno_exit(_("xmbstowcs: `%s'"), src);
|
||||
}
|
||||
} else if (p != NULL) {
|
||||
// Multibyte string was too long: truncate dest
|
||||
dest[len - 1] = L'\0';
|
||||
n--;
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(s);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// xwcrtomb: Convert a wide character to a multibyte sequence
|
||||
|
||||
size_t xwcrtomb (char *restrict dest, wchar_t wc, mbstate_t *restrict mbstate)
|
||||
{
|
||||
mbstate_t mbcopy;
|
||||
size_t n;
|
||||
|
||||
|
||||
assert(dest != NULL);
|
||||
assert(mbstate != NULL);
|
||||
|
||||
memcpy(&mbcopy, mbstate, sizeof(mbcopy));
|
||||
|
||||
if ((n = wcrtomb(dest, wc, &mbcopy)) == (size_t) -1) {
|
||||
if (errno == EILSEQ) {
|
||||
/* wc cannot be represented in current locale.
|
||||
|
||||
Note that the shift state in mbcopy is now undefined.
|
||||
Hence, restore the original, try to store an ending shift
|
||||
sequence, then EILSEQ_REPL. */
|
||||
memcpy(&mbcopy, mbstate, sizeof(mbcopy));
|
||||
if ((n = wcrtomb(dest, L'\0', &mbcopy)) == (size_t) -1) {
|
||||
errno_exit(_("xwcrtomb: NUL"));
|
||||
}
|
||||
dest[n] = EILSEQ_REPL;
|
||||
dest[n++] = '\0';
|
||||
} else {
|
||||
errno_exit(_("xwcrtomb: `%lc'"), wc);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(mbstate, &mbcopy, sizeof(mbcopy));
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// End of file
|
||||
|
140
src/utils.h
140
src/utils.h
@ -42,42 +42,43 @@
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
|
||||
#define EILSEQ_REPL '?' // Illegal character sequence replacement
|
||||
#define EILSEQ_REPL_WC L'?' // ... wide character version
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Global variable declarations *
|
||||
************************************************************************/
|
||||
|
||||
extern const char *program_name; // Canonical program name
|
||||
|
||||
|
||||
// Global copy, suitably modified, of localeconv() information
|
||||
extern struct lconv lconvinfo;
|
||||
|
||||
// localeconv() information, converted to wide strings
|
||||
extern wchar_t *decimal_point; // Locale's radix character
|
||||
extern wchar_t *thousands_sep; // Locale's thousands separator
|
||||
extern wchar_t *currency_symbol; // Local currency symbol
|
||||
extern wchar_t *mon_decimal_point; // Local monetary radix character
|
||||
extern wchar_t *mon_thousands_sep; // Local monetary thousands separator
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Initialisation and environment function prototypes *
|
||||
************************************************************************/
|
||||
|
||||
/*
|
||||
Function: init_program_name - Make the program name "canonical"
|
||||
Parameters: argv - Same as passed to main()
|
||||
Function: init_program_name - Make the program name canonical
|
||||
Parameters: argv0 - Same as passed to main() as argv[0]
|
||||
Returns: (nothing)
|
||||
|
||||
This function modifies the argv[0] pointer to eliminate any leading
|
||||
This function modifies the argv0 pointer to eliminate any leading
|
||||
pathname (directory) components from the program name, leaving just the
|
||||
basename of the program. It also saves a copy that can be accessed via
|
||||
the program_name() function.
|
||||
the program_name global variable.
|
||||
*/
|
||||
extern void init_program_name (char *argv[]);
|
||||
|
||||
|
||||
/*
|
||||
Function: program_name - Return the canonical program name
|
||||
Parameters: (none)
|
||||
Returns: const char * - Pointer to program name
|
||||
|
||||
This function returns the canonical program name (the program name as
|
||||
invoked on the command line, without any leading pathname components).
|
||||
NULL should never be returned; however, init_program_name() SHOULD be
|
||||
called before using this function.
|
||||
*/
|
||||
extern const char *program_name (void);
|
||||
extern void init_program_name (const char *argv0);
|
||||
|
||||
|
||||
/*
|
||||
@ -100,7 +101,7 @@ extern const char *home_directory (void);
|
||||
|
||||
This function returns the full pathname to a potentially-writable
|
||||
subdirectory within the user's home directory. Essentially, this
|
||||
function returns home_directory() + "/." + program_name(). Note that
|
||||
function returns home_directory() + "/." + program_name. Note that
|
||||
this path is NOT created by this function, nor is the writability of
|
||||
this path checked. NULL is returned if this path cannot be determined.
|
||||
*/
|
||||
@ -226,18 +227,19 @@ extern int randi (int limit);
|
||||
Parameters: (none)
|
||||
Returns: (nothing)
|
||||
|
||||
This function initialises the global variable lconvinfo with values
|
||||
suitable for this program. In particular, if the POSIX or C locale is
|
||||
in effect, the currency_symbol and frac_digits members are updated to
|
||||
be something reasonable. This function must be called before using
|
||||
localeconf_info.
|
||||
This function initialises the global variable lconvinfo, as well as
|
||||
decimal_point, thousands_sep, currency_symbol, mon_decimal_point and
|
||||
mon_thousands_sep, with values suitable for this program. In
|
||||
particular, if the POSIX or C locale is in effect, the currency_symbol
|
||||
and frac_digits members of lconvinfo are updated to be something
|
||||
reasonable. This function must be called before using localeconf_info.
|
||||
*/
|
||||
extern void init_locale (void);
|
||||
|
||||
|
||||
/*
|
||||
Function: l_strfmon - Convert monetary value to a string
|
||||
Parameters: s - Buffer to receive result
|
||||
Parameters: buf - Buffer to receive result
|
||||
maxsize - Maximum size of buffer
|
||||
format - strfmon() format to use
|
||||
val - Monetary value to convert
|
||||
@ -249,7 +251,7 @@ extern void init_locale (void);
|
||||
function overcomes the limitation that the POSIX locale does not define
|
||||
anything for localeconv()->currency_symbol.
|
||||
*/
|
||||
extern ssize_t l_strfmon (char *restrict s, size_t maxsize,
|
||||
extern ssize_t l_strfmon (char *restrict buf, size_t maxsize,
|
||||
const char *restrict format, double val);
|
||||
|
||||
|
||||
@ -300,4 +302,90 @@ extern char *scramble (int key, char *restrict buf, int bufsize);
|
||||
extern char *unscramble (int key, char *restrict buf, int bufsize);
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Miscellaneous function prototypes *
|
||||
************************************************************************/
|
||||
|
||||
/*
|
||||
Function: xmalloc - Allocate a new block of memory, with checking
|
||||
Parameters: size - Size of new block of memory in bytes
|
||||
Returns: void * - Pointer to new block of memory
|
||||
|
||||
This wrapper function allocates a new block of memory by calling
|
||||
malloc(), then checks if a NULL pointer has been returned. If so, the
|
||||
program terminates with an "Out of memory" error.
|
||||
*/
|
||||
extern void *xmalloc (size_t size);
|
||||
|
||||
|
||||
/*
|
||||
Function: xstrdup - Duplicate a string, with checking
|
||||
Parameters: str - String to duplicate
|
||||
Returns: char * - Pointer to new string, allocated with malloc()
|
||||
|
||||
This wrapper function duplicates a string by calling strdup(), then
|
||||
checks if a NULL pointer has been returned. If so, the program
|
||||
terminates with an "Out of memory" error.
|
||||
*/
|
||||
extern char *xstrdup (const char *str);
|
||||
|
||||
|
||||
/*
|
||||
Function: xchstrdup - Duplicate a chtype string
|
||||
Parameters: chstr - String to duplicate
|
||||
Returns: chtype * - Pointer to new (duplicated) string
|
||||
|
||||
This function returns a new string of type chtype * that contains a
|
||||
copy of the string in chstr. No errors are returned: if sufficient
|
||||
memory is not available, the program terminates with an "Out of memory"
|
||||
message.
|
||||
*/
|
||||
extern chtype *xchstrdup (const chtype *restrict chstr);
|
||||
|
||||
|
||||
/*
|
||||
Function: xwcsdup - Duplicate a wide-character string, with checking
|
||||
Parameters: str - String to duplicate
|
||||
Returns: wchar_t * - Pointer to new string, allocated with malloc()
|
||||
|
||||
This wrapper function duplicates a string by calling wcsdup(), then
|
||||
checks if a NULL pointer has been returned. If so, the program
|
||||
terminates with an "Out of memory" error.
|
||||
*/
|
||||
extern wchar_t *xwcsdup (const wchar_t *str);
|
||||
|
||||
|
||||
/*
|
||||
Function: xmbstowcs - Convert a multibyte string to a wide-character string
|
||||
Parameters: dest - Location of wide-string buffer
|
||||
src - String to convert
|
||||
len - Size of dest, in multiples of wchar_t
|
||||
Returns: size_t - Number of characters placed in dest (excluding NUL)
|
||||
|
||||
This wrapper function converts a multibyte string to a wide-character
|
||||
one by calling mbsrtowcs() continually until the whole string is
|
||||
converted. If any illegal sequences are present, they are converted to
|
||||
the EILSEQ_REPL character. If the destination buffer is too small, the
|
||||
string is truncated.
|
||||
*/
|
||||
extern size_t xmbstowcs (wchar_t *restrict dest, const char *restrict src,
|
||||
size_t len);
|
||||
|
||||
|
||||
/*
|
||||
Function: xwcrtomb - Convert a wide character to a multibyte sequence
|
||||
Parameters: dest - Location of multibyte buffer (size >= MB_CUR_MAX + 1)
|
||||
wc - Character to convert
|
||||
mbstate - Pointer to current multibyte shift state
|
||||
Returns: size_t - Number of characters placed in dest
|
||||
|
||||
This wrapper function converts the wide character in wc (which may be
|
||||
NUL) by calling wcrtomb(). If wc cannot be represented in the current
|
||||
locale, EILSEQ_REPL is used instead (with any characters needed to move
|
||||
to an initial shift state prior to EILSEQ_REPL).
|
||||
*/
|
||||
extern size_t xwcrtomb (char *restrict dest, wchar_t wc,
|
||||
mbstate_t *restrict mbstate);
|
||||
|
||||
|
||||
#endif /* included_UTILS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user