tThe directory structure is now reorganised; the separate clients, and the gtkport stuff, have their own directories. Stub functions for missing clients have been added to dopewars.c. - vaccinewars - be a doctor and try to vaccinate the world (HTM) git clone git://src.adamsgaard.dk/vaccinewars (DIR) Log (DIR) Files (DIR) Refs (DIR) README (DIR) LICENSE --- (DIR) commit ef90a6dc064a2a31b8bdbc0c52a215da6d058623 (DIR) parent a449a445fedb565c9b1096a5622b3e4fb33351c3 (HTM) Author: Ben Webb <ben@salilab.org> Date: Mon, 25 Feb 2002 19:32:03 +0000 The directory structure is now reorganised; the separate clients, and the gtkport stuff, have their own directories. Stub functions for missing clients have been added to dopewars.c. Diffstat: M Makefile.in | 8 +++----- M aclocal.m4 | 101 +++++++++++++------------------ M configure | 466 +++++++++++++++++-------------- M configure.in | 74 ++++++++++++++++++++----------- M doc/Makefile.in | 11 ++++++----- M src/Makefile.am | 30 ++++++++++++++++++++++++------ M src/Makefile.in | 163 ++++++++++++++++++++++++------- D src/curses_client.c | 2425 ------------------------------- A src/curses_client/Makefile.am | 6 ++++++ A src/curses_client/Makefile.in | 325 +++++++++++++++++++++++++++++++ A src/curses_client/curses_client.c | 2409 +++++++++++++++++++++++++++++++ R src/curses_client.h -> src/curses_… | 0 M src/dopewars.c | 46 +++++++++++++++++++++++++++++-- M src/dopewars.h | 14 ++++++++++++++ D src/gtk_client.c | 3930 ------------------------------- D src/gtk_client.h | 40 ------------------------------- A src/gtkport/Makefile.am | 6 ++++++ A src/gtkport/Makefile.in | 325 +++++++++++++++++++++++++++++++ R src/gtkport.c -> src/gtkport/gtkpo… | 0 R src/gtkport.h -> src/gtkport/gtkpo… | 0 A src/gui_client/Makefile.am | 6 ++++++ A src/gui_client/Makefile.in | 325 +++++++++++++++++++++++++++++++ A src/gui_client/gtk_client.c | 3910 +++++++++++++++++++++++++++++++ A src/gui_client/gtk_client.h | 41 +++++++++++++++++++++++++++++++ M src/winmain.c | 43 +++++++++++++++++++++---------- 25 files changed, 7948 insertions(+), 6756 deletions(-) --- (DIR) diff --git a/Makefile.in b/Makefile.in t@@ -1,6 +1,6 @@ -# Makefile.in generated automatically by automake 1.4 from Makefile.am +# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am -# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. t@@ -71,8 +71,6 @@ GLIB_CONFIG = @GLIB_CONFIG@ GLIB_LIBS = @GLIB_LIBS@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ -GTKPORT_C = @GTKPORT_C@ -GTKPORT_O = @GTKPORT_O@ GTK_CFLAGS = @GTK_CFLAGS@ GTK_CONFIG = @GTK_CONFIG@ GTK_LIBS = @GTK_LIBS@ t@@ -194,7 +192,7 @@ maintainer-clean-recursive: dot_seen=no; \ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ rev="$$subdir $$rev"; \ - test "$$subdir" = "." && dot_seen=yes; \ + test "$$subdir" != "." || dot_seen=yes; \ done; \ test "$$dot_seen" = "no" && rev=". $$rev"; \ target=`echo $@ | sed s/-recursive//`; \ (DIR) diff --git a/aclocal.m4 b/aclocal.m4 t@@ -1,6 +1,6 @@ -dnl aclocal.m4 generated automatically by aclocal 1.4 +dnl aclocal.m4 generated automatically by aclocal 1.4-p5 -dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. t@@ -19,7 +19,7 @@ dnl PARTICULAR PURPOSE. dnl Usage: dnl AM_INIT_AUTOMAKE(package,version, [no-define]) -AC_DEFUN(AM_INIT_AUTOMAKE, +AC_DEFUN([AM_INIT_AUTOMAKE], [AC_REQUIRE([AC_PROG_INSTALL]) PACKAGE=[$1] AC_SUBST(PACKAGE) t@@ -47,7 +47,7 @@ AC_REQUIRE([AC_PROG_MAKE_SET])]) # Check to make sure that the build environment is sane. # -AC_DEFUN(AM_SANITY_CHECK, +AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 t@@ -88,7 +88,7 @@ AC_MSG_RESULT(yes)]) dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) dnl The program must properly implement --version. -AC_DEFUN(AM_MISSING_PROG, +AC_DEFUN([AM_MISSING_PROG], [AC_MSG_CHECKING(for working $2) # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. t@@ -104,7 +104,7 @@ AC_SUBST($1)]) # Like AC_CONFIG_HEADER, but automatically create stamp file. -AC_DEFUN(AM_CONFIG_HEADER, +AC_DEFUN([AM_CONFIG_HEADER], [AC_PREREQ([2.12]) AC_CONFIG_HEADER([$1]) dnl When config.status generates a header, we must update the stamp-h file. t@@ -539,15 +539,11 @@ main () # Ulrich Drepper <drepper@cygnus.com>, 1995. # # 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 or the GNU Library General Public License but which still want -# to provide support for the GNU gettext functionality. -# Please note that the actual code of the GNU gettext library is covered -# by the GNU Library General Public License, and the rest of the GNU -# gettext package package is covered by the GNU General Public License. -# They are *not* in the public domain. +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. -# serial 10 +# serial 9 dnl Usage: AM_WITH_NLS([TOOLSYMBOL], [NEEDSYMBOL], [LIBDIR]). dnl If TOOLSYMBOL is specified and is 'use-libtool', then a libtool library t@@ -658,14 +654,14 @@ return (int) gettext ("")]ifelse([$2], need-ngettext, [ + (int) ngettext ("", "" AC_CHECK_FUNCS(dcgettext) LIBS="$gt_save_LIBS" - dnl Search for GNU msgfmt in the PATH. AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, - [$ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1], :) - AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl + if test "$MSGFMT" != "no"; then + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + fi - dnl Search for GNU xgettext in the PATH. AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, - [$ac_dir/$ac_word --omit-header /dev/null >/dev/null 2>&1], :) + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) CATOBJEXT=.gmo fi t@@ -682,10 +678,10 @@ return (int) gettext ("")]ifelse([$2], need-ngettext, [ + (int) ngettext ("", "" dnl Mark actions used to generate GNU NLS library. INTLOBJS="\$(GETTOBJS)" AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, - [$ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1], :) + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], msgfmt) AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, - [$ac_dir/$ac_word --omit-header /dev/null >/dev/null 2>&1], :) + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) AC_SUBST(MSGFMT) BUILD_INCLUDED_LIBINTL=yes USE_INCLUDED_LIBINTL=yes t@@ -694,26 +690,11 @@ return (int) gettext ("")]ifelse([$2], need-ngettext, [ + (int) ngettext ("", "" LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` fi - dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. - dnl Test whether we really found GNU msgfmt. - if test "$GMSGFMT" != ":"; then - dnl If it is no GNU msgfmt we define it as : so that the - dnl Makefiles still can work. - if $GMSGFMT --statistics /dev/null >/dev/null 2>&1; then - : ; - else - AC_MSG_RESULT( - [found msgfmt program is not GNU msgfmt; ignore it]) - GMSGFMT=":" - fi - fi - - dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. dnl Test whether we really found GNU xgettext. if test "$XGETTEXT" != ":"; then dnl If it is no GNU xgettext we define it as : so that the dnl Makefiles still can work. - if $XGETTEXT --omit-header /dev/null >/dev/null 2>&1; then + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then : ; else AC_MSG_RESULT( t@@ -737,9 +718,6 @@ return (int) gettext ("")]ifelse([$2], need-ngettext, [ + (int) ngettext ("", "" ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` - # In autoconf-2.13 it is called $ac_given_srcdir. - # In autoconf-2.50 it is called $srcdir. - test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; t@@ -747,9 +725,9 @@ return (int) gettext ("")]ifelse([$2], need-ngettext, [ + (int) ngettext ("", "" esac if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then rm -f "$ac_dir/POTFILES" - test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + echo creating "$ac_dir/POTFILES" sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," -e "\$s/\(.*\) \\\\/\1/" < "$ac_given_srcdir/$ac_dir/POTFILES.in" > "$ac_dir/POTFILES" - test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + echo creating "$ac_dir/Makefile" sed -e "/POTFILES =/r $ac_dir/POTFILES" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" fi ;; t@@ -780,7 +758,7 @@ return (int) gettext ("")]ifelse([$2], need-ngettext, [ + (int) ngettext ("", "" dnl Found it, now check the version. AC_MSG_CHECKING([version of bison]) changequote(<<,>>)dnl - ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` + ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison .* \([0-9]*\.[0-9.]*\).*$/\1/p'` case $ac_prog_version in '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) t@@ -910,15 +888,11 @@ strdup strtoul tsearch __argz_count __argz_stringify __argz_next]) # Ulrich Drepper <drepper@cygnus.com>, 1996. # # 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 or the GNU Library General Public License but which still want -# to provide support for the GNU gettext functionality. -# Please note that the actual code of the GNU gettext library is covered -# by the GNU Library General Public License, and the rest of the GNU -# gettext package package is covered by the GNU General Public License. -# They are *not* in the public domain. +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. -# serial 2 +# serial 1 dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) t@@ -950,7 +924,7 @@ ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" ;; esac])dnl $1="$ac_cv_path_$1" -if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then +if test -n "[$]$1"; then AC_MSG_RESULT([$]$1) else AC_MSG_RESULT(no) t@@ -1077,13 +1051,9 @@ AC_DEFUN([AM_LANGINFO_CODESET], # Ulrich Drepper <drepper@cygnus.com>, 1995. # # 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 or the GNU Library General Public License but which still want -# to provide support for the GNU gettext functionality. -# Please note that the actual code of the GNU gettext library is covered -# by the GNU Library General Public License, and the rest of the GNU -# gettext package package is covered by the GNU General Public License. -# They are *not* in the public domain. +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. # serial 2 t@@ -1098,3 +1068,16 @@ AC_DEFUN([AM_LC_MESSAGES], fi fi]) +# Define a conditional. + +AC_DEFUN([AM_CONDITIONAL], +[AC_SUBST($1_TRUE) +AC_SUBST($1_FALSE) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi]) + (DIR) diff --git a/configure b/configure t@@ -16,6 +16,8 @@ ac_help="$ac_help ac_help="$ac_help --enable-curses-client include curses client" ac_help="$ac_help + --enable-gui-server use a simple GTK+/Win32 GUI for the server" +ac_help="$ac_help --enable-nativewin32 build a native Win32 binary under Cygwin" ac_help="$ac_help --with-glib-prefix=PFX Prefix where GLIB is installed (optional)" t@@ -36,8 +38,6 @@ ac_help="$ac_help ac_help="$ac_help --with-included-gettext use the GNU gettext library included here" ac_help="$ac_help - --enable-gui-server use a simple GTK+/Win32 GUI for the server" -ac_help="$ac_help --enable-networking dopewars will use TCP/IP to connect to servers" ac_help="$ac_help --enable-strict if using gcc, enable extra warnings above -Wall" t@@ -1542,7 +1542,7 @@ if test "${enable_gui_client+set}" = set; then enableval="$enable_gui_client" GUI_CLIENT="$enableval" else - GUI_CLIENT="yes" + GUI_CLIENT="probe" fi t@@ -1551,17 +1551,26 @@ if test "${enable_curses_client+set}" = set; then enableval="$enable_curses_client" CURSES_CLIENT="$enableval" else - CURSES_CLIENT="yes" + CURSES_CLIENT="probe" +fi + + +# Check whether --enable-gui-server or --disable-gui-server was given. +if test "${enable_gui_server+set}" = set; then + enableval="$enable_gui_server" + GUI_SERVER="$enableval" +else + GUI_SERVER="probe" fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:1560: checking for Cygwin environment" >&5 +echo "configure:1569: checking for Cygwin environment" >&5 if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1565 "configure" +#line 1574 "configure" #include "confdefs.h" int main() { t@@ -1572,7 +1581,7 @@ int main() { return __CYGWIN__; ; return 0; } EOF -if { (eval echo configure:1576: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1585: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else t@@ -1613,7 +1622,9 @@ EOF HAVE_FIXED_GTK="yes" - GUI_SERVER="yes" + if test "$GUI_SERVER" = "probe"; then + GUI_SERVER="yes" + fi else echo "$ac_t"""Configuring for Unix binary"" 1>&6 t@@ -1670,7 +1681,7 @@ fi # Extract the first word of "glib-config", so it can be a program name with args. set dummy glib-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1674: checking for $ac_word" >&5 +echo "configure:1685: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GLIB_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -1705,7 +1716,7 @@ fi min_glib_version=1.2.0 echo $ac_n "checking for GLIB - version >= $min_glib_version""... $ac_c" 1>&6 -echo "configure:1709: checking for GLIB - version >= $min_glib_version" >&5 +echo "configure:1720: checking for GLIB - version >= $min_glib_version" >&5 no_glib="" if test "$GLIB_CONFIG" = "no" ; then no_glib=yes t@@ -1728,7 +1739,7 @@ echo "configure:1709: checking for GLIB - version >= $min_glib_version" >&5 echo $ac_n "cross compiling; assumed OK... $ac_c" else cat > conftest.$ac_ext <<EOF -#line 1732 "configure" +#line 1743 "configure" #include "confdefs.h" #include <glib.h> t@@ -1804,7 +1815,7 @@ main () } EOF -if { (eval echo configure:1808: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1819: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else t@@ -1838,7 +1849,7 @@ fi CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$LIBS $GLIB_LIBS" cat > conftest.$ac_ext <<EOF -#line 1842 "configure" +#line 1853 "configure" #include "confdefs.h" #include <glib.h> t@@ -1848,7 +1859,7 @@ int main() { return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ; return 0; } EOF -if { (eval echo configure:1852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1863: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GLIB or finding the wrong" t@@ -1887,9 +1898,9 @@ rm -f conftest* rm -f conf.glibtest - if test "$CURSES_CLIENT" = "yes" ; then + if test "$CURSES_CLIENT" != "no" ; then echo $ac_n "checking for newterm in -lncurses""... $ac_c" 1>&6 -echo "configure:1893: checking for newterm in -lncurses" >&5 +echo "configure:1904: checking for newterm in -lncurses" >&5 ac_lib_var=`echo ncurses'_'newterm | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 t@@ -1897,7 +1908,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lncurses $LIBS" cat > conftest.$ac_ext <<EOF -#line 1901 "configure" +#line 1912 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 t@@ -1908,7 +1919,7 @@ int main() { newterm() ; return 0; } EOF -if { (eval echo configure:1912: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1923: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else t@@ -1937,7 +1948,7 @@ fi if test "$ac_cv_lib_ncurses_newterm" = "no" ; then echo $ac_n "checking for newterm in -lcurses""... $ac_c" 1>&6 -echo "configure:1941: checking for newterm in -lcurses" >&5 +echo "configure:1952: checking for newterm in -lcurses" >&5 ac_lib_var=`echo curses'_'newterm | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 t@@ -1945,7 +1956,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lcurses $LIBS" cat > conftest.$ac_ext <<EOF -#line 1949 "configure" +#line 1960 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 t@@ -1956,7 +1967,7 @@ int main() { newterm() ; return 0; } EOF -if { (eval echo configure:1960: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1971: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else t@@ -1985,7 +1996,7 @@ fi if test "$ac_cv_lib_curses_newterm" = "no" ; then echo $ac_n "checking for newterm in -lcur_colr""... $ac_c" 1>&6 -echo "configure:1989: checking for newterm in -lcur_colr" >&5 +echo "configure:2000: checking for newterm in -lcur_colr" >&5 ac_lib_var=`echo cur_colr'_'newterm | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 t@@ -1993,7 +2004,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lcur_colr $LIBS" cat > conftest.$ac_ext <<EOF -#line 1997 "configure" +#line 2008 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 t@@ -2004,7 +2015,7 @@ int main() { newterm() ; return 0; } EOF -if { (eval echo configure:2008: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else t@@ -2032,14 +2043,18 @@ else fi if test "$ac_cv_lib_cur_colr_newterm" = "no" ; then - echo "configure: warning: Cannot find any curses-type library" 1>&2 - CURSES_CLIENT="no" + if test "$CURSES_CLIENT" = "yes" ; then + { echo "configure: error: Cannot find any curses-type library" 1>&2; exit 1; } + else + echo "configure: warning: Cannot find any curses-type library" 1>&2 + CURSES_CLIENT="no" + fi fi fi fi fi - if test "$GUI_CLIENT" = "yes" ; then + if test "$GUI_CLIENT" != "no" -o "$GUI_SERVER" != "no"; then # Check whether --with-gtk-prefix or --without-gtk-prefix was given. if test "${with_gtk_prefix+set}" = set; then withval="$with_gtk_prefix" t@@ -2090,7 +2105,7 @@ fi # Extract the first word of "gtk-config", so it can be a program name with args. set dummy gtk-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2094: checking for $ac_word" >&5 +echo "configure:2109: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GTK_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -2125,7 +2140,7 @@ fi min_gtk_version=1.2.0 echo $ac_n "checking for GTK - version >= $min_gtk_version""... $ac_c" 1>&6 -echo "configure:2129: checking for GTK - version >= $min_gtk_version" >&5 +echo "configure:2144: checking for GTK - version >= $min_gtk_version" >&5 no_gtk="" if test "$GTK_CONFIG" = "no" ; then no_gtk=yes t@@ -2148,7 +2163,7 @@ echo "configure:2129: checking for GTK - version >= $min_gtk_version" >&5 echo $ac_n "cross compiling; assumed OK... $ac_c" else cat > conftest.$ac_ext <<EOF -#line 2152 "configure" +#line 2167 "configure" #include "confdefs.h" #include <gtk/gtk.h> t@@ -2226,7 +2241,7 @@ main () } EOF -if { (eval echo configure:2230: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2245: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else t@@ -2260,7 +2275,7 @@ fi CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" cat > conftest.$ac_ext <<EOF -#line 2264 "configure" +#line 2279 "configure" #include "confdefs.h" #include <gtk/gtk.h> t@@ -2270,7 +2285,7 @@ int main() { return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ; return 0; } EOF -if { (eval echo configure:2274: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2289: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GTK or finding the wrong" t@@ -2309,11 +2324,16 @@ rm -f conftest* rm -f conf.gtktest if test "$gtk_found" = "no" ; then - echo "configure: warning: Cannot find GTK+" 1>&2 - GUI_CLIENT="no" + if test "$GUI_CLIENT" = "yes" -o "$GUI_SERVER" = "yes" ; then + { echo "configure: error: Cannot find GTK+" 1>&2; exit 1; } + else + echo "configure: warning: Cannot find GTK+" 1>&2 + GUI_CLIENT="no" + GUI_SERVER="no" + fi else echo $ac_n "checking for non-buggy GTK+ ( >= 1.2.10 )""... $ac_c" 1>&6 -echo "configure:2317: checking for non-buggy GTK+ ( >= 1.2.10 )" >&5 +echo "configure:2337: checking for non-buggy GTK+ ( >= 1.2.10 )" >&5 if test "$gtk_config_major_version" -gt 1 ; then HAVE_FIXED_GTK="yes" elif test "$gtk_config_major_version" -eq 1 ; then t@@ -2331,12 +2351,14 @@ echo "configure:2317: checking for non-buggy GTK+ ( >= 1.2.10 )" >&5 CFLAGS="$CFLAGS `glib-config --cflags`" LDFLAGS="$LDFLAGS `glib-config --libs`" - GUI_SERVER="no" + if test "$GUI_SERVER" = "probe"; then + GUI_SERVER="no" + fi echo $ac_n "checking for socklen_t data type""... $ac_c" 1>&6 -echo "configure:2338: checking for socklen_t data type" >&5 +echo "configure:2360: checking for socklen_t data type" >&5 cat > conftest.$ac_ext <<EOF -#line 2340 "configure" +#line 2362 "configure" #include "confdefs.h" #include <sys/types.h> #include <sys/socket.h> t@@ -2344,7 +2366,7 @@ int main() { socklen_t val ; return 0; } EOF -if { (eval echo configure:2348: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2370: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF t@@ -2360,11 +2382,18 @@ fi rm -f conftest* fi +if test "$GUI_CLIENT" = "probe"; then + GUI_CLIENT="yes" +fi +if test "$CURSES_CLIENT" = "probe"; then + CURSES_CLIENT="yes" +fi + ALL_LINGUAS="de pl pt_BR fr" # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2368: checking for $ac_word" >&5 +echo "configure:2397: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -2392,12 +2421,12 @@ else fi echo $ac_n "checking for working const""... $ac_c" 1>&6 -echo "configure:2396: checking for working const" >&5 +echo "configure:2425: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2401 "configure" +#line 2430 "configure" #include "confdefs.h" int main() { t@@ -2446,7 +2475,7 @@ ccp = (char const *const *) p; ; return 0; } EOF -if { (eval echo configure:2450: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2479: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else t@@ -2467,21 +2496,21 @@ EOF fi echo $ac_n "checking for inline""... $ac_c" 1>&6 -echo "configure:2471: checking for inline" >&5 +echo "configure:2500: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <<EOF -#line 2478 "configure" +#line 2507 "configure" #include "confdefs.h" int main() { } $ac_kw foo() { ; return 0; } EOF -if { (eval echo configure:2485: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2514: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else t@@ -2507,12 +2536,12 @@ EOF esac echo $ac_n "checking for off_t""... $ac_c" 1>&6 -echo "configure:2511: checking for off_t" >&5 +echo "configure:2540: checking for off_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2516 "configure" +#line 2545 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS t@@ -2540,12 +2569,12 @@ EOF fi echo $ac_n "checking for size_t""... $ac_c" 1>&6 -echo "configure:2544: checking for size_t" >&5 +echo "configure:2573: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2549 "configure" +#line 2578 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS t@@ -2575,19 +2604,19 @@ fi # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 -echo "configure:2579: checking for working alloca.h" >&5 +echo "configure:2608: checking for working alloca.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2584 "configure" +#line 2613 "configure" #include "confdefs.h" #include <alloca.h> int main() { char *p = alloca(2 * sizeof(int)); ; return 0; } EOF -if { (eval echo configure:2591: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2620: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_header_alloca_h=yes else t@@ -2608,12 +2637,12 @@ EOF fi echo $ac_n "checking for alloca""... $ac_c" 1>&6 -echo "configure:2612: checking for alloca" >&5 +echo "configure:2641: checking for alloca" >&5 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2617 "configure" +#line 2646 "configure" #include "confdefs.h" #ifdef __GNUC__ t@@ -2641,7 +2670,7 @@ int main() { char *p = (char *) alloca(1); ; return 0; } EOF -if { (eval echo configure:2645: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2674: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_func_alloca_works=yes else t@@ -2673,12 +2702,12 @@ EOF echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 -echo "configure:2677: checking whether alloca needs Cray hooks" >&5 +echo "configure:2706: checking whether alloca needs Cray hooks" >&5 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2682 "configure" +#line 2711 "configure" #include "confdefs.h" #if defined(CRAY) && ! defined(CRAY2) webecray t@@ -2703,12 +2732,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6 if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2707: checking for $ac_func" >&5 +echo "configure:2736: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2712 "configure" +#line 2741 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ t@@ -2731,7 +2760,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2735: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2764: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else t@@ -2758,7 +2787,7 @@ done fi echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 -echo "configure:2762: checking stack direction for C alloca" >&5 +echo "configure:2791: checking stack direction for C alloca" >&5 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -2766,7 +2795,7 @@ else ac_cv_c_stack_direction=0 else cat > conftest.$ac_ext <<EOF -#line 2770 "configure" +#line 2799 "configure" #include "confdefs.h" find_stack_direction () { t@@ -2785,7 +2814,7 @@ main () exit (find_stack_direction() < 0); } EOF -if { (eval echo configure:2789: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2818: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_stack_direction=1 else t@@ -2806,21 +2835,21 @@ EOF fi -for ac_hdr in unistd.h +for ac_hdr in stdlib.h unistd.h sys/stat.h sys/types.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:2814: checking for $ac_hdr" >&5 +echo "configure:2843: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2819 "configure" +#line 2848 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2824: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2853: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* t@@ -2849,12 +2878,12 @@ done for ac_func in getpagesize do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2853: checking for $ac_func" >&5 +echo "configure:2882: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2858 "configure" +#line 2887 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ t@@ -2877,7 +2906,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2881: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2910: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else t@@ -2902,7 +2931,7 @@ fi done echo $ac_n "checking for working mmap""... $ac_c" 1>&6 -echo "configure:2906: checking for working mmap" >&5 +echo "configure:2935: checking for working mmap" >&5 if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -2910,7 +2939,7 @@ else ac_cv_func_mmap_fixed_mapped=no else cat > conftest.$ac_ext <<EOF -#line 2914 "configure" +#line 2943 "configure" #include "confdefs.h" /* Thanks to Mike Haertel and Jim Avera for this test. t@@ -2938,11 +2967,24 @@ else #include <fcntl.h> #include <sys/mman.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#if HAVE_STDLIB_H +# include <stdlib.h> +#endif + +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif + +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + /* This mess was copied from the GNU getpagesize.h. */ #ifndef HAVE_GETPAGESIZE -# ifdef HAVE_UNISTD_H -# include <unistd.h> -# endif /* Assume that all systems that can run configure have sys/param.h. */ # ifndef HAVE_SYS_PARAM_H t@@ -3050,7 +3092,7 @@ main() } EOF -if { (eval echo configure:3054: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3096: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_mmap_fixed_mapped=yes else t@@ -3074,12 +3116,12 @@ fi echo $ac_n "checking whether we are using the GNU C Library 2.1 or newer""... $ac_c" 1>&6 -echo "configure:3078: checking whether we are using the GNU C Library 2.1 or newer" >&5 +echo "configure:3120: checking whether we are using the GNU C Library 2.1 or newer" >&5 if eval "test \"`echo '$''{'ac_cv_gnu_library_2_1'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3083 "configure" +#line 3125 "configure" #include "confdefs.h" #include <features.h> t@@ -3115,17 +3157,17 @@ stdlib.h string.h unistd.h sys/param.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:3119: checking for $ac_hdr" >&5 +echo "configure:3161: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3124 "configure" +#line 3166 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3129: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3171: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* t@@ -3156,12 +3198,12 @@ getgid getuid mempcpy munmap putenv setenv setlocale stpcpy strchr strcasecmp \ strdup strtoul tsearch __argz_count __argz_stringify __argz_next do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3160: checking for $ac_func" >&5 +echo "configure:3202: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3165 "configure" +#line 3207 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ t@@ -3184,7 +3226,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3188: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3230: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else t@@ -3224,7 +3266,7 @@ fi echo $ac_n "checking for iconv""... $ac_c" 1>&6 -echo "configure:3228: checking for iconv" >&5 +echo "configure:3270: checking for iconv" >&5 if eval "test \"`echo '$''{'am_cv_func_iconv'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -3232,7 +3274,7 @@ else am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no cat > conftest.$ac_ext <<EOF -#line 3236 "configure" +#line 3278 "configure" #include "confdefs.h" #include <stdlib.h> #include <iconv.h> t@@ -3242,7 +3284,7 @@ iconv_t cd = iconv_open("",""); iconv_close(cd); ; return 0; } EOF -if { (eval echo configure:3246: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3288: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* am_cv_func_iconv=yes else t@@ -3254,7 +3296,7 @@ rm -f conftest* am_save_LIBS="$LIBS" LIBS="$LIBS -liconv" cat > conftest.$ac_ext <<EOF -#line 3258 "configure" +#line 3300 "configure" #include "confdefs.h" #include <stdlib.h> #include <iconv.h> t@@ -3264,7 +3306,7 @@ iconv_t cd = iconv_open("",""); iconv_close(cd); ; return 0; } EOF -if { (eval echo configure:3268: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3310: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* am_cv_lib_iconv=yes am_cv_func_iconv=yes t@@ -3285,13 +3327,13 @@ echo "$ac_t""$am_cv_func_iconv" 1>&6 EOF echo $ac_n "checking for iconv declaration""... $ac_c" 1>&6 -echo "configure:3289: checking for iconv declaration" >&5 +echo "configure:3331: checking for iconv declaration" >&5 if eval "test \"`echo '$''{'am_cv_proto_iconv'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3295 "configure" +#line 3337 "configure" #include "confdefs.h" #include <stdlib.h> t@@ -3310,7 +3352,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:3314: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3356: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* am_cv_proto_iconv_arg1="" else t@@ -3339,19 +3381,19 @@ EOF echo $ac_n "checking for nl_langinfo and CODESET""... $ac_c" 1>&6 -echo "configure:3343: checking for nl_langinfo and CODESET" >&5 +echo "configure:3385: checking for nl_langinfo and CODESET" >&5 if eval "test \"`echo '$''{'am_cv_langinfo_codeset'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3348 "configure" +#line 3390 "configure" #include "confdefs.h" #include <langinfo.h> int main() { char* cs = nl_langinfo(CODESET); ; return 0; } EOF -if { (eval echo configure:3355: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3397: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* am_cv_langinfo_codeset=yes else t@@ -3374,19 +3416,19 @@ EOF if test $ac_cv_header_locale_h = yes; then echo $ac_n "checking for LC_MESSAGES""... $ac_c" 1>&6 -echo "configure:3378: checking for LC_MESSAGES" >&5 +echo "configure:3420: checking for LC_MESSAGES" >&5 if eval "test \"`echo '$''{'am_cv_val_LC_MESSAGES'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3383 "configure" +#line 3425 "configure" #include "confdefs.h" #include <locale.h> int main() { return LC_MESSAGES ; return 0; } EOF -if { (eval echo configure:3390: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3432: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* am_cv_val_LC_MESSAGES=yes else t@@ -3407,7 +3449,7 @@ EOF fi fi echo $ac_n "checking whether NLS is requested""... $ac_c" 1>&6 -echo "configure:3411: checking whether NLS is requested" >&5 +echo "configure:3453: checking whether NLS is requested" >&5 # Check whether --enable-nls or --disable-nls was given. if test "${enable_nls+set}" = set; then enableval="$enable_nls" t@@ -3429,7 +3471,7 @@ fi EOF echo $ac_n "checking whether included gettext is requested""... $ac_c" 1>&6 -echo "configure:3433: checking whether included gettext is requested" >&5 +echo "configure:3475: checking whether included gettext is requested" >&5 # Check whether --with-included-gettext or --without-included-gettext was given. if test "${with_included_gettext+set}" = set; then withval="$with_included_gettext" t@@ -3449,17 +3491,17 @@ fi ac_safe=`echo "libintl.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for libintl.h""... $ac_c" 1>&6 -echo "configure:3453: checking for libintl.h" >&5 +echo "configure:3495: checking for libintl.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3458 "configure" +#line 3500 "configure" #include "confdefs.h" #include <libintl.h> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:3463: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:3505: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* t@@ -3476,12 +3518,12 @@ fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for GNU gettext in libc""... $ac_c" 1>&6 -echo "configure:3480: checking for GNU gettext in libc" >&5 +echo "configure:3522: checking for GNU gettext in libc" >&5 if eval "test \"`echo '$''{'gt_cv_func_gnugettext1_libc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3485 "configure" +#line 3527 "configure" #include "confdefs.h" #include <libintl.h> extern int _nl_msg_cat_cntr; t@@ -3490,7 +3532,7 @@ bindtextdomain ("", ""); return (int) gettext ("") + _nl_msg_cat_cntr ; return 0; } EOF -if { (eval echo configure:3494: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3536: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* gt_cv_func_gnugettext1_libc=yes else t@@ -3506,14 +3548,14 @@ echo "$ac_t""$gt_cv_func_gnugettext1_libc" 1>&6 if test "$gt_cv_func_gnugettext1_libc" != "yes"; then echo $ac_n "checking for GNU gettext in libintl""... $ac_c" 1>&6 -echo "configure:3510: checking for GNU gettext in libintl" >&5 +echo "configure:3552: checking for GNU gettext in libintl" >&5 if eval "test \"`echo '$''{'gt_cv_func_gnugettext1_libintl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else gt_save_LIBS="$LIBS" LIBS="$LIBS -lintl $LIBICONV" cat > conftest.$ac_ext <<EOF -#line 3517 "configure" +#line 3559 "configure" #include "confdefs.h" #include <libintl.h> extern int _nl_msg_cat_cntr; t@@ -3522,7 +3564,7 @@ bindtextdomain ("", ""); return (int) gettext ("") + _nl_msg_cat_cntr ; return 0; } EOF -if { (eval echo configure:3526: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3568: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* gt_cv_func_gnugettext1_libintl=yes else t@@ -3555,12 +3597,12 @@ EOF for ac_func in dcgettext do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3559: checking for $ac_func" >&5 +echo "configure:3601: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3564 "configure" +#line 3606 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ t@@ -3583,7 +3625,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3587: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3629: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else t@@ -3609,10 +3651,10 @@ done LIBS="$gt_save_LIBS" - # Extract the first word of "msgfmt", so it can be a program name with args. + # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3616: checking for $ac_word" >&5 +echo "configure:3658: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -3625,28 +3667,28 @@ else for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then - if $ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then ac_cv_path_MSGFMT="$ac_dir/$ac_word" break fi fi done IFS="$ac_save_ifs" - test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT="no" ;; esac fi MSGFMT="$ac_cv_path_MSGFMT" -if test "$MSGFMT" != ":"; then +if test -n "$MSGFMT"; then echo "$ac_t""$MSGFMT" 1>&6 else echo "$ac_t""no" 1>&6 fi - - # Extract the first word of "gmsgfmt", so it can be a program name with args. + if test "$MSGFMT" != "no"; then + # Extract the first word of "gmsgfmt", so it can be a program name with args. set dummy gmsgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3650: checking for $ac_word" >&5 +echo "configure:3692: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -3679,11 +3721,12 @@ else echo "$ac_t""no" 1>&6 fi + fi - # Extract the first word of "xgettext", so it can be a program name with args. + # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3687: checking for $ac_word" >&5 +echo "configure:3730: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -3696,7 +3739,7 @@ else for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then - if $ac_dir/$ac_word --omit-header /dev/null >/dev/null 2>&1; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then ac_cv_path_XGETTEXT="$ac_dir/$ac_word" break fi t@@ -3708,7 +3751,7 @@ else esac fi XGETTEXT="$ac_cv_path_XGETTEXT" -if test "$XGETTEXT" != ":"; then +if test -n "$XGETTEXT"; then echo "$ac_t""$XGETTEXT" 1>&6 else echo "$ac_t""no" 1>&6 t@@ -3733,7 +3776,7 @@ fi # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3737: checking for $ac_word" >&5 +echo "configure:3780: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -3746,19 +3789,19 @@ else for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then - if $ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then ac_cv_path_MSGFMT="$ac_dir/$ac_word" break fi fi done IFS="$ac_save_ifs" - test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT="msgfmt" ;; esac fi MSGFMT="$ac_cv_path_MSGFMT" -if test "$MSGFMT" != ":"; then +if test -n "$MSGFMT"; then echo "$ac_t""$MSGFMT" 1>&6 else echo "$ac_t""no" 1>&6 t@@ -3767,7 +3810,7 @@ fi # Extract the first word of "gmsgfmt", so it can be a program name with args. set dummy gmsgfmt; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3771: checking for $ac_word" >&5 +echo "configure:3814: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -3803,7 +3846,7 @@ fi # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3807: checking for $ac_word" >&5 +echo "configure:3850: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -3816,7 +3859,7 @@ else for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then - if $ac_dir/$ac_word --omit-header /dev/null >/dev/null 2>&1; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then ac_cv_path_XGETTEXT="$ac_dir/$ac_word" break fi t@@ -3828,7 +3871,7 @@ else esac fi XGETTEXT="$ac_cv_path_XGETTEXT" -if test "$XGETTEXT" != ":"; then +if test -n "$XGETTEXT"; then echo "$ac_t""$XGETTEXT" 1>&6 else echo "$ac_t""no" 1>&6 t@@ -3842,17 +3885,8 @@ fi LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` fi - if test "$GMSGFMT" != ":"; then - if $GMSGFMT --statistics /dev/null >/dev/null 2>&1; then - : ; - else - echo "$ac_t""found msgfmt program is not GNU msgfmt; ignore it" 1>&6 - GMSGFMT=":" - fi - fi - - if test "$XGETTEXT" != ":"; then - if $XGETTEXT --omit-header /dev/null >/dev/null 2>&1; then + if test "$XGETTEXT" != ":"; then + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then : ; else echo "$ac_t""found xgettext program is not GNU xgettext; ignore it" 1>&6 t@@ -3874,7 +3908,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3878: checking for $ac_word" >&5 +echo "configure:3912: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_INTLBISON'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -3907,8 +3941,8 @@ done ac_verc_fail=yes else echo $ac_n "checking version of bison""... $ac_c" 1>&6 -echo "configure:3911: checking version of bison" >&5 - ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` +echo "configure:3945: checking version of bison" >&5 + ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison .* \([0-9]*\.[0-9.]*\).*$/\1/p'` case $ac_prog_version in '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) t@@ -3954,7 +3988,7 @@ echo "configure:3911: checking version of bison" >&5 LINGUAS= else echo $ac_n "checking for catalogs to be installed""... $ac_c" 1>&6 -echo "configure:3958: checking for catalogs to be installed" >&5 +echo "configure:3992: checking for catalogs to be installed" >&5 NEW_LINGUAS= for presentlang in $ALL_LINGUAS; do useit=no t@@ -3994,7 +4028,7 @@ echo "configure:3958: checking for catalogs to be installed" >&5 if test "$gt_cv_func_gettext_libintl" = "yes"; then - LIBS="-lintl $LIBS" + LIBS="-lintl $LIBS" fi localedir=${datadir}/locale t@@ -4014,13 +4048,6 @@ EOF fi -# Check whether --enable-gui-server or --disable-gui-server was given. -if test "${enable_gui_server+set}" = set; then - enableval="$enable_gui_server" - GUI_SERVER="$enableval" -fi - - if test "$GUI_SERVER" = "yes" ; then cat >> confdefs.h <<\EOF #define GUI_SERVER 1 t@@ -4035,15 +4062,8 @@ EOF fi -if test "$GUI_CLIENT" = "yes" -o "$GUI_SERVER" = "yes" ; then - GTKPORT_C="gtkport.c" - GTKPORT_O="gtkport.o" - - -fi - echo $ac_n "checking size of long long""... $ac_c" 1>&6 -echo "configure:4047: checking size of long long" >&5 +echo "configure:4067: checking size of long long" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -4051,18 +4071,18 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <<EOF -#line 4055 "configure" +#line 4075 "configure" #include "confdefs.h" #include <stdio.h> -main() +int main() { FILE *f=fopen("conftestval", "w"); - if (!f) exit(1); + if (!f) return(1); fprintf(f, "%d\n", sizeof(long long)); - exit(0); + return(0); } EOF -if { (eval echo configure:4066: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4086: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_long_long=`cat conftestval` else t@@ -4083,7 +4103,7 @@ EOF echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 -echo "configure:4087: checking for 8-bit clean memcmp" >&5 +echo "configure:4107: checking for 8-bit clean memcmp" >&5 if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -4091,7 +4111,7 @@ else ac_cv_func_memcmp_clean=no else cat > conftest.$ac_ext <<EOF -#line 4095 "configure" +#line 4115 "configure" #include "confdefs.h" main() t@@ -4101,7 +4121,7 @@ main() } EOF -if { (eval echo configure:4105: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4125: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_memcmp_clean=yes else t@@ -4119,7 +4139,7 @@ echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" echo $ac_n "checking whether setvbuf arguments are reversed""... $ac_c" 1>&6 -echo "configure:4123: checking whether setvbuf arguments are reversed" >&5 +echo "configure:4143: checking whether setvbuf arguments are reversed" >&5 if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else t@@ -4127,7 +4147,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <<EOF -#line 4131 "configure" +#line 4151 "configure" #include "confdefs.h" #include <stdio.h> /* If setvbuf has the reversed format, exit 0. */ t@@ -4141,7 +4161,7 @@ main () { exit(0); /* Non-reversed systems segv here. */ } EOF -if { (eval echo configure:4145: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4165: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_setvbuf_reversed=yes else t@@ -4165,12 +4185,12 @@ EOF fi echo $ac_n "checking for strftime""... $ac_c" 1>&6 -echo "configure:4169: checking for strftime" >&5 +echo "configure:4189: checking for strftime" >&5 if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4174 "configure" +#line 4194 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char strftime(); below. */ t@@ -4193,7 +4213,7 @@ strftime(); ; return 0; } EOF -if { (eval echo configure:4197: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4217: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_strftime=yes" else t@@ -4215,7 +4235,7 @@ else echo "$ac_t""no" 1>&6 # strftime is in -lintl on SCO UNIX. echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6 -echo "configure:4219: checking for strftime in -lintl" >&5 +echo "configure:4239: checking for strftime in -lintl" >&5 ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 t@@ -4223,7 +4243,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lintl $LIBS" cat > conftest.$ac_ext <<EOF -#line 4227 "configure" +#line 4247 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 t@@ -4234,7 +4254,7 @@ int main() { strftime() ; return 0; } EOF -if { (eval echo configure:4238: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4258: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else t@@ -4263,12 +4283,12 @@ fi for ac_func in strdup strstr getopt_long fork do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:4267: checking for $ac_func" >&5 +echo "configure:4287: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4272 "configure" +#line 4292 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ t@@ -4291,7 +4311,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:4295: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4315: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else t@@ -4322,14 +4342,14 @@ if test "$CYGWIN" = "yes" ; then else echo $ac_n "checking for library containing socket""... $ac_c" 1>&6 -echo "configure:4326: checking for library containing socket" >&5 +echo "configure:4346: checking for library containing socket" >&5 if eval "test \"`echo '$''{'ac_cv_search_socket'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_func_search_save_LIBS="$LIBS" ac_cv_search_socket="no" cat > conftest.$ac_ext <<EOF -#line 4333 "configure" +#line 4353 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 t@@ -4340,7 +4360,7 @@ int main() { socket() ; return 0; } EOF -if { (eval echo configure:4344: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4364: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_socket="none required" else t@@ -4351,7 +4371,7 @@ rm -f conftest* test "$ac_cv_search_socket" = "no" && for i in socket; do LIBS="-l$i $ac_func_search_save_LIBS" cat > conftest.$ac_ext <<EOF -#line 4355 "configure" +#line 4375 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 t@@ -4362,7 +4382,7 @@ int main() { socket() ; return 0; } EOF -if { (eval echo configure:4366: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4386: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_socket="-l$i" break t@@ -4384,14 +4404,14 @@ else : fi echo $ac_n "checking for library containing gethostbyname""... $ac_c" 1>&6 -echo "configure:4388: checking for library containing gethostbyname" >&5 +echo "configure:4408: checking for library containing gethostbyname" >&5 if eval "test \"`echo '$''{'ac_cv_search_gethostbyname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_func_search_save_LIBS="$LIBS" ac_cv_search_gethostbyname="no" cat > conftest.$ac_ext <<EOF -#line 4395 "configure" +#line 4415 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 t@@ -4402,7 +4422,7 @@ int main() { gethostbyname() ; return 0; } EOF -if { (eval echo configure:4406: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4426: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_gethostbyname="none required" else t@@ -4413,7 +4433,7 @@ rm -f conftest* test "$ac_cv_search_gethostbyname" = "no" && for i in nsl socket; do LIBS="-l$i $ac_func_search_save_LIBS" cat > conftest.$ac_ext <<EOF -#line 4417 "configure" +#line 4437 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 t@@ -4424,7 +4444,7 @@ int main() { gethostbyname() ; return 0; } EOF -if { (eval echo configure:4428: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4448: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_search_gethostbyname="-l$i" break t@@ -4447,12 +4467,12 @@ fi for ac_func in socket gethostbyname select do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:4451: checking for $ac_func" >&5 +echo "configure:4471: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4456 "configure" +#line 4476 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ t@@ -4475,7 +4495,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:4479: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4499: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else t@@ -4539,6 +4559,35 @@ fi CFLAGS="$CFLAGS -DDATADIR=\\\"${datadir}\\\"" + + +if test "$GUI_CLIENT" = "yes"; then + GUI_CLIENT_TRUE= + GUI_CLIENT_FALSE='#' +else + GUI_CLIENT_TRUE='#' + GUI_CLIENT_FALSE= +fi + + +if test "$CURSES_CLIENT" = "yes"; then + CURSES_CLIENT_TRUE= + CURSES_CLIENT_FALSE='#' +else + CURSES_CLIENT_TRUE='#' + CURSES_CLIENT_FALSE= +fi + + + +if test "$GUI_CLIENT" = "yes" -o "$GUI_SERVER" = "yes"; then + GTKPORT_TRUE= + GTKPORT_FALSE='#' +else + GTKPORT_TRUE='#' + GTKPORT_FALSE= +fi + trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure t@@ -4643,6 +4692,9 @@ ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo " Makefile src/Makefile +src/gui_client/Makefile +src/curses_client/Makefile +src/gtkport/Makefile doc/Makefile intl/Makefile po/Makefile.in config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 t@@ -4726,9 +4778,13 @@ s%@GENCAT@%$GENCAT%g s%@MKINSTALLDIRS@%$MKINSTALLDIRS%g s%@INTL_LIBTOOL_SUFFIX_PREFIX@%$INTL_LIBTOOL_SUFFIX_PREFIX%g s%@localedir@%$localedir%g -s%@GTKPORT_C@%$GTKPORT_C%g -s%@GTKPORT_O@%$GTKPORT_O%g s%@LIBOBJS@%$LIBOBJS%g +s%@GUI_CLIENT_TRUE@%$GUI_CLIENT_TRUE%g +s%@GUI_CLIENT_FALSE@%$GUI_CLIENT_FALSE%g +s%@CURSES_CLIENT_TRUE@%$CURSES_CLIENT_TRUE%g +s%@CURSES_CLIENT_FALSE@%$CURSES_CLIENT_FALSE%g +s%@GTKPORT_TRUE@%$GTKPORT_TRUE%g +s%@GTKPORT_FALSE@%$GTKPORT_FALSE%g CEOF EOF t@@ -4772,6 +4828,9 @@ cat >> $CONFIG_STATUS <<EOF CONFIG_FILES=\${CONFIG_FILES-"Makefile src/Makefile +src/gui_client/Makefile +src/curses_client/Makefile +src/gtkport/Makefile doc/Makefile intl/Makefile po/Makefile.in"} t@@ -4959,9 +5018,6 @@ for ac_file in $CONFIG_FILES; do ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` - # In autoconf-2.13 it is called $ac_given_srcdir. - # In autoconf-2.50 it is called $srcdir. - test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; t@@ -4969,9 +5025,9 @@ for ac_file in $CONFIG_FILES; do esac if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then rm -f "$ac_dir/POTFILES" - test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + echo creating "$ac_dir/POTFILES" sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," -e "\$s/\(.*\) \\\\/\1/" < "$ac_given_srcdir/$ac_dir/POTFILES.in" > "$ac_dir/POTFILES" - test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + echo creating "$ac_dir/Makefile" sed -e "/POTFILES =/r $ac_dir/POTFILES" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" fi ;; (DIR) diff --git a/configure.in b/configure.in t@@ -35,11 +35,15 @@ HAVE_FIXED_GTK="no" dnl Process client options AC_ARG_ENABLE(gui-client, [ --enable-gui-client include graphical client (GTK+/Win32)], -[ GUI_CLIENT="$enableval" ],[ GUI_CLIENT="yes" ]) +[ GUI_CLIENT="$enableval" ],[ GUI_CLIENT="probe" ]) AC_ARG_ENABLE(curses-client, [ --enable-curses-client include curses client], -[ CURSES_CLIENT="$enableval" ],[ CURSES_CLIENT="yes" ]) +[ CURSES_CLIENT="$enableval" ],[ CURSES_CLIENT="probe" ]) + +AC_ARG_ENABLE(gui-server, +[ --enable-gui-server use a simple GTK+/Win32 GUI for the server], +[ GUI_SERVER="$enableval" ],[ GUI_SERVER="probe" ]) dnl Test for Cygwin environment AC_CYGWIN t@@ -74,7 +78,9 @@ if test "$CYGWIN" = "yes" ; then HAVE_FIXED_GTK="yes" dnl Use graphical server by default - GUI_SERVER="yes" + if test "$GUI_SERVER" = "probe"; then + GUI_SERVER="yes" + fi else AC_MSG_RESULT("Configuring for Unix binary") t@@ -82,26 +88,35 @@ else AM_PATH_GLIB(1.2.0,,[AC_MSG_ERROR(Cannot find glib - aborting)]) dnl On true Unix systems, test for valid curses-like libraries - if test "$CURSES_CLIENT" = "yes" ; then + if test "$CURSES_CLIENT" != "no" ; then AC_CHECK_LIB(ncurses,newterm) if test "$ac_cv_lib_ncurses_newterm" = "no" ; then AC_CHECK_LIB(curses,newterm) if test "$ac_cv_lib_curses_newterm" = "no" ; then AC_CHECK_LIB(cur_colr,newterm) if test "$ac_cv_lib_cur_colr_newterm" = "no" ; then - AC_MSG_WARN(Cannot find any curses-type library) - CURSES_CLIENT="no" + if test "$CURSES_CLIENT" = "yes" ; then + AC_MSG_ERROR(Cannot find any curses-type library) + else + AC_MSG_WARN(Cannot find any curses-type library) + CURSES_CLIENT="no" + fi fi fi fi fi - if test "$GUI_CLIENT" = "yes" ; then + if test "$GUI_CLIENT" != "no" -o "$GUI_SERVER" != "no"; then dnl Tests for GTK AM_PATH_GTK(1.2.0,gtk_found="yes",gtk_found="no") if test "$gtk_found" = "no" ; then - AC_MSG_WARN(Cannot find GTK+) - GUI_CLIENT="no" + if test "$GUI_CLIENT" = "yes" -o "$GUI_SERVER" = "yes" ; then + AC_MSG_ERROR(Cannot find GTK+) + else + AC_MSG_WARN(Cannot find GTK+) + GUI_CLIENT="no" + GUI_SERVER="no" + fi else AC_MSG_CHECKING([for non-buggy GTK+ ( >= 1.2.10 )]) dnl Versions older than 1.2.10 are buggy t@@ -125,7 +140,9 @@ else LDFLAGS="$LDFLAGS `glib-config --libs`" dnl Use console server by default - GUI_SERVER="no" + if test "$GUI_SERVER" = "probe"; then + GUI_SERVER="no" + fi dnl Some systems use int rather than socklen_t as an argument to getsockopt AC_MSG_CHECKING([for socklen_t data type]) t@@ -136,11 +153,20 @@ else [AC_MSG_RESULT([no])]) fi +dnl If probing was unsuccessful, these will be set to "no"; therefore, +dnl if still set to "probe" then everything worked, so set to "yes" +if test "$GUI_CLIENT" = "probe"; then + GUI_CLIENT="yes" +fi +if test "$CURSES_CLIENT" = "probe"; then + CURSES_CLIENT="yes" +fi + dnl Do i18n stuff ALL_LINGUAS="de pl pt_BR fr" AM_GNU_GETTEXT if test "$gt_cv_func_gettext_libintl" = "yes"; then - LIBS="-lintl $LIBS" + LIBS="-lintl $LIBS" fi localedir=${datadir}/locale t@@ -154,12 +180,6 @@ if test "$CURSES_CLIENT" = "yes" ; then AC_DEFINE(CURSES_CLIENT) fi -dnl Let the user override the server interface with the -dnl --enable-gui-server option -AC_ARG_ENABLE(gui-server, -[ --enable-gui-server use a simple GTK+/Win32 GUI for the server], -[ GUI_SERVER="$enableval" ]) - if test "$GUI_SERVER" = "yes" ; then AC_DEFINE(GUI_SERVER) fi t@@ -168,14 +188,6 @@ if test "$HAVE_FIXED_GTK" = "yes" ; then AC_DEFINE(HAVE_FIXED_GTK) fi -if test "$GUI_CLIENT" = "yes" -o "$GUI_SERVER" = "yes" ; then - dnl Compile in the gtkport stuff for any kind of GUI - GTKPORT_C="gtkport.c" - GTKPORT_O="gtkport.o" - AC_SUBST(GTKPORT_C) - AC_SUBST(GTKPORT_O) -fi - dnl Can we use a long long datatype for price_t ? AC_CHECK_SIZEOF(long long) t@@ -230,12 +242,22 @@ if test -n "$GCC"; then fi dnl Pass the data directory to the compiler so the program knows -dnl where the high score file is +dnl where the high scores and docs are CFLAGS="$CFLAGS -DDATADIR=\\\"${datadir}\\\"" +dnl Add in the required clients +AM_CONDITIONAL(GUI_CLIENT, test "$GUI_CLIENT" = "yes") +AM_CONDITIONAL(CURSES_CLIENT, test "$CURSES_CLIENT" = "yes") + +dnl Compile in the gtkport stuff for any kind of GUI +AM_CONDITIONAL(GTKPORT, test "$GUI_CLIENT" = "yes" -o "$GUI_SERVER" = "yes") + AC_OUTPUT([ Makefile src/Makefile +src/gui_client/Makefile +src/curses_client/Makefile +src/gtkport/Makefile doc/Makefile intl/Makefile po/Makefile.in], (DIR) diff --git a/doc/Makefile.in b/doc/Makefile.in t@@ -1,6 +1,6 @@ -# Makefile.in generated automatically by automake 1.4 from Makefile.am +# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am -# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. t@@ -71,8 +71,6 @@ GLIB_CONFIG = @GLIB_CONFIG@ GLIB_LIBS = @GLIB_LIBS@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ -GTKPORT_C = @GTKPORT_C@ -GTKPORT_O = @GTKPORT_O@ GTK_CFLAGS = @GTK_CFLAGS@ GTK_CONFIG = @GTK_CONFIG@ GTK_LIBS = @GTK_LIBS@ t@@ -96,7 +94,10 @@ WNDRES = @WNDRES@ localedir = @localedir@ DOCPATH = ${DESTDIR}${datadir}/doc/${PACKAGE}-${VERSION}/ -DOCS = aiplayer.html configfile.html index.html i18n.html server.html clientplay.html credits.html installation.html servercommands.html commandline.html developer.html metaserver.html protocol.html windows.html +DOCS = aiplayer.html configfile.html index.html i18n.html server.html \ + clientplay.html credits.html installation.html \ + servercommands.html commandline.html developer.html \ + metaserver.html protocol.html windows.html man_MANS = dopewars.6 EXTRA_DIST = ${man_MANS} (DIR) diff --git a/src/Makefile.am b/src/Makefile.am t@@ -1,10 +1,28 @@ +if GUI_CLIENT +GUISUBDIR = gui_client +GUIDEP = gui_client/libguiclient.a +endif + +if CURSES_CLIENT +CURSESSUBDIR = curses_client +CURSESDEP = curses_client/libcursesclient.a +endif + +if GTKPORT +GTKPORTSUBDIR = gtkport +GTKPORTDEP = gtkport/libgtkport.a +endif + +SUBDIRS = $(GUISUBDIR) $(CURSESSUBDIR) $(GTKPORTSUBDIR) +dopewars_DEPENDENCIES = @INTLLIBS@ @WNDRES@ $(GUIDEP) $(CURSESDEP) $(GTKPORTDEP) +dopewars_LDADD = $(GUIDEP) $(CURSESDEP) $(GTKPORTDEP) @GTK_LIBS@ @INTLLIBS@ @WNDRES@ + bin_PROGRAMS = dopewars -dopewars_SOURCES = admin.c AIPlayer.c curses_client.c dopeos.c dopewars.c \ - error.c gtk_client.c message.c network.c serverside.c \ - tstring.c winmain.c @GTKPORT_C@ -dopewars_DEPENDENCIES = @INTLLIBS@ @GTKPORT_O@ @WNDRES@ -INCLUDES = @GTK_CFLAGS@ -I.. -I. -LDADD = @GTKPORT_O@ @GTK_LIBS@ @INTLLIBS@ @WNDRES@ +dopewars_SOURCES = admin.c AIPlayer.c dopeos.c dopewars.c \ + error.c message.c network.c serverside.c \ + tstring.c winmain.c + +INCLUDES = -I.. -I. @GTK_CFLAGS@ DEFS = @DEFS@ -DLOCALEDIR=\"${localedir}\" PIXDIR = ${DESTDIR}${datadir}/pixmaps PIXMAPS = dopewars-pill.png dopewars-shot.png dopewars-weed.png (DIR) diff --git a/src/Makefile.in b/src/Makefile.in t@@ -1,6 +1,6 @@ -# Makefile.in generated automatically by automake 1.4 from Makefile.am +# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am -# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. t@@ -71,8 +71,6 @@ GLIB_CONFIG = @GLIB_CONFIG@ GLIB_LIBS = @GLIB_LIBS@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ -GTKPORT_C = @GTKPORT_C@ -GTKPORT_O = @GTKPORT_O@ GTK_CFLAGS = @GTK_CFLAGS@ GTK_CONFIG = @GTK_CONFIG@ GTK_LIBS = @GTK_LIBS@ t@@ -95,12 +93,26 @@ VERSION = @VERSION@ WNDRES = @WNDRES@ localedir = @localedir@ +@GUI_CLIENT_TRUE@GUISUBDIR = @GUI_CLIENT_TRUE@gui_client +@GUI_CLIENT_TRUE@GUIDEP = @GUI_CLIENT_TRUE@gui_client/libguiclient.a + +@CURSES_CLIENT_TRUE@CURSESSUBDIR = @CURSES_CLIENT_TRUE@curses_client +@CURSES_CLIENT_TRUE@CURSESDEP = @CURSES_CLIENT_TRUE@curses_client/libcursesclient.a + +@GTKPORT_TRUE@GTKPORTSUBDIR = @GTKPORT_TRUE@gtkport +@GTKPORT_TRUE@GTKPORTDEP = @GTKPORT_TRUE@gtkport/libgtkport.a + +SUBDIRS = $(GUISUBDIR) $(CURSESSUBDIR) $(GTKPORTSUBDIR) +dopewars_DEPENDENCIES = @INTLLIBS@ @WNDRES@ $(GUIDEP) $(CURSESDEP) $(GTKPORTDEP) +dopewars_LDADD = $(GUIDEP) $(CURSESDEP) $(GTKPORTDEP) @GTK_LIBS@ @INTLLIBS@ @WNDRES@ + bin_PROGRAMS = dopewars -dopewars_SOURCES = admin.c AIPlayer.c curses_client.c dopeos.c dopewars.c error.c gtk_client.c message.c network.c serverside.c tstring.c winmain.c @GTKPORT_C@ +dopewars_SOURCES = admin.c AIPlayer.c dopeos.c dopewars.c \ + error.c message.c network.c serverside.c \ + tstring.c winmain.c -dopewars_DEPENDENCIES = @INTLLIBS@ @GTKPORT_O@ @WNDRES@ -INCLUDES = @GTK_CFLAGS@ -I.. -I. -LDADD = @GTKPORT_O@ @GTK_LIBS@ @INTLLIBS@ @WNDRES@ + +INCLUDES = -I.. -I. @GTK_CFLAGS@ DEFS = @DEFS@ -DLOCALEDIR=\"${localedir}\" PIXDIR = ${DESTDIR}${datadir}/pixmaps PIXMAPS = dopewars-pill.png dopewars-shot.png dopewars-weed.png t@@ -114,10 +126,8 @@ PROGRAMS = $(bin_PROGRAMS) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ -dopewars_OBJECTS = admin.o AIPlayer.o curses_client.o dopeos.o \ -dopewars.o error.o gtk_client.o message.o network.o serverside.o \ -tstring.o winmain.o -dopewars_LDADD = $(LDADD) +dopewars_OBJECTS = admin.o AIPlayer.o dopeos.o dopewars.o error.o \ +message.o network.o serverside.o tstring.o winmain.o dopewars_LDFLAGS = CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) t@@ -130,10 +140,10 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = gtar GZIP_ENV = --best -DEP_FILES = .deps/AIPlayer.P .deps/admin.P .deps/curses_client.P \ -.deps/dopeos.P .deps/dopewars.P .deps/error.P .deps/gtk_client.P \ -.deps/message.P .deps/network.P .deps/serverside.P .deps/tstring.P \ -.deps/winmain.P +DIST_SUBDIRS = gui_client curses_client gtkport +DEP_FILES = .deps/AIPlayer.P .deps/admin.P .deps/dopeos.P \ +.deps/dopewars.P .deps/error.P .deps/message.P .deps/network.P \ +.deps/serverside.P .deps/tstring.P .deps/winmain.P SOURCES = $(dopewars_SOURCES) OBJECTS = $(dopewars_OBJECTS) t@@ -193,6 +203,61 @@ dopewars: $(dopewars_OBJECTS) $(dopewars_DEPENDENCIES) @rm -f dopewars $(LINK) $(dopewars_LDFLAGS) $(dopewars_OBJECTS) $(dopewars_LDADD) $(LIBS) +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" != "." || dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) t@@ -203,9 +268,14 @@ ID: $(HEADERS) $(SOURCES) $(LISP) here=`pwd` && cd $(srcdir) \ && mkid -f$$here/ID $$unique $(LISP) -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) tags=; \ here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ t@@ -242,6 +312,16 @@ distdir: $(DISTFILES) || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done + for subdir in $(DIST_SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) t@@ -275,31 +355,32 @@ maintainer-clean-depend: >> .deps/$(*F).P; \ rm -f .deps/$(*F).pp info-am: -info: info-am +info: info-recursive dvi-am: -dvi: dvi-am +dvi: dvi-recursive check-am: all-am -check: check-am +check: check-recursive installcheck-am: -installcheck: installcheck-am +installcheck: installcheck-recursive install-exec-am: install-binPROGRAMS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook -install-exec: install-exec-am +install-exec: install-exec-recursive install-data-am: install-data-local -install-data: install-data-am +install-data: install-data-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -install: install-am +install: install-recursive uninstall-am: uninstall-binPROGRAMS -uninstall: uninstall-am +uninstall: uninstall-recursive all-am: Makefile $(PROGRAMS) -all-redirect: all-am +all-redirect: all-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install -installdirs: +installdirs: installdirs-recursive +installdirs-am: $(mkinstalldirs) $(DESTDIR)$(bindir) t@@ -315,17 +396,17 @@ maintainer-clean-generic: mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ mostlyclean-tags mostlyclean-depend mostlyclean-generic -mostlyclean: mostlyclean-am +mostlyclean: mostlyclean-recursive clean-am: clean-binPROGRAMS clean-compile clean-tags clean-depend \ clean-generic mostlyclean-am -clean: clean-am +clean: clean-recursive distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \ distclean-depend distclean-generic clean-am -distclean: distclean-am +distclean: distclean-recursive maintainer-clean-am: maintainer-clean-binPROGRAMS \ maintainer-clean-compile maintainer-clean-tags \ t@@ -334,18 +415,24 @@ maintainer-clean-am: maintainer-clean-binPROGRAMS \ @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." -maintainer-clean: maintainer-clean-am +maintainer-clean: maintainer-clean-recursive .PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ mostlyclean-compile distclean-compile clean-compile \ -maintainer-clean-compile tags mostlyclean-tags distclean-tags \ -clean-tags maintainer-clean-tags distdir mostlyclean-depend \ -distclean-depend clean-depend maintainer-clean-depend info-am info \ -dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ -install-exec install-data-local install-data-am install-data install-am \ -install uninstall-am uninstall all-redirect all-am all installdirs \ -mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir \ +mostlyclean-depend distclean-depend clean-depend \ +maintainer-clean-depend info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-local install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs-am \ +installdirs mostlyclean-generic distclean-generic clean-generic \ maintainer-clean-generic clean mostlyclean distclean maintainer-clean (DIR) diff --git a/src/curses_client.c b/src/curses_client.c t@@ -1,2425 +0,0 @@ -/************************************************************************ - * curses_client.c dopewars client using the (n)curses console library * - * Copyright (C) 1998-2002 Ben Webb * - * Email: ben@bellatrix.pcl.ox.ac.uk * - * WWW: http://dopewars.sourceforge.net/ * - * * - * 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 2 * - * 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, write to the Free Software * - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * - * MA 02111-1307, USA. * - ************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef CURSES_CLIENT - -#include <string.h> -#include <stdlib.h> -#include <sys/types.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <ctype.h> -#include <signal.h> -#include <errno.h> -#include <glib.h> -#include "curses_client.h" -#include "dopeos.h" -#include "dopewars.h" -#include "message.h" -#include "nls.h" -#include "serverside.h" -#include "tstring.h" - -static void PrepareHighScoreScreen(void); -static void PrintHighScore(char *Data); - -static int ResizedFlag; -static SCREEN *cur_screen; - -#ifdef NETWORKING -static enum { - CM_SERVER, CM_PROMPT, CM_META, CM_SINGLE -} ConnectMethod = CM_SERVER; -#endif - -static gboolean CanFire = FALSE, RunHere = FALSE; -static FightPoint fp; - -/* Function definitions; make them static so as not to clash with - * functions of the same name in different clients */ -static void display_intro(void); -static void ResizeHandle(int sig); -static void CheckForResize(Player *Play); -static int GetKey(char *allowed, char *orig_allowed, gboolean AllowOther, - gboolean PrintAllowed, gboolean ExpandOut); -static void clear_bottom(void), clear_screen(void); -static void clear_line(int line), clear_exceptfor(int skip); -static void nice_wait(void); -static void DisplayFightMessage(Player *Play, char *text); -static void DisplaySpyReports(char *Data, Player *From, Player *To); -static void display_message(char *buf); -static void print_location(char *text); -static void print_status(Player *Play, gboolean DispDrug); -static char *nice_input(char *prompt, int sy, int sx, gboolean digitsonly, - char *displaystr, char passwdchar); -static Player *ListPlayers(Player *Play, gboolean Select, char *Prompt); -static void HandleClientMessage(char *buf, Player *Play); -static void PrintMessage(const gchar *text); -static void GunShop(Player *Play); -static void LoanShark(Player *Play); -static void Bank(Player *Play); - -#ifdef NETWORKING -static void HttpAuthFunc(HttpConnection *conn, gboolean proxyauth, - gchar *realm, gpointer data); -static void SocksAuthFunc(NetworkBuffer *netbuf, gpointer data); -#endif - -static DispMode DisplayMode; -static gboolean QuitRequest; - -/* - * Initialises the curses library for accessing the screen. - */ -static void start_curses(void) -{ - cur_screen = newterm(NULL, stdout, stdin); - if (WantColour) { - start_color(); - init_pair(1, COLOR_MAGENTA, COLOR_WHITE); - init_pair(2, COLOR_BLACK, COLOR_WHITE); - init_pair(3, COLOR_BLACK, COLOR_WHITE); - init_pair(4, COLOR_BLUE, COLOR_WHITE); - init_pair(5, COLOR_WHITE, COLOR_BLUE); - init_pair(6, COLOR_RED, COLOR_WHITE); - } - cbreak(); - noecho(); - nodelay(stdscr, FALSE); - keypad(stdscr, TRUE); - curs_set(0); -} - -/* - * Shuts down the curses screen library. - */ -static void end_curses(void) -{ - keypad(stdscr, FALSE); - curs_set(1); - erase(); - refresh(); - endwin(); -} - -/* - * Handles a SIGWINCH signal, which is sent to indicate that the - * size of the curses screen has changed. - */ -void ResizeHandle(int sig) -{ - ResizedFlag = 1; -} - -/* - * Checks to see if the curses window needs to be resized - i.e. if a - * SIGWINCH signal has been received. - */ -void CheckForResize(Player *Play) -{ - sigset_t sigset; - - sigemptyset(&sigset); - sigaddset(&sigset, SIGWINCH); - sigprocmask(SIG_BLOCK, &sigset, NULL); - if (ResizedFlag) { - ResizedFlag = 0; - end_curses(); - start_curses(); - Width = COLS; - Depth = LINES; - attrset(TextAttr); - clear_screen(); - display_message(""); - DisplayFightMessage(Play, ""); - print_status(Play, TRUE); - } - sigprocmask(SIG_UNBLOCK, &sigset, NULL); -} - -static void LogMessage(const gchar *log_domain, GLogLevelFlags log_level, - const gchar *message, gpointer user_data) -{ - attrset(TextAttr); - clear_bottom(); - PrintMessage(message); - nice_wait(); - attrset(TextAttr); - clear_bottom(); -} - -/* - * Displays a dopewars introduction screen. - */ -void display_intro(void) -{ - GString *text; - - attrset(TextAttr); - clear_screen(); - attrset(TitleAttr); - - /* Curses client introduction screen */ - text = g_string_new(_("D O P E W A R S")); - mvaddstr(1, (Width - text->len) / 2, text->str); - - attrset(TextAttr); - - mvaddstr(3, 1, _("Based on John E. Dell's old Drug Wars game, dopewars " - "is a simulation of an")); - mvaddstr(4, 1, _("imaginary drug market. dopewars is an All-American " - "game which features")); - mvaddstr(5, 1, _("buying, selling, and trying to get past the cops!")); - - mvaddstr(7, 1, _("The first thing you need to do is pay off your " - "debt to the Loan Shark. After")); - mvaddstr(8, 1, _("that, your goal is to make as much money as " - "possible (and stay alive)! You")); - mvaddstr(9, 1, _("have one month of game time to make your fortune.")); - - mvaddstr(11, 18, _("Copyright (C) 1998-2002 Ben Webb " - "ben@bellatrix.pcl.ox.ac.uk")); - g_string_sprintf(text, _("Version %s"), VERSION); - mvaddstr(11, 2, text->str); - g_string_assign(text, _("dopewars is released under the GNU " - "General Public Licence")); - mvaddstr(12, (Width - text->len) / 2, text->str); - - mvaddstr(14, 7, _("Icons and Graphics Ocelot Mantis")); - mvaddstr(15, 7, _("Drug Dealing and Research Dan Wolf")); - mvaddstr(16, 7, _("Play Testing Phil Davis " - "Owen Walsh")); - mvaddstr(17, 7, _("Extensive Play Testing Katherine Holt " - "Caroline Moore")); - mvaddstr(18, 7, _("Constructive Criticism Andrea Elliot-Smith " - "Pete Winn")); - mvaddstr(19, 7, _("Unconstructive Criticism James Matthews")); - - mvaddstr(21, 3, _("For information on the command line options, type " - "dopewars -h at your")); - mvaddstr(22, 1, - _("Unix prompt. This will display a help screen, listing " - "the available options.")); - - g_string_free(text, TRUE); - nice_wait(); - attrset(TextAttr); - clear_screen(); - refresh(); -} - -#ifdef NETWORKING -/* - * Prompts the user to enter a server name and port to connect to. - */ -static void SelectServerManually(void) -{ - gchar *text, *PortText; - - if (ServerName[0] == '(') - AssignName(&ServerName, "localhost"); - attrset(TextAttr); - clear_bottom(); - mvaddstr(17, 1, - /* Prompts for hostname and port when selecting a server - * manually */ - _("Please enter the hostname and port of a dopewars server:-")); - text = nice_input(_("Hostname: "), 18, 1, FALSE, ServerName, '\0'); - AssignName(&ServerName, text); - g_free(text); - PortText = g_strdup_printf("%d", Port); - text = nice_input(_("Port: "), 19, 1, TRUE, PortText, '\0'); - Port = atoi(text); - g_free(text); - g_free(PortText); -} - -/* - * Contacts the dopewars metaserver, and obtains a list of valid - * server/port pairs, one of which the user should select. - * Returns TRUE on success; on failure FALSE is returned, and - * errstr is assigned an error message. - */ -static gboolean SelectServerFromMetaServer(Player *Play, GString *errstr) -{ - int c; - GSList *ListPt; - ServerData *ThisServer; - GString *text; - gint index; - fd_set readfds, writefds; - int maxsock; - gboolean DoneOK; - HttpConnection *MetaConn; - - attrset(TextAttr); - clear_bottom(); - mvaddstr(17, 1, _("Please wait... attempting to contact metaserver...")); - refresh(); - - if (OpenMetaHttpConnection(&MetaConn)) { - SetHttpAuthFunc(MetaConn, HttpAuthFunc, NULL); - SetNetworkBufferUserPasswdFunc(&MetaConn->NetBuf, SocksAuthFunc, NULL); - } else { - g_string_assign_error(errstr, MetaConn->NetBuf.error); - CloseHttpConnection(MetaConn); - return FALSE; - } - - ClearServerList(&ServerList); - - do { - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_SET(0, &readfds); - maxsock = 1; - SetSelectForNetworkBuffer(&MetaConn->NetBuf, &readfds, &writefds, - NULL, &maxsock); - if (bselect(maxsock, &readfds, &writefds, NULL, NULL) == -1) { - if (errno == EINTR) { - CheckForResize(Play); - continue; - } - perror("bselect"); - exit(1); - } - if (FD_ISSET(0, &readfds)) { - /* So that Ctrl-L works */ - c = getch(); -#ifndef CYGWIN - if (c == '\f') - wrefresh(curscr); -#endif - } - if (RespondToSelect - (&MetaConn->NetBuf, &readfds, &writefds, NULL, &DoneOK)) { - while (HandleWaitingMetaServerData(MetaConn, &ServerList, &DoneOK)) { - } - } - if (!DoneOK && HandleHttpCompletion(MetaConn)) { - if (IsHttpError(MetaConn)) { - g_string_assign_error(errstr, MetaConn->NetBuf.error); - CloseHttpConnection(MetaConn); - return FALSE; - } - } - } while (DoneOK); - CloseHttpConnection(MetaConn); - - text = g_string_new(""); - - ListPt = ServerList; - while (ListPt) { - ThisServer = (ServerData *)(ListPt->data); - attrset(TextAttr); - clear_bottom(); - /* Printout of metaserver information in curses client */ - g_string_sprintf(text, _("Server : %s"), ThisServer->Name); - mvaddstr(17, 1, text->str); - g_string_sprintf(text, _("Port : %d"), ThisServer->Port); - mvaddstr(18, 1, text->str); - g_string_sprintf(text, _("Version : %s"), ThisServer->Version); - mvaddstr(18, 40, text->str); - if (ThisServer->CurPlayers == -1) { - g_string_sprintf(text, _("Players: -unknown- (maximum %d)"), - ThisServer->MaxPlayers); - } else { - g_string_sprintf(text, _("Players: %d (maximum %d)"), - ThisServer->CurPlayers, ThisServer->MaxPlayers); - } - mvaddstr(19, 1, text->str); - g_string_sprintf(text, _("Up since : %s"), ThisServer->UpSince); - mvaddstr(19, 40, text->str); - g_string_sprintf(text, _("Comment: %s"), ThisServer->Comment); - mvaddstr(20, 1, text->str); - attrset(PromptAttr); - mvaddstr(23, 1, - _("N>ext server; P>revious server; S>elect this server... ")); - - /* The three keys that are valid responses to the previous question - - * if you translate them, keep the keys in the same order (N>ext, - * P>revious, S>elect) as they are here, otherwise they'll do the - * wrong things. */ - c = GetKey(_("NPS"), "NPS", FALSE, FALSE, FALSE); - switch (c) { - case 'S': - AssignName(&ServerName, ThisServer->Name); - Port = ThisServer->Port; - ListPt = NULL; - break; - case 'N': - ListPt = g_slist_next(ListPt); - if (!ListPt) - ListPt = ServerList; - break; - case 'P': - index = g_slist_position(ServerList, ListPt) - 1; - if (index >= 0) - ListPt = g_slist_nth(ServerList, (guint)index); - else - ListPt = g_slist_last(ListPt); - break; - } - } - if (!ServerList) { - g_string_assign(errstr, "No servers listed on metaserver"); - return FALSE; - } - clear_line(17); - refresh(); - g_string_free(text, TRUE); - return TRUE; -} - -static void DisplayConnectStatus(NetworkBuffer *netbuf, - NBStatus oldstatus, - NBSocksStatus oldsocks) -{ - NBStatus status; - NBSocksStatus sockstat; - GString *text; - - status = netbuf->status; - sockstat = netbuf->sockstat; - - if (oldstatus == status && oldsocks == sockstat) - return; - - text = g_string_new(""); - - switch (status) { - case NBS_PRECONNECT: - break; - case NBS_SOCKSCONNECT: - switch (sockstat) { - case NBSS_METHODS: - g_string_sprintf(text, _("Connected to SOCKS server %s..."), - Socks.name); - break; - case NBSS_USERPASSWD: - g_string_assign(text, _("Authenticating with SOCKS server")); - break; - case NBSS_CONNECT: - g_string_sprintf(text, _("Asking SOCKS for connect to %s..."), - ServerName); - break; - } - break; - case NBS_CONNECTED: - break; - } - if (text->str[0]) { - mvaddstr(17, 1, text->str); - refresh(); - } - g_string_free(text, TRUE); -} - -void HttpAuthFunc(HttpConnection *conn, gboolean proxyauth, - gchar *realm, gpointer data) -{ - gchar *text, *user, *password = NULL; - - attrset(TextAttr); - clear_bottom(); - if (proxyauth) { - text = g_strdup_printf(_("Proxy authentication required for realm %s"), - realm); - } else { - text = - g_strdup_printf(_("Authentication required for realm %s"), realm); - } - mvaddstr(17, 1, text); - mvaddstr(18, 1, _("(Enter a blank username to cancel)")); - g_free(text); - - user = nice_input(_("User name: "), 19, 1, FALSE, NULL, '\0'); - if (user && user[0]) { - password = nice_input(_("Password: "), 20, 1, FALSE, NULL, '*'); - } - - SetHttpAuthentication(conn, proxyauth, user, password); - g_free(user); - g_free(password); -} - -void SocksAuthFunc(NetworkBuffer *netbuf, gpointer data) -{ - gchar *user, *password = NULL; - - attrset(TextAttr); - clear_bottom(); - mvaddstr(17, 1, _("SOCKS authentication required (enter a blank " - "username to cancel)")); - - user = nice_input(_("User name: "), 18, 1, FALSE, NULL, '\0'); - if (user && user[0]) { - password = nice_input(_("Password: "), 19, 1, FALSE, NULL, '*'); - } - - SendSocks5UserPasswd(netbuf, user, password); - g_free(user); - g_free(password); -} - -static gboolean DoConnect(Player *Play, GString *errstr) -{ - NetworkBuffer *netbuf; - fd_set readfds, writefds; - int maxsock, c; - gboolean doneOK = TRUE; - NBStatus oldstatus; - NBSocksStatus oldsocks; - - netbuf = &Play->NetBuf; - oldstatus = netbuf->status; - oldsocks = netbuf->sockstat; - - if (!StartNetworkBufferConnect(netbuf, ServerName, Port)) { - doneOK = FALSE; - } else { - SetNetworkBufferUserPasswdFunc(netbuf, SocksAuthFunc, NULL); - while (netbuf->status != NBS_CONNECTED) { - DisplayConnectStatus(netbuf, oldstatus, oldsocks); - oldstatus = netbuf->status; - oldsocks = netbuf->sockstat; - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_SET(0, &readfds); - maxsock = 1; - SetSelectForNetworkBuffer(netbuf, &readfds, &writefds, NULL, - &maxsock); - if (bselect(maxsock, &readfds, &writefds, NULL, NULL) == -1) { - if (errno == EINTR) { - CheckForResize(Play); - continue; - } - perror("bselect"); - exit(1); - } - if (FD_ISSET(0, &readfds)) { - /* So that Ctrl-L works */ - c = getch(); -#ifndef CYGWIN - if (c == '\f') - wrefresh(curscr); -#endif - } - RespondToSelect(netbuf, &readfds, &writefds, NULL, &doneOK); - } - } - - if (!doneOK) - g_string_assign_error(errstr, netbuf->error); - return doneOK; -} - -/* - * Connects to a dopewars server. Prompts the user to select a server - * if necessary. Returns TRUE, unless the user elected to quit the - * program rather than choose a valid server. - */ -static gboolean ConnectToServer(Player *Play) -{ - gboolean MetaOK = TRUE, NetOK = TRUE, firstrun = FALSE; - GString *errstr; - gchar *text; - int c; - - errstr = g_string_new(""); - - if (g_strcasecmp(ServerName, SN_META) == 0 || ConnectMethod == CM_META) { - ConnectMethod = CM_META; - MetaOK = SelectServerFromMetaServer(Play, errstr); - } else if (g_strcasecmp(ServerName, SN_PROMPT) == 0 || - ConnectMethod == CM_PROMPT) { - ConnectMethod = CM_PROMPT; - SelectServerManually(); - } else if (g_strcasecmp(ServerName, SN_SINGLE) == 0 || - ConnectMethod == CM_SINGLE) { - ConnectMethod = CM_SINGLE; - g_string_free(errstr, TRUE); - return TRUE; - } else - firstrun = TRUE; - - while (1) { - attrset(TextAttr); - clear_bottom(); - if (MetaOK && !firstrun) { - mvaddstr(17, 1, _("Please wait... attempting to contact " - "dopewars server...")); - refresh(); - NetOK = DoConnect(Play, errstr); - } - if (!NetOK || !MetaOK || firstrun) { - firstrun = FALSE; - clear_line(16); - clear_line(17); - if (!MetaOK) { - /* Display of an error while contacting the metaserver */ - mvaddstr(16, 1, _("Cannot get metaserver details")); - text = g_strdup_printf(" (%s)", errstr->str); - mvaddstr(17, 1, text); - g_free(text); - } else if (!NetOK) { - /* Display of an error message while trying to contact a dopewars - * server (the error message itself is displayed on the next - * screen line) */ - mvaddstr(16, 1, _("Could not start multiplayer dopewars")); - text = g_strdup_printf(" (%s)", errstr->str); - mvaddstr(17, 1, text); - g_free(text); - } - MetaOK = NetOK = TRUE; - attrset(PromptAttr); - mvaddstr(18, 1, - _("Will you... C>onnect to a named dopewars server")); - mvaddstr(19, 1, - _(" L>ist the servers on the metaserver, and " - "select one")); - mvaddstr(20, 1, - _(" Q>uit (where you can start a server " - "by typing \"dopewars -s\")")); - mvaddstr(21, 1, _(" or P>lay single-player ? ")); - attrset(TextAttr); - - /* Translate these 4 keys in line with the above options, keeping - * the order the same (C>onnect, L>ist, Q>uit, P>lay single-player) */ - c = GetKey(_("CLQP"), "CLQP", FALSE, FALSE, FALSE); - switch (c) { - case 'Q': - g_string_free(errstr, TRUE); - return FALSE; - case 'P': - g_string_free(errstr, TRUE); - return TRUE; - case 'L': - MetaOK = SelectServerFromMetaServer(Play, errstr); - break; - case 'C': - SelectServerManually(); - break; - } - } else - break; - } - g_string_free(errstr, TRUE); - Client = Network = TRUE; - return TRUE; -} -#endif /* NETWORKING */ - -/* - * Displays the list of locations and prompts the user to select one. - * If "AllowReturn" is TRUE, then if the current location is selected - * simply drop back to the main game loop, otherwise send a request - * to the server to move to the new location. If FALSE, the user MUST - * choose a new location to move to. The active client player is - * passed in "Play". - * N.B. May set the global variable DisplayMode. - * Returns: TRUE if the user chose to jet to a new location, - * FALSE if the action was cancelled instead. - */ -static gboolean jet(Player *Play, gboolean AllowReturn) -{ - int i, c; - char text[80]; - - attrset(TextAttr); - clear_bottom(); - for (i = 0; i < NumLocation; i++) { - sprintf(text, "%d. %s", i + 1, Location[i].Name); - mvaddstr(17 + i / 3, (i % 3) * 20 + 12, text); - } - attrset(PromptAttr); - - /* Prompt when the player chooses to "jet" to a new location */ - mvaddstr(22, 22, _("Where to, dude ? ")); - attrset(TextAttr); - curs_set(1); - do { - c = bgetch(); - if (c >= '1' && c < '1' + NumLocation) { - addstr(Location[c - '1'].Name); - if (Play->IsAt != c - '1') { - sprintf(text, "%d", c - '1'); - DisplayMode = DM_NONE; - SendClientMessage(Play, C_NONE, C_REQUESTJET, NULL, text); - } else - c = 0; - } else - c = 0; - } while (c == 0 && !AllowReturn); - - curs_set(0); - return (c != 0); -} - -/* - * Prompts the user "Play" to drop some of the currently carried drugs. - */ -static void DropDrugs(Player *Play) -{ - int i, c, num, NumDrugs; - GString *text; - gchar *buf; - - attrset(TextAttr); - clear_bottom(); - text = g_string_new(""); - dpg_string_sprintf(text, - /* List of drugs that you can drop (%tde = "drugs" by - * default) */ - _("You can\'t get any cash for the following " - "carried %tde :"), Names.Drugs); - mvaddstr(16, 1, text->str); - NumDrugs = 0; - for (i = 0; i < NumDrug; i++) { - if (Play->Drugs[i].Carried > 0 && Play->Drugs[i].Price == 0) { - g_string_sprintf(text, "%c. %-10s %-8d", NumDrugs + 'A', - Drug[i].Name, Play->Drugs[i].Carried); - mvaddstr(17 + NumDrugs / 3, (NumDrugs % 3) * 25 + 4, text->str); - NumDrugs++; - } - } - attrset(PromptAttr); - mvaddstr(22, 20, _("What do you want to drop? ")); - curs_set(1); - attrset(TextAttr); - c = bgetch(); - c = toupper(c); - for (i = 0; c >= 'A' && c < 'A' + NumDrugs && i < NumDrug; i++) { - if (Play->Drugs[i].Carried > 0 && Play->Drugs[i].Price == 0) { - c--; - if (c < 'A') { - addstr(Drug[i].Name); - buf = - nice_input(_("How many do you drop? "), 23, 8, TRUE, NULL, - '\0'); - num = atoi(buf); - g_free(buf); - if (num > 0) { - g_string_sprintf(text, "drug^%d^%d", i, -num); - SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text->str); - } - } - } - } - g_string_free(text, TRUE); -} - -/* - * Prompts the user (i.e. the owner of client "Play") to buy drugs if - * "Buy" is TRUE, or to sell drugs otherwise. A list of available drugs - * is displayed, and on receiving the selection, the user is prompted - * for the number of drugs desired. Finally a message is sent to the - * server to buy or sell the required quantity. - */ -static void DealDrugs(Player *Play, gboolean Buy) -{ - int i, c, NumDrugsHere; - gchar *text, *input; - int DrugNum, CanCarry, CanAfford; - - NumDrugsHere = 0; - for (c = 0; c < NumDrug; c++) - if (Play->Drugs[c].Price > 0) - NumDrugsHere++; - - clear_line(22); - attrset(PromptAttr); - if (Buy) { - /* Buy and sell prompts for dealing drugs or guns */ - mvaddstr(22, 20, _("What do you wish to buy? ")); - } else { - mvaddstr(22, 20, _("What do you wish to sell? ")); - } - curs_set(1); - attrset(TextAttr); - c = bgetch(); - c = toupper(c); - if (c >= 'A' && c < 'A' + NumDrugsHere) { - DrugNum = -1; - c -= 'A'; - for (i = 0; i <= c; i++) - DrugNum = GetNextDrugIndex(DrugNum, Play); - addstr(Drug[DrugNum].Name); - CanCarry = Play->CoatSize; - CanAfford = Play->Cash / Play->Drugs[DrugNum].Price; - - if (Buy) { - /* Display of number of drugs you could buy and/or carry, when - * buying drugs */ - text = g_strdup_printf(_("You can afford %d, and can carry %d. "), - CanAfford, CanCarry); - mvaddstr(23, 2, text); - input = nice_input(_("How many do you buy? "), 23, 2 + strlen(text), - TRUE, NULL, '\0'); - c = atoi(input); - g_free(input); - g_free(text); - if (c >= 0) { - text = g_strdup_printf("drug^%d^%d", DrugNum, c); - SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text); - g_free(text); - } - } else { - /* Display of number of drugs you have, when selling drugs */ - text = - g_strdup_printf(_("You have %d. "), - Play->Drugs[DrugNum].Carried); - mvaddstr(23, 2, text); - input = nice_input(_("How many do you sell? "), 23, 2 + strlen(text), - TRUE, NULL, '\0'); - c = atoi(input); - g_free(input); - g_free(text); - if (c >= 0) { - text = g_strdup_printf("drug^%d^%d", DrugNum, -c); - SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text); - g_free(text); - } - } - } - curs_set(0); -} - -/* - * Prompts the user (player "Play") to give an errand to one of his/her - * bitches. The decision is relayed to the server for implementation. - */ -static void GiveErrand(Player *Play) -{ - int c, y; - GString *text; - Player *To; - - text = g_string_new(""); - attrset(TextAttr); - clear_bottom(); - y = 17; - - /* Prompt for sending your bitches out to spy etc. (%tde = "bitches" by - * default) */ - dpg_string_sprintf(text, - _("Choose an errand to give one of your %tde..."), - Names.Bitches); - mvaddstr(y++, 1, text->str); - attrset(PromptAttr); - if (Play->Bitches.Carried > 0) { - dpg_string_sprintf(text, - _(" S>py on another dealer " - "(cost: %P)"), Prices.Spy); - mvaddstr(y++, 2, text->str); - dpg_string_sprintf(text, - _(" T>ip off the cops to another dealer " - "(cost: %P)"), Prices.Tipoff); - mvaddstr(y++, 2, text->str); - mvaddstr(y++, 2, _(" G>et stuffed")); - } - if (Play->Flags & SPYINGON) { - mvaddstr(y++, 2, _("or C>ontact your spies and receive reports")); - } - mvaddstr(y++, 2, _("or N>o errand ? ")); - curs_set(1); - attrset(TextAttr); - - /* Translate these 5 keys to match the above options, keeping the - * original order the same (S>py, T>ip off, G>et stuffed, C>ontact spy, - * N>o errand) */ - c = GetKey(_("STGCN"), "STGCN", TRUE, FALSE, FALSE); - - if (Play->Bitches.Carried > 0 || c == 'C') - switch (c) { - case 'S': - To = ListPlayers(Play, TRUE, _("Whom do you want to spy on? ")); - if (To) - SendClientMessage(Play, C_NONE, C_SPYON, To, NULL); - break; - case 'T': - To = ListPlayers(Play, TRUE, - _("Whom do you want to tip the cops off to? ")); - if (To) - SendClientMessage(Play, C_NONE, C_TIPOFF, To, NULL); - break; - case 'G': - attrset(PromptAttr); - /* Prompt for confirmation of sacking a bitch */ - addstr(_(" Are you sure? ")); - - /* The two keys that are valid for answering Yes/No - if you - * translate them, keep them in the same order - i.e. "Yes" before - * "No" */ - c = GetKey(_("YN"), "YN", FALSE, TRUE, FALSE); - - if (c == 'Y') - SendClientMessage(Play, C_NONE, C_SACKBITCH, NULL, NULL); - break; - case 'C': - if (Play->Flags & SPYINGON) { - SendClientMessage(Play, C_NONE, C_CONTACTSPY, NULL, NULL); - } - break; - } -} - -/* - * Asks the user if he/she _really_ wants to quit dopewars. - */ -static int want_to_quit(void) -{ - attrset(TextAttr); - clear_line(22); - attrset(PromptAttr); - mvaddstr(22, 1, _("Are you sure you want to quit? ")); - attrset(TextAttr); - return (GetKey(_("YN"), "YN", FALSE, TRUE, FALSE) != 'N'); -} - -/* - * Prompts the user to change his or her name, and notifies the server. - */ -static void change_name(Player *Play, gboolean nullname) -{ - gchar *NewName; - - /* Prompt for player to change his/her name */ - NewName = nice_input(_("New name: "), 23, 0, FALSE, NULL, '\0'); - - if (NewName[0]) { - if (nullname) { - SendNullClientMessage(Play, C_NONE, C_NAME, NULL, NewName); - } else { - SendClientMessage(Play, C_NONE, C_NAME, NULL, NewName); - } - SetPlayerName(Play, NewName); - } - g_free(NewName); -} - -/* - * Given a message "Message" coming in for player "Play", performs - * processing and reacts properly; if a message indicates the end of the - * game, the global variable QuitRequest is set. The global variable - * DisplayMode may also be changed by this routine as a result of network - * traffic. - */ -void HandleClientMessage(char *Message, Player *Play) -{ - char *pt, *Data, *wrd; - AICode AI; - MsgCode Code; - Player *From, *tmp; - GSList *list; - gchar *text; - int i; - gboolean Handled; - - /* Ignore To: field - all messages will be for Player "Play" */ - if (ProcessMessage(Message, Play, &From, &AI, &Code, &Data, FirstClient) - == -1) { - return; - } - - Handled = - HandleGenericClientMessage(From, AI, Code, Play, Data, &DisplayMode); - switch (Code) { - case C_ENDLIST: - if (FirstClient && g_slist_next(FirstClient)) { - ListPlayers(Play, FALSE, NULL); - } - break; - case C_STARTHISCORE: - PrepareHighScoreScreen(); - break; - case C_HISCORE: - PrintHighScore(Data); - break; - case C_ENDHISCORE: - if (strcmp(Data, "end") == 0) { - QuitRequest = TRUE; - } else { - nice_wait(); - clear_screen(); - display_message(""); - print_status(Play, TRUE); - refresh(); - } - break; - case C_PUSH: - attrset(TextAttr); - clear_line(22); - mvaddstr(22, 0, _("You have been pushed from the server. " - "Reverting to single player mode.")); - nice_wait(); - SwitchToSinglePlayer(Play); - print_status(Play, TRUE); - break; - case C_QUIT: - attrset(TextAttr); - clear_line(22); - mvaddstr(22, 0, - _("The server has terminated. Reverting to " - "single player mode.")); - nice_wait(); - SwitchToSinglePlayer(Play); - print_status(Play, TRUE); - break; - case C_MSG: - text = g_strdup_printf("%s: %s", GetPlayerName(From), Data); - display_message(text); - g_free(text); - break; - case C_MSGTO: - text = g_strdup_printf("%s->%s: %s", GetPlayerName(From), - GetPlayerName(Play), Data); - display_message(text); - g_free(text); - break; - case C_JOIN: - text = g_strdup_printf(_("%s joins the game!"), Data); - display_message(text); - g_free(text); - break; - case C_LEAVE: - if (From != &Noone) { - text = g_strdup_printf(_("%s has left the game."), Data); - display_message(text); - g_free(text); - } - break; - case C_RENAME: - /* Displayed when a player changes his/her name */ - text = g_strdup_printf(_("%s will now be known as %s."), - GetPlayerName(From), Data); - SetPlayerName(From, Data); - mvaddstr(22, 0, text); - g_free(text); - nice_wait(); - break; - case C_PRINTMESSAGE: - PrintMessage(Data); - nice_wait(); - break; - case C_FIGHTPRINT: - DisplayFightMessage(Play, Data); - break; - case C_SUBWAYFLASH: - DisplayFightMessage(Play, NULL); - for (list = FirstClient; list; list = g_slist_next(list)) { - tmp = (Player *)list->data; - tmp->Flags &= ~FIGHTING; - } - for (i = 0; i < 4; i++) { - print_location(_("S U B W A Y")); - refresh(); - MicroSleep(100000); - print_location(""); - refresh(); - MicroSleep(100000); - } - print_location(Location[(int)Play->IsAt].Name); - break; - case C_QUESTION: - pt = Data; - wrd = GetNextWord(&pt, ""); - PrintMessage(pt); - addch(' '); - i = GetKey(_(wrd), wrd, FALSE, TRUE, TRUE); - wrd = g_strdup_printf("%c", i); - SendClientMessage(Play, C_NONE, C_ANSWER, - From == &Noone ? NULL : From, wrd); - g_free(wrd); - break; - case C_LOANSHARK: - LoanShark(Play); - SendClientMessage(Play, C_NONE, C_DONE, NULL, NULL); - break; - case C_BANK: - Bank(Play); - SendClientMessage(Play, C_NONE, C_DONE, NULL, NULL); - break; - case C_GUNSHOP: - GunShop(Play); - SendClientMessage(Play, C_NONE, C_DONE, NULL, NULL); - break; - case C_UPDATE: - if (From == &Noone) { - ReceivePlayerData(Play, Data, Play); - print_status(Play, TRUE); - refresh(); - } else { - DisplaySpyReports(Data, From, Play); - } - break; - case C_NEWNAME: - clear_line(22); - clear_line(23); - attrset(TextAttr); - mvaddstr(22, 0, _("Unfortunately, somebody else is already " - "using \"your\" name. Please change it.")); - change_name(Play, TRUE); - break; - default: - if (!Handled) { - text = g_strdup_printf("%s^%c^%s^%s", GetPlayerName(From), Code, - GetPlayerName(Play), Data); - mvaddstr(22, 0, text); - g_free(text); - nice_wait(); - } - break; - } -} - -/* - * Responds to a "starthiscore" message by clearing the screen and - * displaying the title for the high scores screen. - */ -void PrepareHighScoreScreen(void) -{ - char *text; - - attrset(TextAttr); - clear_screen(); - attrset(TitleAttr); - text = _("H I G H S C O R E S"); - mvaddstr(0, (Width - strlen(text)) / 2, text); - attrset(TextAttr); -} - -/* - * Prints a high score coded in "Data"; first word is the index of the - * score (i.e. y screen coordinate), second word is the text, the first - * letter of which identifies whether it's to be printed bold or not. - */ -void PrintHighScore(char *Data) -{ - char *cp; - int index; - - cp = Data; - index = GetNextInt(&cp, 0); - if (!cp || strlen(cp) < 2) - return; - move(index + 2, 0); - attrset(TextAttr); - if (cp[0] == 'B') - standout(); - addstr(&cp[1]); - if (cp[0] == 'B') - standend(); -} - -/* - * Prints a message "text" received via. a "printmessage" message in the - * bottom part of the screen. - */ -void PrintMessage(const gchar *text) -{ - guint i, line; - - attrset(TextAttr); - clear_line(16); - - line = 1; - for (i = 0; i < strlen(text) && (text[i] == '^' || text[i] == '\n'); i++) - line++; - clear_exceptfor(line); - - line = 17; - move(line, 1); - for (i = 0; i < strlen(text); i++) { - if (text[i] == '^' || text[i] == '\n') { - line++; - move(line, 1); - } else if (text[i] != '\r') - addch((guchar)text[i]); - } -} - -static void SellGun(Player *Play) -{ - gchar *text; - gint gunind; - - clear_line(22); - if (TotalGunsCarried(Play) == 0) { - /* Error - player tried to sell guns that he/she doesn't have - * (%tde="guns" by default) */ - text = dpg_strdup_printf(_("You don't have any %tde to sell!"), - Names.Guns); - mvaddstr(22, (Width - strlen(text)) / 2, text); - g_free(text); - nice_wait(); - clear_line(23); - } else { - attrset(PromptAttr); - mvaddstr(22, 20, _("What do you wish to sell? ")); - curs_set(1); - attrset(TextAttr); - gunind = bgetch(); - gunind = toupper(gunind); - if (gunind >= 'A' && gunind < 'A' + NumGun) { - gunind -= 'A'; - addstr(Gun[gunind].Name); - if (Play->Guns[gunind].Carried == 0) { - clear_line(22); - /* Error - player tried to sell some guns that he/she doesn't have */ - mvaddstr(22, 10, _("You don't have any to sell!")); - nice_wait(); - clear_line(23); - } else { - Play->Cash += Gun[gunind].Price; - Play->CoatSize += Gun[gunind].Space; - Play->Guns[gunind].Carried--; - text = g_strdup_printf("gun^%d^-1", gunind); - SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text); - g_free(text); - print_status(Play, FALSE); - } - } - } -} - -static void BuyGun(Player *Play) -{ - gchar *text; - gint gunind; - - clear_line(22); - if (TotalGunsCarried(Play) >= Play->Bitches.Carried + 2) { - text = dpg_strdup_printf( - /* Error - player tried to buy more guns - * than his/her bitches can carry (1st - * %tde="bitches", 2nd %tde="guns" by - * default) */ - _("You'll need more %tde to carry " - "any more %tde!"), - Names.Bitches, Names.Guns); - mvaddstr(22, (Width - strlen(text)) / 2, text); - g_free(text); - nice_wait(); - clear_line(23); - } else { - attrset(PromptAttr); - mvaddstr(22, 20, _("What do you wish to buy? ")); - curs_set(1); - attrset(TextAttr); - gunind = bgetch(); - gunind = toupper(gunind); - if (gunind >= 'A' && gunind < 'A' + NumGun) { - gunind -= 'A'; - addstr(Gun[gunind].Name); - if (Gun[gunind].Space > Play->CoatSize) { - clear_line(22); - /* Error - player tried to buy a gun that he/she doesn't have - * space for (%tde="gun" by default) */ - text = dpg_strdup_printf(_("You don't have enough space to " - "carry that %tde!"), Names.Gun); - mvaddstr(22, (Width - strlen(text)) / 2, text); - g_free(text); - nice_wait(); - clear_line(23); - } else if (Gun[gunind].Price > Play->Cash) { - clear_line(22); - /* Error - player tried to buy a gun that he/she can't afford - * (%tde="gun" by default) */ - text = dpg_strdup_printf(_("You don't have enough cash to buy " - "that %tde!"), Names.Gun); - mvaddstr(22, (Width - strlen(text)) / 2, text); - g_free(text); - nice_wait(); - clear_line(23); - } else { - Play->Cash -= Gun[gunind].Price; - Play->CoatSize -= Gun[gunind].Space; - Play->Guns[gunind].Carried++; - text = g_strdup_printf("gun^%d^1", gunind); - SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text); - g_free(text); - print_status(Play, FALSE); - } - } - } -} - -/* - * Allows player "Play" to buy and sell guns interactively. Passes the - * decisions on to the server for sanity checking and implementation. - */ -void GunShop(Player *Play) -{ - int i, action; - gchar *text; - - print_status(Play, FALSE); - attrset(TextAttr); - clear_bottom(); - for (i = 0; i < NumGun; i++) { - text = - dpg_strdup_printf("%c. %-22tde %12P", 'A' + i, Gun[i].Name, - Gun[i].Price); - mvaddstr(17 + i / 2, (i % 2) * 40 + 1, text); - g_free(text); - } - do { - /* Prompt for actions in the gun shop */ - text = _("Will you B>uy, S>ell, or L>eave? "); - attrset(PromptAttr); - clear_line(22); - mvaddstr(22, 40 - strlen(text) / 2, text); - attrset(TextAttr); - - /* Translate these three keys in line with the above options, keeping - * the order (B>uy, S>ell, L>eave) the same - you can change the - * wording of the prompt, but if you change the order in this key - * list, the keys will do the wrong things! */ - action = GetKey(_("BSL"), "BSL", FALSE, FALSE, FALSE); - if (action == 'S') - SellGun(Play); - else if (action == 'B') - BuyGun(Play); - } while (action != 'L'); - print_status(Play, TRUE); -} - -/* - * Allows player "Play" to pay off loans interactively. - */ -void LoanShark(Player *Play) -{ - gchar *text, *prstr; - price_t money; - - do { - clear_bottom(); - attrset(PromptAttr); - - /* Prompt for paying back loans from the loan shark */ - text = - nice_input(_("How much money do you pay back? "), 19, 1, TRUE, - NULL, '\0'); - attrset(TextAttr); - money = strtoprice(text); - g_free(text); - if (money < 0) - money = 0; - if (money > Play->Debt) - money = Play->Debt; - if (money > Play->Cash) { - /* Error - player doesn't have enough money to pay back the loan */ - mvaddstr(20, 1, _("You don't have that much money!")); - nice_wait(); - } else { - SendClientMessage(Play, C_NONE, C_PAYLOAN, NULL, - (prstr = pricetostr(money))); - g_free(prstr); - money = 0; - } - } while (money != 0); -} - -/* - * Allows player "Play" to pay in or withdraw money from the bank - * interactively. - */ -void Bank(Player *Play) -{ - gchar *text, *prstr; - price_t money = 0; - int action; - - do { - clear_bottom(); - attrset(PromptAttr); - /* Prompt for dealing with the bank in the curses client */ - mvaddstr(18, 1, _("Do you want to D>eposit money, W>ithdraw money, " - "or L>eave ? ")); - attrset(TextAttr); - - /* Make sure you keep the order the same if you translate these keys! - * (D>eposit, W>ithdraw, L>eave) */ - action = GetKey(_("DWL"), "DWL", FALSE, FALSE, FALSE); - - if (action == 'D' || action == 'W') { - /* Prompt for putting money in or taking money out of the bank */ - text = nice_input(_("How much money? "), 19, 1, TRUE, NULL, '\0'); - - money = strtoprice(text); - g_free(text); - if (money < 0) - money = 0; - if (action == 'W') - money = -money; - if (money > Play->Cash) { - /* Error - player has tried to put more money into the bank than - * he/she has */ - mvaddstr(20, 1, _("You don't have that much money!")); - nice_wait(); - } else if (-money > Play->Bank) { - /* Error - player has tried to withdraw more money from the bank - * than there is in the account */ - mvaddstr(20, 1, _("There isn't that much money in the bank...")); - nice_wait(); - } else if (money != 0) { - SendClientMessage(Play, C_NONE, C_DEPOSIT, NULL, - (prstr = pricetostr(money))); - g_free(prstr); - money = 0; - } - } - } while (action != 'L' && money != 0); -} - -/* - * Waits for keyboard input; will only accept a key listed in the - * "allowed" string. This string may have been translated; thus - * the "orig_allowed" string contains the untranslated keys. - * Returns the untranslated key corresponding to the key pressed - * (e.g. if allowed[2] is pressed, orig_allowed[2] is returned) - * Case insensitive. If "AllowOther" is TRUE, keys other than the - * given selection are allowed, and cause a zero return value. - * If "PrintAllowed" is TRUE, the allowed keys are printed after - * the prompt. If "ExpandOut" is also TRUE, the full words for - * the commands, rather than just their first letters, are displayed. - */ -int GetKey(char *allowed, char *orig_allowed, gboolean AllowOther, - gboolean PrintAllowed, gboolean ExpandOut) -{ - int ch; - guint AllowInd, WordInd, i; - - /* Expansions of the single-letter keypresses for the benefit of the - * user. i.e. "Yes" is printed for the key "Y" etc. You should indicate - * to the user which letter in the word corresponds to the keypress, by - * capitalising it or similar. */ - gchar *Words[] = { N_("Y:Yes"), N_("N:No"), N_("R:Run"), - N_("F:Fight"), N_("A:Attack"), N_("E:Evade") - }; - guint numWords = sizeof(Words) / sizeof(Words[0]); - gchar *trWord; - - curs_set(1); - ch = '\0'; - - if (!allowed || strlen(allowed) == 0) - return 0; - - if (PrintAllowed) { - addch('[' | TextAttr); - for (AllowInd = 0; AllowInd < strlen(allowed); AllowInd++) { - if (AllowInd > 0) - addch('/' | TextAttr); - WordInd = 0; - while (WordInd < numWords && - orig_allowed[AllowInd] != Words[WordInd][0]) - WordInd++; - - if (ExpandOut && WordInd < numWords) { - trWord = _(Words[WordInd]); - for (i = 2; i < strlen(trWord); i++) - addch((guchar)trWord[i] | TextAttr); - } else - addch((guchar)allowed[AllowInd] | TextAttr); - } - addch(']' | TextAttr); - addch(' ' | TextAttr); - } - - do { - ch = bgetch(); - ch = toupper(ch); - for (AllowInd = 0; AllowInd < strlen(allowed); AllowInd++) { - if (allowed[AllowInd] == ch) { - addch((guint)ch | TextAttr); - curs_set(0); - return orig_allowed[AllowInd]; - } - } - } while (!AllowOther); - - curs_set(0); - return 0; -} - -/* - * Clears one whole line on the curses screen. - */ -void clear_line(int line) -{ - int i; - - move(line, 0); - for (i = 0; i < Width; i++) - addch(' '); -} - -/* - * Clears the bottom of the screen (i.e. from line 16 to line 23) - * except for the top "skip" lines. - */ -void clear_exceptfor(int skip) -{ - int i; - - for (i = 16 + skip; i <= 23; i++) - clear_line(i); -} - - -/* - * Clears screen lines 16 to 23. - */ -void clear_bottom(void) -{ - int i; - - for (i = 16; i <= 23; i++) - clear_line(i); -} - -/* - * Clears the entire screen; 24 lines of 80 characters each. - */ -void clear_screen(void) -{ - int i; - - for (i = 0; i < Depth; i++) - clear_line(i); -} - -/* - * Displays a prompt on the bottom screen line and waits for the user - * to press a key. - */ -void nice_wait() -{ - gchar *text; - - attrset(PromptAttr); - text = _("Press any key..."); - mvaddstr(23, (Width - strlen(text)) / 2, text); - bgetch(); - attrset(TextAttr); -} - -/* - * Handles the display of messages pertaining to player-player fights - * in the lower part of screen (fighting sub-screen). Adds the new line - * of text in "text" and scrolls up previous messages if necessary - * If "text" is NULL, initialises the area - * If "text" is a blank string, redisplays the message area - * Messages are displayed from lines 16 to 20; line 22 is used for - * the prompt for the user. - */ -void DisplayFightMessage(Player *Play, char *text) -{ - static char Messages[5][79]; - static int x, y; - gchar *textpt; - gchar *AttackName, *DefendName, *BitchName; - gint i, DefendHealth, DefendBitches, BitchesKilled, ArmPercent; - gboolean Loot; - - if (text == NULL) { - x = 0; - y = 15; - for (i = 0; i < 5; i++) - Messages[i][0] = '\0'; - } else if (!text[0]) { - attrset(TextAttr); - clear_bottom(); - for (i = 16; i <= 20; i++) - mvaddstr(i, 1, Messages[i - 16]); - } else { - if (HaveAbility(Play, A_NEWFIGHT)) { - ReceiveFightMessage(text, &AttackName, &DefendName, &DefendHealth, - &DefendBitches, &BitchName, &BitchesKilled, - &ArmPercent, &fp, &RunHere, &Loot, &CanFire, - &textpt); - } else { - textpt = text; - if (Play->Flags & FIGHTING) - fp = F_MSG; - else - fp = F_LASTLEAVE; - CanFire = (Play->Flags & CANSHOOT); - RunHere = FALSE; - } - while (textpt[0]) { - if (y < 20) - y++; - else - for (i = 0; i < 4; i++) - strcpy(Messages[i], Messages[i + 1]); - - strncpy(Messages[y - 16], textpt, 78); - Messages[y - 16][78] = '\0'; - textpt += MIN(strlen(textpt), 78); - } - } -} - -/* - * Displays a network message "buf" in the message area (lines - * 10 to 14) scrolling previous messages up. - * If "buf" is NULL, clears the message area - * If "buf" is a blank string, redisplays the message area - */ -void display_message(char *buf) -{ - guint x, y; - guint wid; - static gchar Messages[5][200]; - gchar *bufpt; - - if (Width <= 4) - return; - - wid = MIN(Width - 4, 200); - - if (!buf) { - for (y = 0; y < 5; y++) { - memset(Messages[y], ' ', 200); - if (Network) { - mvaddch(y + 10, 0, ' ' | TextAttr); - addch(ACS_VLINE | StatsAttr); - for (x = 0; x < wid; x++) - addch(' ' | StatsAttr); - addch(ACS_VLINE | StatsAttr); - addch(' ' | TextAttr); - } - } - } else if (Network) { - bufpt = buf; - while (bufpt[0] != 0) { - memmove(Messages[0], Messages[1], 200 * 4); - memset(Messages[4], ' ', 200); - memcpy(Messages[4], bufpt, - strlen(bufpt) > wid ? wid : strlen(bufpt)); - bufpt += MIN(strlen(bufpt), wid); - } - for (y = 0; y < 5; y++) - for (x = 0; x < wid; x++) { - mvaddch(y + 10, x + 2, (guchar)Messages[y][x] | StatsAttr); - } - refresh(); - } -} - -/* - * Displays the string "text" at the top of the screen. Usually used for - * displaying the current location or the "Subway" flash. - */ -void print_location(char *text) -{ - int i; - - if (!text) - return; - attrset(LocationAttr); - move(0, Width / 2 - 9); - for (i = 0; i < 18; i++) - addch(' '); - mvaddstr(0, (Width - strlen(text)) / 2, text); - attrset(TextAttr); -} - -/* - * Displays the status of player "Play" - i.e. the current turn, the - * location, bitches, available space, cash, guns, health and bank - * details. If "DispDrugs" is TRUE, displays the carried drugs on the - * right hand side of the screen; if FALSE, displays the carried guns. - */ -void print_status(Player *Play, gboolean DispDrug) -{ - int i, c; - GString *text; - - text = g_string_new(NULL); - attrset(TitleAttr); - clear_line(0); - g_string_sprintf(text, "%s%02d%s", Names.Month, Play->Turn, Names.Year); - mvaddstr(0, 3, text->str); - - attrset(StatsAttr); - for (i = 2; i <= 14; i++) { - mvaddch(i, 1, ACS_VLINE); - mvaddch(i, Width - 2, ACS_VLINE); - } - mvaddch(1, 1, ACS_ULCORNER); - for (i = 0; i < Width - 4; i++) - addch(ACS_HLINE); - addch(ACS_URCORNER); - - mvaddch(1, Width / 2, ACS_TTEE); - for (i = 2; i <= (Network ? 8 : 13); i++) { - move(i, 2); - for (c = 2; c < Width / 2; c++) - addch(' '); - addch(ACS_VLINE); - for (c = Width / 2 + 1; c < Width - 2; c++) - addch(' '); - } - if (!Network) { - mvaddch(14, 1, ACS_LLCORNER); - for (i = 0; i < Width - 4; i++) - addch(ACS_HLINE); - addch(ACS_LRCORNER); - mvaddch(14, Width / 2, ACS_BTEE); - } else { - mvaddch(9, 1, ACS_LTEE); - for (i = 0; i < Width - 4; i++) - addch(ACS_HLINE); - addch(ACS_RTEE); - - /* Title of the "Messages" window in the curses client */ - mvaddstr(9, 15, _("Messages")); - - mvaddch(9, Width / 2, ACS_BTEE); - mvaddch(15, 1, ACS_LLCORNER); - for (i = 0; i < Width - 4; i++) - addch(ACS_HLINE); - addch(ACS_LRCORNER); - } - - /* Title of the "Stats" window in the curses client */ - mvaddstr(1, Width / 4 - 2, _("Stats")); - - attrset(StatsAttr); - - /* Display of the player's cash in the stats window (careful to keep the - * formatting if you change the length of the "Cash" word) */ - dpg_string_sprintf(text, _("Cash %17P"), Play->Cash); - mvaddstr(3, 9, text->str); - - /* Display of the total number of guns carried (%Tde="Guns" by default) */ - dpg_string_sprintf(text, _("%-19Tde%3d"), Names.Guns, - TotalGunsCarried(Play)); - mvaddstr(Network ? 4 : 5, 9, text->str); - - /* Display of the player's health */ - g_string_sprintf(text, _("Health %3d"), Play->Health); - mvaddstr(Network ? 5 : 7, 9, text->str); - - /* Display of the player's bank balance */ - dpg_string_sprintf(text, _("Bank %17P"), Play->Bank); - mvaddstr(Network ? 6 : 9, 9, text->str); - - if (Play->Debt > 0) - attrset(DebtAttr); - /* Display of the player's debt */ - dpg_string_sprintf(text, _("Debt %17P"), Play->Debt); - mvaddstr(Network ? 7 : 11, 9, text->str); - attrset(TitleAttr); - - /* Display of the player's trenchcoat size (antique mode only) */ - if (WantAntique) - g_string_sprintf(text, _("Space %6d"), Play->CoatSize); - else { - /* Display of the player's number of bitches, and available space - * (%Tde="Bitches" by default) */ - dpg_string_sprintf(text, _("%Tde %3d Space %6d"), Names.Bitches, - Play->Bitches.Carried, Play->CoatSize); - } - mvaddstr(0, Width - 2 - strlen(text->str), text->str); - print_location(Location[(int)Play->IsAt].Name); - attrset(StatsAttr); - - c = 0; - if (DispDrug) { - /* Title of the "trenchcoat" window (antique mode only) */ - if (WantAntique) - mvaddstr(1, Width * 3 / 4 - 5, _("Trenchcoat")); - else { - /* Title of the "drugs" window (the only important bit in this - * string is the "%Tde" which is "Drugs" by default; the %/.../ part - * is ignored, so you don't need to translate it; see doc/i18n.html) - */ - dpg_string_sprintf(text, _("%/Stats: Drugs/%Tde"), Names.Drugs); - mvaddstr(1, Width * 3 / 4 - strlen(text->str) / 2, text->str); - } - for (i = 0; i < NumDrug; i++) { - if (Play->Drugs[i].Carried > 0) { - /* Display of carried drugs with price (%tde="Opium", etc. by - * default) */ - if (HaveAbility(Play, A_DRUGVALUE)) { - dpg_string_sprintf(text, _("%-7tde %3d @ %P"), Drug[i].Name, - Play->Drugs[i].Carried, - Play->Drugs[i].TotalValue / - Play->Drugs[i].Carried); - mvaddstr(3 + c, Width / 2 + 3, text->str); - } else { - /* Display of carried drugs (%tde="Opium", etc. by default) */ - dpg_string_sprintf(text, _("%-7tde %3d"), Drug[i].Name, - Play->Drugs[i].Carried); - mvaddstr(3 + c / 2, Width / 2 + 3 + (c % 2) * 17, text->str); - } - c++; - } - } - } else { - /* Title of the "guns" window (the only important bit in this string - * is the "%Tde" which is "Guns" by default) */ - dpg_string_sprintf(text, _("%/Stats: Guns/%Tde"), Names.Guns); - mvaddstr(1, Width * 3 / 4 - strlen(text->str) / 2, text->str); - for (i = 0; i < NumGun; i++) { - if (Play->Guns[i].Carried > 0) { - /* Display of carried guns (%tde="Baretta", etc. by default) */ - dpg_string_sprintf(text, _("%-22tde %3d"), Gun[i].Name, - Play->Guns[i].Carried); - mvaddstr(3 + c, Width / 2 + 3, text->str); - c++; - } - } - } - attrset(TextAttr); - if (!Network) - clear_line(15); - refresh(); - g_string_free(text, TRUE); -} - -/* - * Parses details about player "From" from string "Data" and then - * displays the lot, drugs and guns. - */ -void DisplaySpyReports(char *Data, Player *From, Player *To) -{ - gchar *text; - - ReceivePlayerData(To, Data, From); - - clear_bottom(); - text = g_strdup_printf(_("Spy reports for %s"), GetPlayerName(From)); - mvaddstr(17, 1, text); - g_free(text); - - /* Message displayed with a spy's list of drugs (%Tde="Drugs" by - * default) */ - text = dpg_strdup_printf(_("%/Spy: Drugs/%Tde..."), Names.Drugs); - mvaddstr(19, 20, text); - g_free(text); - print_status(From, TRUE); - nice_wait(); - clear_line(19); - - /* Message displayed with a spy's list of guns (%Tde="Guns" by default) */ - text = dpg_strdup_printf(_("%/Spy: Guns/%Tde..."), Names.Guns); - mvaddstr(19, 20, text); - g_free(text); - print_status(From, FALSE); - nice_wait(); - - print_status(To, TRUE); - refresh(); -} - -/* - * Displays the "Prompt" if non-NULL, and then lists all clients - * currently playing dopewars, other than the current player "Play". - * If "Select" is TRUE, gives each player a letter and asks the user - * to select one, which is returned by the function. - */ -Player *ListPlayers(Player *Play, gboolean Select, char *Prompt) -{ - Player *tmp = NULL; - GSList *list; - int i, c; - gchar *text; - - attrset(TextAttr); - clear_bottom(); - if (!FirstClient || (!g_slist_next(FirstClient) && - FirstClient->data == Play)) { - text = _("No other players are currently logged on!"); - mvaddstr(18, (Width - strlen(text)) / 2, text); - nice_wait(); - return 0; - } - mvaddstr(16, 1, _("Players currently logged on:-")); - - i = 0; - for (list = FirstClient; list; list = g_slist_next(list)) { - tmp = (Player *)list->data; - if (strcmp(GetPlayerName(tmp), GetPlayerName(Play)) == 0) - continue; - if (Select) - text = g_strdup_printf("%c. %s", 'A' + i, GetPlayerName(tmp)); - else - text = g_strdup(GetPlayerName(tmp)); - mvaddstr(17 + i / 2, (i % 2) * 40 + 1, text); - g_free(text); - i++; - } - - if (Prompt) { - attrset(PromptAttr); - mvaddstr(22, 10, Prompt); - attrset(TextAttr); - } - if (Select) { - curs_set(1); - attrset(TextAttr); - c = 0; - while (c < 'A' || c >= 'A' + i) { - c = bgetch(); - c = toupper(c); - } - if (Prompt) - addch((guint)c); - list = FirstClient; - while (c >= 'A') { - if (list != FirstClient) - list = g_slist_next(list); - tmp = (Player *)list->data; - while (strcmp(GetPlayerName(tmp), GetPlayerName(Play)) == 0) { - list = g_slist_next(list); - tmp = (Player *)list->data; - } - c--; - } - return tmp; - } else { - nice_wait(); - } - return NULL; -} - -/* - * Displays the given "prompt" (if non-NULL) at coordinates sx,sy and - * allows the user to input a string, which is returned. This is a - * dynamically allocated string, and so must be freed by the calling - * routine. If "digitsonly" is TRUE, the user will be permitted only to - * input numbers, although the suffixes m and k are allowed (the - * strtoprice routine understands this notation for a 1000000 or 1000 - * multiplier) as well as a decimal point (. or ,) - * If "displaystr" is non-NULL, it is taken as a default response. - * If "passwdchar" is non-zero, it is displayed instead of the user's - * keypresses (e.g. for entering passwords) - */ -char *nice_input(char *prompt, int sy, int sx, gboolean digitsonly, - char *displaystr, char passwdchar) -{ - int i, c, x; - gboolean DecimalPoint, Suffix; - GString *text; - gchar *ReturnString; - - DecimalPoint = Suffix = FALSE; - - x = sx; - move(sy, x); - if (prompt) { - attrset(PromptAttr); - addstr(prompt); - x += strlen(prompt); - } - attrset(TextAttr); - if (displaystr) { - if (passwdchar) { - for (i = strlen(displaystr); i; i--) - addch((guint)passwdchar); - } else { - addstr(displaystr); - } - i = strlen(displaystr); - text = g_string_new(displaystr); - } else { - i = 0; - text = g_string_new(""); - } - - curs_set(1); - do { - move(sy + (x + i) / Width, (x + i) % Width); - c = bgetch(); - if ((c == 8 || c == KEY_BACKSPACE || c == 127) && i > 0) { - move(sy + (x + i - 1) / Width, (x + i - 1) % Width); - addch(' '); - i--; - if (DecimalPoint && text->str[i] == '.') - DecimalPoint = FALSE; - if (Suffix) - Suffix = FALSE; - g_string_truncate(text, i); - } else if (!Suffix) { - if ((digitsonly && c >= '0' && c <= '9') || - (!digitsonly && c >= 32 && c != '^' && c < 127)) { - g_string_append_c(text, c); - i++; - addch((guint)passwdchar ? passwdchar : c); - } else if (digitsonly && (c == '.' || c == ',') && !DecimalPoint) { - g_string_append_c(text, '.'); - i++; - addch((guint)passwdchar ? passwdchar : c); - DecimalPoint = TRUE; - } else if (digitsonly - && (c == 'M' || c == 'm' || c == 'k' || c == 'K') - && !Suffix) { - g_string_append_c(text, c); - i++; - addch((guint)passwdchar ? passwdchar : c); - Suffix = TRUE; - } - } - } while (c != '\n' && c != KEY_ENTER); - curs_set(0); - move(sy, x); - ReturnString = text->str; - g_string_free(text, FALSE); /* Leave the buffer to return */ - return ReturnString; -} - -/* - * Loop which handles the user playing an interactive game (i.e. "Play" - * is a client connected to a server, either locally or remotely) - * dopewars is essentially server-driven, so this loop simply has to - * make the screen look pretty, respond to user keypresses, and react - * to messages from the server. - */ -static void Curses_DoGame(Player *Play) -{ - gchar *buf, *OldName, *TalkMsg; - GString *text; - int i, c; - char IsCarrying; - -#if NETWORKING || HAVE_SELECT - fd_set readfs; -#endif -#ifdef NETWORKING - fd_set writefs; - gboolean DoneOK; - gchar *pt; - gboolean justconnected = FALSE; -#endif - int NumDrugsHere; - int MaxSock; - char HaveWorthless; - Player *tmp; - struct sigaction sact; - - DisplayMode = DM_NONE; - QuitRequest = FALSE; - - ResizedFlag = 0; - sact.sa_handler = ResizeHandle; - sact.sa_flags = 0; - sigemptyset(&sact.sa_mask); - if (sigaction(SIGWINCH, &sact, NULL) == -1) { - g_warning(_("Cannot install SIGWINCH interrupt handler!")); - } - OldName = g_strdup(GetPlayerName(Play)); - attrset(TextAttr); - clear_screen(); - display_message(NULL); - DisplayFightMessage(Play, NULL); - print_status(Play, TRUE); - - attrset(TextAttr); - clear_bottom(); - buf = NULL; - do { - g_free(buf); - buf = - nice_input(_("Hey dude, what's your name? "), 17, 1, FALSE, - OldName, '\0'); - } while (buf[0] == 0); -#if NETWORKING - if (WantNetwork) { - if (!ConnectToServer(Play)) { - end_curses(); - exit(1); - } - justconnected = TRUE; - } -#endif /* NETWORKING */ - print_status(Play, TRUE); - display_message(""); - - InitAbilities(Play); - SendAbilities(Play); - SetPlayerName(Play, buf); - SendNullClientMessage(Play, C_NONE, C_NAME, NULL, buf); - g_free(buf); - g_free(OldName); - - text = g_string_new(""); - - while (1) { - if (Play->Health == 0) - DisplayMode = DM_NONE; - HaveWorthless = 0; - IsCarrying = 0; - for (i = 0; i < NumDrug; i++) { - if (Play->Drugs[i].Carried > 0) { - IsCarrying = 1; - if (Play->Drugs[i].Price == 0) - HaveWorthless = 1; - } - } - switch (DisplayMode) { - case DM_STREET: - attrset(TextAttr); - NumDrugsHere = 0; - for (i = 0; i < NumDrug; i++) - if (Play->Drugs[i].Price > 0) - NumDrugsHere++; - clear_bottom(); - /* Display of drug prices (%tde="drugs" by default) */ - dpg_string_sprintf(text, _("Hey dude, the prices of %tde here are:"), - Names.Drugs); - mvaddstr(16, 1, text->str); - for (c = 0, i = GetNextDrugIndex(-1, Play); - c < NumDrugsHere && i != -1; - c++, i = GetNextDrugIndex(i, Play)) { - /* List of individual drug names for selection (%tde="Opium" etc. - * by default) */ - dpg_string_sprintf(text, _("%c. %-10tde %8P"), 'A' + c, - Drug[i].Name, Play->Drugs[i].Price); - mvaddstr(17 + c / 3, (c % 3) * 25 + 4, text->str); - } - attrset(PromptAttr); - /* Prompts for "normal" actions in curses client */ - g_string_assign(text, _("Will you B>uy")); - if (IsCarrying) - g_string_append(text, _(", S>ell")); - if (HaveWorthless && !WantAntique) - g_string_append(text, _(", D>rop")); - if (Network) - g_string_append(text, _(", T>alk, P>age, L>ist")); - if (!WantAntique && (Play->Bitches.Carried > 0 || - Play->Flags & SPYINGON)) { - g_string_append(text, _(", G>ive")); - } - if (Play->Flags & FIGHTING) { - g_string_append(text, _(", F>ight")); - } else { - g_string_append(text, _(", J>et")); - } - g_string_append(text, _(", or Q>uit? ")); - mvaddstr(22, 40 - strlen(text->str) / 2, text->str); - attrset(TextAttr); - curs_set(1); - break; - case DM_FIGHT: - DisplayFightMessage(Play, ""); - attrset(PromptAttr); - /* Prompts for actions during fights in curses client */ - g_string_assign(text, _("Do you ")); - if (CanFire) { - if (TotalGunsCarried(Play) > 0) { - g_string_append(text, _("F>ight, ")); - } else { - g_string_append(text, _("S>tand, ")); - } - } - if (fp != F_LASTLEAVE) - g_string_append(text, _("R>un, ")); - if (!RunHere || fp == F_LASTLEAVE) - /* (%tde = "drugs" by default here) */ - dpg_string_sprintfa(text, _("D>eal %tde, "), Names.Drugs); - g_string_append(text, _("or Q>uit? ")); - mvaddstr(22, 40 - strlen(text->str) / 2, text->str); - attrset(TextAttr); - curs_set(1); - break; - case DM_DEAL: - attrset(TextAttr); - clear_bottom(); - mvaddstr(16, 1, "Your trade:-"); - mvaddstr(19, 1, "His trade:-"); - g_string_assign(text, "Do you A>dd, R>emove, O>K, D>eal "); - g_string_append(text, Names.Drugs); - g_string_append(text, ", or Q>uit? "); - attrset(PromptAttr); - mvaddstr(22, 40 - strlen(text->str) / 2, text->str); - attrset(TextAttr); - curs_set(1); - break; - case DM_NONE: - break; - } - refresh(); - - if (QuitRequest) - return; -#if NETWORKING - FD_ZERO(&readfs); - FD_ZERO(&writefs); - FD_SET(0, &readfs); - MaxSock = 1; - if (Client) { - if (justconnected) { - /* Deal with any messages that came in while we were connect()ing */ - justconnected = FALSE; - while ((pt = GetWaitingPlayerMessage(Play)) != NULL) { - HandleClientMessage(pt, Play); - g_free(pt); - } - if (QuitRequest) - return; - } - SetSelectForNetworkBuffer(&Play->NetBuf, &readfs, &writefs, - NULL, &MaxSock); - } - if (bselect(MaxSock, &readfs, &writefs, NULL, NULL) == -1) { - if (errno == EINTR) { - CheckForResize(Play); - continue; - } - perror("bselect"); - exit(1); - } - if (Client) { - if (RespondToSelect(&Play->NetBuf, &readfs, &writefs, NULL, &DoneOK)) { - while ((pt = GetWaitingPlayerMessage(Play)) != NULL) { - HandleClientMessage(pt, Play); - g_free(pt); - } - if (QuitRequest) - return; - } - if (!DoneOK) { - attrset(TextAttr); - clear_line(22); - mvaddstr(22, 0, _("Connection to server lost! " - "Reverting to single player mode")); - nice_wait(); - SwitchToSinglePlayer(Play); - print_status(Play, TRUE); - } - } - if (FD_ISSET(0, &readfs)) { -#elif HAVE_SELECT - FD_ZERO(&readfs); - FD_SET(0, &readfs); - MaxSock = 1; - if (bselect(MaxSock, &readfs, NULL, NULL, NULL) == -1) { - if (errno == EINTR) { - CheckForResize(Play); - continue; - } - perror("bselect"); - exit(1); - } -#endif /* NETWORKING */ - if (DisplayMode == DM_STREET) { - /* N.B. You must keep the order of these keys the same as the - * original when you translate (B>uy, S>ell, D>rop, T>alk, P>age, - * L>ist, G>ive errand, F>ight, J>et, Q>uit) */ - c = GetKey(_("BSDTPLGFJQ"), "BSDTPLGFJQ", TRUE, FALSE, FALSE); - - } else if (DisplayMode == DM_FIGHT) { - /* N.B. You must keep the order of these keys the same as the - * original when you translate (D>eal drugs, R>un, F>ight, S>tand, - * Q>uit) */ - c = GetKey(_("DRFSQ"), "DRFSQ", TRUE, FALSE, FALSE); - - } else - c = 0; -#if ! (NETWORKING || HAVE_SELECT) - CheckForResize(Play); -#endif - if (DisplayMode == DM_STREET) { - if (c == 'J' && !(Play->Flags & FIGHTING)) { - jet(Play, TRUE); - } else if (c == 'F' && Play->Flags & FIGHTING) { - DisplayMode = DM_FIGHT; - } else if (c == 'T' && Play->Flags & TRADING) { - DisplayMode = DM_DEAL; - } else if (c == 'B') { - DealDrugs(Play, TRUE); - } else if (c == 'S' && IsCarrying) { - DealDrugs(Play, FALSE); - } else if (c == 'D' && HaveWorthless && !WantAntique) { - DropDrugs(Play); - } else if (c == 'G' && !WantAntique && Play->Bitches.Carried > 0) { - GiveErrand(Play); - } else if (c == 'Q') { - if (want_to_quit() == 1) { - DisplayMode = DM_NONE; - clear_bottom(); - SendClientMessage(Play, C_NONE, C_WANTQUIT, NULL, NULL); - } - } else if (c == 'L' && Network) { - attrset(PromptAttr); - mvaddstr(23, 20, _("List what? P>layers or S>cores? ")); - /* P>layers, S>cores */ - i = GetKey(_("PS"), "PS", TRUE, FALSE, FALSE); - if (i == 'P') { - ListPlayers(Play, FALSE, NULL); - } else if (i == 'S') { - DisplayMode = DM_NONE; - SendClientMessage(Play, C_NONE, C_REQUESTSCORE, NULL, NULL); - } - } else if (c == 'P' && Network) { - tmp = ListPlayers(Play, TRUE, - _("Whom do you want to page " - "(talk privately to) ? ")); - if (tmp) { - attrset(TextAttr); - clear_line(22); - /* Prompt for sending player-player messages */ - TalkMsg = nice_input(_("Talk: "), 22, 0, FALSE, NULL, '\0'); - if (TalkMsg[0]) { - SendClientMessage(Play, C_NONE, C_MSGTO, tmp, TalkMsg); - buf = g_strdup_printf("%s->%s: %s", GetPlayerName(Play), - GetPlayerName(tmp), TalkMsg); - display_message(buf); - g_free(buf); - } - g_free(TalkMsg); - } - } else if (c == 'T' && Client) { - attrset(TextAttr); - clear_line(22); - TalkMsg = nice_input(_("Talk: "), 22, 0, FALSE, NULL, '\0'); - if (TalkMsg[0]) { - SendClientMessage(Play, C_NONE, C_MSG, NULL, TalkMsg); - buf = g_strdup_printf("%s: %s", GetPlayerName(Play), TalkMsg); - display_message(buf); - g_free(buf); - } - g_free(TalkMsg); - } - } else if (DisplayMode == DM_FIGHT) { - switch (c) { - case 'D': - DisplayMode = DM_STREET; - break; - case 'R': - if (RunHere) { - SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, "R"); - } else { - jet(Play, TRUE); - } - break; - case 'F': - if (TotalGunsCarried(Play) > 0 && CanFire) { - buf = g_strdup_printf("%c", c); - Play->Flags &= ~CANSHOOT; - SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, buf); - g_free(buf); - } - break; - case 'S': - if (TotalGunsCarried(Play) == 0 && CanFire) { - buf = g_strdup_printf("%c", c); - Play->Flags &= ~CANSHOOT; - SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, buf); - g_free(buf); - } - break; - case 'Q': - if (want_to_quit() == 1) { - DisplayMode = DM_NONE; - clear_bottom(); - SendClientMessage(Play, C_NONE, C_WANTQUIT, NULL, NULL); - } - break; - } - } else if (DisplayMode == DM_DEAL) { - switch (c) { - case 'D': - DisplayMode = DM_STREET; - break; - case 'Q': - if (want_to_quit() == 1) { - DisplayMode = DM_NONE; - clear_bottom(); - SendClientMessage(Play, C_NONE, C_WANTQUIT, NULL, NULL); - } - break; - } - } -#if NETWORKING - } -#endif - curs_set(0); - } - g_string_free(text, TRUE); -} - -void CursesLoop(void) -{ - char c; - Player *Play; - - if (!CheckHighScoreFileConfig()) - return; - - /* Save the configuration, so we can restore those elements that get - * overwritten when we connect to a dopewars server */ - BackupConfig(); - - start_curses(); - Width = COLS; - Depth = LINES; - - /* Set up message handlers */ - ClientMessageHandlerPt = HandleClientMessage; - - /* Make the GLib log messages display nicely */ - g_log_set_handler(NULL, - LogMask() | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING, - LogMessage, NULL); - - display_intro(); - - Play = g_new(Player, 1); - FirstClient = AddPlayer(0, Play, FirstClient); - do { - Curses_DoGame(Play); - ShutdownNetwork(Play); - CleanUpServer(); - RestoreConfig(); - attrset(TextAttr); - mvaddstr(23, 20, _("Play again? ")); - c = GetKey(_("YN"), "YN", TRUE, TRUE, FALSE); - } while (c == 'Y'); - FirstClient = RemovePlayer(Play, FirstClient); - end_curses(); -} - -#else - -#include <glib.h> -#include "nls.h" /* We need this for the definition of '_' */ - -void CursesLoop(void) -{ - g_print(_("No curses client available - rebuild the binary passing the\n" - "--enable-curses-client option to configure, or use a windowed\n" - "client (if available) instead!\n")); -} - -#endif /* CURSES_CLIENT */ (DIR) diff --git a/src/curses_client/Makefile.am b/src/curses_client/Makefile.am t@@ -0,0 +1,6 @@ +noinst_LIBRARIES = libcursesclient.a +libcursesclient_a_SOURCES = curses_client.c +libcursesclient_a_DEPENDENCIES = @INTLLIBS@ +INCLUDES = -I.. -I../.. -I. +LDADD = @INTLLIBS@ +DEFS = @DEFS@ -DLOCALEDIR=\"${localedir}\" (DIR) diff --git a/src/curses_client/Makefile.in b/src/curses_client/Makefile.in t@@ -0,0 +1,325 @@ +# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = ../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +DATADIRNAME = @DATADIRNAME@ +GENCAT = @GENCAT@ +GLIBC21 = @GLIBC21@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_CONFIG = @GLIB_CONFIG@ +GLIB_LIBS = @GLIB_LIBS@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_CONFIG = @GTK_CONFIG@ +GTK_LIBS = @GTK_LIBS@ +INSTOBJEXT = @INSTOBJEXT@ +INTLBISON = @INTLBISON@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ +LIBICONV = @LIBICONV@ +MAKEINFO = @MAKEINFO@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +PACKAGE = @PACKAGE@ +POFILES = @POFILES@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WNDRES = @WNDRES@ +localedir = @localedir@ + +noinst_LIBRARIES = libcursesclient.a +libcursesclient_a_SOURCES = curses_client.c +libcursesclient_a_DEPENDENCIES = @INTLLIBS@ +INCLUDES = -I.. -I../.. -I. +LDADD = @INTLLIBS@ +DEFS = @DEFS@ -DLOCALEDIR=\"${localedir}\" +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libcursesclient_a_LIBADD = +libcursesclient_a_OBJECTS = curses_client.o +AR = ar +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +DEP_FILES = .deps/curses_client.P +SOURCES = $(libcursesclient_a_SOURCES) +OBJECTS = $(libcursesclient_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu src/curses_client/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libcursesclient.a: $(libcursesclient_a_OBJECTS) $(libcursesclient_a_DEPENDENCIES) + -rm -f libcursesclient.a + $(AR) cru libcursesclient.a $(libcursesclient_a_OBJECTS) $(libcursesclient_a_LIBADD) + $(RANLIB) libcursesclient.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = src/curses_client + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/curses_client/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-depend mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-depend \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-depend distclean-generic \ + clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-depend maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir mostlyclean-depend \ +distclean-depend clean-depend maintainer-clean-depend info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: (DIR) diff --git a/src/curses_client/curses_client.c b/src/curses_client/curses_client.c t@@ -0,0 +1,2409 @@ +/************************************************************************ + * curses_client.c dopewars client using the (n)curses console library * + * Copyright (C) 1998-2002 Ben Webb * + * Email: ben@bellatrix.pcl.ox.ac.uk * + * WWW: http://dopewars.sourceforge.net/ * + * * + * 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 2 * + * 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, write to the Free Software * + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * + * MA 02111-1307, USA. * + ************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <glib.h> +#include "curses_client.h" +#include "dopeos.h" +#include "dopewars.h" +#include "message.h" +#include "nls.h" +#include "serverside.h" +#include "tstring.h" + +static void PrepareHighScoreScreen(void); +static void PrintHighScore(char *Data); + +static int ResizedFlag; +static SCREEN *cur_screen; + +#ifdef NETWORKING +static enum { + CM_SERVER, CM_PROMPT, CM_META, CM_SINGLE +} ConnectMethod = CM_SERVER; +#endif + +static gboolean CanFire = FALSE, RunHere = FALSE; +static FightPoint fp; + +/* Function definitions; make them static so as not to clash with + * functions of the same name in different clients */ +static void display_intro(void); +static void ResizeHandle(int sig); +static void CheckForResize(Player *Play); +static int GetKey(char *allowed, char *orig_allowed, gboolean AllowOther, + gboolean PrintAllowed, gboolean ExpandOut); +static void clear_bottom(void), clear_screen(void); +static void clear_line(int line), clear_exceptfor(int skip); +static void nice_wait(void); +static void DisplayFightMessage(Player *Play, char *text); +static void DisplaySpyReports(char *Data, Player *From, Player *To); +static void display_message(char *buf); +static void print_location(char *text); +static void print_status(Player *Play, gboolean DispDrug); +static char *nice_input(char *prompt, int sy, int sx, gboolean digitsonly, + char *displaystr, char passwdchar); +static Player *ListPlayers(Player *Play, gboolean Select, char *Prompt); +static void HandleClientMessage(char *buf, Player *Play); +static void PrintMessage(const gchar *text); +static void GunShop(Player *Play); +static void LoanShark(Player *Play); +static void Bank(Player *Play); + +#ifdef NETWORKING +static void HttpAuthFunc(HttpConnection *conn, gboolean proxyauth, + gchar *realm, gpointer data); +static void SocksAuthFunc(NetworkBuffer *netbuf, gpointer data); +#endif + +static DispMode DisplayMode; +static gboolean QuitRequest; + +/* + * Initialises the curses library for accessing the screen. + */ +static void start_curses(void) +{ + cur_screen = newterm(NULL, stdout, stdin); + if (WantColour) { + start_color(); + init_pair(1, COLOR_MAGENTA, COLOR_WHITE); + init_pair(2, COLOR_BLACK, COLOR_WHITE); + init_pair(3, COLOR_BLACK, COLOR_WHITE); + init_pair(4, COLOR_BLUE, COLOR_WHITE); + init_pair(5, COLOR_WHITE, COLOR_BLUE); + init_pair(6, COLOR_RED, COLOR_WHITE); + } + cbreak(); + noecho(); + nodelay(stdscr, FALSE); + keypad(stdscr, TRUE); + curs_set(0); +} + +/* + * Shuts down the curses screen library. + */ +static void end_curses(void) +{ + keypad(stdscr, FALSE); + curs_set(1); + erase(); + refresh(); + endwin(); +} + +/* + * Handles a SIGWINCH signal, which is sent to indicate that the + * size of the curses screen has changed. + */ +void ResizeHandle(int sig) +{ + ResizedFlag = 1; +} + +/* + * Checks to see if the curses window needs to be resized - i.e. if a + * SIGWINCH signal has been received. + */ +void CheckForResize(Player *Play) +{ + sigset_t sigset; + + sigemptyset(&sigset); + sigaddset(&sigset, SIGWINCH); + sigprocmask(SIG_BLOCK, &sigset, NULL); + if (ResizedFlag) { + ResizedFlag = 0; + end_curses(); + start_curses(); + Width = COLS; + Depth = LINES; + attrset(TextAttr); + clear_screen(); + display_message(""); + DisplayFightMessage(Play, ""); + print_status(Play, TRUE); + } + sigprocmask(SIG_UNBLOCK, &sigset, NULL); +} + +static void LogMessage(const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ + attrset(TextAttr); + clear_bottom(); + PrintMessage(message); + nice_wait(); + attrset(TextAttr); + clear_bottom(); +} + +/* + * Displays a dopewars introduction screen. + */ +void display_intro(void) +{ + GString *text; + + attrset(TextAttr); + clear_screen(); + attrset(TitleAttr); + + /* Curses client introduction screen */ + text = g_string_new(_("D O P E W A R S")); + mvaddstr(1, (Width - text->len) / 2, text->str); + + attrset(TextAttr); + + mvaddstr(3, 1, _("Based on John E. Dell's old Drug Wars game, dopewars " + "is a simulation of an")); + mvaddstr(4, 1, _("imaginary drug market. dopewars is an All-American " + "game which features")); + mvaddstr(5, 1, _("buying, selling, and trying to get past the cops!")); + + mvaddstr(7, 1, _("The first thing you need to do is pay off your " + "debt to the Loan Shark. After")); + mvaddstr(8, 1, _("that, your goal is to make as much money as " + "possible (and stay alive)! You")); + mvaddstr(9, 1, _("have one month of game time to make your fortune.")); + + mvaddstr(11, 18, _("Copyright (C) 1998-2002 Ben Webb " + "ben@bellatrix.pcl.ox.ac.uk")); + g_string_sprintf(text, _("Version %s"), VERSION); + mvaddstr(11, 2, text->str); + g_string_assign(text, _("dopewars is released under the GNU " + "General Public Licence")); + mvaddstr(12, (Width - text->len) / 2, text->str); + + mvaddstr(14, 7, _("Icons and Graphics Ocelot Mantis")); + mvaddstr(15, 7, _("Drug Dealing and Research Dan Wolf")); + mvaddstr(16, 7, _("Play Testing Phil Davis " + "Owen Walsh")); + mvaddstr(17, 7, _("Extensive Play Testing Katherine Holt " + "Caroline Moore")); + mvaddstr(18, 7, _("Constructive Criticism Andrea Elliot-Smith " + "Pete Winn")); + mvaddstr(19, 7, _("Unconstructive Criticism James Matthews")); + + mvaddstr(21, 3, _("For information on the command line options, type " + "dopewars -h at your")); + mvaddstr(22, 1, + _("Unix prompt. This will display a help screen, listing " + "the available options.")); + + g_string_free(text, TRUE); + nice_wait(); + attrset(TextAttr); + clear_screen(); + refresh(); +} + +#ifdef NETWORKING +/* + * Prompts the user to enter a server name and port to connect to. + */ +static void SelectServerManually(void) +{ + gchar *text, *PortText; + + if (ServerName[0] == '(') + AssignName(&ServerName, "localhost"); + attrset(TextAttr); + clear_bottom(); + mvaddstr(17, 1, + /* Prompts for hostname and port when selecting a server + * manually */ + _("Please enter the hostname and port of a dopewars server:-")); + text = nice_input(_("Hostname: "), 18, 1, FALSE, ServerName, '\0'); + AssignName(&ServerName, text); + g_free(text); + PortText = g_strdup_printf("%d", Port); + text = nice_input(_("Port: "), 19, 1, TRUE, PortText, '\0'); + Port = atoi(text); + g_free(text); + g_free(PortText); +} + +/* + * Contacts the dopewars metaserver, and obtains a list of valid + * server/port pairs, one of which the user should select. + * Returns TRUE on success; on failure FALSE is returned, and + * errstr is assigned an error message. + */ +static gboolean SelectServerFromMetaServer(Player *Play, GString *errstr) +{ + int c; + GSList *ListPt; + ServerData *ThisServer; + GString *text; + gint index; + fd_set readfds, writefds; + int maxsock; + gboolean DoneOK; + HttpConnection *MetaConn; + + attrset(TextAttr); + clear_bottom(); + mvaddstr(17, 1, _("Please wait... attempting to contact metaserver...")); + refresh(); + + if (OpenMetaHttpConnection(&MetaConn)) { + SetHttpAuthFunc(MetaConn, HttpAuthFunc, NULL); + SetNetworkBufferUserPasswdFunc(&MetaConn->NetBuf, SocksAuthFunc, NULL); + } else { + g_string_assign_error(errstr, MetaConn->NetBuf.error); + CloseHttpConnection(MetaConn); + return FALSE; + } + + ClearServerList(&ServerList); + + do { + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_SET(0, &readfds); + maxsock = 1; + SetSelectForNetworkBuffer(&MetaConn->NetBuf, &readfds, &writefds, + NULL, &maxsock); + if (bselect(maxsock, &readfds, &writefds, NULL, NULL) == -1) { + if (errno == EINTR) { + CheckForResize(Play); + continue; + } + perror("bselect"); + exit(1); + } + if (FD_ISSET(0, &readfds)) { + /* So that Ctrl-L works */ + c = getch(); +#ifndef CYGWIN + if (c == '\f') + wrefresh(curscr); +#endif + } + if (RespondToSelect + (&MetaConn->NetBuf, &readfds, &writefds, NULL, &DoneOK)) { + while (HandleWaitingMetaServerData(MetaConn, &ServerList, &DoneOK)) { + } + } + if (!DoneOK && HandleHttpCompletion(MetaConn)) { + if (IsHttpError(MetaConn)) { + g_string_assign_error(errstr, MetaConn->NetBuf.error); + CloseHttpConnection(MetaConn); + return FALSE; + } + } + } while (DoneOK); + CloseHttpConnection(MetaConn); + + text = g_string_new(""); + + ListPt = ServerList; + while (ListPt) { + ThisServer = (ServerData *)(ListPt->data); + attrset(TextAttr); + clear_bottom(); + /* Printout of metaserver information in curses client */ + g_string_sprintf(text, _("Server : %s"), ThisServer->Name); + mvaddstr(17, 1, text->str); + g_string_sprintf(text, _("Port : %d"), ThisServer->Port); + mvaddstr(18, 1, text->str); + g_string_sprintf(text, _("Version : %s"), ThisServer->Version); + mvaddstr(18, 40, text->str); + if (ThisServer->CurPlayers == -1) { + g_string_sprintf(text, _("Players: -unknown- (maximum %d)"), + ThisServer->MaxPlayers); + } else { + g_string_sprintf(text, _("Players: %d (maximum %d)"), + ThisServer->CurPlayers, ThisServer->MaxPlayers); + } + mvaddstr(19, 1, text->str); + g_string_sprintf(text, _("Up since : %s"), ThisServer->UpSince); + mvaddstr(19, 40, text->str); + g_string_sprintf(text, _("Comment: %s"), ThisServer->Comment); + mvaddstr(20, 1, text->str); + attrset(PromptAttr); + mvaddstr(23, 1, + _("N>ext server; P>revious server; S>elect this server... ")); + + /* The three keys that are valid responses to the previous question - + * if you translate them, keep the keys in the same order (N>ext, + * P>revious, S>elect) as they are here, otherwise they'll do the + * wrong things. */ + c = GetKey(_("NPS"), "NPS", FALSE, FALSE, FALSE); + switch (c) { + case 'S': + AssignName(&ServerName, ThisServer->Name); + Port = ThisServer->Port; + ListPt = NULL; + break; + case 'N': + ListPt = g_slist_next(ListPt); + if (!ListPt) + ListPt = ServerList; + break; + case 'P': + index = g_slist_position(ServerList, ListPt) - 1; + if (index >= 0) + ListPt = g_slist_nth(ServerList, (guint)index); + else + ListPt = g_slist_last(ListPt); + break; + } + } + if (!ServerList) { + g_string_assign(errstr, "No servers listed on metaserver"); + return FALSE; + } + clear_line(17); + refresh(); + g_string_free(text, TRUE); + return TRUE; +} + +static void DisplayConnectStatus(NetworkBuffer *netbuf, + NBStatus oldstatus, + NBSocksStatus oldsocks) +{ + NBStatus status; + NBSocksStatus sockstat; + GString *text; + + status = netbuf->status; + sockstat = netbuf->sockstat; + + if (oldstatus == status && oldsocks == sockstat) + return; + + text = g_string_new(""); + + switch (status) { + case NBS_PRECONNECT: + break; + case NBS_SOCKSCONNECT: + switch (sockstat) { + case NBSS_METHODS: + g_string_sprintf(text, _("Connected to SOCKS server %s..."), + Socks.name); + break; + case NBSS_USERPASSWD: + g_string_assign(text, _("Authenticating with SOCKS server")); + break; + case NBSS_CONNECT: + g_string_sprintf(text, _("Asking SOCKS for connect to %s..."), + ServerName); + break; + } + break; + case NBS_CONNECTED: + break; + } + if (text->str[0]) { + mvaddstr(17, 1, text->str); + refresh(); + } + g_string_free(text, TRUE); +} + +void HttpAuthFunc(HttpConnection *conn, gboolean proxyauth, + gchar *realm, gpointer data) +{ + gchar *text, *user, *password = NULL; + + attrset(TextAttr); + clear_bottom(); + if (proxyauth) { + text = g_strdup_printf(_("Proxy authentication required for realm %s"), + realm); + } else { + text = + g_strdup_printf(_("Authentication required for realm %s"), realm); + } + mvaddstr(17, 1, text); + mvaddstr(18, 1, _("(Enter a blank username to cancel)")); + g_free(text); + + user = nice_input(_("User name: "), 19, 1, FALSE, NULL, '\0'); + if (user && user[0]) { + password = nice_input(_("Password: "), 20, 1, FALSE, NULL, '*'); + } + + SetHttpAuthentication(conn, proxyauth, user, password); + g_free(user); + g_free(password); +} + +void SocksAuthFunc(NetworkBuffer *netbuf, gpointer data) +{ + gchar *user, *password = NULL; + + attrset(TextAttr); + clear_bottom(); + mvaddstr(17, 1, _("SOCKS authentication required (enter a blank " + "username to cancel)")); + + user = nice_input(_("User name: "), 18, 1, FALSE, NULL, '\0'); + if (user && user[0]) { + password = nice_input(_("Password: "), 19, 1, FALSE, NULL, '*'); + } + + SendSocks5UserPasswd(netbuf, user, password); + g_free(user); + g_free(password); +} + +static gboolean DoConnect(Player *Play, GString *errstr) +{ + NetworkBuffer *netbuf; + fd_set readfds, writefds; + int maxsock, c; + gboolean doneOK = TRUE; + NBStatus oldstatus; + NBSocksStatus oldsocks; + + netbuf = &Play->NetBuf; + oldstatus = netbuf->status; + oldsocks = netbuf->sockstat; + + if (!StartNetworkBufferConnect(netbuf, ServerName, Port)) { + doneOK = FALSE; + } else { + SetNetworkBufferUserPasswdFunc(netbuf, SocksAuthFunc, NULL); + while (netbuf->status != NBS_CONNECTED) { + DisplayConnectStatus(netbuf, oldstatus, oldsocks); + oldstatus = netbuf->status; + oldsocks = netbuf->sockstat; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_SET(0, &readfds); + maxsock = 1; + SetSelectForNetworkBuffer(netbuf, &readfds, &writefds, NULL, + &maxsock); + if (bselect(maxsock, &readfds, &writefds, NULL, NULL) == -1) { + if (errno == EINTR) { + CheckForResize(Play); + continue; + } + perror("bselect"); + exit(1); + } + if (FD_ISSET(0, &readfds)) { + /* So that Ctrl-L works */ + c = getch(); +#ifndef CYGWIN + if (c == '\f') + wrefresh(curscr); +#endif + } + RespondToSelect(netbuf, &readfds, &writefds, NULL, &doneOK); + } + } + + if (!doneOK) + g_string_assign_error(errstr, netbuf->error); + return doneOK; +} + +/* + * Connects to a dopewars server. Prompts the user to select a server + * if necessary. Returns TRUE, unless the user elected to quit the + * program rather than choose a valid server. + */ +static gboolean ConnectToServer(Player *Play) +{ + gboolean MetaOK = TRUE, NetOK = TRUE, firstrun = FALSE; + GString *errstr; + gchar *text; + int c; + + errstr = g_string_new(""); + + if (g_strcasecmp(ServerName, SN_META) == 0 || ConnectMethod == CM_META) { + ConnectMethod = CM_META; + MetaOK = SelectServerFromMetaServer(Play, errstr); + } else if (g_strcasecmp(ServerName, SN_PROMPT) == 0 || + ConnectMethod == CM_PROMPT) { + ConnectMethod = CM_PROMPT; + SelectServerManually(); + } else if (g_strcasecmp(ServerName, SN_SINGLE) == 0 || + ConnectMethod == CM_SINGLE) { + ConnectMethod = CM_SINGLE; + g_string_free(errstr, TRUE); + return TRUE; + } else + firstrun = TRUE; + + while (1) { + attrset(TextAttr); + clear_bottom(); + if (MetaOK && !firstrun) { + mvaddstr(17, 1, _("Please wait... attempting to contact " + "dopewars server...")); + refresh(); + NetOK = DoConnect(Play, errstr); + } + if (!NetOK || !MetaOK || firstrun) { + firstrun = FALSE; + clear_line(16); + clear_line(17); + if (!MetaOK) { + /* Display of an error while contacting the metaserver */ + mvaddstr(16, 1, _("Cannot get metaserver details")); + text = g_strdup_printf(" (%s)", errstr->str); + mvaddstr(17, 1, text); + g_free(text); + } else if (!NetOK) { + /* Display of an error message while trying to contact a dopewars + * server (the error message itself is displayed on the next + * screen line) */ + mvaddstr(16, 1, _("Could not start multiplayer dopewars")); + text = g_strdup_printf(" (%s)", errstr->str); + mvaddstr(17, 1, text); + g_free(text); + } + MetaOK = NetOK = TRUE; + attrset(PromptAttr); + mvaddstr(18, 1, + _("Will you... C>onnect to a named dopewars server")); + mvaddstr(19, 1, + _(" L>ist the servers on the metaserver, and " + "select one")); + mvaddstr(20, 1, + _(" Q>uit (where you can start a server " + "by typing \"dopewars -s\")")); + mvaddstr(21, 1, _(" or P>lay single-player ? ")); + attrset(TextAttr); + + /* Translate these 4 keys in line with the above options, keeping + * the order the same (C>onnect, L>ist, Q>uit, P>lay single-player) */ + c = GetKey(_("CLQP"), "CLQP", FALSE, FALSE, FALSE); + switch (c) { + case 'Q': + g_string_free(errstr, TRUE); + return FALSE; + case 'P': + g_string_free(errstr, TRUE); + return TRUE; + case 'L': + MetaOK = SelectServerFromMetaServer(Play, errstr); + break; + case 'C': + SelectServerManually(); + break; + } + } else + break; + } + g_string_free(errstr, TRUE); + Client = Network = TRUE; + return TRUE; +} +#endif /* NETWORKING */ + +/* + * Displays the list of locations and prompts the user to select one. + * If "AllowReturn" is TRUE, then if the current location is selected + * simply drop back to the main game loop, otherwise send a request + * to the server to move to the new location. If FALSE, the user MUST + * choose a new location to move to. The active client player is + * passed in "Play". + * N.B. May set the global variable DisplayMode. + * Returns: TRUE if the user chose to jet to a new location, + * FALSE if the action was cancelled instead. + */ +static gboolean jet(Player *Play, gboolean AllowReturn) +{ + int i, c; + char text[80]; + + attrset(TextAttr); + clear_bottom(); + for (i = 0; i < NumLocation; i++) { + sprintf(text, "%d. %s", i + 1, Location[i].Name); + mvaddstr(17 + i / 3, (i % 3) * 20 + 12, text); + } + attrset(PromptAttr); + + /* Prompt when the player chooses to "jet" to a new location */ + mvaddstr(22, 22, _("Where to, dude ? ")); + attrset(TextAttr); + curs_set(1); + do { + c = bgetch(); + if (c >= '1' && c < '1' + NumLocation) { + addstr(Location[c - '1'].Name); + if (Play->IsAt != c - '1') { + sprintf(text, "%d", c - '1'); + DisplayMode = DM_NONE; + SendClientMessage(Play, C_NONE, C_REQUESTJET, NULL, text); + } else + c = 0; + } else + c = 0; + } while (c == 0 && !AllowReturn); + + curs_set(0); + return (c != 0); +} + +/* + * Prompts the user "Play" to drop some of the currently carried drugs. + */ +static void DropDrugs(Player *Play) +{ + int i, c, num, NumDrugs; + GString *text; + gchar *buf; + + attrset(TextAttr); + clear_bottom(); + text = g_string_new(""); + dpg_string_sprintf(text, + /* List of drugs that you can drop (%tde = "drugs" by + * default) */ + _("You can\'t get any cash for the following " + "carried %tde :"), Names.Drugs); + mvaddstr(16, 1, text->str); + NumDrugs = 0; + for (i = 0; i < NumDrug; i++) { + if (Play->Drugs[i].Carried > 0 && Play->Drugs[i].Price == 0) { + g_string_sprintf(text, "%c. %-10s %-8d", NumDrugs + 'A', + Drug[i].Name, Play->Drugs[i].Carried); + mvaddstr(17 + NumDrugs / 3, (NumDrugs % 3) * 25 + 4, text->str); + NumDrugs++; + } + } + attrset(PromptAttr); + mvaddstr(22, 20, _("What do you want to drop? ")); + curs_set(1); + attrset(TextAttr); + c = bgetch(); + c = toupper(c); + for (i = 0; c >= 'A' && c < 'A' + NumDrugs && i < NumDrug; i++) { + if (Play->Drugs[i].Carried > 0 && Play->Drugs[i].Price == 0) { + c--; + if (c < 'A') { + addstr(Drug[i].Name); + buf = + nice_input(_("How many do you drop? "), 23, 8, TRUE, NULL, + '\0'); + num = atoi(buf); + g_free(buf); + if (num > 0) { + g_string_sprintf(text, "drug^%d^%d", i, -num); + SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text->str); + } + } + } + } + g_string_free(text, TRUE); +} + +/* + * Prompts the user (i.e. the owner of client "Play") to buy drugs if + * "Buy" is TRUE, or to sell drugs otherwise. A list of available drugs + * is displayed, and on receiving the selection, the user is prompted + * for the number of drugs desired. Finally a message is sent to the + * server to buy or sell the required quantity. + */ +static void DealDrugs(Player *Play, gboolean Buy) +{ + int i, c, NumDrugsHere; + gchar *text, *input; + int DrugNum, CanCarry, CanAfford; + + NumDrugsHere = 0; + for (c = 0; c < NumDrug; c++) + if (Play->Drugs[c].Price > 0) + NumDrugsHere++; + + clear_line(22); + attrset(PromptAttr); + if (Buy) { + /* Buy and sell prompts for dealing drugs or guns */ + mvaddstr(22, 20, _("What do you wish to buy? ")); + } else { + mvaddstr(22, 20, _("What do you wish to sell? ")); + } + curs_set(1); + attrset(TextAttr); + c = bgetch(); + c = toupper(c); + if (c >= 'A' && c < 'A' + NumDrugsHere) { + DrugNum = -1; + c -= 'A'; + for (i = 0; i <= c; i++) + DrugNum = GetNextDrugIndex(DrugNum, Play); + addstr(Drug[DrugNum].Name); + CanCarry = Play->CoatSize; + CanAfford = Play->Cash / Play->Drugs[DrugNum].Price; + + if (Buy) { + /* Display of number of drugs you could buy and/or carry, when + * buying drugs */ + text = g_strdup_printf(_("You can afford %d, and can carry %d. "), + CanAfford, CanCarry); + mvaddstr(23, 2, text); + input = nice_input(_("How many do you buy? "), 23, 2 + strlen(text), + TRUE, NULL, '\0'); + c = atoi(input); + g_free(input); + g_free(text); + if (c >= 0) { + text = g_strdup_printf("drug^%d^%d", DrugNum, c); + SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text); + g_free(text); + } + } else { + /* Display of number of drugs you have, when selling drugs */ + text = + g_strdup_printf(_("You have %d. "), + Play->Drugs[DrugNum].Carried); + mvaddstr(23, 2, text); + input = nice_input(_("How many do you sell? "), 23, 2 + strlen(text), + TRUE, NULL, '\0'); + c = atoi(input); + g_free(input); + g_free(text); + if (c >= 0) { + text = g_strdup_printf("drug^%d^%d", DrugNum, -c); + SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text); + g_free(text); + } + } + } + curs_set(0); +} + +/* + * Prompts the user (player "Play") to give an errand to one of his/her + * bitches. The decision is relayed to the server for implementation. + */ +static void GiveErrand(Player *Play) +{ + int c, y; + GString *text; + Player *To; + + text = g_string_new(""); + attrset(TextAttr); + clear_bottom(); + y = 17; + + /* Prompt for sending your bitches out to spy etc. (%tde = "bitches" by + * default) */ + dpg_string_sprintf(text, + _("Choose an errand to give one of your %tde..."), + Names.Bitches); + mvaddstr(y++, 1, text->str); + attrset(PromptAttr); + if (Play->Bitches.Carried > 0) { + dpg_string_sprintf(text, + _(" S>py on another dealer " + "(cost: %P)"), Prices.Spy); + mvaddstr(y++, 2, text->str); + dpg_string_sprintf(text, + _(" T>ip off the cops to another dealer " + "(cost: %P)"), Prices.Tipoff); + mvaddstr(y++, 2, text->str); + mvaddstr(y++, 2, _(" G>et stuffed")); + } + if (Play->Flags & SPYINGON) { + mvaddstr(y++, 2, _("or C>ontact your spies and receive reports")); + } + mvaddstr(y++, 2, _("or N>o errand ? ")); + curs_set(1); + attrset(TextAttr); + + /* Translate these 5 keys to match the above options, keeping the + * original order the same (S>py, T>ip off, G>et stuffed, C>ontact spy, + * N>o errand) */ + c = GetKey(_("STGCN"), "STGCN", TRUE, FALSE, FALSE); + + if (Play->Bitches.Carried > 0 || c == 'C') + switch (c) { + case 'S': + To = ListPlayers(Play, TRUE, _("Whom do you want to spy on? ")); + if (To) + SendClientMessage(Play, C_NONE, C_SPYON, To, NULL); + break; + case 'T': + To = ListPlayers(Play, TRUE, + _("Whom do you want to tip the cops off to? ")); + if (To) + SendClientMessage(Play, C_NONE, C_TIPOFF, To, NULL); + break; + case 'G': + attrset(PromptAttr); + /* Prompt for confirmation of sacking a bitch */ + addstr(_(" Are you sure? ")); + + /* The two keys that are valid for answering Yes/No - if you + * translate them, keep them in the same order - i.e. "Yes" before + * "No" */ + c = GetKey(_("YN"), "YN", FALSE, TRUE, FALSE); + + if (c == 'Y') + SendClientMessage(Play, C_NONE, C_SACKBITCH, NULL, NULL); + break; + case 'C': + if (Play->Flags & SPYINGON) { + SendClientMessage(Play, C_NONE, C_CONTACTSPY, NULL, NULL); + } + break; + } +} + +/* + * Asks the user if he/she _really_ wants to quit dopewars. + */ +static int want_to_quit(void) +{ + attrset(TextAttr); + clear_line(22); + attrset(PromptAttr); + mvaddstr(22, 1, _("Are you sure you want to quit? ")); + attrset(TextAttr); + return (GetKey(_("YN"), "YN", FALSE, TRUE, FALSE) != 'N'); +} + +/* + * Prompts the user to change his or her name, and notifies the server. + */ +static void change_name(Player *Play, gboolean nullname) +{ + gchar *NewName; + + /* Prompt for player to change his/her name */ + NewName = nice_input(_("New name: "), 23, 0, FALSE, NULL, '\0'); + + if (NewName[0]) { + if (nullname) { + SendNullClientMessage(Play, C_NONE, C_NAME, NULL, NewName); + } else { + SendClientMessage(Play, C_NONE, C_NAME, NULL, NewName); + } + SetPlayerName(Play, NewName); + } + g_free(NewName); +} + +/* + * Given a message "Message" coming in for player "Play", performs + * processing and reacts properly; if a message indicates the end of the + * game, the global variable QuitRequest is set. The global variable + * DisplayMode may also be changed by this routine as a result of network + * traffic. + */ +void HandleClientMessage(char *Message, Player *Play) +{ + char *pt, *Data, *wrd; + AICode AI; + MsgCode Code; + Player *From, *tmp; + GSList *list; + gchar *text; + int i; + gboolean Handled; + + /* Ignore To: field - all messages will be for Player "Play" */ + if (ProcessMessage(Message, Play, &From, &AI, &Code, &Data, FirstClient) + == -1) { + return; + } + + Handled = + HandleGenericClientMessage(From, AI, Code, Play, Data, &DisplayMode); + switch (Code) { + case C_ENDLIST: + if (FirstClient && g_slist_next(FirstClient)) { + ListPlayers(Play, FALSE, NULL); + } + break; + case C_STARTHISCORE: + PrepareHighScoreScreen(); + break; + case C_HISCORE: + PrintHighScore(Data); + break; + case C_ENDHISCORE: + if (strcmp(Data, "end") == 0) { + QuitRequest = TRUE; + } else { + nice_wait(); + clear_screen(); + display_message(""); + print_status(Play, TRUE); + refresh(); + } + break; + case C_PUSH: + attrset(TextAttr); + clear_line(22); + mvaddstr(22, 0, _("You have been pushed from the server. " + "Reverting to single player mode.")); + nice_wait(); + SwitchToSinglePlayer(Play); + print_status(Play, TRUE); + break; + case C_QUIT: + attrset(TextAttr); + clear_line(22); + mvaddstr(22, 0, + _("The server has terminated. Reverting to " + "single player mode.")); + nice_wait(); + SwitchToSinglePlayer(Play); + print_status(Play, TRUE); + break; + case C_MSG: + text = g_strdup_printf("%s: %s", GetPlayerName(From), Data); + display_message(text); + g_free(text); + break; + case C_MSGTO: + text = g_strdup_printf("%s->%s: %s", GetPlayerName(From), + GetPlayerName(Play), Data); + display_message(text); + g_free(text); + break; + case C_JOIN: + text = g_strdup_printf(_("%s joins the game!"), Data); + display_message(text); + g_free(text); + break; + case C_LEAVE: + if (From != &Noone) { + text = g_strdup_printf(_("%s has left the game."), Data); + display_message(text); + g_free(text); + } + break; + case C_RENAME: + /* Displayed when a player changes his/her name */ + text = g_strdup_printf(_("%s will now be known as %s."), + GetPlayerName(From), Data); + SetPlayerName(From, Data); + mvaddstr(22, 0, text); + g_free(text); + nice_wait(); + break; + case C_PRINTMESSAGE: + PrintMessage(Data); + nice_wait(); + break; + case C_FIGHTPRINT: + DisplayFightMessage(Play, Data); + break; + case C_SUBWAYFLASH: + DisplayFightMessage(Play, NULL); + for (list = FirstClient; list; list = g_slist_next(list)) { + tmp = (Player *)list->data; + tmp->Flags &= ~FIGHTING; + } + for (i = 0; i < 4; i++) { + print_location(_("S U B W A Y")); + refresh(); + MicroSleep(100000); + print_location(""); + refresh(); + MicroSleep(100000); + } + print_location(Location[(int)Play->IsAt].Name); + break; + case C_QUESTION: + pt = Data; + wrd = GetNextWord(&pt, ""); + PrintMessage(pt); + addch(' '); + i = GetKey(_(wrd), wrd, FALSE, TRUE, TRUE); + wrd = g_strdup_printf("%c", i); + SendClientMessage(Play, C_NONE, C_ANSWER, + From == &Noone ? NULL : From, wrd); + g_free(wrd); + break; + case C_LOANSHARK: + LoanShark(Play); + SendClientMessage(Play, C_NONE, C_DONE, NULL, NULL); + break; + case C_BANK: + Bank(Play); + SendClientMessage(Play, C_NONE, C_DONE, NULL, NULL); + break; + case C_GUNSHOP: + GunShop(Play); + SendClientMessage(Play, C_NONE, C_DONE, NULL, NULL); + break; + case C_UPDATE: + if (From == &Noone) { + ReceivePlayerData(Play, Data, Play); + print_status(Play, TRUE); + refresh(); + } else { + DisplaySpyReports(Data, From, Play); + } + break; + case C_NEWNAME: + clear_line(22); + clear_line(23); + attrset(TextAttr); + mvaddstr(22, 0, _("Unfortunately, somebody else is already " + "using \"your\" name. Please change it.")); + change_name(Play, TRUE); + break; + default: + if (!Handled) { + text = g_strdup_printf("%s^%c^%s^%s", GetPlayerName(From), Code, + GetPlayerName(Play), Data); + mvaddstr(22, 0, text); + g_free(text); + nice_wait(); + } + break; + } +} + +/* + * Responds to a "starthiscore" message by clearing the screen and + * displaying the title for the high scores screen. + */ +void PrepareHighScoreScreen(void) +{ + char *text; + + attrset(TextAttr); + clear_screen(); + attrset(TitleAttr); + text = _("H I G H S C O R E S"); + mvaddstr(0, (Width - strlen(text)) / 2, text); + attrset(TextAttr); +} + +/* + * Prints a high score coded in "Data"; first word is the index of the + * score (i.e. y screen coordinate), second word is the text, the first + * letter of which identifies whether it's to be printed bold or not. + */ +void PrintHighScore(char *Data) +{ + char *cp; + int index; + + cp = Data; + index = GetNextInt(&cp, 0); + if (!cp || strlen(cp) < 2) + return; + move(index + 2, 0); + attrset(TextAttr); + if (cp[0] == 'B') + standout(); + addstr(&cp[1]); + if (cp[0] == 'B') + standend(); +} + +/* + * Prints a message "text" received via. a "printmessage" message in the + * bottom part of the screen. + */ +void PrintMessage(const gchar *text) +{ + guint i, line; + + attrset(TextAttr); + clear_line(16); + + line = 1; + for (i = 0; i < strlen(text) && (text[i] == '^' || text[i] == '\n'); i++) + line++; + clear_exceptfor(line); + + line = 17; + move(line, 1); + for (i = 0; i < strlen(text); i++) { + if (text[i] == '^' || text[i] == '\n') { + line++; + move(line, 1); + } else if (text[i] != '\r') + addch((guchar)text[i]); + } +} + +static void SellGun(Player *Play) +{ + gchar *text; + gint gunind; + + clear_line(22); + if (TotalGunsCarried(Play) == 0) { + /* Error - player tried to sell guns that he/she doesn't have + * (%tde="guns" by default) */ + text = dpg_strdup_printf(_("You don't have any %tde to sell!"), + Names.Guns); + mvaddstr(22, (Width - strlen(text)) / 2, text); + g_free(text); + nice_wait(); + clear_line(23); + } else { + attrset(PromptAttr); + mvaddstr(22, 20, _("What do you wish to sell? ")); + curs_set(1); + attrset(TextAttr); + gunind = bgetch(); + gunind = toupper(gunind); + if (gunind >= 'A' && gunind < 'A' + NumGun) { + gunind -= 'A'; + addstr(Gun[gunind].Name); + if (Play->Guns[gunind].Carried == 0) { + clear_line(22); + /* Error - player tried to sell some guns that he/she doesn't have */ + mvaddstr(22, 10, _("You don't have any to sell!")); + nice_wait(); + clear_line(23); + } else { + Play->Cash += Gun[gunind].Price; + Play->CoatSize += Gun[gunind].Space; + Play->Guns[gunind].Carried--; + text = g_strdup_printf("gun^%d^-1", gunind); + SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text); + g_free(text); + print_status(Play, FALSE); + } + } + } +} + +static void BuyGun(Player *Play) +{ + gchar *text; + gint gunind; + + clear_line(22); + if (TotalGunsCarried(Play) >= Play->Bitches.Carried + 2) { + text = dpg_strdup_printf( + /* Error - player tried to buy more guns + * than his/her bitches can carry (1st + * %tde="bitches", 2nd %tde="guns" by + * default) */ + _("You'll need more %tde to carry " + "any more %tde!"), + Names.Bitches, Names.Guns); + mvaddstr(22, (Width - strlen(text)) / 2, text); + g_free(text); + nice_wait(); + clear_line(23); + } else { + attrset(PromptAttr); + mvaddstr(22, 20, _("What do you wish to buy? ")); + curs_set(1); + attrset(TextAttr); + gunind = bgetch(); + gunind = toupper(gunind); + if (gunind >= 'A' && gunind < 'A' + NumGun) { + gunind -= 'A'; + addstr(Gun[gunind].Name); + if (Gun[gunind].Space > Play->CoatSize) { + clear_line(22); + /* Error - player tried to buy a gun that he/she doesn't have + * space for (%tde="gun" by default) */ + text = dpg_strdup_printf(_("You don't have enough space to " + "carry that %tde!"), Names.Gun); + mvaddstr(22, (Width - strlen(text)) / 2, text); + g_free(text); + nice_wait(); + clear_line(23); + } else if (Gun[gunind].Price > Play->Cash) { + clear_line(22); + /* Error - player tried to buy a gun that he/she can't afford + * (%tde="gun" by default) */ + text = dpg_strdup_printf(_("You don't have enough cash to buy " + "that %tde!"), Names.Gun); + mvaddstr(22, (Width - strlen(text)) / 2, text); + g_free(text); + nice_wait(); + clear_line(23); + } else { + Play->Cash -= Gun[gunind].Price; + Play->CoatSize -= Gun[gunind].Space; + Play->Guns[gunind].Carried++; + text = g_strdup_printf("gun^%d^1", gunind); + SendClientMessage(Play, C_NONE, C_BUYOBJECT, NULL, text); + g_free(text); + print_status(Play, FALSE); + } + } + } +} + +/* + * Allows player "Play" to buy and sell guns interactively. Passes the + * decisions on to the server for sanity checking and implementation. + */ +void GunShop(Player *Play) +{ + int i, action; + gchar *text; + + print_status(Play, FALSE); + attrset(TextAttr); + clear_bottom(); + for (i = 0; i < NumGun; i++) { + text = + dpg_strdup_printf("%c. %-22tde %12P", 'A' + i, Gun[i].Name, + Gun[i].Price); + mvaddstr(17 + i / 2, (i % 2) * 40 + 1, text); + g_free(text); + } + do { + /* Prompt for actions in the gun shop */ + text = _("Will you B>uy, S>ell, or L>eave? "); + attrset(PromptAttr); + clear_line(22); + mvaddstr(22, 40 - strlen(text) / 2, text); + attrset(TextAttr); + + /* Translate these three keys in line with the above options, keeping + * the order (B>uy, S>ell, L>eave) the same - you can change the + * wording of the prompt, but if you change the order in this key + * list, the keys will do the wrong things! */ + action = GetKey(_("BSL"), "BSL", FALSE, FALSE, FALSE); + if (action == 'S') + SellGun(Play); + else if (action == 'B') + BuyGun(Play); + } while (action != 'L'); + print_status(Play, TRUE); +} + +/* + * Allows player "Play" to pay off loans interactively. + */ +void LoanShark(Player *Play) +{ + gchar *text, *prstr; + price_t money; + + do { + clear_bottom(); + attrset(PromptAttr); + + /* Prompt for paying back loans from the loan shark */ + text = + nice_input(_("How much money do you pay back? "), 19, 1, TRUE, + NULL, '\0'); + attrset(TextAttr); + money = strtoprice(text); + g_free(text); + if (money < 0) + money = 0; + if (money > Play->Debt) + money = Play->Debt; + if (money > Play->Cash) { + /* Error - player doesn't have enough money to pay back the loan */ + mvaddstr(20, 1, _("You don't have that much money!")); + nice_wait(); + } else { + SendClientMessage(Play, C_NONE, C_PAYLOAN, NULL, + (prstr = pricetostr(money))); + g_free(prstr); + money = 0; + } + } while (money != 0); +} + +/* + * Allows player "Play" to pay in or withdraw money from the bank + * interactively. + */ +void Bank(Player *Play) +{ + gchar *text, *prstr; + price_t money = 0; + int action; + + do { + clear_bottom(); + attrset(PromptAttr); + /* Prompt for dealing with the bank in the curses client */ + mvaddstr(18, 1, _("Do you want to D>eposit money, W>ithdraw money, " + "or L>eave ? ")); + attrset(TextAttr); + + /* Make sure you keep the order the same if you translate these keys! + * (D>eposit, W>ithdraw, L>eave) */ + action = GetKey(_("DWL"), "DWL", FALSE, FALSE, FALSE); + + if (action == 'D' || action == 'W') { + /* Prompt for putting money in or taking money out of the bank */ + text = nice_input(_("How much money? "), 19, 1, TRUE, NULL, '\0'); + + money = strtoprice(text); + g_free(text); + if (money < 0) + money = 0; + if (action == 'W') + money = -money; + if (money > Play->Cash) { + /* Error - player has tried to put more money into the bank than + * he/she has */ + mvaddstr(20, 1, _("You don't have that much money!")); + nice_wait(); + } else if (-money > Play->Bank) { + /* Error - player has tried to withdraw more money from the bank + * than there is in the account */ + mvaddstr(20, 1, _("There isn't that much money in the bank...")); + nice_wait(); + } else if (money != 0) { + SendClientMessage(Play, C_NONE, C_DEPOSIT, NULL, + (prstr = pricetostr(money))); + g_free(prstr); + money = 0; + } + } + } while (action != 'L' && money != 0); +} + +/* + * Waits for keyboard input; will only accept a key listed in the + * "allowed" string. This string may have been translated; thus + * the "orig_allowed" string contains the untranslated keys. + * Returns the untranslated key corresponding to the key pressed + * (e.g. if allowed[2] is pressed, orig_allowed[2] is returned) + * Case insensitive. If "AllowOther" is TRUE, keys other than the + * given selection are allowed, and cause a zero return value. + * If "PrintAllowed" is TRUE, the allowed keys are printed after + * the prompt. If "ExpandOut" is also TRUE, the full words for + * the commands, rather than just their first letters, are displayed. + */ +int GetKey(char *allowed, char *orig_allowed, gboolean AllowOther, + gboolean PrintAllowed, gboolean ExpandOut) +{ + int ch; + guint AllowInd, WordInd, i; + + /* Expansions of the single-letter keypresses for the benefit of the + * user. i.e. "Yes" is printed for the key "Y" etc. You should indicate + * to the user which letter in the word corresponds to the keypress, by + * capitalising it or similar. */ + gchar *Words[] = { N_("Y:Yes"), N_("N:No"), N_("R:Run"), + N_("F:Fight"), N_("A:Attack"), N_("E:Evade") + }; + guint numWords = sizeof(Words) / sizeof(Words[0]); + gchar *trWord; + + curs_set(1); + ch = '\0'; + + if (!allowed || strlen(allowed) == 0) + return 0; + + if (PrintAllowed) { + addch('[' | TextAttr); + for (AllowInd = 0; AllowInd < strlen(allowed); AllowInd++) { + if (AllowInd > 0) + addch('/' | TextAttr); + WordInd = 0; + while (WordInd < numWords && + orig_allowed[AllowInd] != Words[WordInd][0]) + WordInd++; + + if (ExpandOut && WordInd < numWords) { + trWord = _(Words[WordInd]); + for (i = 2; i < strlen(trWord); i++) + addch((guchar)trWord[i] | TextAttr); + } else + addch((guchar)allowed[AllowInd] | TextAttr); + } + addch(']' | TextAttr); + addch(' ' | TextAttr); + } + + do { + ch = bgetch(); + ch = toupper(ch); + for (AllowInd = 0; AllowInd < strlen(allowed); AllowInd++) { + if (allowed[AllowInd] == ch) { + addch((guint)ch | TextAttr); + curs_set(0); + return orig_allowed[AllowInd]; + } + } + } while (!AllowOther); + + curs_set(0); + return 0; +} + +/* + * Clears one whole line on the curses screen. + */ +void clear_line(int line) +{ + int i; + + move(line, 0); + for (i = 0; i < Width; i++) + addch(' '); +} + +/* + * Clears the bottom of the screen (i.e. from line 16 to line 23) + * except for the top "skip" lines. + */ +void clear_exceptfor(int skip) +{ + int i; + + for (i = 16 + skip; i <= 23; i++) + clear_line(i); +} + + +/* + * Clears screen lines 16 to 23. + */ +void clear_bottom(void) +{ + int i; + + for (i = 16; i <= 23; i++) + clear_line(i); +} + +/* + * Clears the entire screen; 24 lines of 80 characters each. + */ +void clear_screen(void) +{ + int i; + + for (i = 0; i < Depth; i++) + clear_line(i); +} + +/* + * Displays a prompt on the bottom screen line and waits for the user + * to press a key. + */ +void nice_wait() +{ + gchar *text; + + attrset(PromptAttr); + text = _("Press any key..."); + mvaddstr(23, (Width - strlen(text)) / 2, text); + bgetch(); + attrset(TextAttr); +} + +/* + * Handles the display of messages pertaining to player-player fights + * in the lower part of screen (fighting sub-screen). Adds the new line + * of text in "text" and scrolls up previous messages if necessary + * If "text" is NULL, initialises the area + * If "text" is a blank string, redisplays the message area + * Messages are displayed from lines 16 to 20; line 22 is used for + * the prompt for the user. + */ +void DisplayFightMessage(Player *Play, char *text) +{ + static char Messages[5][79]; + static int x, y; + gchar *textpt; + gchar *AttackName, *DefendName, *BitchName; + gint i, DefendHealth, DefendBitches, BitchesKilled, ArmPercent; + gboolean Loot; + + if (text == NULL) { + x = 0; + y = 15; + for (i = 0; i < 5; i++) + Messages[i][0] = '\0'; + } else if (!text[0]) { + attrset(TextAttr); + clear_bottom(); + for (i = 16; i <= 20; i++) + mvaddstr(i, 1, Messages[i - 16]); + } else { + if (HaveAbility(Play, A_NEWFIGHT)) { + ReceiveFightMessage(text, &AttackName, &DefendName, &DefendHealth, + &DefendBitches, &BitchName, &BitchesKilled, + &ArmPercent, &fp, &RunHere, &Loot, &CanFire, + &textpt); + } else { + textpt = text; + if (Play->Flags & FIGHTING) + fp = F_MSG; + else + fp = F_LASTLEAVE; + CanFire = (Play->Flags & CANSHOOT); + RunHere = FALSE; + } + while (textpt[0]) { + if (y < 20) + y++; + else + for (i = 0; i < 4; i++) + strcpy(Messages[i], Messages[i + 1]); + + strncpy(Messages[y - 16], textpt, 78); + Messages[y - 16][78] = '\0'; + textpt += MIN(strlen(textpt), 78); + } + } +} + +/* + * Displays a network message "buf" in the message area (lines + * 10 to 14) scrolling previous messages up. + * If "buf" is NULL, clears the message area + * If "buf" is a blank string, redisplays the message area + */ +void display_message(char *buf) +{ + guint x, y; + guint wid; + static gchar Messages[5][200]; + gchar *bufpt; + + if (Width <= 4) + return; + + wid = MIN(Width - 4, 200); + + if (!buf) { + for (y = 0; y < 5; y++) { + memset(Messages[y], ' ', 200); + if (Network) { + mvaddch(y + 10, 0, ' ' | TextAttr); + addch(ACS_VLINE | StatsAttr); + for (x = 0; x < wid; x++) + addch(' ' | StatsAttr); + addch(ACS_VLINE | StatsAttr); + addch(' ' | TextAttr); + } + } + } else if (Network) { + bufpt = buf; + while (bufpt[0] != 0) { + memmove(Messages[0], Messages[1], 200 * 4); + memset(Messages[4], ' ', 200); + memcpy(Messages[4], bufpt, + strlen(bufpt) > wid ? wid : strlen(bufpt)); + bufpt += MIN(strlen(bufpt), wid); + } + for (y = 0; y < 5; y++) + for (x = 0; x < wid; x++) { + mvaddch(y + 10, x + 2, (guchar)Messages[y][x] | StatsAttr); + } + refresh(); + } +} + +/* + * Displays the string "text" at the top of the screen. Usually used for + * displaying the current location or the "Subway" flash. + */ +void print_location(char *text) +{ + int i; + + if (!text) + return; + attrset(LocationAttr); + move(0, Width / 2 - 9); + for (i = 0; i < 18; i++) + addch(' '); + mvaddstr(0, (Width - strlen(text)) / 2, text); + attrset(TextAttr); +} + +/* + * Displays the status of player "Play" - i.e. the current turn, the + * location, bitches, available space, cash, guns, health and bank + * details. If "DispDrugs" is TRUE, displays the carried drugs on the + * right hand side of the screen; if FALSE, displays the carried guns. + */ +void print_status(Player *Play, gboolean DispDrug) +{ + int i, c; + GString *text; + + text = g_string_new(NULL); + attrset(TitleAttr); + clear_line(0); + g_string_sprintf(text, "%s%02d%s", Names.Month, Play->Turn, Names.Year); + mvaddstr(0, 3, text->str); + + attrset(StatsAttr); + for (i = 2; i <= 14; i++) { + mvaddch(i, 1, ACS_VLINE); + mvaddch(i, Width - 2, ACS_VLINE); + } + mvaddch(1, 1, ACS_ULCORNER); + for (i = 0; i < Width - 4; i++) + addch(ACS_HLINE); + addch(ACS_URCORNER); + + mvaddch(1, Width / 2, ACS_TTEE); + for (i = 2; i <= (Network ? 8 : 13); i++) { + move(i, 2); + for (c = 2; c < Width / 2; c++) + addch(' '); + addch(ACS_VLINE); + for (c = Width / 2 + 1; c < Width - 2; c++) + addch(' '); + } + if (!Network) { + mvaddch(14, 1, ACS_LLCORNER); + for (i = 0; i < Width - 4; i++) + addch(ACS_HLINE); + addch(ACS_LRCORNER); + mvaddch(14, Width / 2, ACS_BTEE); + } else { + mvaddch(9, 1, ACS_LTEE); + for (i = 0; i < Width - 4; i++) + addch(ACS_HLINE); + addch(ACS_RTEE); + + /* Title of the "Messages" window in the curses client */ + mvaddstr(9, 15, _("Messages")); + + mvaddch(9, Width / 2, ACS_BTEE); + mvaddch(15, 1, ACS_LLCORNER); + for (i = 0; i < Width - 4; i++) + addch(ACS_HLINE); + addch(ACS_LRCORNER); + } + + /* Title of the "Stats" window in the curses client */ + mvaddstr(1, Width / 4 - 2, _("Stats")); + + attrset(StatsAttr); + + /* Display of the player's cash in the stats window (careful to keep the + * formatting if you change the length of the "Cash" word) */ + dpg_string_sprintf(text, _("Cash %17P"), Play->Cash); + mvaddstr(3, 9, text->str); + + /* Display of the total number of guns carried (%Tde="Guns" by default) */ + dpg_string_sprintf(text, _("%-19Tde%3d"), Names.Guns, + TotalGunsCarried(Play)); + mvaddstr(Network ? 4 : 5, 9, text->str); + + /* Display of the player's health */ + g_string_sprintf(text, _("Health %3d"), Play->Health); + mvaddstr(Network ? 5 : 7, 9, text->str); + + /* Display of the player's bank balance */ + dpg_string_sprintf(text, _("Bank %17P"), Play->Bank); + mvaddstr(Network ? 6 : 9, 9, text->str); + + if (Play->Debt > 0) + attrset(DebtAttr); + /* Display of the player's debt */ + dpg_string_sprintf(text, _("Debt %17P"), Play->Debt); + mvaddstr(Network ? 7 : 11, 9, text->str); + attrset(TitleAttr); + + /* Display of the player's trenchcoat size (antique mode only) */ + if (WantAntique) + g_string_sprintf(text, _("Space %6d"), Play->CoatSize); + else { + /* Display of the player's number of bitches, and available space + * (%Tde="Bitches" by default) */ + dpg_string_sprintf(text, _("%Tde %3d Space %6d"), Names.Bitches, + Play->Bitches.Carried, Play->CoatSize); + } + mvaddstr(0, Width - 2 - strlen(text->str), text->str); + print_location(Location[(int)Play->IsAt].Name); + attrset(StatsAttr); + + c = 0; + if (DispDrug) { + /* Title of the "trenchcoat" window (antique mode only) */ + if (WantAntique) + mvaddstr(1, Width * 3 / 4 - 5, _("Trenchcoat")); + else { + /* Title of the "drugs" window (the only important bit in this + * string is the "%Tde" which is "Drugs" by default; the %/.../ part + * is ignored, so you don't need to translate it; see doc/i18n.html) + */ + dpg_string_sprintf(text, _("%/Stats: Drugs/%Tde"), Names.Drugs); + mvaddstr(1, Width * 3 / 4 - strlen(text->str) / 2, text->str); + } + for (i = 0; i < NumDrug; i++) { + if (Play->Drugs[i].Carried > 0) { + /* Display of carried drugs with price (%tde="Opium", etc. by + * default) */ + if (HaveAbility(Play, A_DRUGVALUE)) { + dpg_string_sprintf(text, _("%-7tde %3d @ %P"), Drug[i].Name, + Play->Drugs[i].Carried, + Play->Drugs[i].TotalValue / + Play->Drugs[i].Carried); + mvaddstr(3 + c, Width / 2 + 3, text->str); + } else { + /* Display of carried drugs (%tde="Opium", etc. by default) */ + dpg_string_sprintf(text, _("%-7tde %3d"), Drug[i].Name, + Play->Drugs[i].Carried); + mvaddstr(3 + c / 2, Width / 2 + 3 + (c % 2) * 17, text->str); + } + c++; + } + } + } else { + /* Title of the "guns" window (the only important bit in this string + * is the "%Tde" which is "Guns" by default) */ + dpg_string_sprintf(text, _("%/Stats: Guns/%Tde"), Names.Guns); + mvaddstr(1, Width * 3 / 4 - strlen(text->str) / 2, text->str); + for (i = 0; i < NumGun; i++) { + if (Play->Guns[i].Carried > 0) { + /* Display of carried guns (%tde="Baretta", etc. by default) */ + dpg_string_sprintf(text, _("%-22tde %3d"), Gun[i].Name, + Play->Guns[i].Carried); + mvaddstr(3 + c, Width / 2 + 3, text->str); + c++; + } + } + } + attrset(TextAttr); + if (!Network) + clear_line(15); + refresh(); + g_string_free(text, TRUE); +} + +/* + * Parses details about player "From" from string "Data" and then + * displays the lot, drugs and guns. + */ +void DisplaySpyReports(char *Data, Player *From, Player *To) +{ + gchar *text; + + ReceivePlayerData(To, Data, From); + + clear_bottom(); + text = g_strdup_printf(_("Spy reports for %s"), GetPlayerName(From)); + mvaddstr(17, 1, text); + g_free(text); + + /* Message displayed with a spy's list of drugs (%Tde="Drugs" by + * default) */ + text = dpg_strdup_printf(_("%/Spy: Drugs/%Tde..."), Names.Drugs); + mvaddstr(19, 20, text); + g_free(text); + print_status(From, TRUE); + nice_wait(); + clear_line(19); + + /* Message displayed with a spy's list of guns (%Tde="Guns" by default) */ + text = dpg_strdup_printf(_("%/Spy: Guns/%Tde..."), Names.Guns); + mvaddstr(19, 20, text); + g_free(text); + print_status(From, FALSE); + nice_wait(); + + print_status(To, TRUE); + refresh(); +} + +/* + * Displays the "Prompt" if non-NULL, and then lists all clients + * currently playing dopewars, other than the current player "Play". + * If "Select" is TRUE, gives each player a letter and asks the user + * to select one, which is returned by the function. + */ +Player *ListPlayers(Player *Play, gboolean Select, char *Prompt) +{ + Player *tmp = NULL; + GSList *list; + int i, c; + gchar *text; + + attrset(TextAttr); + clear_bottom(); + if (!FirstClient || (!g_slist_next(FirstClient) && + FirstClient->data == Play)) { + text = _("No other players are currently logged on!"); + mvaddstr(18, (Width - strlen(text)) / 2, text); + nice_wait(); + return 0; + } + mvaddstr(16, 1, _("Players currently logged on:-")); + + i = 0; + for (list = FirstClient; list; list = g_slist_next(list)) { + tmp = (Player *)list->data; + if (strcmp(GetPlayerName(tmp), GetPlayerName(Play)) == 0) + continue; + if (Select) + text = g_strdup_printf("%c. %s", 'A' + i, GetPlayerName(tmp)); + else + text = g_strdup(GetPlayerName(tmp)); + mvaddstr(17 + i / 2, (i % 2) * 40 + 1, text); + g_free(text); + i++; + } + + if (Prompt) { + attrset(PromptAttr); + mvaddstr(22, 10, Prompt); + attrset(TextAttr); + } + if (Select) { + curs_set(1); + attrset(TextAttr); + c = 0; + while (c < 'A' || c >= 'A' + i) { + c = bgetch(); + c = toupper(c); + } + if (Prompt) + addch((guint)c); + list = FirstClient; + while (c >= 'A') { + if (list != FirstClient) + list = g_slist_next(list); + tmp = (Player *)list->data; + while (strcmp(GetPlayerName(tmp), GetPlayerName(Play)) == 0) { + list = g_slist_next(list); + tmp = (Player *)list->data; + } + c--; + } + return tmp; + } else { + nice_wait(); + } + return NULL; +} + +/* + * Displays the given "prompt" (if non-NULL) at coordinates sx,sy and + * allows the user to input a string, which is returned. This is a + * dynamically allocated string, and so must be freed by the calling + * routine. If "digitsonly" is TRUE, the user will be permitted only to + * input numbers, although the suffixes m and k are allowed (the + * strtoprice routine understands this notation for a 1000000 or 1000 + * multiplier) as well as a decimal point (. or ,) + * If "displaystr" is non-NULL, it is taken as a default response. + * If "passwdchar" is non-zero, it is displayed instead of the user's + * keypresses (e.g. for entering passwords) + */ +char *nice_input(char *prompt, int sy, int sx, gboolean digitsonly, + char *displaystr, char passwdchar) +{ + int i, c, x; + gboolean DecimalPoint, Suffix; + GString *text; + gchar *ReturnString; + + DecimalPoint = Suffix = FALSE; + + x = sx; + move(sy, x); + if (prompt) { + attrset(PromptAttr); + addstr(prompt); + x += strlen(prompt); + } + attrset(TextAttr); + if (displaystr) { + if (passwdchar) { + for (i = strlen(displaystr); i; i--) + addch((guint)passwdchar); + } else { + addstr(displaystr); + } + i = strlen(displaystr); + text = g_string_new(displaystr); + } else { + i = 0; + text = g_string_new(""); + } + + curs_set(1); + do { + move(sy + (x + i) / Width, (x + i) % Width); + c = bgetch(); + if ((c == 8 || c == KEY_BACKSPACE || c == 127) && i > 0) { + move(sy + (x + i - 1) / Width, (x + i - 1) % Width); + addch(' '); + i--; + if (DecimalPoint && text->str[i] == '.') + DecimalPoint = FALSE; + if (Suffix) + Suffix = FALSE; + g_string_truncate(text, i); + } else if (!Suffix) { + if ((digitsonly && c >= '0' && c <= '9') || + (!digitsonly && c >= 32 && c != '^' && c < 127)) { + g_string_append_c(text, c); + i++; + addch((guint)passwdchar ? passwdchar : c); + } else if (digitsonly && (c == '.' || c == ',') && !DecimalPoint) { + g_string_append_c(text, '.'); + i++; + addch((guint)passwdchar ? passwdchar : c); + DecimalPoint = TRUE; + } else if (digitsonly + && (c == 'M' || c == 'm' || c == 'k' || c == 'K') + && !Suffix) { + g_string_append_c(text, c); + i++; + addch((guint)passwdchar ? passwdchar : c); + Suffix = TRUE; + } + } + } while (c != '\n' && c != KEY_ENTER); + curs_set(0); + move(sy, x); + ReturnString = text->str; + g_string_free(text, FALSE); /* Leave the buffer to return */ + return ReturnString; +} + +/* + * Loop which handles the user playing an interactive game (i.e. "Play" + * is a client connected to a server, either locally or remotely) + * dopewars is essentially server-driven, so this loop simply has to + * make the screen look pretty, respond to user keypresses, and react + * to messages from the server. + */ +static void Curses_DoGame(Player *Play) +{ + gchar *buf, *OldName, *TalkMsg; + GString *text; + int i, c; + char IsCarrying; + +#if NETWORKING || HAVE_SELECT + fd_set readfs; +#endif +#ifdef NETWORKING + fd_set writefs; + gboolean DoneOK; + gchar *pt; + gboolean justconnected = FALSE; +#endif + int NumDrugsHere; + int MaxSock; + char HaveWorthless; + Player *tmp; + struct sigaction sact; + + DisplayMode = DM_NONE; + QuitRequest = FALSE; + + ResizedFlag = 0; + sact.sa_handler = ResizeHandle; + sact.sa_flags = 0; + sigemptyset(&sact.sa_mask); + if (sigaction(SIGWINCH, &sact, NULL) == -1) { + g_warning(_("Cannot install SIGWINCH interrupt handler!")); + } + OldName = g_strdup(GetPlayerName(Play)); + attrset(TextAttr); + clear_screen(); + display_message(NULL); + DisplayFightMessage(Play, NULL); + print_status(Play, TRUE); + + attrset(TextAttr); + clear_bottom(); + buf = NULL; + do { + g_free(buf); + buf = + nice_input(_("Hey dude, what's your name? "), 17, 1, FALSE, + OldName, '\0'); + } while (buf[0] == 0); +#if NETWORKING + if (WantNetwork) { + if (!ConnectToServer(Play)) { + end_curses(); + exit(1); + } + justconnected = TRUE; + } +#endif /* NETWORKING */ + print_status(Play, TRUE); + display_message(""); + + InitAbilities(Play); + SendAbilities(Play); + SetPlayerName(Play, buf); + SendNullClientMessage(Play, C_NONE, C_NAME, NULL, buf); + g_free(buf); + g_free(OldName); + + text = g_string_new(""); + + while (1) { + if (Play->Health == 0) + DisplayMode = DM_NONE; + HaveWorthless = 0; + IsCarrying = 0; + for (i = 0; i < NumDrug; i++) { + if (Play->Drugs[i].Carried > 0) { + IsCarrying = 1; + if (Play->Drugs[i].Price == 0) + HaveWorthless = 1; + } + } + switch (DisplayMode) { + case DM_STREET: + attrset(TextAttr); + NumDrugsHere = 0; + for (i = 0; i < NumDrug; i++) + if (Play->Drugs[i].Price > 0) + NumDrugsHere++; + clear_bottom(); + /* Display of drug prices (%tde="drugs" by default) */ + dpg_string_sprintf(text, _("Hey dude, the prices of %tde here are:"), + Names.Drugs); + mvaddstr(16, 1, text->str); + for (c = 0, i = GetNextDrugIndex(-1, Play); + c < NumDrugsHere && i != -1; + c++, i = GetNextDrugIndex(i, Play)) { + /* List of individual drug names for selection (%tde="Opium" etc. + * by default) */ + dpg_string_sprintf(text, _("%c. %-10tde %8P"), 'A' + c, + Drug[i].Name, Play->Drugs[i].Price); + mvaddstr(17 + c / 3, (c % 3) * 25 + 4, text->str); + } + attrset(PromptAttr); + /* Prompts for "normal" actions in curses client */ + g_string_assign(text, _("Will you B>uy")); + if (IsCarrying) + g_string_append(text, _(", S>ell")); + if (HaveWorthless && !WantAntique) + g_string_append(text, _(", D>rop")); + if (Network) + g_string_append(text, _(", T>alk, P>age, L>ist")); + if (!WantAntique && (Play->Bitches.Carried > 0 || + Play->Flags & SPYINGON)) { + g_string_append(text, _(", G>ive")); + } + if (Play->Flags & FIGHTING) { + g_string_append(text, _(", F>ight")); + } else { + g_string_append(text, _(", J>et")); + } + g_string_append(text, _(", or Q>uit? ")); + mvaddstr(22, 40 - strlen(text->str) / 2, text->str); + attrset(TextAttr); + curs_set(1); + break; + case DM_FIGHT: + DisplayFightMessage(Play, ""); + attrset(PromptAttr); + /* Prompts for actions during fights in curses client */ + g_string_assign(text, _("Do you ")); + if (CanFire) { + if (TotalGunsCarried(Play) > 0) { + g_string_append(text, _("F>ight, ")); + } else { + g_string_append(text, _("S>tand, ")); + } + } + if (fp != F_LASTLEAVE) + g_string_append(text, _("R>un, ")); + if (!RunHere || fp == F_LASTLEAVE) + /* (%tde = "drugs" by default here) */ + dpg_string_sprintfa(text, _("D>eal %tde, "), Names.Drugs); + g_string_append(text, _("or Q>uit? ")); + mvaddstr(22, 40 - strlen(text->str) / 2, text->str); + attrset(TextAttr); + curs_set(1); + break; + case DM_DEAL: + attrset(TextAttr); + clear_bottom(); + mvaddstr(16, 1, "Your trade:-"); + mvaddstr(19, 1, "His trade:-"); + g_string_assign(text, "Do you A>dd, R>emove, O>K, D>eal "); + g_string_append(text, Names.Drugs); + g_string_append(text, ", or Q>uit? "); + attrset(PromptAttr); + mvaddstr(22, 40 - strlen(text->str) / 2, text->str); + attrset(TextAttr); + curs_set(1); + break; + case DM_NONE: + break; + } + refresh(); + + if (QuitRequest) + return; +#if NETWORKING + FD_ZERO(&readfs); + FD_ZERO(&writefs); + FD_SET(0, &readfs); + MaxSock = 1; + if (Client) { + if (justconnected) { + /* Deal with any messages that came in while we were connect()ing */ + justconnected = FALSE; + while ((pt = GetWaitingPlayerMessage(Play)) != NULL) { + HandleClientMessage(pt, Play); + g_free(pt); + } + if (QuitRequest) + return; + } + SetSelectForNetworkBuffer(&Play->NetBuf, &readfs, &writefs, + NULL, &MaxSock); + } + if (bselect(MaxSock, &readfs, &writefs, NULL, NULL) == -1) { + if (errno == EINTR) { + CheckForResize(Play); + continue; + } + perror("bselect"); + exit(1); + } + if (Client) { + if (RespondToSelect(&Play->NetBuf, &readfs, &writefs, NULL, &DoneOK)) { + while ((pt = GetWaitingPlayerMessage(Play)) != NULL) { + HandleClientMessage(pt, Play); + g_free(pt); + } + if (QuitRequest) + return; + } + if (!DoneOK) { + attrset(TextAttr); + clear_line(22); + mvaddstr(22, 0, _("Connection to server lost! " + "Reverting to single player mode")); + nice_wait(); + SwitchToSinglePlayer(Play); + print_status(Play, TRUE); + } + } + if (FD_ISSET(0, &readfs)) { +#elif HAVE_SELECT + FD_ZERO(&readfs); + FD_SET(0, &readfs); + MaxSock = 1; + if (bselect(MaxSock, &readfs, NULL, NULL, NULL) == -1) { + if (errno == EINTR) { + CheckForResize(Play); + continue; + } + perror("bselect"); + exit(1); + } +#endif /* NETWORKING */ + if (DisplayMode == DM_STREET) { + /* N.B. You must keep the order of these keys the same as the + * original when you translate (B>uy, S>ell, D>rop, T>alk, P>age, + * L>ist, G>ive errand, F>ight, J>et, Q>uit) */ + c = GetKey(_("BSDTPLGFJQ"), "BSDTPLGFJQ", TRUE, FALSE, FALSE); + + } else if (DisplayMode == DM_FIGHT) { + /* N.B. You must keep the order of these keys the same as the + * original when you translate (D>eal drugs, R>un, F>ight, S>tand, + * Q>uit) */ + c = GetKey(_("DRFSQ"), "DRFSQ", TRUE, FALSE, FALSE); + + } else + c = 0; +#if ! (NETWORKING || HAVE_SELECT) + CheckForResize(Play); +#endif + if (DisplayMode == DM_STREET) { + if (c == 'J' && !(Play->Flags & FIGHTING)) { + jet(Play, TRUE); + } else if (c == 'F' && Play->Flags & FIGHTING) { + DisplayMode = DM_FIGHT; + } else if (c == 'T' && Play->Flags & TRADING) { + DisplayMode = DM_DEAL; + } else if (c == 'B') { + DealDrugs(Play, TRUE); + } else if (c == 'S' && IsCarrying) { + DealDrugs(Play, FALSE); + } else if (c == 'D' && HaveWorthless && !WantAntique) { + DropDrugs(Play); + } else if (c == 'G' && !WantAntique && Play->Bitches.Carried > 0) { + GiveErrand(Play); + } else if (c == 'Q') { + if (want_to_quit() == 1) { + DisplayMode = DM_NONE; + clear_bottom(); + SendClientMessage(Play, C_NONE, C_WANTQUIT, NULL, NULL); + } + } else if (c == 'L' && Network) { + attrset(PromptAttr); + mvaddstr(23, 20, _("List what? P>layers or S>cores? ")); + /* P>layers, S>cores */ + i = GetKey(_("PS"), "PS", TRUE, FALSE, FALSE); + if (i == 'P') { + ListPlayers(Play, FALSE, NULL); + } else if (i == 'S') { + DisplayMode = DM_NONE; + SendClientMessage(Play, C_NONE, C_REQUESTSCORE, NULL, NULL); + } + } else if (c == 'P' && Network) { + tmp = ListPlayers(Play, TRUE, + _("Whom do you want to page " + "(talk privately to) ? ")); + if (tmp) { + attrset(TextAttr); + clear_line(22); + /* Prompt for sending player-player messages */ + TalkMsg = nice_input(_("Talk: "), 22, 0, FALSE, NULL, '\0'); + if (TalkMsg[0]) { + SendClientMessage(Play, C_NONE, C_MSGTO, tmp, TalkMsg); + buf = g_strdup_printf("%s->%s: %s", GetPlayerName(Play), + GetPlayerName(tmp), TalkMsg); + display_message(buf); + g_free(buf); + } + g_free(TalkMsg); + } + } else if (c == 'T' && Client) { + attrset(TextAttr); + clear_line(22); + TalkMsg = nice_input(_("Talk: "), 22, 0, FALSE, NULL, '\0'); + if (TalkMsg[0]) { + SendClientMessage(Play, C_NONE, C_MSG, NULL, TalkMsg); + buf = g_strdup_printf("%s: %s", GetPlayerName(Play), TalkMsg); + display_message(buf); + g_free(buf); + } + g_free(TalkMsg); + } + } else if (DisplayMode == DM_FIGHT) { + switch (c) { + case 'D': + DisplayMode = DM_STREET; + break; + case 'R': + if (RunHere) { + SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, "R"); + } else { + jet(Play, TRUE); + } + break; + case 'F': + if (TotalGunsCarried(Play) > 0 && CanFire) { + buf = g_strdup_printf("%c", c); + Play->Flags &= ~CANSHOOT; + SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, buf); + g_free(buf); + } + break; + case 'S': + if (TotalGunsCarried(Play) == 0 && CanFire) { + buf = g_strdup_printf("%c", c); + Play->Flags &= ~CANSHOOT; + SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, buf); + g_free(buf); + } + break; + case 'Q': + if (want_to_quit() == 1) { + DisplayMode = DM_NONE; + clear_bottom(); + SendClientMessage(Play, C_NONE, C_WANTQUIT, NULL, NULL); + } + break; + } + } else if (DisplayMode == DM_DEAL) { + switch (c) { + case 'D': + DisplayMode = DM_STREET; + break; + case 'Q': + if (want_to_quit() == 1) { + DisplayMode = DM_NONE; + clear_bottom(); + SendClientMessage(Play, C_NONE, C_WANTQUIT, NULL, NULL); + } + break; + } + } +#if NETWORKING + } +#endif + curs_set(0); + } + g_string_free(text, TRUE); +} + +void CursesLoop(void) +{ + char c; + Player *Play; + + if (!CheckHighScoreFileConfig()) + return; + + /* Save the configuration, so we can restore those elements that get + * overwritten when we connect to a dopewars server */ + BackupConfig(); + + start_curses(); + Width = COLS; + Depth = LINES; + + /* Set up message handlers */ + ClientMessageHandlerPt = HandleClientMessage; + + /* Make the GLib log messages display nicely */ + g_log_set_handler(NULL, + LogMask() | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING, + LogMessage, NULL); + + display_intro(); + + Play = g_new(Player, 1); + FirstClient = AddPlayer(0, Play, FirstClient); + do { + Curses_DoGame(Play); + ShutdownNetwork(Play); + CleanUpServer(); + RestoreConfig(); + attrset(TextAttr); + mvaddstr(23, 20, _("Play again? ")); + c = GetKey(_("YN"), "YN", TRUE, TRUE, FALSE); + } while (c == 'Y'); + FirstClient = RemovePlayer(Play, FirstClient); + end_curses(); +} (DIR) diff --git a/src/curses_client.h b/src/curses_client/curses_client.h (DIR) diff --git a/src/dopewars.c b/src/dopewars.c t@@ -43,9 +43,7 @@ #include <glib.h> #include <stdarg.h> #include "admin.h" -#include "curses_client.h" #include "dopeos.h" -#include "gtk_client.h" #include "message.h" #include "nls.h" #include "serverside.h" t@@ -53,8 +51,16 @@ #include "AIPlayer.h" #include "winmain.h" +#ifdef CURSES_CLIENT +#include "curses_client/curses_client.h" +#endif + +#ifdef GUI_CLIENT +#include "gui_client/gtk_client.h" +#endif + #ifdef GUI_SERVER -#include "gtkport.h" +#include "gtkport/gtkport.h" #endif int ClientSock, ListenSock; t@@ -2651,6 +2657,40 @@ static void ServerLogMessage(const gchar *log_domain, } #endif +#ifndef CURSES_CLIENT +/* + * Stub function to report an error if the Curses client is requested and + * it isn't compiled in. + */ +void CursesLoop(void) +{ + g_print(_("No curses client available - rebuild the binary passing the\n" + "--enable-curses-client option to configure, or use a windowed\n" + "client (if available) instead!\n")); +} +#endif + +#ifndef GUI_CLIENT +/* + * Stub function to report an error if the GTK+ client is requested and + * it isn't compiled in. + */ +#ifdef CYGWIN +gboolean GtkLoop(HINSTANCE hInstance, HINSTANCE hPrevInstance, + gboolean ReturnOnFail) +#else +gboolean GtkLoop(int *argc, char **argv[], gboolean ReturnOnFail) +#endif +{ + if (!ReturnOnFail) { + g_print(_("No graphical client available - rebuild the binary\n" + "passing the --enable-gui-client option to configure, or\n" + "use the curses client (if available) instead!\n")); + } + return FALSE; +} +#endif + /* * Standard program entry - Win32 uses WinMain() instead, in winmain.c */ (DIR) diff --git a/src/dopewars.h b/src/dopewars.h t@@ -422,4 +422,18 @@ gboolean IsConnectedPlayer(Player *play); void BackupConfig(void); void WriteConfigFile(void); gchar *GetDocIndex(void); + +#ifndef CURSES_CLIENT +void CursesLoop(void); +#endif + +#ifndef GUI_CLIENT +#ifdef CYGWIN +gboolean GtkLoop(HINSTANCE hInstance, HINSTANCE hPrevInstance, + gboolean ReturnOnFail); +#else +gboolean GtkLoop(int *argc, char **argv[], gboolean ReturnOnFail); +#endif +#endif + #endif (DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c t@@ -1,3930 +0,0 @@ -/************************************************************************ - * gtk_client.c dopewars client using the GTK+ toolkit * - * Copyright (C) 1998-2002 Ben Webb * - * Email: ben@bellatrix.pcl.ox.ac.uk * - * WWW: http://dopewars.sourceforge.net/ * - * * - * 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 2 * - * 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, write to the Free Software * - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * - * MA 02111-1307, USA. * - ************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef GUI_CLIENT - -#include <stdlib.h> -#include <ctype.h> -#include <string.h> - -#include "dopeos.h" -#include "dopewars.h" -#include "gtk_client.h" -#include "message.h" -#include "nls.h" -#include "serverside.h" -#include "tstring.h" -#include "gtkport.h" -#include "dopewars-pill.xpm" - -#define BT_BUY (GINT_TO_POINTER(1)) -#define BT_SELL (GINT_TO_POINTER(2)) -#define BT_DROP (GINT_TO_POINTER(3)) - -#define ET_SPY 0 -#define ET_TIPOFF 1 - -/* Which notebook page to display in the New Game dialog */ -static gint NewGameType = 0; - -struct InventoryWidgets { - GtkWidget *HereList, *CarriedList; - GtkWidget *HereFrame, *CarriedFrame; - GtkWidget *BuyButton, *SellButton, *DropButton; - GtkWidget *vbbox; -}; - -struct StatusWidgets { - GtkWidget *Location, *Date, *SpaceName, *SpaceValue, *CashName; - GtkWidget *CashValue, *DebtName, *DebtValue, *BankName, *BankValue; - GtkWidget *GunsName, *GunsValue, *BitchesName, *BitchesValue; - GtkWidget *HealthName, *HealthValue; -}; - -struct ClientDataStruct { - GtkWidget *window, *messages; - Player *Play; - GtkItemFactory *Menu; - struct StatusWidgets Status; - struct InventoryWidgets Drug, Gun, InvenDrug, InvenGun; - GtkWidget *JetButton, *vbox, *PlayerList, *TalkList; - guint JetAccel; -}; - -GtkWidget *MainWindow; - -struct StartGameStruct { - GtkWidget *dialog, *name, *hostname, *port, *antique, *status, *metaserv; -#ifdef NETWORKING - HttpConnection *MetaConn; - GSList *NewMetaList; -#endif -}; - -static struct ClientDataStruct ClientData; -static gboolean InGame = FALSE; - -static GtkWidget *FightDialog = NULL, *SpyReportsDialog; -static gboolean IsShowingPlayerList = FALSE, IsShowingTalkList = FALSE; -static gboolean IsShowingInventory = FALSE, IsShowingGunShop = FALSE; - -static void display_intro(GtkWidget *widget, gpointer data); -static void QuitGame(GtkWidget *widget, gpointer data); -static void DestroyGtk(GtkWidget *widget, gpointer data); -static void NewGame(GtkWidget *widget, gpointer data); -static void ListScores(GtkWidget *widget, gpointer data); -static void ListInventory(GtkWidget *widget, gpointer data); -static void NewGameDialog(void); -static void StartGame(void); -static void EndGame(void); -static void Jet(GtkWidget *parent); -static void UpdateMenus(void); - -#ifdef NETWORKING -static void DisplayConnectStatus(struct StartGameStruct *widgets, - gboolean meta, NBStatus oldstatus, - NBSocksStatus oldsocks); -static void AuthDialog(HttpConnection *conn, gboolean proxyauth, - gchar *realm, gpointer data); -static void MetaSocksAuthDialog(NetworkBuffer *netbuf, gpointer data); -static void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data); -static void GetClientMessage(gpointer data, gint socket, - GdkInputCondition condition); -static void SocketStatus(NetworkBuffer *NetBuf, gboolean Read, - gboolean Write, gboolean CallNow); -static void MetaSocketStatus(NetworkBuffer *NetBuf, gboolean Read, - gboolean Write, gboolean CallNow); -static void FinishServerConnect(struct StartGameStruct *widgets, - gboolean ConnectOK); - -/* List of servers on the metaserver */ -static GSList *MetaList = NULL; - -#endif /* NETWORKING */ - -static void HandleClientMessage(char *buf, Player *Play); -static void PrepareHighScoreDialog(void); -static void AddScoreToDialog(char *Data); -static void CompleteHighScoreDialog(gboolean AtEnd); -static void PrintMessage(char *Data); -static void DisplayFightMessage(char *Data); -static GtkWidget *CreateStatusWidgets(struct StatusWidgets *Status); -static void DisplayStats(Player *Play, struct StatusWidgets *Status); -static void UpdateStatus(Player *Play); -static void SetJetButtonTitle(GtkAccelGroup *accel_group); -static void UpdateInventory(struct InventoryWidgets *Inven, - Inventory *Objects, int NumObjects, - gboolean AreDrugs); -static void JetButtonPressed(GtkWidget *widget, gpointer data); -static void DealDrugs(GtkWidget *widget, gpointer data); -static void DealGuns(GtkWidget *widget, gpointer data); -static void QuestionDialog(char *Data, Player *From); -static void TransferDialog(gboolean Debt); -static void ListPlayers(GtkWidget *widget, gpointer data); -static void TalkToAll(GtkWidget *widget, gpointer data); -static void TalkToPlayers(GtkWidget *widget, gpointer data); -static void TalkDialog(gboolean TalkToAll); -static GtkWidget *CreatePlayerList(void); -static void UpdatePlayerList(GtkWidget *clist, gboolean IncludeSelf); -static void TipOff(GtkWidget *widget, gpointer data); -static void SpyOnPlayer(GtkWidget *widget, gpointer data); -static void ErrandDialog(gint ErrandType); -static void SackBitch(GtkWidget *widget, gpointer data); -static void DestroyShowing(GtkWidget *widget, gpointer data); -static gint DisallowDelete(GtkWidget *widget, GdkEvent * event, - gpointer data); -static void GunShopDialog(void); -static void NewNameDialog(void); -static void UpdatePlayerLists(void); -static void CreateInventory(GtkWidget *hbox, gchar *Objects, - GtkAccelGroup *accel_group, - gboolean CreateButtons, gboolean CreateHere, - struct InventoryWidgets *widgets, - GtkSignalFunc CallBack); -static void GetSpyReports(GtkWidget *widget, gpointer data); -static void DisplaySpyReports(Player *Play); - -static GtkItemFactoryEntry menu_items[] = { - /* The names of the the menus and their items in the GTK+ client */ - {N_("/_Game"), NULL, NULL, 0, "<Branch>"}, - {N_("/Game/_New..."), "<control>N", NewGame, 0, NULL}, - {N_("/Game/_Quit..."), "<control>Q", QuitGame, 0, NULL}, - {N_("/_Talk"), NULL, NULL, 0, "<Branch>"}, - {N_("/Talk/To _All..."), NULL, TalkToAll, 0, NULL}, - {N_("/Talk/To _Player..."), NULL, TalkToPlayers, 0, NULL}, - {N_("/_List"), NULL, NULL, 0, "<Branch>"}, - {N_("/List/_Players..."), NULL, ListPlayers, 0, NULL}, - {N_("/List/_Scores..."), NULL, ListScores, 0, NULL}, - {N_("/List/_Inventory..."), NULL, ListInventory, 0, NULL}, - {N_("/_Errands"), NULL, NULL, 0, "<Branch>"}, - {N_("/Errands/_Spy..."), NULL, SpyOnPlayer, 0, NULL}, - {N_("/Errands/_Tipoff..."), NULL, TipOff, 0, NULL}, - /* N.B. "Sack Bitch" has to be recreated (and thus translated) at the - * start of each game, below, so is not marked for gettext here */ - {"/Errands/S_ack Bitch...", NULL, SackBitch, 0, NULL}, - {N_("/Errands/_Get spy reports..."), NULL, GetSpyReports, 0, NULL}, - {N_("/_Help"), NULL, NULL, 0, "<LastBranch>"}, - {N_("/Help/_About..."), "F1", display_intro, 0, NULL} -}; - -static gchar *MenuTranslate(const gchar *path, gpointer func_data) -{ - /* Translate menu items, using gettext */ - return _(path); -} - -static void LogMessage(const gchar *log_domain, GLogLevelFlags log_level, - const gchar *message, gpointer user_data) -{ - GtkMessageBox(NULL, message, - /* Titles of the message boxes for warnings and errors */ - log_level & G_LOG_LEVEL_WARNING ? _("Warning") : - log_level & G_LOG_LEVEL_CRITICAL ? _("Error") : - _("Message"), - MB_OK | (gtk_main_level() > 0 ? MB_IMMRETURN : 0)); -} - -void QuitGame(GtkWidget *widget, gpointer data) -{ - if (!InGame || GtkMessageBox(ClientData.window, - /* Prompt in 'quit game' dialog */ - _("Abandon current game?"), - /* Title of 'quit game' dialog */ - _("Quit Game"), MB_YESNO) == IDYES) { - gtk_main_quit(); - } -} - -void DestroyGtk(GtkWidget *widget, gpointer data) -{ - gtk_main_quit(); -} - -gint MainDelete(GtkWidget *widget, GdkEvent * event, gpointer data) -{ - return (InGame - && GtkMessageBox(ClientData.window, _("Abandon current game?"), - _("Quit Game"), MB_YESNO) == IDNO); -} - - -void NewGame(GtkWidget *widget, gpointer data) -{ - if (InGame) { - if (GtkMessageBox(ClientData.window, _("Abandon current game?"), - /* Title of 'stop game to start a new game' dialog */ - _("Start new game"), MB_YESNO) == IDYES) - EndGame(); - else - return; - } - - /* Save the configuration, so we can restore those elements that get - * overwritten when we connect to a dopewars server */ - BackupConfig(); - - NewGameDialog(); -} - -void ListScores(GtkWidget *widget, gpointer data) -{ - SendClientMessage(ClientData.Play, C_NONE, C_REQUESTSCORE, NULL, NULL); -} - -void ListInventory(GtkWidget *widget, gpointer data) -{ - GtkWidget *window, *button, *hsep, *vbox, *hbox; - GtkAccelGroup *accel_group; - - if (IsShowingInventory) - return; - window = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_window_set_default_size(GTK_WINDOW(window), 550, 120); - accel_group = gtk_accel_group_new(); - gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); - - /* Title of inventory window */ - gtk_window_set_title(GTK_WINDOW(window), _("Inventory")); - - IsShowingInventory = TRUE; - gtk_window_set_modal(GTK_WINDOW(window), FALSE); - gtk_object_set_data(GTK_OBJECT(window), "IsShowing", - (gpointer)&IsShowingInventory); - gtk_signal_connect(GTK_OBJECT(window), "destroy", - GTK_SIGNAL_FUNC(DestroyShowing), NULL); - - gtk_window_set_transient_for(GTK_WINDOW(window), - GTK_WINDOW(ClientData.window)); - gtk_container_set_border_width(GTK_CONTAINER(window), 7); - - vbox = gtk_vbox_new(FALSE, 7); - - hbox = gtk_hbox_new(FALSE, 7); - CreateInventory(hbox, Names.Drugs, accel_group, FALSE, FALSE, - &ClientData.InvenDrug, NULL); - CreateInventory(hbox, Names.Guns, accel_group, FALSE, FALSE, - &ClientData.InvenGun, NULL); - - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - /* Caption of the button to close a dialog */ - button = gtk_button_new_with_label(_("Close")); - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)window); - gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(window), vbox); - - UpdateInventory(&ClientData.InvenDrug, ClientData.Play->Drugs, NumDrug, - TRUE); - UpdateInventory(&ClientData.InvenGun, ClientData.Play->Guns, NumGun, - FALSE); - - gtk_widget_show_all(window); -} - -#ifdef NETWORKING -void GetClientMessage(gpointer data, gint socket, - GdkInputCondition condition) -{ - gchar *pt; - NetworkBuffer *NetBuf; - gboolean DoneOK, datawaiting; - NBStatus status, oldstatus; - NBSocksStatus oldsocks; - - NetBuf = &ClientData.Play->NetBuf; - - oldstatus = NetBuf->status; - oldsocks = NetBuf->sockstat; - - datawaiting = - PlayerHandleNetwork(ClientData.Play, condition & GDK_INPUT_READ, - condition & GDK_INPUT_WRITE, &DoneOK); - - status = NetBuf->status; - - if (status != NBS_CONNECTED) { - /* The start game dialog isn't visible once we're connected... */ - DisplayConnectStatus((struct StartGameStruct *)data, FALSE, - oldstatus, oldsocks); - } - - if (oldstatus != NBS_CONNECTED && (status == NBS_CONNECTED || !DoneOK)) { - FinishServerConnect(data, DoneOK); - } - if (status == NBS_CONNECTED && datawaiting) { - while ((pt = GetWaitingPlayerMessage(ClientData.Play)) != NULL) { - HandleClientMessage(pt, ClientData.Play); - g_free(pt); - } - } - if (!DoneOK) { - if (status == NBS_CONNECTED) { - /* The network connection to the server was dropped unexpectedly */ - g_warning(_("Connection to server lost - switching to " - "single player mode")); - SwitchToSinglePlayer(ClientData.Play); - UpdatePlayerLists(); - UpdateMenus(); - } else { - ShutdownNetworkBuffer(&ClientData.Play->NetBuf); - } - } -} - -void SocketStatus(NetworkBuffer *NetBuf, gboolean Read, gboolean Write, - gboolean CallNow) -{ - if (NetBuf->InputTag) - gdk_input_remove(NetBuf->InputTag); - NetBuf->InputTag = 0; - if (Read || Write) { - NetBuf->InputTag = gdk_input_add(NetBuf->fd, - (Read ? GDK_INPUT_READ : 0) | - (Write ? GDK_INPUT_WRITE : 0), - GetClientMessage, - NetBuf->CallBackData); - } - if (CallNow) - GetClientMessage(NetBuf->CallBackData, NetBuf->fd, 0); -} -#endif /* NETWORKING */ - -void HandleClientMessage(char *pt, Player *Play) -{ - char *Data; - DispMode DisplayMode; - AICode AI; - MsgCode Code; - Player *From, *tmp; - gchar *text; - gboolean Handled; - GtkWidget *MenuItem; - GSList *list; - - if (ProcessMessage(pt, Play, &From, &AI, &Code, - &Data, FirstClient) == -1) { - return; - } - - Handled = - HandleGenericClientMessage(From, AI, Code, Play, Data, &DisplayMode); - switch (Code) { - case C_STARTHISCORE: - PrepareHighScoreDialog(); - break; - case C_HISCORE: - AddScoreToDialog(Data); - break; - case C_ENDHISCORE: - CompleteHighScoreDialog((strcmp(Data, "end") == 0)); - break; - case C_PRINTMESSAGE: - PrintMessage(Data); - break; - case C_FIGHTPRINT: - DisplayFightMessage(Data); - break; - case C_PUSH: - /* The server admin has asked us to leave - so warn the user, and do - * so */ - g_warning(_("You have been pushed from the server.\n" - "Switching to single player mode.")); - SwitchToSinglePlayer(Play); - UpdatePlayerLists(); - UpdateMenus(); - break; - case C_QUIT: - /* The server has sent us notice that it is shutting down */ - g_warning(_("The server has terminated.\n" - "Switching to single player mode.")); - SwitchToSinglePlayer(Play); - UpdatePlayerLists(); - UpdateMenus(); - break; - case C_NEWNAME: - NewNameDialog(); - break; - case C_BANK: - TransferDialog(FALSE); - break; - case C_LOANSHARK: - TransferDialog(TRUE); - break; - case C_GUNSHOP: - GunShopDialog(); - break; - case C_MSG: - text = g_strdup_printf("%s: %s", GetPlayerName(From), Data); - PrintMessage(text); - g_free(text); - break; - case C_MSGTO: - text = g_strdup_printf("%s->%s: %s", GetPlayerName(From), - GetPlayerName(Play), Data); - PrintMessage(text); - g_free(text); - break; - case C_JOIN: - text = g_strdup_printf(_("%s joins the game!"), Data); - PrintMessage(text); - g_free(text); - UpdatePlayerLists(); - UpdateMenus(); - break; - case C_LEAVE: - if (From != &Noone) { - text = g_strdup_printf(_("%s has left the game."), Data); - PrintMessage(text); - g_free(text); - UpdatePlayerLists(); - UpdateMenus(); - } - break; - case C_QUESTION: - QuestionDialog(Data, From == &Noone ? NULL : From); - break; - case C_SUBWAYFLASH: - DisplayFightMessage(NULL); - for (list = FirstClient; list; list = g_slist_next(list)) { - tmp = (Player *)list->data; - tmp->Flags &= ~FIGHTING; - } - /* Message displayed when the player "jets" to a new location */ - text = dpg_strdup_printf(_("Jetting to %tde"), - Location[(int)Play->IsAt].Name); - PrintMessage(text); - g_free(text); - break; - case C_ENDLIST: - MenuItem = gtk_item_factory_get_widget(ClientData.Menu, - "<main>/Errands/Sack Bitch..."); - - /* Text for the Errands/Sack Bitch menu item */ - text = dpg_strdup_printf(_("%/Sack Bitch menu item/S_ack %Tde..."), - Names.Bitch); - SetAccelerator(MenuItem, text, NULL, NULL, NULL); - g_free(text); - - MenuItem = gtk_item_factory_get_widget(ClientData.Menu, - "<main>/Errands/Spy..."); - - /* Text to update the Errands/Spy menu item with the price for spying */ - text = dpg_strdup_printf(_("_Spy (%P)"), Prices.Spy); - SetAccelerator(MenuItem, text, NULL, NULL, NULL); - g_free(text); - - /* Text to update the Errands/Tipoff menu item with the price for a - * tipoff */ - text = dpg_strdup_printf(_("_Tipoff (%P)"), Prices.Tipoff); - MenuItem = gtk_item_factory_get_widget(ClientData.Menu, - "<main>/Errands/Tipoff..."); - SetAccelerator(MenuItem, text, NULL, NULL, NULL); - g_free(text); - if (FirstClient->next) - ListPlayers(NULL, NULL); - UpdateMenus(); - break; - case C_UPDATE: - if (From == &Noone) { - ReceivePlayerData(Play, Data, Play); - UpdateStatus(Play); - } else { - ReceivePlayerData(Play, Data, From); - DisplaySpyReports(From); - } - break; - case C_DRUGHERE: - UpdateInventory(&ClientData.Drug, Play->Drugs, NumDrug, TRUE); - gtk_clist_sort(GTK_CLIST(ClientData.Drug.HereList)); - if (IsShowingInventory) { - UpdateInventory(&ClientData.InvenDrug, Play->Drugs, NumDrug, TRUE); - } - break; - default: - if (!Handled) { - g_print("Unknown network message received: %s^%c^%s^%s", - GetPlayerName(From), Code, GetPlayerName(Play), Data); - } - break; - } -} - -struct HiScoreDiaStruct { - GtkWidget *dialog, *table, *vbox; -}; -static struct HiScoreDiaStruct HiScoreDialog = { NULL, NULL, NULL }; - -/* - * Creates an empty dialog to display high scores. - */ -void PrepareHighScoreDialog(void) -{ - GtkWidget *dialog, *vbox, *hsep, *table; - - /* Make sure the server doesn't fool us into creating multiple dialogs */ - if (HiScoreDialog.dialog) - return; - - HiScoreDialog.dialog = dialog = gtk_window_new(GTK_WINDOW_DIALOG); - - /* Title of the GTK+ high score dialog */ - gtk_window_set_title(GTK_WINDOW(dialog), _("High Scores")); - - gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); - - HiScoreDialog.vbox = vbox = gtk_vbox_new(FALSE, 7); - HiScoreDialog.table = table = gtk_table_new(NUMHISCORE, 4, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(table), 5); - gtk_table_set_col_spacings(GTK_TABLE(table), 30); - - gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(dialog), vbox); - gtk_widget_show_all(dialog); -} - -/* - * Adds a single high score (coded in "Data", which is the information - * received in the relevant network message) to the dialog created by - * PrepareHighScoreDialog(), above. - */ -void AddScoreToDialog(char *Data) -{ - GtkWidget *label; - char *cp; - gchar **spl1, **spl2; - int index, slen; - gboolean bold; - - if (!HiScoreDialog.dialog) - return; - - cp = Data; - index = GetNextInt(&cp, 0); - if (!cp || strlen(cp) < 3) - return; - - bold = (*cp == 'B'); /* Is this score "our" score? (Currently - * ignored) */ - - /* Step past the 'bold' character, and the initial '>' (if present) */ - cp += 2; - g_strchug(cp); - - /* Get the first word - the score */ - spl1 = g_strsplit(cp, " ", 1); - if (!spl1 || !spl1[0] || !spl1[1]) { - /* Error - the high score from the server is invalid */ - g_warning(_("Corrupt high score!")); - g_strfreev(spl1); - return; - } - label = gtk_label_new(spl1[0]); - gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); - gtk_table_attach_defaults(GTK_TABLE(HiScoreDialog.table), label, - 0, 1, index, index + 1); - gtk_widget_show(label); - - /* Remove any leading whitespace from the remainder, since g_strsplit - * will split at every space character, not at a run of them */ - g_strchug(spl1[1]); - - /* Get the second word - the date */ - spl2 = g_strsplit(spl1[1], " ", 1); - if (!spl2 || !spl2[0] || !spl2[1]) { - g_warning(_("Corrupt high score!")); - g_strfreev(spl2); - return; - } - label = gtk_label_new(spl2[0]); - gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5); - gtk_table_attach_defaults(GTK_TABLE(HiScoreDialog.table), label, - 1, 2, index, index + 1); - gtk_widget_show(label); - - /* The remainder is the name, terminated with (R.I.P.) if the player - * died, and '<' for the 'current' score */ - g_strchug(spl2[1]); - - /* Remove '<' suffix if present */ - slen = strlen(spl2[1]); - if (slen >= 1 && spl2[1][slen - 1] == '<') { - spl2[1][slen - 1] = '\0'; - } - slen--; - - /* Check for (R.I.P.) suffix, and add it to the 4th column if found */ - if (slen > 8 && spl2[1][slen - 1] == ')' && spl2[1][slen - 8] == '(') { - label = gtk_label_new(&spl2[1][slen - 8]); - gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5); - gtk_table_attach_defaults(GTK_TABLE(HiScoreDialog.table), label, - 3, 4, index, index + 1); - gtk_widget_show(label); - spl2[1][slen - 8] = '\0'; /* Remove suffix from the player name */ - } - - /* Finally, add in what's left of the player name */ - g_strchomp(spl2[1]); - label = gtk_label_new(spl2[1]); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_table_attach_defaults(GTK_TABLE(HiScoreDialog.table), label, - 2, 3, index, index + 1); - gtk_widget_show(label); - - g_strfreev(spl1); - g_strfreev(spl2); -} - -/* - * If the high scores are being displayed at the end of the game, - * this function is used to end the game when the high score dialog's - * "OK" button is pressed. - */ -static void EndHighScore(GtkWidget *widget) -{ - EndGame(); -} - -/* - * Called when all high scores have been received. Finishes off the - * high score dialog by adding an "OK" button. If the game has ended, - * then "AtEnd" is TRUE, and clicking this button will end the game. - */ -void CompleteHighScoreDialog(gboolean AtEnd) -{ - GtkWidget *OKButton, *dialog; - - dialog = HiScoreDialog.dialog; - - if (!HiScoreDialog.dialog) - return; - - /* Caption of the "OK" button in dialogs */ - OKButton = gtk_button_new_with_label(_("OK")); - gtk_signal_connect_object(GTK_OBJECT(OKButton), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)dialog); - if (AtEnd) { - InGame = FALSE; - gtk_signal_connect_object(GTK_OBJECT(dialog), "destroy", - GTK_SIGNAL_FUNC(EndHighScore), NULL); - } - gtk_box_pack_start(GTK_BOX(HiScoreDialog.vbox), OKButton, TRUE, TRUE, 0); - - GTK_WIDGET_SET_FLAGS(OKButton, GTK_CAN_DEFAULT); - gtk_widget_grab_default(OKButton); - gtk_widget_show(OKButton); - - /* OK, we're done - allow the creation of new high score dialogs */ - HiScoreDialog.dialog = NULL; -} - -/* - * Prints an information message in the display area of the GTK+ client. - * This area is used for displaying drug busts, messages from other - * players, etc. The message is passed in as the string "text". - */ -void PrintMessage(char *text) -{ - gint EditPos; - char *cr = "\n"; - GtkEditable *messages; - - messages = GTK_EDITABLE(ClientData.messages); - - gtk_text_freeze(GTK_TEXT(messages)); - g_strdelimit(text, "^", '\n'); - EditPos = gtk_text_get_length(GTK_TEXT(ClientData.messages)); - while (*text == '\n') - text++; - gtk_editable_insert_text(messages, text, strlen(text), &EditPos); - if (text[strlen(text) - 1] != '\n') { - gtk_editable_insert_text(messages, cr, strlen(cr), &EditPos); - } - gtk_text_thaw(GTK_TEXT(messages)); - gtk_editable_set_position(messages, EditPos); -} - -/* - * Called when one of the action buttons in the Fight dialog is clicked. - * "data" specifies which button (Deal Drugs/Run/Fight/Stand) was pressed. - */ -static void FightCallback(GtkWidget *widget, gpointer data) -{ - gint Answer; - Player *Play; - gchar text[4]; - GtkWidget *window; - gpointer CanRunHere = NULL; - - window = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); - if (window) - CanRunHere = gtk_object_get_data(GTK_OBJECT(window), "CanRunHere"); - - Answer = GPOINTER_TO_INT(data); - Play = ClientData.Play; - switch (Answer) { - case 'D': - gtk_widget_hide(FightDialog); - break; - case 'R': - if (CanRunHere) { - SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, "R"); - } else { - Jet(FightDialog); - } - break; - case 'F': - case 'S': - text[0] = Answer; - text[1] = '\0'; - SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, text); - break; - } -} - -/* - * Adds an action button to the hbox at the base of the Fight dialog. - * The button's caption is given by "Text", and the keyboard shortcut - * (if any) is added to "accel_group". "Answer" gives the identifier - * passed to FightCallback, above. - */ -static GtkWidget *AddFightButton(gchar *Text, GtkAccelGroup *accel_group, - GtkBox *box, gint Answer) -{ - GtkWidget *button; - - button = gtk_button_new_with_label(""); - SetAccelerator(button, Text, button, "clicked", accel_group); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(FightCallback), - GINT_TO_POINTER(Answer)); - gtk_box_pack_start(box, button, TRUE, TRUE, 0); - return button; -} - -/* Data used to keep track of the widgets giving the information about a - * player/cop involved in a fight */ -struct combatant { - GtkWidget *name, *bitches, *healthprog, *healthlabel; -}; - -/* - * Creates an empty Fight dialog. Usually this only needs to be done once, - * as when the user "closes" it, it is only hidden, ready to be reshown - * later. Buttons for all actions are added here, and are hidden/shown - * as necessary. - */ -static void CreateFightDialog(void) -{ - GtkWidget *dialog, *vbox, *button, *hbox, *hbbox, *hsep, *text, *table; - GtkAccelGroup *accel_group; - GArray *combatants; - gchar *buf; - - FightDialog = dialog = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300); - gtk_signal_connect(GTK_OBJECT(dialog), "delete_event", - GTK_SIGNAL_FUNC(DisallowDelete), NULL); - gtk_window_set_default_size(GTK_WINDOW(dialog), 240, 130); - accel_group = gtk_accel_group_new(); - gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group); - gtk_window_set_title(GTK_WINDOW(dialog), _("Fight")); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); - - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); - - vbox = gtk_vbox_new(FALSE, 7); - - table = gtk_table_new(2, 4, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(table), 5); - gtk_table_set_col_spacings(GTK_TABLE(table), 5); - - hsep = gtk_hseparator_new(); - gtk_table_attach_defaults(GTK_TABLE(table), hsep, 0, 4, 1, 2); - gtk_widget_show_all(table); - gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); - gtk_object_set_data(GTK_OBJECT(dialog), "table", table); - - combatants = g_array_new(FALSE, TRUE, sizeof(struct combatant)); - g_array_set_size(combatants, 1); - gtk_object_set_data(GTK_OBJECT(dialog), "combatants", combatants); - - text = gtk_scrolled_text_new(NULL, NULL, &hbox); - gtk_widget_set_usize(text, 150, 120); - - gtk_text_set_editable(GTK_TEXT(text), FALSE); - gtk_text_set_word_wrap(GTK_TEXT(text), TRUE); - gtk_object_set_data(GTK_OBJECT(dialog), "text", text); - gtk_widget_show_all(hbox); - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - gtk_widget_show(hsep); - - hbbox = gtk_hbutton_box_new(); - - /* Button for closing the "Fight" dialog and going back to dealing drugs - * (%Tde = "Drugs" by default) */ - buf = dpg_strdup_printf(_("_Deal %Tde"), Names.Drugs); - button = AddFightButton(buf, accel_group, GTK_BOX(hbbox), 'D'); - gtk_object_set_data(GTK_OBJECT(dialog), "deal", button); - g_free(buf); - - /* Button for shooting at other players in the "Fight" dialog, or for - * popping up the "Fight" dialog from the main window */ - button = AddFightButton(_("_Fight"), accel_group, GTK_BOX(hbbox), 'F'); - gtk_object_set_data(GTK_OBJECT(dialog), "fight", button); - - /* Button to stand and take it in the "Fight" dialog */ - button = AddFightButton(_("_Stand"), accel_group, GTK_BOX(hbbox), 'S'); - gtk_object_set_data(GTK_OBJECT(dialog), "stand", button); - - /* Button to run from combat in the "Fight" dialog */ - button = AddFightButton(_("_Run"), accel_group, GTK_BOX(hbbox), 'R'); - gtk_object_set_data(GTK_OBJECT(dialog), "run", button); - - gtk_widget_show(hsep); - gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); - gtk_widget_show(hbbox); - gtk_widget_show(vbox); - gtk_container_add(GTK_CONTAINER(dialog), vbox); - gtk_widget_show(dialog); -} - -/* - * Updates the display of information for a player/cop in the Fight dialog. - * If the player's name (DefendName) already exists, updates the display of - * total health and number of bitches - otherwise, adds a new entry. If - * DefendBitches is -1, then the player has left. - */ -static void UpdateCombatant(gchar *DefendName, int DefendBitches, - gchar *BitchName, int DefendHealth) -{ - guint i, RowIndex; - gchar *name; - struct combatant *compt; - GArray *combatants; - GtkWidget *table; - gchar *BitchText, *HealthText; - gfloat ProgPercent; - - combatants = (GArray *)gtk_object_get_data(GTK_OBJECT(FightDialog), - "combatants"); - table = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "table")); - if (!combatants) - return; - - if (DefendName[0]) { - compt = NULL; - for (i = 1, RowIndex = 2; i < combatants->len; i++, RowIndex++) { - compt = &g_array_index(combatants, struct combatant, i); - - if (!compt || !compt->name) { - compt = NULL; - continue; - } - gtk_label_get(GTK_LABEL(compt->name), &name); - if (name && strcmp(name, DefendName) == 0) - break; - compt = NULL; - } - if (!compt) { - i = combatants->len; - g_array_set_size(combatants, i + 1); - compt = &g_array_index(combatants, struct combatant, i); - - gtk_table_resize(GTK_TABLE(table), i + 2, 4); - RowIndex = i + 1; - } - } else { - compt = &g_array_index(combatants, struct combatant, 0); - - RowIndex = 0; - } - - /* Display of number of bitches or deputies during combat - * (%tde="bitches" or "deputies" (etc.) by default) */ - BitchText = dpg_strdup_printf(_("%/Combat: Bitches/%d %tde"), - DefendBitches, BitchName); - - /* Display of health during combat */ - if (DefendBitches == -1) { - HealthText = g_strdup(_("(Left)")); - } else if (DefendHealth == 0 && DefendBitches == 0) { - HealthText = g_strdup(_("(Dead)")); - } else { - HealthText = g_strdup_printf(_("Health: %d"), DefendHealth); - } - - ProgPercent = (gfloat)DefendHealth / 100.0; - - if (compt->name) { - if (DefendName[0]) { - gtk_label_set_text(GTK_LABEL(compt->name), DefendName); - } - if (DefendBitches >= 0) { - gtk_label_set_text(GTK_LABEL(compt->bitches), BitchText); - } - gtk_label_set_text(GTK_LABEL(compt->healthlabel), HealthText); - gtk_progress_bar_update(GTK_PROGRESS_BAR(compt->healthprog), - ProgPercent); - } else { - /* Display of the current player's name during combat */ - compt->name = gtk_label_new(DefendName[0] ? DefendName : _("You")); - - gtk_table_attach_defaults(GTK_TABLE(table), compt->name, 0, 1, - RowIndex, RowIndex + 1); - compt->bitches = gtk_label_new(DefendBitches >= 0 ? BitchText : ""); - gtk_table_attach_defaults(GTK_TABLE(table), compt->bitches, 1, 2, - RowIndex, RowIndex + 1); - compt->healthprog = gtk_progress_bar_new(); - gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(compt->healthprog), - GTK_PROGRESS_LEFT_TO_RIGHT); - gtk_progress_bar_update(GTK_PROGRESS_BAR(compt->healthprog), - ProgPercent); - gtk_table_attach_defaults(GTK_TABLE(table), compt->healthprog, 2, 3, - RowIndex, RowIndex + 1); - compt->healthlabel = gtk_label_new(HealthText); - gtk_table_attach_defaults(GTK_TABLE(table), compt->healthlabel, 3, 4, - RowIndex, RowIndex + 1); - gtk_widget_show(compt->name); - gtk_widget_show(compt->bitches); - gtk_widget_show(compt->healthprog); - gtk_widget_show(compt->healthlabel); - } - - g_free(BitchText); - g_free(HealthText); -} - -/* - * Cleans up the list of all players/cops involved in a fight. - */ -static void FreeCombatants(void) -{ - GArray *combatants; - - combatants = (GArray *)gtk_object_get_data(GTK_OBJECT(FightDialog), - "combatants"); - if (!combatants) - return; - - g_array_free(combatants, TRUE); -} - -/* - * Given the network message "Data" concerning some happening during - * combat, extracts the relevant data and updates the Fight dialog, - * creating and/or showing it if necessary. - * If "Data" is NULL, then closes the dialog. If "Data" is a blank - * string, then just shows the dialog, displaying no new messages. - */ -void DisplayFightMessage(char *Data) -{ - Player *Play; - gint EditPos; - GtkAccelGroup *accel_group; - GtkWidget *Deal, *Fight, *Stand, *Run, *Text; - char cr[] = "\n"; - gchar *AttackName, *DefendName, *BitchName, *Message; - FightPoint fp; - int DefendHealth, DefendBitches, BitchesKilled, ArmPercent; - gboolean CanRunHere, Loot, CanFire; - - if (!Data) { - if (FightDialog) { - FreeCombatants(); - gtk_widget_destroy(FightDialog); - FightDialog = NULL; - } - return; - } - if (FightDialog) { - if (!GTK_WIDGET_VISIBLE(FightDialog)) - gtk_widget_show(FightDialog); - } else { - CreateFightDialog(); - } - if (!FightDialog || !Data[0]) - return; - - Deal = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "deal")); - Fight = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "fight")); - Stand = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "stand")); - Run = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "run")); - Text = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "text")); - - Play = ClientData.Play; - - if (HaveAbility(Play, A_NEWFIGHT)) { - ReceiveFightMessage(Data, &AttackName, &DefendName, &DefendHealth, - &DefendBitches, &BitchName, &BitchesKilled, - &ArmPercent, &fp, &CanRunHere, &Loot, &CanFire, - &Message); - Play->Flags |= FIGHTING; - switch (fp) { - case F_HIT: - case F_ARRIVED: - case F_MISS: - UpdateCombatant(DefendName, DefendBitches, BitchName, DefendHealth); - break; - case F_LEAVE: - if (AttackName[0]) { - UpdateCombatant(AttackName, -1, BitchName, 0); - } - break; - case F_LASTLEAVE: - Play->Flags &= ~FIGHTING; - break; - default: - } - accel_group = (GtkAccelGroup *) - gtk_object_get_data(GTK_OBJECT(ClientData.window), "accel_group"); - SetJetButtonTitle(accel_group); - } else { - Message = Data; - if (Play->Flags & FIGHTING) - fp = F_MSG; - else - fp = F_LASTLEAVE; - CanFire = (Play->Flags & CANSHOOT); - CanRunHere = FALSE; - } - gtk_object_set_data(GTK_OBJECT(FightDialog), "CanRunHere", - GINT_TO_POINTER(CanRunHere)); - - g_strdelimit(Message, "^", '\n'); - if (strlen(Message) > 0) { - EditPos = gtk_text_get_length(GTK_TEXT(Text)); - gtk_editable_insert_text(GTK_EDITABLE(Text), Message, - strlen(Message), &EditPos); - gtk_editable_insert_text(GTK_EDITABLE(Text), cr, strlen(cr), &EditPos); - } - - if (!CanRunHere || fp == F_LASTLEAVE) - gtk_widget_show(Deal); - else - gtk_widget_hide(Deal); - if (CanFire && TotalGunsCarried(Play) > 0) - gtk_widget_show(Fight); - else - gtk_widget_hide(Fight); - if (CanFire && TotalGunsCarried(Play) == 0) - gtk_widget_show(Stand); - else - gtk_widget_hide(Stand); - if (fp != F_LASTLEAVE) - gtk_widget_show(Run); - else - gtk_widget_hide(Run); -} - -/* - * Updates the display of pertinent data about player "Play" (location, - * health, etc. in the status widgets given by "Status". This can point - * to the widgets at the top of the main window, or those in a Spy - * Reports dialog. - */ -void DisplayStats(Player *Play, struct StatusWidgets *Status) -{ - gchar *prstr; - GString *text; - - text = g_string_new(NULL); - - gtk_label_set_text(GTK_LABEL(Status->Location), - Location[(int)Play->IsAt].Name); - - g_string_sprintf(text, "%s%02d%s", Names.Month, Play->Turn, Names.Year); - gtk_label_set_text(GTK_LABEL(Status->Date), text->str); - - g_string_sprintf(text, "%d", Play->CoatSize); - gtk_label_set_text(GTK_LABEL(Status->SpaceValue), text->str); - - prstr = FormatPrice(Play->Cash); - gtk_label_set_text(GTK_LABEL(Status->CashValue), prstr); - g_free(prstr); - - prstr = FormatPrice(Play->Bank); - gtk_label_set_text(GTK_LABEL(Status->BankValue), prstr); - g_free(prstr); - - prstr = FormatPrice(Play->Debt); - gtk_label_set_text(GTK_LABEL(Status->DebtValue), prstr); - g_free(prstr); - - /* Display of carried guns in GTK+ client status window (%Tde="Guns" by - * default) */ - dpg_string_sprintf(text, _("%/GTK Stats: Guns/%Tde"), Names.Guns); - gtk_label_set_text(GTK_LABEL(Status->GunsName), text->str); - g_string_sprintf(text, "%d", TotalGunsCarried(Play)); - gtk_label_set_text(GTK_LABEL(Status->GunsValue), text->str); - - if (!WantAntique) { - /* Display of number of bitches in GTK+ client status window - * (%Tde="Bitches" by default) */ - dpg_string_sprintf(text, _("%/GTK Stats: Bitches/%Tde"), - Names.Bitches); - gtk_label_set_text(GTK_LABEL(Status->BitchesName), text->str); - g_string_sprintf(text, "%d", Play->Bitches.Carried); - gtk_label_set_text(GTK_LABEL(Status->BitchesValue), text->str); - } else { - gtk_label_set_text(GTK_LABEL(Status->BitchesName), NULL); - gtk_label_set_text(GTK_LABEL(Status->BitchesValue), NULL); - } - - g_string_sprintf(text, "%d", Play->Health); - gtk_label_set_text(GTK_LABEL(Status->HealthValue), text->str); - - g_string_free(text, TRUE); -} - -/* - * Updates all of the player status in response to a message from the - * server. This includes the main window display, the gun shop (if - * displayed) and the inventory (if displayed). - */ -void UpdateStatus(Player *Play) -{ - GtkAccelGroup *accel_group; - - DisplayStats(Play, &ClientData.Status); - UpdateInventory(&ClientData.Drug, ClientData.Play->Drugs, NumDrug, TRUE); - gtk_clist_sort(GTK_CLIST(ClientData.Drug.HereList)); - accel_group = (GtkAccelGroup *) - gtk_object_get_data(GTK_OBJECT(ClientData.window), "accel_group"); - SetJetButtonTitle(accel_group); - if (IsShowingGunShop) { - UpdateInventory(&ClientData.Gun, ClientData.Play->Guns, NumGun, FALSE); - } - if (IsShowingInventory) { - UpdateInventory(&ClientData.InvenDrug, ClientData.Play->Drugs, - NumDrug, TRUE); - UpdateInventory(&ClientData.InvenGun, ClientData.Play->Guns, - NumGun, FALSE); - } -} - -void UpdateInventory(struct InventoryWidgets *Inven, - Inventory *Objects, int NumObjects, gboolean AreDrugs) -{ - GtkWidget *herelist, *carrylist; - Player *Play; - gint i, row, selectrow[2]; - gpointer rowdata; - price_t price; - gchar *titles[2]; - gboolean CanBuy = FALSE, CanSell = FALSE, CanDrop = FALSE; - GList *glist[2], *selection; - GtkCList *clist[2]; - int numlist; - - Play = ClientData.Play; - herelist = Inven->HereList; - carrylist = Inven->CarriedList; - - if (herelist) - numlist = 2; - else - numlist = 1; - - /* Make lists of the current selections */ - clist[0] = GTK_CLIST(carrylist); - if (herelist) - clist[1] = GTK_CLIST(herelist); - else - clist[1] = NULL; - - for (i = 0; i < numlist; i++) { - glist[i] = NULL; - selectrow[i] = -1; - for (selection = clist[i]->selection; selection; - selection = g_list_next(selection)) { - row = GPOINTER_TO_INT(selection->data); - rowdata = gtk_clist_get_row_data(clist[i], row); - glist[i] = g_list_append(glist[i], rowdata); - } - } - - gtk_clist_freeze(GTK_CLIST(carrylist)); - gtk_clist_clear(GTK_CLIST(carrylist)); - - if (herelist) { - gtk_clist_freeze(GTK_CLIST(herelist)); - gtk_clist_clear(GTK_CLIST(herelist)); - } - - for (i = 0; i < NumObjects; i++) { - if (AreDrugs) { - titles[0] = Drug[i].Name; - price = Objects[i].Price; - } else { - titles[0] = Gun[i].Name; - price = Gun[i].Price; - } - - if (herelist && price > 0) { - CanBuy = TRUE; - titles[1] = FormatPrice(price); - row = gtk_clist_append(GTK_CLIST(herelist), titles); - g_free(titles[1]); - gtk_clist_set_row_data(GTK_CLIST(herelist), row, GINT_TO_POINTER(i)); - if (g_list_find(glist[1], GINT_TO_POINTER(i))) { - selectrow[1] = row; - gtk_clist_select_row(GTK_CLIST(herelist), row, 0); - } - } - - if (Objects[i].Carried > 0) { - if (price > 0) - CanSell = TRUE; - else - CanDrop = TRUE; - if (HaveAbility(ClientData.Play, A_DRUGVALUE) && AreDrugs) { - titles[1] = dpg_strdup_printf("%d @ %P", Objects[i].Carried, - Objects[i].TotalValue / - Objects[i].Carried); - } else { - titles[1] = g_strdup_printf("%d", Objects[i].Carried); - } - row = gtk_clist_append(GTK_CLIST(carrylist), titles); - g_free(titles[1]); - gtk_clist_set_row_data(GTK_CLIST(carrylist), row, - GINT_TO_POINTER(i)); - if (g_list_find(glist[0], GINT_TO_POINTER(i))) { - selectrow[0] = row; - gtk_clist_select_row(GTK_CLIST(carrylist), row, 0); - } - } - } - - for (i = 0; i < numlist; i++) { - if (selectrow[i] != -1 && gtk_clist_row_is_visible(clist[i], - selectrow[i]) != - GTK_VISIBILITY_FULL) { - gtk_clist_moveto(clist[i], selectrow[i], 0, 0.0, 0.0); - } - g_list_free(glist[i]); - } - - gtk_clist_thaw(GTK_CLIST(carrylist)); - if (herelist) - gtk_clist_thaw(GTK_CLIST(herelist)); - - if (Inven->vbbox) { - gtk_widget_set_sensitive(Inven->BuyButton, CanBuy); - gtk_widget_set_sensitive(Inven->SellButton, CanSell); - gtk_widget_set_sensitive(Inven->DropButton, CanDrop); - } -} - -static void JetCallback(GtkWidget *widget, gpointer data) -{ - int NewLocation; - gchar *text; - GtkWidget *JetDialog; - - JetDialog = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), "dialog")); - NewLocation = GPOINTER_TO_INT(data); - gtk_widget_destroy(JetDialog); - text = g_strdup_printf("%d", NewLocation); - SendClientMessage(ClientData.Play, C_NONE, C_REQUESTJET, NULL, text); - g_free(text); -} - -void JetButtonPressed(GtkWidget *widget, gpointer data) -{ - if (InGame) { - if (ClientData.Play->Flags & FIGHTING) { - DisplayFightMessage(NULL); - } else { - Jet(NULL); - } - } -} - -void Jet(GtkWidget *parent) -{ - GtkWidget *dialog, *table, *button, *label, *vbox; - GtkAccelGroup *accel_group; - gint boxsize, i, row, col; - gchar *name, AccelChar; - - accel_group = gtk_accel_group_new(); - - dialog = gtk_window_new(GTK_WINDOW_DIALOG); - /* Title of 'Jet' dialog */ - gtk_window_set_title(GTK_WINDOW(dialog), _("Jet to location")); - - gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); - gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(dialog), - parent ? GTK_WINDOW(parent) - : GTK_WINDOW(ClientData.window)); - - vbox = gtk_vbox_new(FALSE, 7); - - /* Prompt in 'Jet' dialog */ - label = gtk_label_new(_("Where to, dude ? ")); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - /* Generate a square box of buttons for all locations */ - boxsize = 1; - while (boxsize * boxsize < NumLocation) - boxsize++; - col = boxsize; - row = 1; - - /* Avoid creating a box with an entire row empty at the bottom */ - while (row * col < NumLocation) - row++; - - table = gtk_table_new(row, col, TRUE); - - for (i = 0; i < NumLocation; i++) { - if (i < 9) - AccelChar = '1' + i; - else if (i < 35) - AccelChar = 'A' + i - 9; - else - AccelChar = '\0'; - - row = i / boxsize; - col = i % boxsize; - if (AccelChar == '\0') { - button = gtk_button_new_with_label(Location[i].Name); - } else { - button = gtk_button_new_with_label(""); - - /* Display of locations in 'Jet' window (%tde="The Bronx" etc. by - * default) */ - name = dpg_strdup_printf(_("_%c. %tde"), AccelChar, Location[i].Name); - SetAccelerator(button, name, button, "clicked", accel_group); - /* Add keypad shortcuts as well */ - if (i < 9) { - gtk_widget_add_accelerator(button, "clicked", accel_group, - GDK_KP_1 + i, 0, - GTK_ACCEL_VISIBLE | - GTK_ACCEL_SIGNAL_VISIBLE); - } - g_free(name); - } - gtk_widget_set_sensitive(button, i != ClientData.Play->IsAt); - gtk_object_set_data(GTK_OBJECT(button), "dialog", dialog); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(JetCallback), GINT_TO_POINTER(i)); - gtk_table_attach_defaults(GTK_TABLE(table), button, col, col + 1, row, - row + 1); - } - gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); - - gtk_container_add(GTK_CONTAINER(dialog), vbox); - gtk_widget_show_all(dialog); -} - -struct DealDiaStruct { - GtkWidget *dialog, *cost, *carrying, *space, *afford, *amount; - gint DrugInd; - gpointer Type; -}; -static struct DealDiaStruct DealDialog; - -static void UpdateDealDialog(void) -{ - GString *text; - GtkAdjustment *spin_adj; - gint DrugInd, CanDrop, CanCarry, CanAfford, MaxDrug; - Player *Play; - - text = g_string_new(NULL); - DrugInd = DealDialog.DrugInd; - Play = ClientData.Play; - - /* Display of the current price of the selected drug in 'Deal Drugs' - * dialog */ - dpg_string_sprintf(text, _("at %P"), Play->Drugs[DrugInd].Price); - gtk_label_set_text(GTK_LABEL(DealDialog.cost), text->str); - - CanDrop = Play->Drugs[DrugInd].Carried; - - /* Display of current inventory of the selected drug in 'Deal Drugs' - * dialog (%tde="Opium" etc. by default) */ - dpg_string_sprintf(text, _("You are currently carrying %d %tde"), - CanDrop, Drug[DrugInd].Name); - gtk_label_set_text(GTK_LABEL(DealDialog.carrying), text->str); - - CanCarry = Play->CoatSize; - - /* Available space for drugs in 'Deal Drugs' dialog */ - g_string_sprintf(text, _("Available space: %d"), CanCarry); - gtk_label_set_text(GTK_LABEL(DealDialog.space), text->str); - - if (DealDialog.Type == BT_BUY) { - CanAfford = Play->Cash / Play->Drugs[DrugInd].Price; - - /* Number of the selected drug that you can afford in 'Deal Drugs' - * dialog */ - g_string_sprintf(text, _("You can afford %d"), CanAfford); - gtk_label_set_text(GTK_LABEL(DealDialog.afford), text->str); - MaxDrug = MIN(CanCarry, CanAfford); - } else - MaxDrug = CanDrop; - - spin_adj = (GtkAdjustment *)gtk_adjustment_new(MaxDrug, 1.0, MaxDrug, - 1.0, 10.0, 10.0); - gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(DealDialog.amount), - spin_adj); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(DealDialog.amount), MaxDrug); - - g_string_free(text, TRUE); -} - -static void DealSelectCallback(GtkWidget *widget, gpointer data) -{ - DealDialog.DrugInd = GPOINTER_TO_INT(data); - UpdateDealDialog(); -} - -static void DealOKCallback(GtkWidget *widget, gpointer data) -{ - GtkWidget *spinner; - gint amount; - gchar *text; - - spinner = DealDialog.amount; - - gtk_spin_button_update(GTK_SPIN_BUTTON(spinner)); - amount = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinner)); - - text = g_strdup_printf("drug^%d^%d", DealDialog.DrugInd, - data == BT_BUY ? amount : -amount); - SendClientMessage(ClientData.Play, C_NONE, C_BUYOBJECT, NULL, text); - g_free(text); - - gtk_widget_destroy(DealDialog.dialog); -} - -void DealDrugs(GtkWidget *widget, gpointer data) -{ - GtkWidget *dialog, *label, *hbox, *hbbox, *button, *spinner, *menu, - *optionmenu, *menuitem, *vbox, *hsep; - GtkAdjustment *spin_adj; - GtkAccelGroup *accel_group; - GtkWidget *clist; - gchar *Action; - GString *text; - GList *selection; - gint row; - Player *Play; - gint DrugInd, i, SelIndex, FirstInd; - gboolean DrugIndOK; - - /* Action in 'Deal Drugs' dialog - "Buy/Sell/Drop Drugs" */ - if (data == BT_BUY) - Action = _("Buy"); - else if (data == BT_SELL) - Action = _("Sell"); - else if (data == BT_DROP) - Action = _("Drop"); - else { - g_warning("Bad DealDrug type"); - return; - } - - DealDialog.Type = data; - Play = ClientData.Play; - - if (data == BT_BUY) - clist = ClientData.Drug.HereList; - else - clist = ClientData.Drug.CarriedList; - selection = GTK_CLIST(clist)->selection; - if (selection) { - row = GPOINTER_TO_INT(selection->data); - DrugInd = - GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(clist), row)); - } else - DrugInd = -1; - - DrugIndOK = FALSE; - FirstInd = -1; - for (i = 0; i < NumDrug; i++) { - if ((data == BT_DROP && Play->Drugs[i].Carried > 0 - && Play->Drugs[i].Price == 0) - || (data == BT_SELL && Play->Drugs[i].Carried > 0 - && Play->Drugs[i].Price != 0) - || (data == BT_BUY && Play->Drugs[i].Price != 0)) { - if (FirstInd == -1) - FirstInd = i; - if (DrugInd == i) - DrugIndOK = TRUE; - } - } - if (!DrugIndOK) { - if (FirstInd == -1) - return; - else - DrugInd = FirstInd; - } - - text = g_string_new(NULL); - accel_group = gtk_accel_group_new(); - dialog = DealDialog.dialog = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_window_set_title(GTK_WINDOW(dialog), Action); - gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); - - vbox = gtk_vbox_new(FALSE, 7); - - hbox = gtk_hbox_new(FALSE, 7); - - label = gtk_label_new(Action); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - - optionmenu = gtk_option_menu_new(); - menu = gtk_menu_new(); - SelIndex = -1; - for (i = 0; i < NumDrug; i++) { - if ((data == BT_DROP && Play->Drugs[i].Carried > 0 - && Play->Drugs[i].Price == 0) - || (data == BT_SELL && Play->Drugs[i].Carried > 0 - && Play->Drugs[i].Price != 0) - || (data == BT_BUY && Play->Drugs[i].Price != 0)) { - menuitem = gtk_menu_item_new_with_label(Drug[i].Name); - gtk_signal_connect(GTK_OBJECT(menuitem), "activate", - GTK_SIGNAL_FUNC(DealSelectCallback), - GINT_TO_POINTER(i)); - gtk_menu_append(GTK_MENU(menu), menuitem); - if (DrugInd >= i) - SelIndex++; - } - } - gtk_menu_set_active(GTK_MENU(menu), SelIndex); - gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu), menu); - gtk_box_pack_start(GTK_BOX(hbox), optionmenu, TRUE, TRUE, 0); - - DealDialog.DrugInd = DrugInd; - - label = DealDialog.cost = gtk_label_new(NULL); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = DealDialog.carrying = gtk_label_new(NULL); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - label = DealDialog.space = gtk_label_new(NULL); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - if (data == BT_BUY) { - label = DealDialog.afford = gtk_label_new(NULL); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - } - hbox = gtk_hbox_new(FALSE, 7); - if (data == BT_BUY) { - /* Prompts for action in the "deal drugs" dialog */ - g_string_sprintf(text, _("Buy how many?")); - } else if (data == BT_SELL) { - g_string_sprintf(text, _("Sell how many?")); - } else { - g_string_sprintf(text, _("Drop how many?")); - } - label = gtk_label_new(text->str); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - spin_adj = (GtkAdjustment *)gtk_adjustment_new(1.0, 1.0, 2.0, - 1.0, 10.0, 10.0); - spinner = DealDialog.amount = gtk_spin_button_new(spin_adj, 1.0, 0); - gtk_signal_connect(GTK_OBJECT(spinner), "activate", - GTK_SIGNAL_FUNC(DealOKCallback), data); - gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - hbbox = gtk_hbutton_box_new(); - button = gtk_button_new_with_label(_("OK")); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(DealOKCallback), data); - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); - gtk_widget_grab_default(button); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - /* Caption of "Cancel" button for GTK+ client dialogs */ - button = gtk_button_new_with_label(_("Cancel")); - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)dialog); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(dialog), vbox); - - g_string_free(text, TRUE); - UpdateDealDialog(); - - gtk_widget_show_all(dialog); -} - -void DealGuns(GtkWidget *widget, gpointer data) -{ - GtkWidget *clist, *dialog; - GList *selection; - gint row, GunInd; - gchar *Action, *Title; - GString *text; - - dialog = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); - if (data == BT_BUY) - Action = _("Buy"); - else if (data == BT_SELL) - Action = _("Sell"); - else - Action = _("Drop"); - - if (data == BT_BUY) - clist = ClientData.Gun.HereList; - else - clist = ClientData.Gun.CarriedList; - selection = GTK_CLIST(clist)->selection; - if (selection) { - row = GPOINTER_TO_INT(selection->data); - GunInd = - GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(clist), row)); - } else - return; - - - /* Title of 'gun shop' dialog (%tde="guns" by default) "Buy/Sell/Drop - * Guns" */ - if (data == BT_BUY) - Title = dpg_strdup_printf(_("Buy %tde"), Names.Guns); - else if (data == BT_SELL) - Title = dpg_strdup_printf(_("Sell %tde"), Names.Guns); - else - Title = dpg_strdup_printf(_("Drop %tde"), Names.Guns); - - text = g_string_new(""); - - if (data != BT_BUY && TotalGunsCarried(ClientData.Play) == 0) { - dpg_string_sprintf(text, _("You don't have any %tde to sell!"), - Names.Guns); - GtkMessageBox(dialog, text->str, Title, MB_OK); - } else if (data == BT_BUY && TotalGunsCarried(ClientData.Play) >= - ClientData.Play->Bitches.Carried + 2) { - dpg_string_sprintf(text, - _("You'll need more %tde to carry any more %tde!"), - Names.Bitches, Names.Guns); - GtkMessageBox(dialog, text->str, Title, MB_OK); - } else if (data == BT_BUY - && Gun[GunInd].Space > ClientData.Play->CoatSize) { - dpg_string_sprintf(text, - _("You don't have enough space to carry that %tde!"), - Names.Gun); - GtkMessageBox(dialog, text->str, Title, MB_OK); - } else if (data == BT_BUY && Gun[GunInd].Price > ClientData.Play->Cash) { - dpg_string_sprintf(text, - _("You don't have enough cash to buy that %tde!"), - Names.Gun); - GtkMessageBox(dialog, text->str, Title, MB_OK); - } else if (data == BT_SELL && ClientData.Play->Guns[GunInd].Carried == 0) { - GtkMessageBox(dialog, _("You don't have any to sell!"), Title, MB_OK); - } else { - g_string_sprintf(text, "gun^%d^%d", GunInd, data == BT_BUY ? 1 : -1); - SendClientMessage(ClientData.Play, C_NONE, C_BUYOBJECT, NULL, - text->str); - } - g_free(Title); - g_string_free(text, TRUE); -} - -static void QuestionCallback(GtkWidget *widget, gpointer data) -{ - gint Answer; - gchar text[5]; - GtkWidget *dialog; - Player *To; - - dialog = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), "dialog")); - To = (Player *)gtk_object_get_data(GTK_OBJECT(dialog), "From"); - Answer = GPOINTER_TO_INT(data); - - text[0] = (gchar)Answer; - text[1] = '\0'; - SendClientMessage(ClientData.Play, C_NONE, C_ANSWER, To, text); - - gtk_widget_destroy(dialog); -} - -void QuestionDialog(char *Data, Player *From) -{ - GtkWidget *dialog, *label, *vbox, *hsep, *hbbox, *button; - GtkAccelGroup *accel_group; - gchar *Responses, **split, *LabelText, *trword, *underline; - - /* Button titles that correspond to the single-keypress options provided - * by the curses client (e.g. _Yes corresponds to 'Y' etc.) */ - gchar *Words[] = { N_("_Yes"), N_("_No"), N_("_Run"), - N_("_Fight"), N_("_Attack"), N_("_Evade") - }; - gint numWords = sizeof(Words) / sizeof(Words[0]); - gint i, j; - - split = g_strsplit(Data, "^", 1); - if (!split[0] || !split[1]) { - g_warning("Bad QUESTION message %s", Data); - return; - } - - g_strdelimit(split[1], "^", '\n'); - - Responses = split[0]; - LabelText = split[1]; - - dialog = gtk_window_new(GTK_WINDOW_DIALOG); - accel_group = gtk_accel_group_new(); - gtk_signal_connect(GTK_OBJECT(dialog), "delete_event", - GTK_SIGNAL_FUNC(DisallowDelete), NULL); - gtk_object_set_data(GTK_OBJECT(dialog), "From", (gpointer)From); - - /* Title of the 'ask player a question' dialog */ - gtk_window_set_title(GTK_WINDOW(dialog), _("Question")); - - gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); - - vbox = gtk_vbox_new(FALSE, 7); - while (*LabelText == '\n') - LabelText++; - label = gtk_label_new(LabelText); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - hbbox = gtk_hbutton_box_new(); - - for (i = 0; i < strlen(Responses); i++) { - for (j = 0, trword = NULL; j < numWords && !trword; j++) { - underline = strchr(Words[j], '_'); - if (underline && toupper(underline[1]) == Responses[i]) { - trword = _(Words[j]); - } - } - button = gtk_button_new_with_label(""); - if (trword) { - SetAccelerator(button, trword, button, "clicked", accel_group); - } else { - trword = g_strdup_printf("_%c", Responses[i]); - SetAccelerator(button, trword, button, "clicked", accel_group); - g_free(trword); - } - gtk_object_set_data(GTK_OBJECT(button), "dialog", (gpointer)dialog); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(QuestionCallback), - GINT_TO_POINTER((gint)Responses[i])); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - } - gtk_box_pack_start(GTK_BOX(vbox), hbbox, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(dialog), vbox); - gtk_widget_show_all(dialog); - - g_strfreev(split); -} - -void StartGame(void) -{ - Player *Play = ClientData.Play; - - InitAbilities(Play); - SendAbilities(Play); - SendNullClientMessage(Play, C_NONE, C_NAME, NULL, GetPlayerName(Play)); - InGame = TRUE; - UpdateMenus(); - gtk_widget_show_all(ClientData.vbox); - UpdatePlayerLists(); -} - -void EndGame(void) -{ - DisplayFightMessage(NULL); - gtk_widget_hide_all(ClientData.vbox); - gtk_editable_delete_text(GTK_EDITABLE(ClientData.messages), 0, -1); - ShutdownNetwork(ClientData.Play); - UpdatePlayerLists(); - CleanUpServer(); - RestoreConfig(); - InGame = FALSE; - UpdateMenus(); -} - -static void ChangeDrugSort(GtkCList *clist, gint column, - gpointer user_data) -{ - if (column == 0) { - DrugSortMethod = (DrugSortMethod == DS_ATOZ ? DS_ZTOA : DS_ATOZ); - } else { - DrugSortMethod = (DrugSortMethod == DS_CHEAPFIRST ? DS_CHEAPLAST : - DS_CHEAPFIRST); - } - gtk_clist_sort(clist); -} - -static gint DrugSortFunc(GtkCList *clist, gconstpointer ptr1, - gconstpointer ptr2) -{ - int index1, index2; - price_t pricediff; - - index1 = GPOINTER_TO_INT(((const GtkCListRow *)ptr1)->data); - index2 = GPOINTER_TO_INT(((const GtkCListRow *)ptr2)->data); - if (index1 < 0 || index1 >= NumDrug || index2 < 0 || index2 >= NumDrug) - return 0; - - switch (DrugSortMethod) { - case DS_ATOZ: - return g_strcasecmp(Drug[index1].Name, Drug[index2].Name); - case DS_ZTOA: - return g_strcasecmp(Drug[index2].Name, Drug[index1].Name); - case DS_CHEAPFIRST: - pricediff = ClientData.Play->Drugs[index1].Price - - ClientData.Play->Drugs[index2].Price; - return pricediff == 0 ? 0 : pricediff < 0 ? -1 : 1; - case DS_CHEAPLAST: - pricediff = ClientData.Play->Drugs[index2].Price - - ClientData.Play->Drugs[index1].Price; - return pricediff == 0 ? 0 : pricediff < 0 ? -1 : 1; - } - return 0; -} - -void UpdateMenus(void) -{ - gboolean MultiPlayer; - gint Bitches; - - MultiPlayer = (FirstClient && FirstClient->next != NULL); - Bitches = InGame - && ClientData.Play ? ClientData.Play->Bitches.Carried : 0; - - gtk_widget_set_sensitive(gtk_item_factory_get_widget(ClientData.Menu, - "<main>/Talk"), - InGame && Network); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "<main>/List"), InGame); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "<main>/List/Players..."), - InGame && Network); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "<main>/Errands"), InGame); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "<main>/Errands/Spy..."), - InGame && MultiPlayer); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "<main>/Errands/Tipoff..."), - InGame && MultiPlayer); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, - "<main>/Errands/Sack Bitch..."), Bitches > 0); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, - "<main>/Errands/Get spy reports..."), InGame - && MultiPlayer); -} - -GtkWidget *CreateStatusWidgets(struct StatusWidgets *Status) -{ - GtkWidget *table, *label; - - table = gtk_table_new(3, 6, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(table), 3); - gtk_table_set_col_spacings(GTK_TABLE(table), 3); - - label = Status->Location = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1); - - label = Status->Date = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 4, 0, 1); - - /* Available space label in GTK+ client status display */ - label = Status->SpaceName = gtk_label_new(_("Space")); - - gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 5, 0, 1); - label = Status->SpaceValue = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 5, 6, 0, 1); - - /* Player's cash label in GTK+ client status display */ - label = Status->CashName = gtk_label_new(_("Cash")); - - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); - label = Status->CashValue = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2); - - /* Player's debt label in GTK+ client status display */ - label = Status->DebtName = gtk_label_new(_("Debt")); - - gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 1, 2); - label = Status->DebtValue = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 3, 4, 1, 2); - - /* Player's bank balance label in GTK+ client status display */ - label = Status->BankName = gtk_label_new(_("Bank")); - - gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 5, 1, 2); - label = Status->BankValue = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 5, 6, 1, 2); - - label = Status->GunsName = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3); - label = Status->GunsValue = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 3); - - label = Status->BitchesName = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 2, 3); - label = Status->BitchesValue = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 3, 4, 2, 3); - - /* Player's health label in GTK+ client status display */ - label = Status->HealthName = gtk_label_new(_("Health")); - - gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 5, 2, 3); - label = Status->HealthValue = gtk_label_new(NULL); - gtk_table_attach_defaults(GTK_TABLE(table), label, 5, 6, 2, 3); - return table; -} - -void SetJetButtonTitle(GtkAccelGroup *accel_group) -{ - GtkWidget *button; - guint accel_key; - - button = ClientData.JetButton; - accel_key = ClientData.JetAccel; - - if (accel_key) { - gtk_widget_remove_accelerator(button, accel_group, accel_key, 0); - } - - ClientData.JetAccel = SetAccelerator(button, - (ClientData.Play - && ClientData.Play-> - Flags & FIGHTING) ? _("_Fight") : - /* Caption of 'Jet' button in main - * window */ - _("_Jet!"), button, "clicked", - accel_group); -} - -static void SetIcon(GtkWidget *window, gchar **xpmdata) -{ -#ifndef CYGWIN - GdkBitmap *mask; - GdkPixmap *icon; - GtkStyle *style; - - style = gtk_widget_get_style(window); - icon = gdk_pixmap_create_from_xpm_d(window->window, &mask, - &style->bg[GTK_STATE_NORMAL], - xpmdata); - gdk_window_set_icon(window->window, NULL, icon, mask); -#endif -} - -#ifdef CYGWIN -char GtkLoop(HINSTANCE hInstance, HINSTANCE hPrevInstance) -{ -#else -char GtkLoop(int *argc, char **argv[], gboolean ReturnOnFail) -{ -#endif - GtkWidget *window, *vbox, *vbox2, *hbox, *frame, *table, *menubar, *text, - *vpaned, *button, *clist; - GtkAccelGroup *accel_group; - GtkItemFactory *item_factory; - GtkAdjustment *adj; - gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); - -#ifdef CYGWIN - win32_init(hInstance, hPrevInstance, "mainicon"); -#else - gtk_set_locale(); - if (ReturnOnFail && !gtk_init_check(argc, argv)) - return FALSE; - else if (!ReturnOnFail) - gtk_init(argc, argv); -#endif - - /* Set up message handlers */ - ClientMessageHandlerPt = HandleClientMessage; - - /* Have the GLib log messages pop up in a nice dialog box */ - g_log_set_handler(NULL, - LogMask() | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING | - G_LOG_LEVEL_CRITICAL, LogMessage, NULL); - - if (!CheckHighScoreFileConfig()) - return TRUE; - - /* Create the main player */ - ClientData.Play = g_new(Player, 1); - FirstClient = AddPlayer(0, ClientData.Play, FirstClient); - - window = MainWindow = ClientData.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - - /* Title of main window in GTK+ client */ - gtk_window_set_title(GTK_WINDOW(window), _("dopewars")); - gtk_window_set_default_size(GTK_WINDOW(window), 450, 390); - gtk_signal_connect(GTK_OBJECT(window), "delete_event", - GTK_SIGNAL_FUNC(MainDelete), NULL); - gtk_signal_connect(GTK_OBJECT(window), "destroy", - GTK_SIGNAL_FUNC(DestroyGtk), NULL); - - accel_group = gtk_accel_group_new(); - gtk_object_set_data(GTK_OBJECT(window), "accel_group", accel_group); - item_factory = ClientData.Menu = gtk_item_factory_new(GTK_TYPE_MENU_BAR, - "<main>", - accel_group); - gtk_item_factory_set_translate_func(item_factory, MenuTranslate, NULL, - NULL); - - gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, - NULL); - gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); - menubar = gtk_item_factory_get_widget(item_factory, "<main>"); - - vbox2 = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox2), menubar, FALSE, FALSE, 0); - gtk_widget_show_all(menubar); - UpdateMenus(); - - vbox = ClientData.vbox = gtk_vbox_new(FALSE, 5); - frame = gtk_frame_new(_("Stats")); - - table = CreateStatusWidgets(&ClientData.Status); - - gtk_container_add(GTK_CONTAINER(frame), table); - - gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); - - vpaned = gtk_vpaned_new(); - - adj = (GtkAdjustment *)gtk_adjustment_new(0.0, 0.0, 100.0, - 1.0, 10.0, 10.0); - text = ClientData.messages = gtk_scrolled_text_new(NULL, adj, &hbox); - gtk_widget_set_usize(text, 100, 80); - gtk_text_set_point(GTK_TEXT(text), 0); - gtk_text_set_editable(GTK_TEXT(text), FALSE); - gtk_text_set_word_wrap(GTK_TEXT(text), TRUE); - gtk_paned_pack1(GTK_PANED(vpaned), hbox, TRUE, TRUE); - - hbox = gtk_hbox_new(FALSE, 7); - CreateInventory(hbox, Names.Drugs, accel_group, TRUE, TRUE, - &ClientData.Drug, DealDrugs); - clist = ClientData.Drug.HereList; - gtk_clist_column_titles_active(GTK_CLIST(clist)); - gtk_clist_set_compare_func(GTK_CLIST(clist), DrugSortFunc); - gtk_signal_connect(GTK_OBJECT(clist), "click-column", - GTK_SIGNAL_FUNC(ChangeDrugSort), NULL); - - button = ClientData.JetButton = gtk_button_new_with_label(""); - ClientData.JetAccel = 0; - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(JetButtonPressed), NULL); - gtk_box_pack_start(GTK_BOX(ClientData.Drug.vbbox), button, TRUE, TRUE, 0); - SetJetButtonTitle(accel_group); - - gtk_paned_pack2(GTK_PANED(vpaned), hbox, TRUE, TRUE); - - gtk_box_pack_start(GTK_BOX(vbox), vpaned, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox2), vbox, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(window), vbox2); - - /* Just show the window, not the vbox - we'll do that when the game - * starts */ - gtk_widget_show(vbox2); - gtk_widget_show(window); - - gtk_widget_realize(window); - - SetIcon(window, dopewars_pill_xpm); - - gtk_main(); - - /* Free the main player */ - FirstClient = RemovePlayer(ClientData.Play, FirstClient); - - return TRUE; -} - -static void PackCentredURL(GtkWidget *vbox, gchar *title, gchar *target, - gchar *browser) -{ - GtkWidget *hbox, *label, *url; - - /* There must surely be a nicer way of making the URL centred - but I - * can't think of one... */ - hbox = gtk_hbox_new(FALSE, 0); - label = gtk_label_new(""); - gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); - - url = gtk_url_new(title, target, browser); - gtk_box_pack_start(GTK_BOX(hbox), url, FALSE, FALSE, 0); - - label = gtk_label_new(""); - gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); -} - -void display_intro(GtkWidget *widget, gpointer data) -{ - GtkWidget *dialog, *label, *table, *OKButton, *vbox, *hsep; - gchar *VersionStr, *docindex; - const int rows = 6, cols = 3; - int i, j; - gchar *table_data[6][3] = { - /* Credits labels in GTK+ 'about' dialog */ - {N_("Icons and graphics"), "Ocelot Mantis", NULL}, - {N_("Drug Dealing and Research"), "Dan Wolf", NULL}, - {N_("Play Testing"), "Phil Davis", "Owen Walsh"}, - {N_("Extensive Play Testing"), "Katherine Holt", - "Caroline Moore"}, - {N_("Constructive Criticism"), "Andrea Elliot-Smith", - "Pete Winn"}, - {N_("Unconstructive Criticism"), "James Matthews", NULL} - }; - - dialog = gtk_window_new(GTK_WINDOW_DIALOG); - - /* Title of GTK+ 'about' dialog */ - gtk_window_set_title(GTK_WINDOW(dialog), _("About dopewars")); - - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); - gtk_container_border_width(GTK_CONTAINER(dialog), 10); - - vbox = gtk_vbox_new(FALSE, 5); - - /* Main content of GTK+ 'about' dialog */ - label = gtk_label_new(_("Based on John E. Dell's old Drug Wars game, " - "dopewars is a simulation of an\nimaginary drug " - "market. dopewars is an All-American game which " - "features\nbuying, selling, and trying to get " - "past the cops!\n\nThe first thing you need to " - "do is pay off your debt to the Loan Shark. " - "After\nthat, your goal is to make as much " - "money as possible (and stay alive)! You\n" - "have one month of game time to make " - "your fortune.\n")); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - /* Version and copyright notice in GTK+ 'about' dialog */ - VersionStr = g_strdup_printf(_("Version %s " - "Copyright (C) 1998-2002 " - "Ben Webb ben@bellatrix.pcl.ox.ac.uk\n" - "dopewars is released under the " - "GNU General Public Licence\n"), VERSION); - label = gtk_label_new(VersionStr); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - g_free(VersionStr); - - table = gtk_table_new(rows, cols, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(table), 3); - gtk_table_set_col_spacings(GTK_TABLE(table), 3); - for (i = 0; i < rows; i++) - for (j = 0; j < cols; j++) - if (table_data[i][j]) { - if (j == 0) - label = gtk_label_new(_(table_data[i][j])); - else - label = gtk_label_new(table_data[i][j]); - gtk_table_attach_defaults(GTK_TABLE(table), label, j, j + 1, i, - i + 1); - } - gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); - - /* Label at the bottom of GTK+ 'about' dialog */ - label = gtk_label_new(_("\nFor information on the command line " - "options, type dopewars -h at your\n" - "Unix prompt. This will display a help " - "screen, listing the available options.\n")); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - docindex = GetDocIndex(); - PackCentredURL(vbox, "Local HTML documentation", docindex, WebBrowser); - g_free(docindex); - - PackCentredURL(vbox, "http://dopewars.sourceforge.net/", - "http://dopewars.sourceforge.net/", WebBrowser); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - OKButton = gtk_button_new_with_label(_("OK")); - gtk_signal_connect_object(GTK_OBJECT(OKButton), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)dialog); - - gtk_box_pack_start(GTK_BOX(vbox), OKButton, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(dialog), vbox); - - GTK_WIDGET_SET_FLAGS(OKButton, GTK_CAN_DEFAULT); - gtk_widget_grab_default(OKButton); - - gtk_widget_show_all(dialog); -} - -static gboolean GetStartGamePlayerName(struct StartGameStruct *widgets, - gchar **PlayerName) -{ - g_free(*PlayerName); - *PlayerName = gtk_editable_get_chars(GTK_EDITABLE(widgets->name), 0, -1); - if (*PlayerName && (*PlayerName)[0]) - return TRUE; - else { - GtkMessageBox(widgets->dialog, - _("You can't start the game without giving a name first!"), - _("New Game"), MB_OK); - return FALSE; - } -} - -static void SetStartGameStatus(struct StartGameStruct *widgets, gchar *msg) -{ - gtk_label_set_text(GTK_LABEL(widgets->status), - msg ? msg : _("Status: Waiting for user input")); -} - -#ifdef NETWORKING -static void ConnectError(struct StartGameStruct *widgets, gboolean meta) -{ - GString *neterr; - gchar *text; - LastError *error; - - if (meta) - error = widgets->MetaConn->NetBuf.error; - else - error = ClientData.Play->NetBuf.error; - - neterr = g_string_new(""); - - if (error) { - g_string_assign_error(neterr, error); - } else { - g_string_assign(neterr, _("Connection closed by remote host")); - } - - if (meta) { - /* Error: GTK+ client could not connect to the metaserver */ - text = - g_strdup_printf(_("Status: Could not connect to metaserver (%s)"), - neterr->str); - } else { - /* Error: GTK+ client could not connect to the given dopewars server */ - text = - g_strdup_printf(_("Status: Could not connect (%s)"), neterr->str); - } - - SetStartGameStatus(widgets, text); - g_free(text); - g_string_free(neterr, TRUE); -} - -void FinishServerConnect(struct StartGameStruct *widgets, - gboolean ConnectOK) -{ - if (ConnectOK) { - Client = Network = TRUE; - gtk_widget_destroy(widgets->dialog); - StartGame(); - } else { - ConnectError(widgets, FALSE); - } -} - -static void DoConnect(struct StartGameStruct *widgets) -{ - gchar *text; - NetworkBuffer *NetBuf; - NBStatus oldstatus; - NBSocksStatus oldsocks; - - NetBuf = &ClientData.Play->NetBuf; - - /* Message displayed during the attempted connect to a dopewars server */ - text = g_strdup_printf(_("Status: Attempting to contact %s..."), - ServerName); - SetStartGameStatus(widgets, text); - g_free(text); - - /* Terminate any existing connection attempts */ - ShutdownNetworkBuffer(NetBuf); - if (widgets->MetaConn) { - CloseHttpConnection(widgets->MetaConn); - widgets->MetaConn = NULL; - } - - oldstatus = NetBuf->status; - oldsocks = NetBuf->sockstat; - if (StartNetworkBufferConnect(NetBuf, ServerName, Port)) { - DisplayConnectStatus(widgets, FALSE, oldstatus, oldsocks); - SetNetworkBufferUserPasswdFunc(NetBuf, SocksAuthDialog, NULL); - SetNetworkBufferCallBack(NetBuf, SocketStatus, (gpointer)widgets); - } else { - ConnectError(widgets, FALSE); - } -} - -static void ConnectToServer(GtkWidget *widget, - struct StartGameStruct *widgets) -{ - gchar *text; - - g_free(ServerName); - ServerName = gtk_editable_get_chars(GTK_EDITABLE(widgets->hostname), - 0, -1); - text = gtk_editable_get_chars(GTK_EDITABLE(widgets->port), 0, -1); - Port = atoi(text); - g_free(text); - - if (!GetStartGamePlayerName(widgets, &ClientData.Play->Name)) - return; - DoConnect(widgets); -} - -static void FillMetaServerList(struct StartGameStruct *widgets, - gboolean UseNewList) -{ - GtkWidget *metaserv; - ServerData *ThisServer; - gchar *titles[5]; - GSList *ListPt; - gint row; - - if (UseNewList && !widgets->NewMetaList) - return; - - metaserv = widgets->metaserv; - gtk_clist_freeze(GTK_CLIST(metaserv)); - gtk_clist_clear(GTK_CLIST(metaserv)); - - if (UseNewList) { - ClearServerList(&MetaList); - MetaList = widgets->NewMetaList; - widgets->NewMetaList = NULL; - } - - for (ListPt = MetaList; ListPt; ListPt = g_slist_next(ListPt)) { - ThisServer = (ServerData *)(ListPt->data); - titles[0] = ThisServer->Name; - titles[1] = g_strdup_printf("%d", ThisServer->Port); - titles[2] = ThisServer->Version; - if (ThisServer->CurPlayers == -1) { - /* Displayed if we don't know how many players are logged on to a - * server */ - titles[3] = _("Unknown"); - } else { - /* e.g. "5 of 20" means 5 players are logged on to a server, out of - * a maximum of 20 */ - titles[3] = g_strdup_printf(_("%d of %d"), ThisServer->CurPlayers, - ThisServer->MaxPlayers); - } - titles[4] = ThisServer->Comment; - row = gtk_clist_append(GTK_CLIST(metaserv), titles); - gtk_clist_set_row_data(GTK_CLIST(metaserv), row, (gpointer)ThisServer); - g_free(titles[1]); - if (ThisServer->CurPlayers != -1) - g_free(titles[3]); - } - gtk_clist_thaw(GTK_CLIST(metaserv)); -} - -void DisplayConnectStatus(struct StartGameStruct *widgets, gboolean meta, - NBStatus oldstatus, NBSocksStatus oldsocks) -{ - NBStatus status; - NBSocksStatus sockstat; - gchar *text; - - if (meta) { - status = widgets->MetaConn->NetBuf.status; - sockstat = widgets->MetaConn->NetBuf.sockstat; - } else { - status = ClientData.Play->NetBuf.status; - sockstat = ClientData.Play->NetBuf.sockstat; - } - if (oldstatus == status && sockstat == oldsocks) - return; - - switch (status) { - case NBS_PRECONNECT: - break; - case NBS_SOCKSCONNECT: - switch (sockstat) { - case NBSS_METHODS: - text = g_strdup_printf(_("Status: Connected to SOCKS server %s..."), - Socks.name); - SetStartGameStatus(widgets, text); - g_free(text); - break; - case NBSS_USERPASSWD: - SetStartGameStatus(widgets, - _("Status: Authenticating with SOCKS server")); - break; - case NBSS_CONNECT: - text = - g_strdup_printf(_("Status: Asking SOCKS for connect to %s..."), - meta ? MetaServer.Name : ServerName); - SetStartGameStatus(widgets, text); - g_free(text); - break; - } - break; - case NBS_CONNECTED: - if (meta) { - SetStartGameStatus(widgets, - _("Status: Obtaining server information " - "from metaserver...")); - } - break; - } -} - -static void MetaDone(struct StartGameStruct *widgets) -{ - if (IsHttpError(widgets->MetaConn)) { - ConnectError(widgets, TRUE); - } else { - SetStartGameStatus(widgets, NULL); - } - CloseHttpConnection(widgets->MetaConn); - widgets->MetaConn = NULL; - FillMetaServerList(widgets, TRUE); -} - -static void HandleMetaSock(gpointer data, gint socket, - GdkInputCondition condition) -{ - struct StartGameStruct *widgets; - gboolean DoneOK; - NBStatus oldstatus; - NBSocksStatus oldsocks; - - widgets = (struct StartGameStruct *)data; - if (!widgets->MetaConn) - return; - - oldstatus = widgets->MetaConn->NetBuf.status; - oldsocks = widgets->MetaConn->NetBuf.sockstat; - - if (NetBufHandleNetwork - (&widgets->MetaConn->NetBuf, condition & GDK_INPUT_READ, - condition & GDK_INPUT_WRITE, &DoneOK)) { - while (HandleWaitingMetaServerData - (widgets->MetaConn, &widgets->NewMetaList, &DoneOK)) { - } - } - - if (!DoneOK && HandleHttpCompletion(widgets->MetaConn)) { - MetaDone(widgets); - } else { - DisplayConnectStatus(widgets, TRUE, oldstatus, oldsocks); - } -} - -void MetaSocketStatus(NetworkBuffer *NetBuf, gboolean Read, gboolean Write, - gboolean CallNow) -{ - if (NetBuf->InputTag) - gdk_input_remove(NetBuf->InputTag); - NetBuf->InputTag = 0; - if (Read || Write) { - NetBuf->InputTag = gdk_input_add(NetBuf->fd, - (Read ? GDK_INPUT_READ : 0) | - (Write ? GDK_INPUT_WRITE : 0), - HandleMetaSock, NetBuf->CallBackData); - } - if (CallNow) - HandleMetaSock(NetBuf->CallBackData, NetBuf->fd, 0); -} - -static void UpdateMetaServerList(GtkWidget *widget, - struct StartGameStruct *widgets) -{ - GtkWidget *metaserv; - gchar *text; - - /* Terminate any existing connection attempts */ - ShutdownNetworkBuffer(&ClientData.Play->NetBuf); - if (widgets->MetaConn) { - CloseHttpConnection(widgets->MetaConn); - widgets->MetaConn = NULL; - } - - ClearServerList(&widgets->NewMetaList); - - /* Message displayed during the attempted connect to the metaserver */ - text = g_strdup_printf(_("Status: Attempting to contact %s..."), - MetaServer.Name); - SetStartGameStatus(widgets, text); - g_free(text); - - if (OpenMetaHttpConnection(&widgets->MetaConn)) { - metaserv = widgets->metaserv; - SetHttpAuthFunc(widgets->MetaConn, AuthDialog, NULL); - SetNetworkBufferUserPasswdFunc(&widgets->MetaConn->NetBuf, - MetaSocksAuthDialog, NULL); - SetNetworkBufferCallBack(&widgets->MetaConn->NetBuf, - MetaSocketStatus, (gpointer)widgets); - } else { - ConnectError(widgets, TRUE); - CloseHttpConnection(widgets->MetaConn); - widgets->MetaConn = NULL; - } -} - -static void MetaServerConnect(GtkWidget *widget, - struct StartGameStruct *widgets) -{ - GList *selection; - gint row; - GtkWidget *clist; - ServerData *ThisServer; - - clist = widgets->metaserv; - selection = GTK_CLIST(clist)->selection; - if (selection) { - row = GPOINTER_TO_INT(selection->data); - ThisServer = (ServerData *)gtk_clist_get_row_data(GTK_CLIST(clist), row); - AssignName(&ServerName, ThisServer->Name); - Port = ThisServer->Port; - - if (!GetStartGamePlayerName(widgets, &ClientData.Play->Name)) - return; - DoConnect(widgets); - } -} -#endif /* NETWORKING */ - -static void StartSinglePlayer(GtkWidget *widget, - struct StartGameStruct *widgets) -{ - WantAntique = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->antique)); - if (!GetStartGamePlayerName(widgets, &ClientData.Play->Name)) - return; - StartGame(); - gtk_widget_destroy(widgets->dialog); -} - -static void CloseNewGameDia(GtkWidget *widget, - struct StartGameStruct *widgets) -{ -#ifdef NETWORKING - /* Terminate any existing connection attempts */ - if (ClientData.Play->NetBuf.status != NBS_CONNECTED) { - ShutdownNetworkBuffer(&ClientData.Play->NetBuf); - } - if (widgets->MetaConn) { - CloseHttpConnection(widgets->MetaConn); - widgets->MetaConn = NULL; - } - ClearServerList(&widgets->NewMetaList); -#endif -} - -void NewGameDialog(void) -{ - GtkWidget *vbox, *vbox2, *hbox, *label, *entry, *notebook; - GtkWidget *frame, *button, *dialog; - GtkAccelGroup *accel_group; - static struct StartGameStruct widgets; - guint AccelKey; - -#ifdef NETWORKING - GtkWidget *clist, *scrollwin, *table, *hbbox; - gchar *server_titles[5], *ServerEntry, *text; - gboolean UpdateMeta = FALSE; - - /* Column titles of metaserver information */ - server_titles[0] = _("Server"); - server_titles[1] = _("Port"); - server_titles[2] = _("Version"); - server_titles[3] = _("Players"); - server_titles[4] = _("Comment"); - - widgets.MetaConn = NULL; - widgets.NewMetaList = NULL; - -#endif /* NETWORKING */ - - widgets.dialog = dialog = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_signal_connect(GTK_OBJECT(dialog), "destroy", - GTK_SIGNAL_FUNC(CloseNewGameDia), (gpointer)&widgets); - - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); -#ifdef NETWORKING - gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300); -#endif - accel_group = gtk_accel_group_new(); - - /* Title of 'New Game' dialog */ - gtk_window_set_title(GTK_WINDOW(widgets.dialog), _("New Game")); - gtk_container_set_border_width(GTK_CONTAINER(widgets.dialog), 7); - gtk_window_add_accel_group(GTK_WINDOW(widgets.dialog), accel_group); - - vbox = gtk_vbox_new(FALSE, 7); - hbox = gtk_hbox_new(FALSE, 7); - - label = gtk_label_new(""); - - AccelKey = gtk_label_parse_uline(GTK_LABEL(label), - /* Prompt for player's name in 'New - * Game' dialog */ - _("Hey dude, what's your _name?")); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - - entry = widgets.name = gtk_entry_new(); - gtk_widget_add_accelerator(entry, "grab-focus", accel_group, AccelKey, 0, - GTK_ACCEL_VISIBLE | GTK_ACCEL_SIGNAL_VISIBLE); - gtk_entry_set_text(GTK_ENTRY(entry), GetPlayerName(ClientData.Play)); - gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - notebook = gtk_notebook_new(); - -#ifdef NETWORKING - frame = gtk_frame_new(_("Server")); - gtk_container_set_border_width(GTK_CONTAINER(frame), 4); - vbox2 = gtk_vbox_new(FALSE, 7); - gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); - table = gtk_table_new(2, 2, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(table), 4); - gtk_table_set_col_spacings(GTK_TABLE(table), 4); - - /* Prompt for hostname to connect to in GTK+ new game dialog */ - label = gtk_label_new(_("Host name")); - - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, - GTK_SHRINK, GTK_SHRINK, 0, 0); - entry = widgets.hostname = gtk_entry_new(); - - ServerEntry = "localhost"; - if (g_strcasecmp(ServerName, SN_META) == 0) { - NewGameType = 2; - UpdateMeta = TRUE; - } else if (g_strcasecmp(ServerName, SN_PROMPT) == 0) - NewGameType = 0; - else if (g_strcasecmp(ServerName, SN_SINGLE) == 0) - NewGameType = 1; - else - ServerEntry = ServerName; - - gtk_entry_set_text(GTK_ENTRY(entry), ServerEntry); - gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); - label = gtk_label_new(_("Port")); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, - GTK_SHRINK, GTK_SHRINK, 0, 0); - entry = widgets.port = gtk_entry_new(); - text = g_strdup_printf("%d", Port); - gtk_entry_set_text(GTK_ENTRY(entry), text); - g_free(text); - gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); - - gtk_box_pack_start(GTK_BOX(vbox2), table, FALSE, FALSE, 0); - - button = gtk_button_new_with_label(""); - /* Button to connect to a named dopewars server */ - SetAccelerator(button, _("_Connect"), button, "clicked", accel_group); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(ConnectToServer), (gpointer)&widgets); - gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(frame), vbox2); - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); - gtk_widget_grab_default(button); - - label = gtk_label_new(_("Server")); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); -#endif /* NETWORKING */ - - /* Title of 'New Game' dialog notebook tab for single-player mode */ - frame = gtk_frame_new(_("Single player")); - gtk_container_set_border_width(GTK_CONTAINER(frame), 4); - vbox2 = gtk_vbox_new(FALSE, 7); - gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); - widgets.antique = gtk_check_button_new_with_label(""); - - /* Checkbox to activate 'antique mode' in single-player games */ - SetAccelerator(widgets.antique, _("_Antique mode"), widgets.antique, - "clicked", accel_group); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widgets.antique), - WantAntique); - gtk_box_pack_start(GTK_BOX(vbox2), widgets.antique, FALSE, FALSE, 0); - button = gtk_button_new_with_label(""); - - /* Button to start a new single-player (standalone, non-network) game */ - SetAccelerator(button, _("_Start single-player game"), button, - "clicked", accel_group); - - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(StartSinglePlayer), - (gpointer)&widgets); - gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(frame), vbox2); - label = gtk_label_new(_("Single player")); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); - -#ifdef NETWORKING - /* Title of Metaserver frame in New Game dialog */ - frame = gtk_frame_new(_("Metaserver")); - gtk_container_set_border_width(GTK_CONTAINER(frame), 4); - - vbox2 = gtk_vbox_new(FALSE, 7); - gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); - - clist = widgets.metaserv = - gtk_scrolled_clist_new_with_titles(5, server_titles, &scrollwin); - gtk_clist_column_titles_passive(GTK_CLIST(clist)); - gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE); - gtk_clist_set_column_width(GTK_CLIST(clist), 0, 130); - gtk_clist_set_column_width(GTK_CLIST(clist), 1, 35); - - gtk_box_pack_start(GTK_BOX(vbox2), scrollwin, TRUE, TRUE, 0); - - hbbox = gtk_hbutton_box_new(); - button = gtk_button_new_with_label(""); - - /* Button to update metaserver information */ - SetAccelerator(button, _("_Update"), button, "clicked", accel_group); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(UpdateMetaServerList), - (gpointer)&widgets); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - button = gtk_button_new_with_label(""); - SetAccelerator(button, _("_Connect"), button, "clicked", accel_group); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(MetaServerConnect), - (gpointer)&widgets); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox2), hbbox, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(frame), vbox2); - - label = gtk_label_new(_("Metaserver")); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); -#endif /* NETWORKING */ - - gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); - - /* Caption of status label in New Game dialog before anything has - * happened */ - label = widgets.status = gtk_label_new(""); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(widgets.dialog), vbox); - - gtk_widget_grab_focus(widgets.name); -#ifdef NETWORKING - if (UpdateMeta) { - UpdateMetaServerList(NULL, &widgets); - } else { - FillMetaServerList(&widgets, FALSE); - } -#endif - - SetStartGameStatus(&widgets, NULL); - gtk_widget_show_all(widgets.dialog); - gtk_notebook_set_page(GTK_NOTEBOOK(notebook), NewGameType); -} - -static void SendDoneMessage(GtkWidget *widget, gpointer data) -{ - SendClientMessage(ClientData.Play, C_NONE, C_DONE, NULL, NULL); -} - -static void TransferPayAll(GtkWidget *widget, GtkWidget *dialog) -{ - gchar *text; - - text = pricetostr(ClientData.Play->Debt); - SendClientMessage(ClientData.Play, C_NONE, C_PAYLOAN, NULL, text); - g_free(text); - gtk_widget_destroy(dialog); -} - -static void TransferOK(GtkWidget *widget, GtkWidget *dialog) -{ - gpointer Debt; - GtkWidget *deposit, *entry; - gchar *text, *title; - price_t money; - gboolean withdraw = FALSE; - - Debt = gtk_object_get_data(GTK_OBJECT(dialog), "debt"); - entry = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(dialog), "entry")); - text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); - money = strtoprice(text); - g_free(text); - - if (Debt) { - /* Title of loan shark dialog - (%Tde="The Loan Shark" by default) */ - title = dpg_strdup_printf(_("%/LoanShark window title/%Tde"), - Names.LoanSharkName); - if (money > ClientData.Play->Debt) - money = ClientData.Play->Debt; - } else { - /* Title of bank dialog - (%Tde="The Bank" by default) */ - title = dpg_strdup_printf(_("%/BankName window title/%Tde"), - Names.BankName); - deposit = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(dialog), "deposit")); - if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(deposit))) { - withdraw = TRUE; - } - } - - if (money < 0) { - GtkMessageBox(dialog, _("You must enter a positive amount of money!"), - title, MB_OK); - } else if (!Debt && withdraw && money > ClientData.Play->Bank) { - GtkMessageBox(dialog, _("There isn't that much money available..."), - title, MB_OK); - } else if (!withdraw && money > ClientData.Play->Cash) { - GtkMessageBox(dialog, _("You don't have that much money!"), - title, MB_OK); - } else { - text = pricetostr(withdraw ? -money : money); - SendClientMessage(ClientData.Play, C_NONE, - Debt ? C_PAYLOAN : C_DEPOSIT, NULL, text); - g_free(text); - gtk_widget_destroy(dialog); - } - g_free(title); -} - -void TransferDialog(gboolean Debt) -{ - GtkWidget *dialog, *button, *label, *radio, *table, *vbox; - GtkWidget *hbbox, *hsep, *entry; - GSList *group; - GString *text; - - text = g_string_new(""); - - dialog = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_signal_connect(GTK_OBJECT(dialog), "destroy", - GTK_SIGNAL_FUNC(SendDoneMessage), NULL); - if (Debt) { - /* Title of loan shark dialog - (%Tde="The Loan Shark" by default) */ - dpg_string_sprintf(text, _("%/LoanShark window title/%Tde"), - Names.LoanSharkName); - } else { - /* Title of bank dialog - (%Tde="The Bank" by default) */ - dpg_string_sprintf(text, _("%/BankName window title/%Tde"), - Names.BankName); - } - gtk_window_set_title(GTK_WINDOW(dialog), text->str); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); - - vbox = gtk_vbox_new(FALSE, 7); - table = gtk_table_new(4, 3, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(table), 4); - gtk_table_set_col_spacings(GTK_TABLE(table), 4); - - /* Display of player's cash in bank or loan shark dialog */ - dpg_string_sprintf(text, _("Cash: %P"), ClientData.Play->Cash); - label = gtk_label_new(text->str); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 0, 1); - - if (Debt) { - /* Display of player's debt in loan shark dialog */ - dpg_string_sprintf(text, _("Debt: %P"), ClientData.Play->Debt); - } else { - /* Display of player's bank balance in bank dialog */ - dpg_string_sprintf(text, _("Bank: %P"), ClientData.Play->Bank); - } - label = gtk_label_new(text->str); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 1, 2); - - gtk_object_set_data(GTK_OBJECT(dialog), "debt", GINT_TO_POINTER(Debt)); - if (Debt) { - /* Prompt for paying back a loan */ - label = gtk_label_new(_("Pay back:")); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 4); - } else { - /* Radio button selected if you want to pay money into the bank */ - radio = gtk_radio_button_new_with_label(NULL, _("Deposit")); - gtk_object_set_data(GTK_OBJECT(dialog), "deposit", radio); - group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio)); - gtk_table_attach_defaults(GTK_TABLE(table), radio, 0, 1, 2, 3); - - /* Radio button selected if you want to withdraw money from the bank */ - radio = gtk_radio_button_new_with_label(group, _("Withdraw")); - gtk_table_attach_defaults(GTK_TABLE(table), radio, 0, 1, 3, 4); - } - label = gtk_label_new(Currency.Symbol); - entry = gtk_entry_new(); - gtk_entry_set_text(GTK_ENTRY(entry), "0"); - gtk_object_set_data(GTK_OBJECT(dialog), "entry", entry); - gtk_signal_connect(GTK_OBJECT(entry), "activate", - GTK_SIGNAL_FUNC(TransferOK), dialog); - - if (Currency.Prefix) { - gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 4); - gtk_table_attach_defaults(GTK_TABLE(table), entry, 2, 3, 2, 4); - } else { - gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 2, 4); - gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 2, 4); - } - - gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - hbbox = gtk_hbutton_box_new(); - button = gtk_button_new_with_label(_("OK")); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(TransferOK), dialog); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - if (Debt && ClientData.Play->Cash >= ClientData.Play->Debt) { - /* Button to pay back the entire loan/debt */ - button = gtk_button_new_with_label(_("Pay all")); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(TransferPayAll), dialog); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - } - button = gtk_button_new_with_label(_("Cancel")); - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)dialog); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(dialog), vbox); - - gtk_widget_show_all(dialog); - - g_string_free(text, TRUE); -} - -void ListPlayers(GtkWidget *widget, gpointer data) -{ - GtkWidget *dialog, *clist, *button, *vbox, *hsep; - - if (IsShowingPlayerList) - return; - dialog = gtk_window_new(GTK_WINDOW_DIALOG); - - /* Title of player list dialog */ - gtk_window_set_title(GTK_WINDOW(dialog), _("Player List")); - - gtk_window_set_default_size(GTK_WINDOW(dialog), 200, 180); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); - - IsShowingPlayerList = TRUE; - gtk_window_set_modal(GTK_WINDOW(dialog), FALSE); - gtk_object_set_data(GTK_OBJECT(dialog), "IsShowing", - (gpointer)&IsShowingPlayerList); - gtk_signal_connect(GTK_OBJECT(dialog), "destroy", - GTK_SIGNAL_FUNC(DestroyShowing), NULL); - - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); - - vbox = gtk_vbox_new(FALSE, 7); - - clist = ClientData.PlayerList = CreatePlayerList(); - UpdatePlayerList(clist, FALSE); - gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - button = gtk_button_new_with_label(_("OK")); - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)dialog); - gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(dialog), vbox); - gtk_widget_show_all(dialog); -} - -struct TalkStruct { - GtkWidget *dialog, *clist, *entry, *checkbutton; -}; - -static void TalkSend(GtkWidget *widget, struct TalkStruct *TalkData) -{ - gboolean AllPlayers; - gchar *text; - GString *msg; - GList *selection; - gint row; - Player *Play; - - AllPlayers = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON - (TalkData->checkbutton)); - text = gtk_editable_get_chars(GTK_EDITABLE(TalkData->entry), 0, -1); - gtk_editable_delete_text(GTK_EDITABLE(TalkData->entry), 0, -1); - if (!text) - return; - - msg = g_string_new(""); - - if (AllPlayers) { - SendClientMessage(ClientData.Play, C_NONE, C_MSG, NULL, text); - g_string_sprintf(msg, "%s: %s", GetPlayerName(ClientData.Play), text); - PrintMessage(msg->str); - } else { - for (selection = GTK_CLIST(TalkData->clist)->selection; selection; - selection = g_list_next(selection)) { - row = GPOINTER_TO_INT(selection->data); - Play = - (Player *)gtk_clist_get_row_data(GTK_CLIST(TalkData->clist), - row); - if (Play) { - SendClientMessage(ClientData.Play, C_NONE, C_MSGTO, Play, text); - g_string_sprintf(msg, "%s->%s: %s", GetPlayerName(ClientData.Play), - GetPlayerName(Play), text); - PrintMessage(msg->str); - } - } - } - g_free(text); - g_string_free(msg, TRUE); -} - -void TalkToAll(GtkWidget *widget, gpointer data) -{ - TalkDialog(TRUE); -} - -void TalkToPlayers(GtkWidget *widget, gpointer data) -{ - TalkDialog(FALSE); -} - -void TalkDialog(gboolean TalkToAll) -{ - GtkWidget *dialog, *clist, *button, *entry, *label, *vbox, *hsep, - *checkbutton, *hbbox; - static struct TalkStruct TalkData; - - if (IsShowingTalkList) - return; - dialog = TalkData.dialog = gtk_window_new(GTK_WINDOW_DIALOG); - - /* Title of talk dialog */ - gtk_window_set_title(GTK_WINDOW(dialog), _("Talk to player(s)")); - - gtk_window_set_default_size(GTK_WINDOW(dialog), 200, 190); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); - - IsShowingTalkList = TRUE; - gtk_window_set_modal(GTK_WINDOW(dialog), FALSE); - gtk_object_set_data(GTK_OBJECT(dialog), "IsShowing", - (gpointer)&IsShowingTalkList); - gtk_signal_connect(GTK_OBJECT(dialog), "destroy", - GTK_SIGNAL_FUNC(DestroyShowing), NULL); - - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); - - vbox = gtk_vbox_new(FALSE, 7); - - clist = TalkData.clist = ClientData.TalkList = CreatePlayerList(); - UpdatePlayerList(clist, FALSE); - gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE); - gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0); - - checkbutton = TalkData.checkbutton = - /* Checkbutton set if you want to talk to all players */ - gtk_check_button_new_with_label(_("Talk to all players")); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), TalkToAll); - gtk_box_pack_start(GTK_BOX(vbox), checkbutton, FALSE, FALSE, 0); - - /* Prompt for you to enter the message to be sent to other players */ - label = gtk_label_new(_("Message:-")); - - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - entry = TalkData.entry = gtk_entry_new(); - gtk_signal_connect(GTK_OBJECT(entry), "activate", - GTK_SIGNAL_FUNC(TalkSend), (gpointer)&TalkData); - gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - hbbox = gtk_hbutton_box_new(); - - /* Button to send a message to other players */ - button = gtk_button_new_with_label(_("Send")); - - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(TalkSend), (gpointer)&TalkData); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - button = gtk_button_new_with_label(_("Close")); - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)dialog); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(dialog), vbox); - gtk_widget_show_all(dialog); -} - -GtkWidget *CreatePlayerList(void) -{ - GtkWidget *clist; - gchar *text[1]; - - text[0] = "Name"; - clist = gtk_clist_new_with_titles(1, text); - gtk_clist_column_titles_passive(GTK_CLIST(clist)); - gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE); - return clist; -} - -void UpdatePlayerList(GtkWidget *clist, gboolean IncludeSelf) -{ - GSList *list; - gchar *text[1]; - gint row; - Player *Play; - - gtk_clist_freeze(GTK_CLIST(clist)); - gtk_clist_clear(GTK_CLIST(clist)); - for (list = FirstClient; list; list = g_slist_next(list)) { - Play = (Player *)list->data; - if (IncludeSelf || Play != ClientData.Play) { - text[0] = GetPlayerName(Play); - row = gtk_clist_append(GTK_CLIST(clist), text); - gtk_clist_set_row_data(GTK_CLIST(clist), row, Play); - } - } - gtk_clist_thaw(GTK_CLIST(clist)); -} - -static void ErrandOK(GtkWidget *widget, GtkWidget *clist) -{ - GList *selection; - Player *Play; - gint row; - GtkWidget *dialog; - gint ErrandType; - - dialog = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), "dialog")); - ErrandType = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(widget), - "errandtype")); - selection = GTK_CLIST(clist)->selection; - if (selection) { - row = GPOINTER_TO_INT(selection->data); - Play = (Player *)gtk_clist_get_row_data(GTK_CLIST(clist), row); - if (ErrandType == ET_SPY) { - SendClientMessage(ClientData.Play, C_NONE, C_SPYON, Play, NULL); - } else { - SendClientMessage(ClientData.Play, C_NONE, C_TIPOFF, Play, NULL); - } - gtk_widget_destroy(dialog); - } -} - -void SpyOnPlayer(GtkWidget *widget, gpointer data) -{ - ErrandDialog(ET_SPY); -} - -void TipOff(GtkWidget *widget, gpointer data) -{ - ErrandDialog(ET_TIPOFF); -} - -void ErrandDialog(gint ErrandType) -{ - GtkWidget *dialog, *clist, *button, *vbox, *hbbox, *hsep, *label; - gchar *text; - - dialog = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); - - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(dialog), - GTK_WINDOW(ClientData.window)); - - vbox = gtk_vbox_new(FALSE, 7); - - if (ErrandType == ET_SPY) { - /* Title of dialog to select a player to spy on */ - gtk_window_set_title(GTK_WINDOW(dialog), _("Spy On Player")); - - /* Informative text for "spy on player" dialog. (%tde = "bitch", - * "bitch", "guns", "drugs", respectively, by default) */ - text = dpg_strdup_printf(_("Please choose the player to spy on. " - "Your %tde will\nthen offer his " - "services to the player, and if " - "successful,\nyou will be able to " - "view the player's stats with the\n" - "\"Get spy reports\" menu. Remember " - "that the %tde will leave\nyou, so " - "any %tde or %tde that he's " - "carrying may be lost!"), Names.Bitch, - Names.Bitch, Names.Guns, Names.Drugs); - label = gtk_label_new(text); - g_free(text); - } else { - - /* Title of dialog to select a player to tip the cops off to */ - gtk_window_set_title(GTK_WINDOW(dialog), _("Tip Off The Cops")); - - /* Informative text for "tip off cops" dialog. (%tde = "bitch", - * "bitch", "guns", "drugs", respectively, by default) */ - text = dpg_strdup_printf(_("Please choose the player to tip off " - "the cops to. Your %tde will\nhelp " - "the cops to attack that player, " - "and then report back to you\non " - "the encounter. Remember that the " - "%tde will leave you temporarily,\n" - "so any %tde or %tde that he's " - "carrying may be lost!"), Names.Bitch, - Names.Bitch, Names.Guns, Names.Drugs); - label = gtk_label_new(text); - g_free(text); - } - - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - clist = ClientData.PlayerList = CreatePlayerList(); - UpdatePlayerList(clist, FALSE); - gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - hbbox = gtk_hbutton_box_new(); - button = gtk_button_new_with_label(_("OK")); - gtk_object_set_data(GTK_OBJECT(button), "dialog", dialog); - gtk_object_set_data(GTK_OBJECT(button), "errandtype", - GINT_TO_POINTER(ErrandType)); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(ErrandOK), (gpointer)clist); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - button = gtk_button_new_with_label(_("Cancel")); - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)dialog); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(dialog), vbox); - gtk_widget_show_all(dialog); -} - -void SackBitch(GtkWidget *widget, gpointer data) -{ - char *title, *text; - - /* Cannot sack bitches if you don't have any! */ - if (ClientData.Play->Bitches.Carried <= 0) - return; - - /* Title of dialog to sack a bitch (%Tde = "Bitch" by default) */ - title = dpg_strdup_printf(_("%/Sack Bitch dialog title/Sack %Tde"), - Names.Bitch); - - /* Confirmation message for sacking a bitch. (%tde = "guns", "drugs", - * "bitch", respectively, by default) */ - text = dpg_strdup_printf(_("Are you sure? (Any %tde or %tde carried\n" - "by this %tde may be lost!)"), Names.Guns, - Names.Drugs, Names.Bitch); - - if (GtkMessageBox(ClientData.window, text, title, MB_YESNO) == IDYES) { - ClientData.Play->Bitches.Carried--; - UpdateMenus(); - SendClientMessage(ClientData.Play, C_NONE, C_SACKBITCH, NULL, NULL); - } - g_free(text); - g_free(title); -} - -void CreateInventory(GtkWidget *hbox, gchar *Objects, - GtkAccelGroup *accel_group, gboolean CreateButtons, - gboolean CreateHere, struct InventoryWidgets *widgets, - GtkSignalFunc CallBack) -{ - GtkWidget *scrollwin, *clist, *vbbox, *frame[2], *button[3]; - gint i, mini; - GString *text; - gchar *titles[2][2]; - gchar *button_text[3]; - gpointer button_type[3] = { BT_BUY, BT_SELL, BT_DROP }; - - /* Column titles for display of drugs/guns carried or available for - * purchase */ - titles[0][0] = titles[1][0] = _("Name"); - titles[0][1] = _("Price"); - titles[1][1] = _("Number"); - - /* Button titles for buying/selling/dropping guns or drugs */ - button_text[0] = _("_Buy ->"); - button_text[1] = _("<- _Sell"); - button_text[2] = _("_Drop <-"); - - text = g_string_new(""); - - if (CreateHere) { - /* Title of the display of available drugs/guns (%Tde = "Guns" or - * "Drugs" by default) */ - dpg_string_sprintf(text, _("%Tde here"), Objects); - widgets->HereFrame = frame[0] = gtk_frame_new(text->str); - } - - /* Title of the display of carried drugs/guns (%Tde = "Guns" or "Drugs" - * by default) */ - dpg_string_sprintf(text, _("%Tde carried"), Objects); - - widgets->CarriedFrame = frame[1] = gtk_frame_new(text->str); - - widgets->HereList = widgets->CarriedList = NULL; - if (CreateHere) - mini = 0; - else - mini = 1; - for (i = mini; i < 2; i++) { - gtk_container_set_border_width(GTK_CONTAINER(frame[i]), 5); - - clist = gtk_scrolled_clist_new_with_titles(2, titles[i], &scrollwin); - gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE); - gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 1, TRUE); - gtk_clist_column_titles_passive(GTK_CLIST(clist)); - gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE); - gtk_clist_set_auto_sort(GTK_CLIST(clist), FALSE); - gtk_container_add(GTK_CONTAINER(frame[i]), scrollwin); - if (i == 0) - widgets->HereList = clist; - else - widgets->CarriedList = clist; - } - if (CreateHere) - gtk_box_pack_start(GTK_BOX(hbox), frame[0], TRUE, TRUE, 0); - - if (CreateButtons) { - widgets->vbbox = vbbox = gtk_vbutton_box_new(); - - for (i = 0; i < 3; i++) { - button[i] = gtk_button_new_with_label(""); - SetAccelerator(button[i], _(button_text[i]), button[i], - "clicked", accel_group); - if (CallBack) - gtk_signal_connect(GTK_OBJECT(button[i]), "clicked", - GTK_SIGNAL_FUNC(CallBack), button_type[i]); - gtk_box_pack_start(GTK_BOX(vbbox), button[i], TRUE, TRUE, 0); - } - widgets->BuyButton = button[0]; - widgets->SellButton = button[1]; - widgets->DropButton = button[2]; - gtk_box_pack_start(GTK_BOX(hbox), vbbox, FALSE, FALSE, 0); - } else - widgets->vbbox = NULL; - - gtk_box_pack_start(GTK_BOX(hbox), frame[1], TRUE, TRUE, 0); - g_string_free(text, TRUE); -} - -void DestroyShowing(GtkWidget *widget, gpointer data) -{ - gboolean *IsShowing; - - IsShowing = - (gboolean *)gtk_object_get_data(GTK_OBJECT(widget), "IsShowing"); - if (IsShowing) - *IsShowing = FALSE; -} - -static void NewNameOK(GtkWidget *widget, GtkWidget *window) -{ - GtkWidget *entry; - gchar *text; - - entry = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(window), "entry")); - text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); - if (text[0]) { - SetPlayerName(ClientData.Play, text); - SendNullClientMessage(ClientData.Play, C_NONE, C_NAME, NULL, text); - gtk_widget_destroy(window); - } - g_free(text); -} - -void NewNameDialog(void) -{ - GtkWidget *window, *button, *hsep, *vbox, *label, *entry; - - window = gtk_window_new(GTK_WINDOW_DIALOG); - - /* Title of dialog for changing a player's name */ - gtk_window_set_title(GTK_WINDOW(window), _("Change Name")); - - gtk_window_set_modal(GTK_WINDOW(window), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(window), - GTK_WINDOW(ClientData.window)); - gtk_container_set_border_width(GTK_CONTAINER(window), 7); - gtk_signal_connect(GTK_OBJECT(window), "delete_event", - GTK_SIGNAL_FUNC(DisallowDelete), NULL); - - vbox = gtk_vbox_new(FALSE, 7); - - /* Informational text to prompt the player to change his/her name */ - label = gtk_label_new(_("Unfortunately, somebody else is already " - "using \"your\" name. Please change it:-")); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - - entry = gtk_entry_new(); - gtk_object_set_data(GTK_OBJECT(window), "entry", entry); - gtk_signal_connect(GTK_OBJECT(entry), "activate", - GTK_SIGNAL_FUNC(NewNameOK), window); - gtk_entry_set_text(GTK_ENTRY(entry), GetPlayerName(ClientData.Play)); - gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - button = gtk_button_new_with_label(_("OK")); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(NewNameOK), window); - gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); - GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); - gtk_widget_grab_default(button); - - gtk_container_add(GTK_CONTAINER(window), vbox); - gtk_widget_show_all(window); -} - -gint DisallowDelete(GtkWidget *widget, GdkEvent *event, gpointer data) -{ - return (TRUE); -} - -void GunShopDialog(void) -{ - GtkWidget *window, *button, *hsep, *vbox, *hbox; - GtkAccelGroup *accel_group; - gchar *text; - - window = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_window_set_default_size(GTK_WINDOW(window), 600, 190); - gtk_signal_connect(GTK_OBJECT(window), "destroy", - GTK_SIGNAL_FUNC(SendDoneMessage), NULL); - accel_group = gtk_accel_group_new(); - gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); - - /* Title of 'gun shop' dialog in GTK+ client (%Tde="Dan's House of Guns" - * by default) */ - text = dpg_strdup_printf(_("%/GTK GunShop window title/%Tde"), - Names.GunShopName); - gtk_window_set_title(GTK_WINDOW(window), text); - g_free(text); - gtk_window_set_modal(GTK_WINDOW(window), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(window), - GTK_WINDOW(ClientData.window)); - gtk_container_set_border_width(GTK_CONTAINER(window), 7); - IsShowingGunShop = TRUE; - gtk_object_set_data(GTK_OBJECT(window), "IsShowing", - (gpointer)&IsShowingGunShop); - gtk_signal_connect(GTK_OBJECT(window), "destroy", - GTK_SIGNAL_FUNC(DestroyShowing), NULL); - - vbox = gtk_vbox_new(FALSE, 7); - - hbox = gtk_hbox_new(FALSE, 7); - CreateInventory(hbox, Names.Guns, accel_group, TRUE, TRUE, - &ClientData.Gun, DealGuns); - - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - /* Button to finish buying/selling guns in the gun shop */ - button = gtk_button_new_with_label(_("Done")); - - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)window); - gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(window), vbox); - - UpdateInventory(&ClientData.Gun, ClientData.Play->Guns, NumGun, FALSE); - gtk_widget_show_all(window); -} - -void UpdatePlayerLists(void) -{ - if (IsShowingPlayerList) - UpdatePlayerList(ClientData.PlayerList, FALSE); - if (IsShowingTalkList) - UpdatePlayerList(ClientData.TalkList, FALSE); -} - -void GetSpyReports(GtkWidget *Widget, gpointer data) -{ - SendClientMessage(ClientData.Play, C_NONE, C_CONTACTSPY, NULL, NULL); -} - -static void DestroySpyReports(GtkWidget *widget, gpointer data) -{ - SpyReportsDialog = NULL; -} - -static void CreateSpyReports(void) -{ - GtkWidget *window, *button, *vbox, *notebook; - GtkAccelGroup *accel_group; - - SpyReportsDialog = window = gtk_window_new(GTK_WINDOW_DIALOG); - accel_group = gtk_accel_group_new(); - gtk_object_set_data(GTK_OBJECT(window), "accel_group", accel_group); - gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); - - /* Title of window to display reports from spies with other players */ - gtk_window_set_title(GTK_WINDOW(window), _("Spy reports")); - - gtk_window_set_modal(GTK_WINDOW(window), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(window), - GTK_WINDOW(ClientData.window)); - gtk_container_set_border_width(GTK_CONTAINER(window), 7); - gtk_signal_connect(GTK_OBJECT(window), "destroy", - GTK_SIGNAL_FUNC(DestroySpyReports), NULL); - - vbox = gtk_vbox_new(FALSE, 5); - notebook = gtk_notebook_new(); - gtk_object_set_data(GTK_OBJECT(window), "notebook", notebook); - - gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); - - button = gtk_button_new_with_label(_("Close")); - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)window); - gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(window), vbox); - - gtk_widget_show_all(window); -} - -void DisplaySpyReports(Player *Play) -{ - GtkWidget *dialog, *notebook, *vbox, *hbox, *frame, *label, *table; - GtkAccelGroup *accel_group; - struct StatusWidgets Status; - struct InventoryWidgets SpyDrugs, SpyGuns; - - if (!SpyReportsDialog) - CreateSpyReports(); - dialog = SpyReportsDialog; - notebook = - GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(dialog), "notebook")); - accel_group = - (GtkAccelGroup - *)(gtk_object_get_data(GTK_OBJECT(dialog), "accel_group")); - vbox = gtk_vbox_new(FALSE, 5); - frame = gtk_frame_new("Stats"); - gtk_container_set_border_width(GTK_CONTAINER(frame), 4); - table = CreateStatusWidgets(&Status); - gtk_container_add(GTK_CONTAINER(frame), table); - gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); - - hbox = gtk_hbox_new(FALSE, 5); - CreateInventory(hbox, Names.Drugs, accel_group, FALSE, FALSE, &SpyDrugs, - NULL); - CreateInventory(hbox, Names.Guns, accel_group, FALSE, FALSE, &SpyGuns, - NULL); - - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); - label = gtk_label_new(GetPlayerName(Play)); - - DisplayStats(Play, &Status); - UpdateInventory(&SpyDrugs, Play->Drugs, NumDrug, TRUE); - UpdateInventory(&SpyGuns, Play->Guns, NumGun, FALSE); - - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label); - - gtk_widget_show_all(notebook); -} - -#ifdef NETWORKING -static void OKAuthDialog(GtkWidget *widget, GtkWidget *window) -{ - gtk_object_set_data(GTK_OBJECT(window), "authok", GINT_TO_POINTER(TRUE)); - gtk_widget_destroy(window); -} - -static void DestroyAuthDialog(GtkWidget *window, gpointer data) -{ - GtkWidget *userentry, *passwdentry; - gchar *username = NULL, *password = NULL; - gpointer proxy, authok; - HttpConnection *conn; - - authok = gtk_object_get_data(GTK_OBJECT(window), "authok"); - proxy = gtk_object_get_data(GTK_OBJECT(window), "proxy"); - userentry = - (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window), "username"); - passwdentry = - (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window), "password"); - conn = - (HttpConnection *)gtk_object_get_data(GTK_OBJECT(window), - "httpconn"); - g_assert(userentry && passwdentry && conn); - - if (authok) { - username = gtk_editable_get_chars(GTK_EDITABLE(userentry), 0, -1); - password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry), 0, -1); - } - - SetHttpAuthentication(conn, GPOINTER_TO_INT(proxy), username, password); - - g_free(username); - g_free(password); -} - -void AuthDialog(HttpConnection *conn, gboolean proxy, gchar *realm, - gpointer data) -{ - GtkWidget *window, *button, *hsep, *vbox, *label, *entry, *table, *hbbox; - - window = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_signal_connect(GTK_OBJECT(window), "destroy", - GTK_SIGNAL_FUNC(DestroyAuthDialog), NULL); - gtk_object_set_data(GTK_OBJECT(window), "proxy", GINT_TO_POINTER(proxy)); - gtk_object_set_data(GTK_OBJECT(window), "httpconn", (gpointer)conn); - - if (proxy) { - gtk_window_set_title(GTK_WINDOW(window), - /* Title of dialog for authenticating with a - * proxy server */ - _("Proxy Authentication Required")); - } else { - /* Title of dialog for authenticating with a web server */ - gtk_window_set_title(GTK_WINDOW(window), _("Authentication Required")); - } - - gtk_window_set_modal(GTK_WINDOW(window), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(window), - GTK_WINDOW(ClientData.window)); - gtk_container_set_border_width(GTK_CONTAINER(window), 7); - - vbox = gtk_vbox_new(FALSE, 7); - - table = gtk_table_new(3, 2, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(table), 10); - gtk_table_set_col_spacings(GTK_TABLE(table), 5); - - label = gtk_label_new("Realm:"); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); - - label = gtk_label_new(realm); - gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1); - - label = gtk_label_new("User name:"); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); - - entry = gtk_entry_new(); - gtk_object_set_data(GTK_OBJECT(window), "username", (gpointer)entry); - gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 1, 2); - - label = gtk_label_new("Password:"); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3); - - entry = gtk_entry_new(); - gtk_object_set_data(GTK_OBJECT(window), "password", (gpointer)entry); - -#ifdef HAVE_FIXED_GTK - /* GTK+ versions earlier than 1.2.10 do bad things with this */ - gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); -#endif - - gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 2, 3); - - gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - hbbox = gtk_hbutton_box_new(); - - button = gtk_button_new_with_label(_("OK")); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(OKAuthDialog), (gpointer)window); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - button = gtk_button_new_with_label(_("Cancel")); - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)window); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), hbbox, TRUE, TRUE, 0); - - gtk_container_add(GTK_CONTAINER(window), vbox); - gtk_widget_show_all(window); -} - -static void OKSocksAuth(GtkWidget *widget, GtkWidget *window) -{ - gtk_object_set_data(GTK_OBJECT(window), "authok", GINT_TO_POINTER(TRUE)); - gtk_widget_destroy(window); -} - -static void DestroySocksAuth(GtkWidget *window, gpointer data) -{ - GtkWidget *userentry, *passwdentry; - gchar *username = NULL, *password = NULL; - gpointer authok, meta; - NetworkBuffer *netbuf; - - authok = gtk_object_get_data(GTK_OBJECT(window), "authok"); - meta = gtk_object_get_data(GTK_OBJECT(window), "meta"); - userentry = - (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window), "username"); - passwdentry = - (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window), "password"); - netbuf = - (NetworkBuffer *)gtk_object_get_data(GTK_OBJECT(window), "netbuf"); - - g_assert(userentry && passwdentry && netbuf); - - if (authok) { - username = gtk_editable_get_chars(GTK_EDITABLE(userentry), 0, -1); - password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry), 0, -1); - } - - SendSocks5UserPasswd(netbuf, username, password); - g_free(username); - g_free(password); -} - -static void RealSocksAuthDialog(NetworkBuffer *netbuf, gboolean meta, - gpointer data) -{ - GtkWidget *window, *button, *hsep, *vbox, *label, *entry, *table, *hbbox; - - window = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_signal_connect(GTK_OBJECT(window), "destroy", - GTK_SIGNAL_FUNC(DestroySocksAuth), NULL); - gtk_object_set_data(GTK_OBJECT(window), "netbuf", (gpointer)netbuf); - gtk_object_set_data(GTK_OBJECT(window), "meta", GINT_TO_POINTER(meta)); - - /* Title of dialog for authenticating with a SOCKS server */ - gtk_window_set_title(GTK_WINDOW(window), - _("SOCKS Authentication Required")); - - gtk_window_set_modal(GTK_WINDOW(window), TRUE); - gtk_window_set_transient_for(GTK_WINDOW(window), - GTK_WINDOW(ClientData.window)); - gtk_container_set_border_width(GTK_CONTAINER(window), 7); - - vbox = gtk_vbox_new(FALSE, 7); - - table = gtk_table_new(2, 2, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(table), 10); - gtk_table_set_col_spacings(GTK_TABLE(table), 5); - - label = gtk_label_new("User name:"); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); - - entry = gtk_entry_new(); - gtk_object_set_data(GTK_OBJECT(window), "username", (gpointer)entry); - gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 0, 1); - - label = gtk_label_new("Password:"); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); - - entry = gtk_entry_new(); - gtk_object_set_data(GTK_OBJECT(window), "password", (gpointer)entry); - -#ifdef HAVE_FIXED_GTK - /* GTK+ versions earlier than 1.2.10 do bad things with this */ - gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); -#endif - - gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 1, 2); - - gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); - - hsep = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); - - hbbox = gtk_hbutton_box_new(); - - button = gtk_button_new_with_label(_("OK")); - gtk_signal_connect(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(OKSocksAuth), (gpointer)window); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - button = gtk_button_new_with_label(_("Cancel")); - gtk_signal_connect_object(GTK_OBJECT(button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer)window); - gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), hbbox, TRUE, TRUE, 0); - - gtk_container_add(GTK_CONTAINER(window), vbox); - gtk_widget_show_all(window); -} - -void MetaSocksAuthDialog(NetworkBuffer *netbuf, gpointer data) -{ - RealSocksAuthDialog(netbuf, TRUE, data); -} - -void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data) -{ - RealSocksAuthDialog(netbuf, FALSE, data); -} - -#endif /* NETWORKING */ - -#else - -#include <glib.h> -#include "nls.h" /* We need this for the definition of '_' */ - -char GtkLoop(int *argc, char **argv[], gboolean ReturnOnFail) -{ - if (!ReturnOnFail) { - /* Error message displayed if the user tries to run the graphical - * client when none is compiled into the dopewars binary. */ - g_print(_("No graphical client available - rebuild the binary\n" - "passing the --enable-gui-client option to configure, or\n" - "use the curses client (if available) instead!\n")); - } - return FALSE; -} - -#endif /* GUI_CLIENT */ (DIR) diff --git a/src/gtk_client.h b/src/gtk_client.h t@@ -1,40 +0,0 @@ -/************************************************************************ - * gtk_client.h dopewars client using the GTK+ toolkit * - * Copyright (C) 1998-2002 Ben Webb * - * Email: ben@bellatrix.pcl.ox.ac.uk * - * WWW: http://dopewars.sourceforge.net/ * - * * - * 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 2 * - * 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, write to the Free Software * - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * - * MA 02111-1307, USA. * - ************************************************************************/ - -#ifndef __GTK_CLIENT_H__ -#define __GTK_CLIENT_H__ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "gtkport.h" - -extern GtkWidget *MainWindow; - -#ifdef CYGWIN -char GtkLoop(HINSTANCE hInstance, HINSTANCE hPrevInstance); -#else -char GtkLoop(int *argc, char **argv[], gboolean ReturnOnFail); -#endif - -#endif (DIR) diff --git a/src/gtkport/Makefile.am b/src/gtkport/Makefile.am t@@ -0,0 +1,6 @@ +noinst_LIBRARIES = libgtkport.a +libgtkport_a_SOURCES = gtkport.c gtkport.h +libgtkport_a_DEPENDENCIES = @INTLLIBS@ +INCLUDES = @GTK_CFLAGS@ -I.. -I../.. -I. +LDADD = @GTK_LIBS@ @INTLLIBS@ +DEFS = @DEFS@ -DLOCALEDIR=\"${localedir}\" (DIR) diff --git a/src/gtkport/Makefile.in b/src/gtkport/Makefile.in t@@ -0,0 +1,325 @@ +# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = ../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +DATADIRNAME = @DATADIRNAME@ +GENCAT = @GENCAT@ +GLIBC21 = @GLIBC21@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_CONFIG = @GLIB_CONFIG@ +GLIB_LIBS = @GLIB_LIBS@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_CONFIG = @GTK_CONFIG@ +GTK_LIBS = @GTK_LIBS@ +INSTOBJEXT = @INSTOBJEXT@ +INTLBISON = @INTLBISON@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ +LIBICONV = @LIBICONV@ +MAKEINFO = @MAKEINFO@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +PACKAGE = @PACKAGE@ +POFILES = @POFILES@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WNDRES = @WNDRES@ +localedir = @localedir@ + +noinst_LIBRARIES = libgtkport.a +libgtkport_a_SOURCES = gtkport.c gtkport.h +libgtkport_a_DEPENDENCIES = @INTLLIBS@ +INCLUDES = @GTK_CFLAGS@ -I.. -I../.. -I. +LDADD = @GTK_LIBS@ @INTLLIBS@ +DEFS = @DEFS@ -DLOCALEDIR=\"${localedir}\" +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libgtkport_a_LIBADD = +libgtkport_a_OBJECTS = gtkport.o +AR = ar +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +DEP_FILES = .deps/gtkport.P +SOURCES = $(libgtkport_a_SOURCES) +OBJECTS = $(libgtkport_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu src/gtkport/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libgtkport.a: $(libgtkport_a_OBJECTS) $(libgtkport_a_DEPENDENCIES) + -rm -f libgtkport.a + $(AR) cru libgtkport.a $(libgtkport_a_OBJECTS) $(libgtkport_a_LIBADD) + $(RANLIB) libgtkport.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = src/gtkport + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/gtkport/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-depend mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-depend \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-depend distclean-generic \ + clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-depend maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir mostlyclean-depend \ +distclean-depend clean-depend maintainer-clean-depend info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: (DIR) diff --git a/src/gtkport.c b/src/gtkport/gtkport.c (DIR) diff --git a/src/gtkport.h b/src/gtkport/gtkport.h (DIR) diff --git a/src/gui_client/Makefile.am b/src/gui_client/Makefile.am t@@ -0,0 +1,6 @@ +noinst_LIBRARIES = libguiclient.a +libguiclient_a_SOURCES = gtk_client.c +libguiclient_a_DEPENDENCIES = @INTLLIBS@ +INCLUDES = @GTK_CFLAGS@ -I.. -I../.. -I. +LDADD = @GTK_LIBS@ @INTLLIBS@ +DEFS = @DEFS@ -DLOCALEDIR=\"${localedir}\" (DIR) diff --git a/src/gui_client/Makefile.in b/src/gui_client/Makefile.in t@@ -0,0 +1,325 @@ +# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = ../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +DATADIRNAME = @DATADIRNAME@ +GENCAT = @GENCAT@ +GLIBC21 = @GLIBC21@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_CONFIG = @GLIB_CONFIG@ +GLIB_LIBS = @GLIB_LIBS@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_CONFIG = @GTK_CONFIG@ +GTK_LIBS = @GTK_LIBS@ +INSTOBJEXT = @INSTOBJEXT@ +INTLBISON = @INTLBISON@ +INTLLIBS = @INTLLIBS@ +INTLOBJS = @INTLOBJS@ +INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ +LIBICONV = @LIBICONV@ +MAKEINFO = @MAKEINFO@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +PACKAGE = @PACKAGE@ +POFILES = @POFILES@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WNDRES = @WNDRES@ +localedir = @localedir@ + +noinst_LIBRARIES = libguiclient.a +libguiclient_a_SOURCES = gtk_client.c +libguiclient_a_DEPENDENCIES = @INTLLIBS@ +INCLUDES = @GTK_CFLAGS@ -I.. -I../.. -I. +LDADD = @GTK_LIBS@ @INTLLIBS@ +DEFS = @DEFS@ -DLOCALEDIR=\"${localedir}\" +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libguiclient_a_LIBADD = +libguiclient_a_OBJECTS = gtk_client.o +AR = ar +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +DEP_FILES = .deps/gtk_client.P +SOURCES = $(libguiclient_a_SOURCES) +OBJECTS = $(libguiclient_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu src/gui_client/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libguiclient.a: $(libguiclient_a_OBJECTS) $(libguiclient_a_DEPENDENCIES) + -rm -f libguiclient.a + $(AR) cru libguiclient.a $(libguiclient_a_OBJECTS) $(libguiclient_a_LIBADD) + $(RANLIB) libguiclient.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = src/gui_client + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/gui_client/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-depend mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-depend \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-depend distclean-generic \ + clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-depend maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir mostlyclean-depend \ +distclean-depend clean-depend maintainer-clean-depend info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: (DIR) diff --git a/src/gui_client/gtk_client.c b/src/gui_client/gtk_client.c t@@ -0,0 +1,3910 @@ +/************************************************************************ + * gtk_client.c dopewars client using the GTK+ toolkit * + * Copyright (C) 1998-2002 Ben Webb * + * Email: ben@bellatrix.pcl.ox.ac.uk * + * WWW: http://dopewars.sourceforge.net/ * + * * + * 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 2 * + * 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, write to the Free Software * + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * + * MA 02111-1307, USA. * + ************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +#include "dopeos.h" +#include "dopewars.h" +#include "gtk_client.h" +#include "message.h" +#include "nls.h" +#include "serverside.h" +#include "tstring.h" +#include "gtkport/gtkport.h" +#include "dopewars-pill.xpm" + +#define BT_BUY (GINT_TO_POINTER(1)) +#define BT_SELL (GINT_TO_POINTER(2)) +#define BT_DROP (GINT_TO_POINTER(3)) + +#define ET_SPY 0 +#define ET_TIPOFF 1 + +/* Which notebook page to display in the New Game dialog */ +static gint NewGameType = 0; + +struct InventoryWidgets { + GtkWidget *HereList, *CarriedList; + GtkWidget *HereFrame, *CarriedFrame; + GtkWidget *BuyButton, *SellButton, *DropButton; + GtkWidget *vbbox; +}; + +struct StatusWidgets { + GtkWidget *Location, *Date, *SpaceName, *SpaceValue, *CashName; + GtkWidget *CashValue, *DebtName, *DebtValue, *BankName, *BankValue; + GtkWidget *GunsName, *GunsValue, *BitchesName, *BitchesValue; + GtkWidget *HealthName, *HealthValue; +}; + +struct ClientDataStruct { + GtkWidget *window, *messages; + Player *Play; + GtkItemFactory *Menu; + struct StatusWidgets Status; + struct InventoryWidgets Drug, Gun, InvenDrug, InvenGun; + GtkWidget *JetButton, *vbox, *PlayerList, *TalkList; + guint JetAccel; +}; + +GtkWidget *MainWindow; + +struct StartGameStruct { + GtkWidget *dialog, *name, *hostname, *port, *antique, *status, *metaserv; +#ifdef NETWORKING + HttpConnection *MetaConn; + GSList *NewMetaList; +#endif +}; + +static struct ClientDataStruct ClientData; +static gboolean InGame = FALSE; + +static GtkWidget *FightDialog = NULL, *SpyReportsDialog; +static gboolean IsShowingPlayerList = FALSE, IsShowingTalkList = FALSE; +static gboolean IsShowingInventory = FALSE, IsShowingGunShop = FALSE; + +static void display_intro(GtkWidget *widget, gpointer data); +static void QuitGame(GtkWidget *widget, gpointer data); +static void DestroyGtk(GtkWidget *widget, gpointer data); +static void NewGame(GtkWidget *widget, gpointer data); +static void ListScores(GtkWidget *widget, gpointer data); +static void ListInventory(GtkWidget *widget, gpointer data); +static void NewGameDialog(void); +static void StartGame(void); +static void EndGame(void); +static void Jet(GtkWidget *parent); +static void UpdateMenus(void); + +#ifdef NETWORKING +static void DisplayConnectStatus(struct StartGameStruct *widgets, + gboolean meta, NBStatus oldstatus, + NBSocksStatus oldsocks); +static void AuthDialog(HttpConnection *conn, gboolean proxyauth, + gchar *realm, gpointer data); +static void MetaSocksAuthDialog(NetworkBuffer *netbuf, gpointer data); +static void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data); +static void GetClientMessage(gpointer data, gint socket, + GdkInputCondition condition); +static void SocketStatus(NetworkBuffer *NetBuf, gboolean Read, + gboolean Write, gboolean CallNow); +static void MetaSocketStatus(NetworkBuffer *NetBuf, gboolean Read, + gboolean Write, gboolean CallNow); +static void FinishServerConnect(struct StartGameStruct *widgets, + gboolean ConnectOK); + +/* List of servers on the metaserver */ +static GSList *MetaList = NULL; + +#endif /* NETWORKING */ + +static void HandleClientMessage(char *buf, Player *Play); +static void PrepareHighScoreDialog(void); +static void AddScoreToDialog(char *Data); +static void CompleteHighScoreDialog(gboolean AtEnd); +static void PrintMessage(char *Data); +static void DisplayFightMessage(char *Data); +static GtkWidget *CreateStatusWidgets(struct StatusWidgets *Status); +static void DisplayStats(Player *Play, struct StatusWidgets *Status); +static void UpdateStatus(Player *Play); +static void SetJetButtonTitle(GtkAccelGroup *accel_group); +static void UpdateInventory(struct InventoryWidgets *Inven, + Inventory *Objects, int NumObjects, + gboolean AreDrugs); +static void JetButtonPressed(GtkWidget *widget, gpointer data); +static void DealDrugs(GtkWidget *widget, gpointer data); +static void DealGuns(GtkWidget *widget, gpointer data); +static void QuestionDialog(char *Data, Player *From); +static void TransferDialog(gboolean Debt); +static void ListPlayers(GtkWidget *widget, gpointer data); +static void TalkToAll(GtkWidget *widget, gpointer data); +static void TalkToPlayers(GtkWidget *widget, gpointer data); +static void TalkDialog(gboolean TalkToAll); +static GtkWidget *CreatePlayerList(void); +static void UpdatePlayerList(GtkWidget *clist, gboolean IncludeSelf); +static void TipOff(GtkWidget *widget, gpointer data); +static void SpyOnPlayer(GtkWidget *widget, gpointer data); +static void ErrandDialog(gint ErrandType); +static void SackBitch(GtkWidget *widget, gpointer data); +static void DestroyShowing(GtkWidget *widget, gpointer data); +static gint DisallowDelete(GtkWidget *widget, GdkEvent * event, + gpointer data); +static void GunShopDialog(void); +static void NewNameDialog(void); +static void UpdatePlayerLists(void); +static void CreateInventory(GtkWidget *hbox, gchar *Objects, + GtkAccelGroup *accel_group, + gboolean CreateButtons, gboolean CreateHere, + struct InventoryWidgets *widgets, + GtkSignalFunc CallBack); +static void GetSpyReports(GtkWidget *widget, gpointer data); +static void DisplaySpyReports(Player *Play); + +static GtkItemFactoryEntry menu_items[] = { + /* The names of the the menus and their items in the GTK+ client */ + {N_("/_Game"), NULL, NULL, 0, "<Branch>"}, + {N_("/Game/_New..."), "<control>N", NewGame, 0, NULL}, + {N_("/Game/_Quit..."), "<control>Q", QuitGame, 0, NULL}, + {N_("/_Talk"), NULL, NULL, 0, "<Branch>"}, + {N_("/Talk/To _All..."), NULL, TalkToAll, 0, NULL}, + {N_("/Talk/To _Player..."), NULL, TalkToPlayers, 0, NULL}, + {N_("/_List"), NULL, NULL, 0, "<Branch>"}, + {N_("/List/_Players..."), NULL, ListPlayers, 0, NULL}, + {N_("/List/_Scores..."), NULL, ListScores, 0, NULL}, + {N_("/List/_Inventory..."), NULL, ListInventory, 0, NULL}, + {N_("/_Errands"), NULL, NULL, 0, "<Branch>"}, + {N_("/Errands/_Spy..."), NULL, SpyOnPlayer, 0, NULL}, + {N_("/Errands/_Tipoff..."), NULL, TipOff, 0, NULL}, + /* N.B. "Sack Bitch" has to be recreated (and thus translated) at the + * start of each game, below, so is not marked for gettext here */ + {"/Errands/S_ack Bitch...", NULL, SackBitch, 0, NULL}, + {N_("/Errands/_Get spy reports..."), NULL, GetSpyReports, 0, NULL}, + {N_("/_Help"), NULL, NULL, 0, "<LastBranch>"}, + {N_("/Help/_About..."), "F1", display_intro, 0, NULL} +}; + +static gchar *MenuTranslate(const gchar *path, gpointer func_data) +{ + /* Translate menu items, using gettext */ + return _(path); +} + +static void LogMessage(const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ + GtkMessageBox(NULL, message, + /* Titles of the message boxes for warnings and errors */ + log_level & G_LOG_LEVEL_WARNING ? _("Warning") : + log_level & G_LOG_LEVEL_CRITICAL ? _("Error") : + _("Message"), + MB_OK | (gtk_main_level() > 0 ? MB_IMMRETURN : 0)); +} + +void QuitGame(GtkWidget *widget, gpointer data) +{ + if (!InGame || GtkMessageBox(ClientData.window, + /* Prompt in 'quit game' dialog */ + _("Abandon current game?"), + /* Title of 'quit game' dialog */ + _("Quit Game"), MB_YESNO) == IDYES) { + gtk_main_quit(); + } +} + +void DestroyGtk(GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} + +gint MainDelete(GtkWidget *widget, GdkEvent * event, gpointer data) +{ + return (InGame + && GtkMessageBox(ClientData.window, _("Abandon current game?"), + _("Quit Game"), MB_YESNO) == IDNO); +} + + +void NewGame(GtkWidget *widget, gpointer data) +{ + if (InGame) { + if (GtkMessageBox(ClientData.window, _("Abandon current game?"), + /* Title of 'stop game to start a new game' dialog */ + _("Start new game"), MB_YESNO) == IDYES) + EndGame(); + else + return; + } + + /* Save the configuration, so we can restore those elements that get + * overwritten when we connect to a dopewars server */ + BackupConfig(); + + NewGameDialog(); +} + +void ListScores(GtkWidget *widget, gpointer data) +{ + SendClientMessage(ClientData.Play, C_NONE, C_REQUESTSCORE, NULL, NULL); +} + +void ListInventory(GtkWidget *widget, gpointer data) +{ + GtkWidget *window, *button, *hsep, *vbox, *hbox; + GtkAccelGroup *accel_group; + + if (IsShowingInventory) + return; + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_default_size(GTK_WINDOW(window), 550, 120); + accel_group = gtk_accel_group_new(); + gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); + + /* Title of inventory window */ + gtk_window_set_title(GTK_WINDOW(window), _("Inventory")); + + IsShowingInventory = TRUE; + gtk_window_set_modal(GTK_WINDOW(window), FALSE); + gtk_object_set_data(GTK_OBJECT(window), "IsShowing", + (gpointer)&IsShowingInventory); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(DestroyShowing), NULL); + + gtk_window_set_transient_for(GTK_WINDOW(window), + GTK_WINDOW(ClientData.window)); + gtk_container_set_border_width(GTK_CONTAINER(window), 7); + + vbox = gtk_vbox_new(FALSE, 7); + + hbox = gtk_hbox_new(FALSE, 7); + CreateInventory(hbox, Names.Drugs, accel_group, FALSE, FALSE, + &ClientData.InvenDrug, NULL); + CreateInventory(hbox, Names.Guns, accel_group, FALSE, FALSE, + &ClientData.InvenGun, NULL); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + /* Caption of the button to close a dialog */ + button = gtk_button_new_with_label(_("Close")); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)window); + gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + + UpdateInventory(&ClientData.InvenDrug, ClientData.Play->Drugs, NumDrug, + TRUE); + UpdateInventory(&ClientData.InvenGun, ClientData.Play->Guns, NumGun, + FALSE); + + gtk_widget_show_all(window); +} + +#ifdef NETWORKING +void GetClientMessage(gpointer data, gint socket, + GdkInputCondition condition) +{ + gchar *pt; + NetworkBuffer *NetBuf; + gboolean DoneOK, datawaiting; + NBStatus status, oldstatus; + NBSocksStatus oldsocks; + + NetBuf = &ClientData.Play->NetBuf; + + oldstatus = NetBuf->status; + oldsocks = NetBuf->sockstat; + + datawaiting = + PlayerHandleNetwork(ClientData.Play, condition & GDK_INPUT_READ, + condition & GDK_INPUT_WRITE, &DoneOK); + + status = NetBuf->status; + + if (status != NBS_CONNECTED) { + /* The start game dialog isn't visible once we're connected... */ + DisplayConnectStatus((struct StartGameStruct *)data, FALSE, + oldstatus, oldsocks); + } + + if (oldstatus != NBS_CONNECTED && (status == NBS_CONNECTED || !DoneOK)) { + FinishServerConnect(data, DoneOK); + } + if (status == NBS_CONNECTED && datawaiting) { + while ((pt = GetWaitingPlayerMessage(ClientData.Play)) != NULL) { + HandleClientMessage(pt, ClientData.Play); + g_free(pt); + } + } + if (!DoneOK) { + if (status == NBS_CONNECTED) { + /* The network connection to the server was dropped unexpectedly */ + g_warning(_("Connection to server lost - switching to " + "single player mode")); + SwitchToSinglePlayer(ClientData.Play); + UpdatePlayerLists(); + UpdateMenus(); + } else { + ShutdownNetworkBuffer(&ClientData.Play->NetBuf); + } + } +} + +void SocketStatus(NetworkBuffer *NetBuf, gboolean Read, gboolean Write, + gboolean CallNow) +{ + if (NetBuf->InputTag) + gdk_input_remove(NetBuf->InputTag); + NetBuf->InputTag = 0; + if (Read || Write) { + NetBuf->InputTag = gdk_input_add(NetBuf->fd, + (Read ? GDK_INPUT_READ : 0) | + (Write ? GDK_INPUT_WRITE : 0), + GetClientMessage, + NetBuf->CallBackData); + } + if (CallNow) + GetClientMessage(NetBuf->CallBackData, NetBuf->fd, 0); +} +#endif /* NETWORKING */ + +void HandleClientMessage(char *pt, Player *Play) +{ + char *Data; + DispMode DisplayMode; + AICode AI; + MsgCode Code; + Player *From, *tmp; + gchar *text; + gboolean Handled; + GtkWidget *MenuItem; + GSList *list; + + if (ProcessMessage(pt, Play, &From, &AI, &Code, + &Data, FirstClient) == -1) { + return; + } + + Handled = + HandleGenericClientMessage(From, AI, Code, Play, Data, &DisplayMode); + switch (Code) { + case C_STARTHISCORE: + PrepareHighScoreDialog(); + break; + case C_HISCORE: + AddScoreToDialog(Data); + break; + case C_ENDHISCORE: + CompleteHighScoreDialog((strcmp(Data, "end") == 0)); + break; + case C_PRINTMESSAGE: + PrintMessage(Data); + break; + case C_FIGHTPRINT: + DisplayFightMessage(Data); + break; + case C_PUSH: + /* The server admin has asked us to leave - so warn the user, and do + * so */ + g_warning(_("You have been pushed from the server.\n" + "Switching to single player mode.")); + SwitchToSinglePlayer(Play); + UpdatePlayerLists(); + UpdateMenus(); + break; + case C_QUIT: + /* The server has sent us notice that it is shutting down */ + g_warning(_("The server has terminated.\n" + "Switching to single player mode.")); + SwitchToSinglePlayer(Play); + UpdatePlayerLists(); + UpdateMenus(); + break; + case C_NEWNAME: + NewNameDialog(); + break; + case C_BANK: + TransferDialog(FALSE); + break; + case C_LOANSHARK: + TransferDialog(TRUE); + break; + case C_GUNSHOP: + GunShopDialog(); + break; + case C_MSG: + text = g_strdup_printf("%s: %s", GetPlayerName(From), Data); + PrintMessage(text); + g_free(text); + break; + case C_MSGTO: + text = g_strdup_printf("%s->%s: %s", GetPlayerName(From), + GetPlayerName(Play), Data); + PrintMessage(text); + g_free(text); + break; + case C_JOIN: + text = g_strdup_printf(_("%s joins the game!"), Data); + PrintMessage(text); + g_free(text); + UpdatePlayerLists(); + UpdateMenus(); + break; + case C_LEAVE: + if (From != &Noone) { + text = g_strdup_printf(_("%s has left the game."), Data); + PrintMessage(text); + g_free(text); + UpdatePlayerLists(); + UpdateMenus(); + } + break; + case C_QUESTION: + QuestionDialog(Data, From == &Noone ? NULL : From); + break; + case C_SUBWAYFLASH: + DisplayFightMessage(NULL); + for (list = FirstClient; list; list = g_slist_next(list)) { + tmp = (Player *)list->data; + tmp->Flags &= ~FIGHTING; + } + /* Message displayed when the player "jets" to a new location */ + text = dpg_strdup_printf(_("Jetting to %tde"), + Location[(int)Play->IsAt].Name); + PrintMessage(text); + g_free(text); + break; + case C_ENDLIST: + MenuItem = gtk_item_factory_get_widget(ClientData.Menu, + "<main>/Errands/Sack Bitch..."); + + /* Text for the Errands/Sack Bitch menu item */ + text = dpg_strdup_printf(_("%/Sack Bitch menu item/S_ack %Tde..."), + Names.Bitch); + SetAccelerator(MenuItem, text, NULL, NULL, NULL); + g_free(text); + + MenuItem = gtk_item_factory_get_widget(ClientData.Menu, + "<main>/Errands/Spy..."); + + /* Text to update the Errands/Spy menu item with the price for spying */ + text = dpg_strdup_printf(_("_Spy (%P)"), Prices.Spy); + SetAccelerator(MenuItem, text, NULL, NULL, NULL); + g_free(text); + + /* Text to update the Errands/Tipoff menu item with the price for a + * tipoff */ + text = dpg_strdup_printf(_("_Tipoff (%P)"), Prices.Tipoff); + MenuItem = gtk_item_factory_get_widget(ClientData.Menu, + "<main>/Errands/Tipoff..."); + SetAccelerator(MenuItem, text, NULL, NULL, NULL); + g_free(text); + if (FirstClient->next) + ListPlayers(NULL, NULL); + UpdateMenus(); + break; + case C_UPDATE: + if (From == &Noone) { + ReceivePlayerData(Play, Data, Play); + UpdateStatus(Play); + } else { + ReceivePlayerData(Play, Data, From); + DisplaySpyReports(From); + } + break; + case C_DRUGHERE: + UpdateInventory(&ClientData.Drug, Play->Drugs, NumDrug, TRUE); + gtk_clist_sort(GTK_CLIST(ClientData.Drug.HereList)); + if (IsShowingInventory) { + UpdateInventory(&ClientData.InvenDrug, Play->Drugs, NumDrug, TRUE); + } + break; + default: + if (!Handled) { + g_print("Unknown network message received: %s^%c^%s^%s", + GetPlayerName(From), Code, GetPlayerName(Play), Data); + } + break; + } +} + +struct HiScoreDiaStruct { + GtkWidget *dialog, *table, *vbox; +}; +static struct HiScoreDiaStruct HiScoreDialog = { NULL, NULL, NULL }; + +/* + * Creates an empty dialog to display high scores. + */ +void PrepareHighScoreDialog(void) +{ + GtkWidget *dialog, *vbox, *hsep, *table; + + /* Make sure the server doesn't fool us into creating multiple dialogs */ + if (HiScoreDialog.dialog) + return; + + HiScoreDialog.dialog = dialog = gtk_window_new(GTK_WINDOW_DIALOG); + + /* Title of the GTK+ high score dialog */ + gtk_window_set_title(GTK_WINDOW(dialog), _("High Scores")); + + gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); + + HiScoreDialog.vbox = vbox = gtk_vbox_new(FALSE, 7); + HiScoreDialog.table = table = gtk_table_new(NUMHISCORE, 4, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 30); + + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(dialog), vbox); + gtk_widget_show_all(dialog); +} + +/* + * Adds a single high score (coded in "Data", which is the information + * received in the relevant network message) to the dialog created by + * PrepareHighScoreDialog(), above. + */ +void AddScoreToDialog(char *Data) +{ + GtkWidget *label; + char *cp; + gchar **spl1, **spl2; + int index, slen; + gboolean bold; + + if (!HiScoreDialog.dialog) + return; + + cp = Data; + index = GetNextInt(&cp, 0); + if (!cp || strlen(cp) < 3) + return; + + bold = (*cp == 'B'); /* Is this score "our" score? (Currently + * ignored) */ + + /* Step past the 'bold' character, and the initial '>' (if present) */ + cp += 2; + g_strchug(cp); + + /* Get the first word - the score */ + spl1 = g_strsplit(cp, " ", 1); + if (!spl1 || !spl1[0] || !spl1[1]) { + /* Error - the high score from the server is invalid */ + g_warning(_("Corrupt high score!")); + g_strfreev(spl1); + return; + } + label = gtk_label_new(spl1[0]); + gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); + gtk_table_attach_defaults(GTK_TABLE(HiScoreDialog.table), label, + 0, 1, index, index + 1); + gtk_widget_show(label); + + /* Remove any leading whitespace from the remainder, since g_strsplit + * will split at every space character, not at a run of them */ + g_strchug(spl1[1]); + + /* Get the second word - the date */ + spl2 = g_strsplit(spl1[1], " ", 1); + if (!spl2 || !spl2[0] || !spl2[1]) { + g_warning(_("Corrupt high score!")); + g_strfreev(spl2); + return; + } + label = gtk_label_new(spl2[0]); + gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5); + gtk_table_attach_defaults(GTK_TABLE(HiScoreDialog.table), label, + 1, 2, index, index + 1); + gtk_widget_show(label); + + /* The remainder is the name, terminated with (R.I.P.) if the player + * died, and '<' for the 'current' score */ + g_strchug(spl2[1]); + + /* Remove '<' suffix if present */ + slen = strlen(spl2[1]); + if (slen >= 1 && spl2[1][slen - 1] == '<') { + spl2[1][slen - 1] = '\0'; + } + slen--; + + /* Check for (R.I.P.) suffix, and add it to the 4th column if found */ + if (slen > 8 && spl2[1][slen - 1] == ')' && spl2[1][slen - 8] == '(') { + label = gtk_label_new(&spl2[1][slen - 8]); + gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5); + gtk_table_attach_defaults(GTK_TABLE(HiScoreDialog.table), label, + 3, 4, index, index + 1); + gtk_widget_show(label); + spl2[1][slen - 8] = '\0'; /* Remove suffix from the player name */ + } + + /* Finally, add in what's left of the player name */ + g_strchomp(spl2[1]); + label = gtk_label_new(spl2[1]); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_table_attach_defaults(GTK_TABLE(HiScoreDialog.table), label, + 2, 3, index, index + 1); + gtk_widget_show(label); + + g_strfreev(spl1); + g_strfreev(spl2); +} + +/* + * If the high scores are being displayed at the end of the game, + * this function is used to end the game when the high score dialog's + * "OK" button is pressed. + */ +static void EndHighScore(GtkWidget *widget) +{ + EndGame(); +} + +/* + * Called when all high scores have been received. Finishes off the + * high score dialog by adding an "OK" button. If the game has ended, + * then "AtEnd" is TRUE, and clicking this button will end the game. + */ +void CompleteHighScoreDialog(gboolean AtEnd) +{ + GtkWidget *OKButton, *dialog; + + dialog = HiScoreDialog.dialog; + + if (!HiScoreDialog.dialog) + return; + + /* Caption of the "OK" button in dialogs */ + OKButton = gtk_button_new_with_label(_("OK")); + gtk_signal_connect_object(GTK_OBJECT(OKButton), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)dialog); + if (AtEnd) { + InGame = FALSE; + gtk_signal_connect_object(GTK_OBJECT(dialog), "destroy", + GTK_SIGNAL_FUNC(EndHighScore), NULL); + } + gtk_box_pack_start(GTK_BOX(HiScoreDialog.vbox), OKButton, TRUE, TRUE, 0); + + GTK_WIDGET_SET_FLAGS(OKButton, GTK_CAN_DEFAULT); + gtk_widget_grab_default(OKButton); + gtk_widget_show(OKButton); + + /* OK, we're done - allow the creation of new high score dialogs */ + HiScoreDialog.dialog = NULL; +} + +/* + * Prints an information message in the display area of the GTK+ client. + * This area is used for displaying drug busts, messages from other + * players, etc. The message is passed in as the string "text". + */ +void PrintMessage(char *text) +{ + gint EditPos; + char *cr = "\n"; + GtkEditable *messages; + + messages = GTK_EDITABLE(ClientData.messages); + + gtk_text_freeze(GTK_TEXT(messages)); + g_strdelimit(text, "^", '\n'); + EditPos = gtk_text_get_length(GTK_TEXT(ClientData.messages)); + while (*text == '\n') + text++; + gtk_editable_insert_text(messages, text, strlen(text), &EditPos); + if (text[strlen(text) - 1] != '\n') { + gtk_editable_insert_text(messages, cr, strlen(cr), &EditPos); + } + gtk_text_thaw(GTK_TEXT(messages)); + gtk_editable_set_position(messages, EditPos); +} + +/* + * Called when one of the action buttons in the Fight dialog is clicked. + * "data" specifies which button (Deal Drugs/Run/Fight/Stand) was pressed. + */ +static void FightCallback(GtkWidget *widget, gpointer data) +{ + gint Answer; + Player *Play; + gchar text[4]; + GtkWidget *window; + gpointer CanRunHere = NULL; + + window = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + if (window) + CanRunHere = gtk_object_get_data(GTK_OBJECT(window), "CanRunHere"); + + Answer = GPOINTER_TO_INT(data); + Play = ClientData.Play; + switch (Answer) { + case 'D': + gtk_widget_hide(FightDialog); + break; + case 'R': + if (CanRunHere) { + SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, "R"); + } else { + Jet(FightDialog); + } + break; + case 'F': + case 'S': + text[0] = Answer; + text[1] = '\0'; + SendClientMessage(Play, C_NONE, C_FIGHTACT, NULL, text); + break; + } +} + +/* + * Adds an action button to the hbox at the base of the Fight dialog. + * The button's caption is given by "Text", and the keyboard shortcut + * (if any) is added to "accel_group". "Answer" gives the identifier + * passed to FightCallback, above. + */ +static GtkWidget *AddFightButton(gchar *Text, GtkAccelGroup *accel_group, + GtkBox *box, gint Answer) +{ + GtkWidget *button; + + button = gtk_button_new_with_label(""); + SetAccelerator(button, Text, button, "clicked", accel_group); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(FightCallback), + GINT_TO_POINTER(Answer)); + gtk_box_pack_start(box, button, TRUE, TRUE, 0); + return button; +} + +/* Data used to keep track of the widgets giving the information about a + * player/cop involved in a fight */ +struct combatant { + GtkWidget *name, *bitches, *healthprog, *healthlabel; +}; + +/* + * Creates an empty Fight dialog. Usually this only needs to be done once, + * as when the user "closes" it, it is only hidden, ready to be reshown + * later. Buttons for all actions are added here, and are hidden/shown + * as necessary. + */ +static void CreateFightDialog(void) +{ + GtkWidget *dialog, *vbox, *button, *hbox, *hbbox, *hsep, *text, *table; + GtkAccelGroup *accel_group; + GArray *combatants; + gchar *buf; + + FightDialog = dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300); + gtk_signal_connect(GTK_OBJECT(dialog), "delete_event", + GTK_SIGNAL_FUNC(DisallowDelete), NULL); + gtk_window_set_default_size(GTK_WINDOW(dialog), 240, 130); + accel_group = gtk_accel_group_new(); + gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group); + gtk_window_set_title(GTK_WINDOW(dialog), _("Fight")); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); + + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); + + vbox = gtk_vbox_new(FALSE, 7); + + table = gtk_table_new(2, 4, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + + hsep = gtk_hseparator_new(); + gtk_table_attach_defaults(GTK_TABLE(table), hsep, 0, 4, 1, 2); + gtk_widget_show_all(table); + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + gtk_object_set_data(GTK_OBJECT(dialog), "table", table); + + combatants = g_array_new(FALSE, TRUE, sizeof(struct combatant)); + g_array_set_size(combatants, 1); + gtk_object_set_data(GTK_OBJECT(dialog), "combatants", combatants); + + text = gtk_scrolled_text_new(NULL, NULL, &hbox); + gtk_widget_set_usize(text, 150, 120); + + gtk_text_set_editable(GTK_TEXT(text), FALSE); + gtk_text_set_word_wrap(GTK_TEXT(text), TRUE); + gtk_object_set_data(GTK_OBJECT(dialog), "text", text); + gtk_widget_show_all(hbox); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + gtk_widget_show(hsep); + + hbbox = gtk_hbutton_box_new(); + + /* Button for closing the "Fight" dialog and going back to dealing drugs + * (%Tde = "Drugs" by default) */ + buf = dpg_strdup_printf(_("_Deal %Tde"), Names.Drugs); + button = AddFightButton(buf, accel_group, GTK_BOX(hbbox), 'D'); + gtk_object_set_data(GTK_OBJECT(dialog), "deal", button); + g_free(buf); + + /* Button for shooting at other players in the "Fight" dialog, or for + * popping up the "Fight" dialog from the main window */ + button = AddFightButton(_("_Fight"), accel_group, GTK_BOX(hbbox), 'F'); + gtk_object_set_data(GTK_OBJECT(dialog), "fight", button); + + /* Button to stand and take it in the "Fight" dialog */ + button = AddFightButton(_("_Stand"), accel_group, GTK_BOX(hbbox), 'S'); + gtk_object_set_data(GTK_OBJECT(dialog), "stand", button); + + /* Button to run from combat in the "Fight" dialog */ + button = AddFightButton(_("_Run"), accel_group, GTK_BOX(hbbox), 'R'); + gtk_object_set_data(GTK_OBJECT(dialog), "run", button); + + gtk_widget_show(hsep); + gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + gtk_widget_show(hbbox); + gtk_widget_show(vbox); + gtk_container_add(GTK_CONTAINER(dialog), vbox); + gtk_widget_show(dialog); +} + +/* + * Updates the display of information for a player/cop in the Fight dialog. + * If the player's name (DefendName) already exists, updates the display of + * total health and number of bitches - otherwise, adds a new entry. If + * DefendBitches is -1, then the player has left. + */ +static void UpdateCombatant(gchar *DefendName, int DefendBitches, + gchar *BitchName, int DefendHealth) +{ + guint i, RowIndex; + gchar *name; + struct combatant *compt; + GArray *combatants; + GtkWidget *table; + gchar *BitchText, *HealthText; + gfloat ProgPercent; + + combatants = (GArray *)gtk_object_get_data(GTK_OBJECT(FightDialog), + "combatants"); + table = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "table")); + if (!combatants) + return; + + if (DefendName[0]) { + compt = NULL; + for (i = 1, RowIndex = 2; i < combatants->len; i++, RowIndex++) { + compt = &g_array_index(combatants, struct combatant, i); + + if (!compt || !compt->name) { + compt = NULL; + continue; + } + gtk_label_get(GTK_LABEL(compt->name), &name); + if (name && strcmp(name, DefendName) == 0) + break; + compt = NULL; + } + if (!compt) { + i = combatants->len; + g_array_set_size(combatants, i + 1); + compt = &g_array_index(combatants, struct combatant, i); + + gtk_table_resize(GTK_TABLE(table), i + 2, 4); + RowIndex = i + 1; + } + } else { + compt = &g_array_index(combatants, struct combatant, 0); + + RowIndex = 0; + } + + /* Display of number of bitches or deputies during combat + * (%tde="bitches" or "deputies" (etc.) by default) */ + BitchText = dpg_strdup_printf(_("%/Combat: Bitches/%d %tde"), + DefendBitches, BitchName); + + /* Display of health during combat */ + if (DefendBitches == -1) { + HealthText = g_strdup(_("(Left)")); + } else if (DefendHealth == 0 && DefendBitches == 0) { + HealthText = g_strdup(_("(Dead)")); + } else { + HealthText = g_strdup_printf(_("Health: %d"), DefendHealth); + } + + ProgPercent = (gfloat)DefendHealth / 100.0; + + if (compt->name) { + if (DefendName[0]) { + gtk_label_set_text(GTK_LABEL(compt->name), DefendName); + } + if (DefendBitches >= 0) { + gtk_label_set_text(GTK_LABEL(compt->bitches), BitchText); + } + gtk_label_set_text(GTK_LABEL(compt->healthlabel), HealthText); + gtk_progress_bar_update(GTK_PROGRESS_BAR(compt->healthprog), + ProgPercent); + } else { + /* Display of the current player's name during combat */ + compt->name = gtk_label_new(DefendName[0] ? DefendName : _("You")); + + gtk_table_attach_defaults(GTK_TABLE(table), compt->name, 0, 1, + RowIndex, RowIndex + 1); + compt->bitches = gtk_label_new(DefendBitches >= 0 ? BitchText : ""); + gtk_table_attach_defaults(GTK_TABLE(table), compt->bitches, 1, 2, + RowIndex, RowIndex + 1); + compt->healthprog = gtk_progress_bar_new(); + gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(compt->healthprog), + GTK_PROGRESS_LEFT_TO_RIGHT); + gtk_progress_bar_update(GTK_PROGRESS_BAR(compt->healthprog), + ProgPercent); + gtk_table_attach_defaults(GTK_TABLE(table), compt->healthprog, 2, 3, + RowIndex, RowIndex + 1); + compt->healthlabel = gtk_label_new(HealthText); + gtk_table_attach_defaults(GTK_TABLE(table), compt->healthlabel, 3, 4, + RowIndex, RowIndex + 1); + gtk_widget_show(compt->name); + gtk_widget_show(compt->bitches); + gtk_widget_show(compt->healthprog); + gtk_widget_show(compt->healthlabel); + } + + g_free(BitchText); + g_free(HealthText); +} + +/* + * Cleans up the list of all players/cops involved in a fight. + */ +static void FreeCombatants(void) +{ + GArray *combatants; + + combatants = (GArray *)gtk_object_get_data(GTK_OBJECT(FightDialog), + "combatants"); + if (!combatants) + return; + + g_array_free(combatants, TRUE); +} + +/* + * Given the network message "Data" concerning some happening during + * combat, extracts the relevant data and updates the Fight dialog, + * creating and/or showing it if necessary. + * If "Data" is NULL, then closes the dialog. If "Data" is a blank + * string, then just shows the dialog, displaying no new messages. + */ +void DisplayFightMessage(char *Data) +{ + Player *Play; + gint EditPos; + GtkAccelGroup *accel_group; + GtkWidget *Deal, *Fight, *Stand, *Run, *Text; + char cr[] = "\n"; + gchar *AttackName, *DefendName, *BitchName, *Message; + FightPoint fp; + int DefendHealth, DefendBitches, BitchesKilled, ArmPercent; + gboolean CanRunHere, Loot, CanFire; + + if (!Data) { + if (FightDialog) { + FreeCombatants(); + gtk_widget_destroy(FightDialog); + FightDialog = NULL; + } + return; + } + if (FightDialog) { + if (!GTK_WIDGET_VISIBLE(FightDialog)) + gtk_widget_show(FightDialog); + } else { + CreateFightDialog(); + } + if (!FightDialog || !Data[0]) + return; + + Deal = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "deal")); + Fight = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "fight")); + Stand = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "stand")); + Run = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "run")); + Text = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(FightDialog), "text")); + + Play = ClientData.Play; + + if (HaveAbility(Play, A_NEWFIGHT)) { + ReceiveFightMessage(Data, &AttackName, &DefendName, &DefendHealth, + &DefendBitches, &BitchName, &BitchesKilled, + &ArmPercent, &fp, &CanRunHere, &Loot, &CanFire, + &Message); + Play->Flags |= FIGHTING; + switch (fp) { + case F_HIT: + case F_ARRIVED: + case F_MISS: + UpdateCombatant(DefendName, DefendBitches, BitchName, DefendHealth); + break; + case F_LEAVE: + if (AttackName[0]) { + UpdateCombatant(AttackName, -1, BitchName, 0); + } + break; + case F_LASTLEAVE: + Play->Flags &= ~FIGHTING; + break; + default: + } + accel_group = (GtkAccelGroup *) + gtk_object_get_data(GTK_OBJECT(ClientData.window), "accel_group"); + SetJetButtonTitle(accel_group); + } else { + Message = Data; + if (Play->Flags & FIGHTING) + fp = F_MSG; + else + fp = F_LASTLEAVE; + CanFire = (Play->Flags & CANSHOOT); + CanRunHere = FALSE; + } + gtk_object_set_data(GTK_OBJECT(FightDialog), "CanRunHere", + GINT_TO_POINTER(CanRunHere)); + + g_strdelimit(Message, "^", '\n'); + if (strlen(Message) > 0) { + EditPos = gtk_text_get_length(GTK_TEXT(Text)); + gtk_editable_insert_text(GTK_EDITABLE(Text), Message, + strlen(Message), &EditPos); + gtk_editable_insert_text(GTK_EDITABLE(Text), cr, strlen(cr), &EditPos); + } + + if (!CanRunHere || fp == F_LASTLEAVE) + gtk_widget_show(Deal); + else + gtk_widget_hide(Deal); + if (CanFire && TotalGunsCarried(Play) > 0) + gtk_widget_show(Fight); + else + gtk_widget_hide(Fight); + if (CanFire && TotalGunsCarried(Play) == 0) + gtk_widget_show(Stand); + else + gtk_widget_hide(Stand); + if (fp != F_LASTLEAVE) + gtk_widget_show(Run); + else + gtk_widget_hide(Run); +} + +/* + * Updates the display of pertinent data about player "Play" (location, + * health, etc. in the status widgets given by "Status". This can point + * to the widgets at the top of the main window, or those in a Spy + * Reports dialog. + */ +void DisplayStats(Player *Play, struct StatusWidgets *Status) +{ + gchar *prstr; + GString *text; + + text = g_string_new(NULL); + + gtk_label_set_text(GTK_LABEL(Status->Location), + Location[(int)Play->IsAt].Name); + + g_string_sprintf(text, "%s%02d%s", Names.Month, Play->Turn, Names.Year); + gtk_label_set_text(GTK_LABEL(Status->Date), text->str); + + g_string_sprintf(text, "%d", Play->CoatSize); + gtk_label_set_text(GTK_LABEL(Status->SpaceValue), text->str); + + prstr = FormatPrice(Play->Cash); + gtk_label_set_text(GTK_LABEL(Status->CashValue), prstr); + g_free(prstr); + + prstr = FormatPrice(Play->Bank); + gtk_label_set_text(GTK_LABEL(Status->BankValue), prstr); + g_free(prstr); + + prstr = FormatPrice(Play->Debt); + gtk_label_set_text(GTK_LABEL(Status->DebtValue), prstr); + g_free(prstr); + + /* Display of carried guns in GTK+ client status window (%Tde="Guns" by + * default) */ + dpg_string_sprintf(text, _("%/GTK Stats: Guns/%Tde"), Names.Guns); + gtk_label_set_text(GTK_LABEL(Status->GunsName), text->str); + g_string_sprintf(text, "%d", TotalGunsCarried(Play)); + gtk_label_set_text(GTK_LABEL(Status->GunsValue), text->str); + + if (!WantAntique) { + /* Display of number of bitches in GTK+ client status window + * (%Tde="Bitches" by default) */ + dpg_string_sprintf(text, _("%/GTK Stats: Bitches/%Tde"), + Names.Bitches); + gtk_label_set_text(GTK_LABEL(Status->BitchesName), text->str); + g_string_sprintf(text, "%d", Play->Bitches.Carried); + gtk_label_set_text(GTK_LABEL(Status->BitchesValue), text->str); + } else { + gtk_label_set_text(GTK_LABEL(Status->BitchesName), NULL); + gtk_label_set_text(GTK_LABEL(Status->BitchesValue), NULL); + } + + g_string_sprintf(text, "%d", Play->Health); + gtk_label_set_text(GTK_LABEL(Status->HealthValue), text->str); + + g_string_free(text, TRUE); +} + +/* + * Updates all of the player status in response to a message from the + * server. This includes the main window display, the gun shop (if + * displayed) and the inventory (if displayed). + */ +void UpdateStatus(Player *Play) +{ + GtkAccelGroup *accel_group; + + DisplayStats(Play, &ClientData.Status); + UpdateInventory(&ClientData.Drug, ClientData.Play->Drugs, NumDrug, TRUE); + gtk_clist_sort(GTK_CLIST(ClientData.Drug.HereList)); + accel_group = (GtkAccelGroup *) + gtk_object_get_data(GTK_OBJECT(ClientData.window), "accel_group"); + SetJetButtonTitle(accel_group); + if (IsShowingGunShop) { + UpdateInventory(&ClientData.Gun, ClientData.Play->Guns, NumGun, FALSE); + } + if (IsShowingInventory) { + UpdateInventory(&ClientData.InvenDrug, ClientData.Play->Drugs, + NumDrug, TRUE); + UpdateInventory(&ClientData.InvenGun, ClientData.Play->Guns, + NumGun, FALSE); + } +} + +void UpdateInventory(struct InventoryWidgets *Inven, + Inventory *Objects, int NumObjects, gboolean AreDrugs) +{ + GtkWidget *herelist, *carrylist; + Player *Play; + gint i, row, selectrow[2]; + gpointer rowdata; + price_t price; + gchar *titles[2]; + gboolean CanBuy = FALSE, CanSell = FALSE, CanDrop = FALSE; + GList *glist[2], *selection; + GtkCList *clist[2]; + int numlist; + + Play = ClientData.Play; + herelist = Inven->HereList; + carrylist = Inven->CarriedList; + + if (herelist) + numlist = 2; + else + numlist = 1; + + /* Make lists of the current selections */ + clist[0] = GTK_CLIST(carrylist); + if (herelist) + clist[1] = GTK_CLIST(herelist); + else + clist[1] = NULL; + + for (i = 0; i < numlist; i++) { + glist[i] = NULL; + selectrow[i] = -1; + for (selection = clist[i]->selection; selection; + selection = g_list_next(selection)) { + row = GPOINTER_TO_INT(selection->data); + rowdata = gtk_clist_get_row_data(clist[i], row); + glist[i] = g_list_append(glist[i], rowdata); + } + } + + gtk_clist_freeze(GTK_CLIST(carrylist)); + gtk_clist_clear(GTK_CLIST(carrylist)); + + if (herelist) { + gtk_clist_freeze(GTK_CLIST(herelist)); + gtk_clist_clear(GTK_CLIST(herelist)); + } + + for (i = 0; i < NumObjects; i++) { + if (AreDrugs) { + titles[0] = Drug[i].Name; + price = Objects[i].Price; + } else { + titles[0] = Gun[i].Name; + price = Gun[i].Price; + } + + if (herelist && price > 0) { + CanBuy = TRUE; + titles[1] = FormatPrice(price); + row = gtk_clist_append(GTK_CLIST(herelist), titles); + g_free(titles[1]); + gtk_clist_set_row_data(GTK_CLIST(herelist), row, GINT_TO_POINTER(i)); + if (g_list_find(glist[1], GINT_TO_POINTER(i))) { + selectrow[1] = row; + gtk_clist_select_row(GTK_CLIST(herelist), row, 0); + } + } + + if (Objects[i].Carried > 0) { + if (price > 0) + CanSell = TRUE; + else + CanDrop = TRUE; + if (HaveAbility(ClientData.Play, A_DRUGVALUE) && AreDrugs) { + titles[1] = dpg_strdup_printf("%d @ %P", Objects[i].Carried, + Objects[i].TotalValue / + Objects[i].Carried); + } else { + titles[1] = g_strdup_printf("%d", Objects[i].Carried); + } + row = gtk_clist_append(GTK_CLIST(carrylist), titles); + g_free(titles[1]); + gtk_clist_set_row_data(GTK_CLIST(carrylist), row, + GINT_TO_POINTER(i)); + if (g_list_find(glist[0], GINT_TO_POINTER(i))) { + selectrow[0] = row; + gtk_clist_select_row(GTK_CLIST(carrylist), row, 0); + } + } + } + + for (i = 0; i < numlist; i++) { + if (selectrow[i] != -1 && gtk_clist_row_is_visible(clist[i], + selectrow[i]) != + GTK_VISIBILITY_FULL) { + gtk_clist_moveto(clist[i], selectrow[i], 0, 0.0, 0.0); + } + g_list_free(glist[i]); + } + + gtk_clist_thaw(GTK_CLIST(carrylist)); + if (herelist) + gtk_clist_thaw(GTK_CLIST(herelist)); + + if (Inven->vbbox) { + gtk_widget_set_sensitive(Inven->BuyButton, CanBuy); + gtk_widget_set_sensitive(Inven->SellButton, CanSell); + gtk_widget_set_sensitive(Inven->DropButton, CanDrop); + } +} + +static void JetCallback(GtkWidget *widget, gpointer data) +{ + int NewLocation; + gchar *text; + GtkWidget *JetDialog; + + JetDialog = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), "dialog")); + NewLocation = GPOINTER_TO_INT(data); + gtk_widget_destroy(JetDialog); + text = g_strdup_printf("%d", NewLocation); + SendClientMessage(ClientData.Play, C_NONE, C_REQUESTJET, NULL, text); + g_free(text); +} + +void JetButtonPressed(GtkWidget *widget, gpointer data) +{ + if (InGame) { + if (ClientData.Play->Flags & FIGHTING) { + DisplayFightMessage(NULL); + } else { + Jet(NULL); + } + } +} + +void Jet(GtkWidget *parent) +{ + GtkWidget *dialog, *table, *button, *label, *vbox; + GtkAccelGroup *accel_group; + gint boxsize, i, row, col; + gchar *name, AccelChar; + + accel_group = gtk_accel_group_new(); + + dialog = gtk_window_new(GTK_WINDOW_DIALOG); + /* Title of 'Jet' dialog */ + gtk_window_set_title(GTK_WINDOW(dialog), _("Jet to location")); + + gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); + gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(dialog), + parent ? GTK_WINDOW(parent) + : GTK_WINDOW(ClientData.window)); + + vbox = gtk_vbox_new(FALSE, 7); + + /* Prompt in 'Jet' dialog */ + label = gtk_label_new(_("Where to, dude ? ")); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + /* Generate a square box of buttons for all locations */ + boxsize = 1; + while (boxsize * boxsize < NumLocation) + boxsize++; + col = boxsize; + row = 1; + + /* Avoid creating a box with an entire row empty at the bottom */ + while (row * col < NumLocation) + row++; + + table = gtk_table_new(row, col, TRUE); + + for (i = 0; i < NumLocation; i++) { + if (i < 9) + AccelChar = '1' + i; + else if (i < 35) + AccelChar = 'A' + i - 9; + else + AccelChar = '\0'; + + row = i / boxsize; + col = i % boxsize; + if (AccelChar == '\0') { + button = gtk_button_new_with_label(Location[i].Name); + } else { + button = gtk_button_new_with_label(""); + + /* Display of locations in 'Jet' window (%tde="The Bronx" etc. by + * default) */ + name = dpg_strdup_printf(_("_%c. %tde"), AccelChar, Location[i].Name); + SetAccelerator(button, name, button, "clicked", accel_group); + /* Add keypad shortcuts as well */ + if (i < 9) { + gtk_widget_add_accelerator(button, "clicked", accel_group, + GDK_KP_1 + i, 0, + GTK_ACCEL_VISIBLE | + GTK_ACCEL_SIGNAL_VISIBLE); + } + g_free(name); + } + gtk_widget_set_sensitive(button, i != ClientData.Play->IsAt); + gtk_object_set_data(GTK_OBJECT(button), "dialog", dialog); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(JetCallback), GINT_TO_POINTER(i)); + gtk_table_attach_defaults(GTK_TABLE(table), button, col, col + 1, row, + row + 1); + } + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + + gtk_container_add(GTK_CONTAINER(dialog), vbox); + gtk_widget_show_all(dialog); +} + +struct DealDiaStruct { + GtkWidget *dialog, *cost, *carrying, *space, *afford, *amount; + gint DrugInd; + gpointer Type; +}; +static struct DealDiaStruct DealDialog; + +static void UpdateDealDialog(void) +{ + GString *text; + GtkAdjustment *spin_adj; + gint DrugInd, CanDrop, CanCarry, CanAfford, MaxDrug; + Player *Play; + + text = g_string_new(NULL); + DrugInd = DealDialog.DrugInd; + Play = ClientData.Play; + + /* Display of the current price of the selected drug in 'Deal Drugs' + * dialog */ + dpg_string_sprintf(text, _("at %P"), Play->Drugs[DrugInd].Price); + gtk_label_set_text(GTK_LABEL(DealDialog.cost), text->str); + + CanDrop = Play->Drugs[DrugInd].Carried; + + /* Display of current inventory of the selected drug in 'Deal Drugs' + * dialog (%tde="Opium" etc. by default) */ + dpg_string_sprintf(text, _("You are currently carrying %d %tde"), + CanDrop, Drug[DrugInd].Name); + gtk_label_set_text(GTK_LABEL(DealDialog.carrying), text->str); + + CanCarry = Play->CoatSize; + + /* Available space for drugs in 'Deal Drugs' dialog */ + g_string_sprintf(text, _("Available space: %d"), CanCarry); + gtk_label_set_text(GTK_LABEL(DealDialog.space), text->str); + + if (DealDialog.Type == BT_BUY) { + CanAfford = Play->Cash / Play->Drugs[DrugInd].Price; + + /* Number of the selected drug that you can afford in 'Deal Drugs' + * dialog */ + g_string_sprintf(text, _("You can afford %d"), CanAfford); + gtk_label_set_text(GTK_LABEL(DealDialog.afford), text->str); + MaxDrug = MIN(CanCarry, CanAfford); + } else + MaxDrug = CanDrop; + + spin_adj = (GtkAdjustment *)gtk_adjustment_new(MaxDrug, 1.0, MaxDrug, + 1.0, 10.0, 10.0); + gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(DealDialog.amount), + spin_adj); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(DealDialog.amount), MaxDrug); + + g_string_free(text, TRUE); +} + +static void DealSelectCallback(GtkWidget *widget, gpointer data) +{ + DealDialog.DrugInd = GPOINTER_TO_INT(data); + UpdateDealDialog(); +} + +static void DealOKCallback(GtkWidget *widget, gpointer data) +{ + GtkWidget *spinner; + gint amount; + gchar *text; + + spinner = DealDialog.amount; + + gtk_spin_button_update(GTK_SPIN_BUTTON(spinner)); + amount = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinner)); + + text = g_strdup_printf("drug^%d^%d", DealDialog.DrugInd, + data == BT_BUY ? amount : -amount); + SendClientMessage(ClientData.Play, C_NONE, C_BUYOBJECT, NULL, text); + g_free(text); + + gtk_widget_destroy(DealDialog.dialog); +} + +void DealDrugs(GtkWidget *widget, gpointer data) +{ + GtkWidget *dialog, *label, *hbox, *hbbox, *button, *spinner, *menu, + *optionmenu, *menuitem, *vbox, *hsep; + GtkAdjustment *spin_adj; + GtkAccelGroup *accel_group; + GtkWidget *clist; + gchar *Action; + GString *text; + GList *selection; + gint row; + Player *Play; + gint DrugInd, i, SelIndex, FirstInd; + gboolean DrugIndOK; + + /* Action in 'Deal Drugs' dialog - "Buy/Sell/Drop Drugs" */ + if (data == BT_BUY) + Action = _("Buy"); + else if (data == BT_SELL) + Action = _("Sell"); + else if (data == BT_DROP) + Action = _("Drop"); + else { + g_warning("Bad DealDrug type"); + return; + } + + DealDialog.Type = data; + Play = ClientData.Play; + + if (data == BT_BUY) + clist = ClientData.Drug.HereList; + else + clist = ClientData.Drug.CarriedList; + selection = GTK_CLIST(clist)->selection; + if (selection) { + row = GPOINTER_TO_INT(selection->data); + DrugInd = + GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(clist), row)); + } else + DrugInd = -1; + + DrugIndOK = FALSE; + FirstInd = -1; + for (i = 0; i < NumDrug; i++) { + if ((data == BT_DROP && Play->Drugs[i].Carried > 0 + && Play->Drugs[i].Price == 0) + || (data == BT_SELL && Play->Drugs[i].Carried > 0 + && Play->Drugs[i].Price != 0) + || (data == BT_BUY && Play->Drugs[i].Price != 0)) { + if (FirstInd == -1) + FirstInd = i; + if (DrugInd == i) + DrugIndOK = TRUE; + } + } + if (!DrugIndOK) { + if (FirstInd == -1) + return; + else + DrugInd = FirstInd; + } + + text = g_string_new(NULL); + accel_group = gtk_accel_group_new(); + dialog = DealDialog.dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_title(GTK_WINDOW(dialog), Action); + gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); + + vbox = gtk_vbox_new(FALSE, 7); + + hbox = gtk_hbox_new(FALSE, 7); + + label = gtk_label_new(Action); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + optionmenu = gtk_option_menu_new(); + menu = gtk_menu_new(); + SelIndex = -1; + for (i = 0; i < NumDrug; i++) { + if ((data == BT_DROP && Play->Drugs[i].Carried > 0 + && Play->Drugs[i].Price == 0) + || (data == BT_SELL && Play->Drugs[i].Carried > 0 + && Play->Drugs[i].Price != 0) + || (data == BT_BUY && Play->Drugs[i].Price != 0)) { + menuitem = gtk_menu_item_new_with_label(Drug[i].Name); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(DealSelectCallback), + GINT_TO_POINTER(i)); + gtk_menu_append(GTK_MENU(menu), menuitem); + if (DrugInd >= i) + SelIndex++; + } + } + gtk_menu_set_active(GTK_MENU(menu), SelIndex); + gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu), menu); + gtk_box_pack_start(GTK_BOX(hbox), optionmenu, TRUE, TRUE, 0); + + DealDialog.DrugInd = DrugInd; + + label = DealDialog.cost = gtk_label_new(NULL); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + label = DealDialog.carrying = gtk_label_new(NULL); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + label = DealDialog.space = gtk_label_new(NULL); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + if (data == BT_BUY) { + label = DealDialog.afford = gtk_label_new(NULL); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + } + hbox = gtk_hbox_new(FALSE, 7); + if (data == BT_BUY) { + /* Prompts for action in the "deal drugs" dialog */ + g_string_sprintf(text, _("Buy how many?")); + } else if (data == BT_SELL) { + g_string_sprintf(text, _("Sell how many?")); + } else { + g_string_sprintf(text, _("Drop how many?")); + } + label = gtk_label_new(text->str); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + spin_adj = (GtkAdjustment *)gtk_adjustment_new(1.0, 1.0, 2.0, + 1.0, 10.0, 10.0); + spinner = DealDialog.amount = gtk_spin_button_new(spin_adj, 1.0, 0); + gtk_signal_connect(GTK_OBJECT(spinner), "activate", + GTK_SIGNAL_FUNC(DealOKCallback), data); + gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + hbbox = gtk_hbutton_box_new(); + button = gtk_button_new_with_label(_("OK")); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(DealOKCallback), data); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + /* Caption of "Cancel" button for GTK+ client dialogs */ + button = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)dialog); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(dialog), vbox); + + g_string_free(text, TRUE); + UpdateDealDialog(); + + gtk_widget_show_all(dialog); +} + +void DealGuns(GtkWidget *widget, gpointer data) +{ + GtkWidget *clist, *dialog; + GList *selection; + gint row, GunInd; + gchar *Action, *Title; + GString *text; + + dialog = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + if (data == BT_BUY) + Action = _("Buy"); + else if (data == BT_SELL) + Action = _("Sell"); + else + Action = _("Drop"); + + if (data == BT_BUY) + clist = ClientData.Gun.HereList; + else + clist = ClientData.Gun.CarriedList; + selection = GTK_CLIST(clist)->selection; + if (selection) { + row = GPOINTER_TO_INT(selection->data); + GunInd = + GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(clist), row)); + } else + return; + + + /* Title of 'gun shop' dialog (%tde="guns" by default) "Buy/Sell/Drop + * Guns" */ + if (data == BT_BUY) + Title = dpg_strdup_printf(_("Buy %tde"), Names.Guns); + else if (data == BT_SELL) + Title = dpg_strdup_printf(_("Sell %tde"), Names.Guns); + else + Title = dpg_strdup_printf(_("Drop %tde"), Names.Guns); + + text = g_string_new(""); + + if (data != BT_BUY && TotalGunsCarried(ClientData.Play) == 0) { + dpg_string_sprintf(text, _("You don't have any %tde to sell!"), + Names.Guns); + GtkMessageBox(dialog, text->str, Title, MB_OK); + } else if (data == BT_BUY && TotalGunsCarried(ClientData.Play) >= + ClientData.Play->Bitches.Carried + 2) { + dpg_string_sprintf(text, + _("You'll need more %tde to carry any more %tde!"), + Names.Bitches, Names.Guns); + GtkMessageBox(dialog, text->str, Title, MB_OK); + } else if (data == BT_BUY + && Gun[GunInd].Space > ClientData.Play->CoatSize) { + dpg_string_sprintf(text, + _("You don't have enough space to carry that %tde!"), + Names.Gun); + GtkMessageBox(dialog, text->str, Title, MB_OK); + } else if (data == BT_BUY && Gun[GunInd].Price > ClientData.Play->Cash) { + dpg_string_sprintf(text, + _("You don't have enough cash to buy that %tde!"), + Names.Gun); + GtkMessageBox(dialog, text->str, Title, MB_OK); + } else if (data == BT_SELL && ClientData.Play->Guns[GunInd].Carried == 0) { + GtkMessageBox(dialog, _("You don't have any to sell!"), Title, MB_OK); + } else { + g_string_sprintf(text, "gun^%d^%d", GunInd, data == BT_BUY ? 1 : -1); + SendClientMessage(ClientData.Play, C_NONE, C_BUYOBJECT, NULL, + text->str); + } + g_free(Title); + g_string_free(text, TRUE); +} + +static void QuestionCallback(GtkWidget *widget, gpointer data) +{ + gint Answer; + gchar text[5]; + GtkWidget *dialog; + Player *To; + + dialog = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), "dialog")); + To = (Player *)gtk_object_get_data(GTK_OBJECT(dialog), "From"); + Answer = GPOINTER_TO_INT(data); + + text[0] = (gchar)Answer; + text[1] = '\0'; + SendClientMessage(ClientData.Play, C_NONE, C_ANSWER, To, text); + + gtk_widget_destroy(dialog); +} + +void QuestionDialog(char *Data, Player *From) +{ + GtkWidget *dialog, *label, *vbox, *hsep, *hbbox, *button; + GtkAccelGroup *accel_group; + gchar *Responses, **split, *LabelText, *trword, *underline; + + /* Button titles that correspond to the single-keypress options provided + * by the curses client (e.g. _Yes corresponds to 'Y' etc.) */ + gchar *Words[] = { N_("_Yes"), N_("_No"), N_("_Run"), + N_("_Fight"), N_("_Attack"), N_("_Evade") + }; + gint numWords = sizeof(Words) / sizeof(Words[0]); + gint i, j; + + split = g_strsplit(Data, "^", 1); + if (!split[0] || !split[1]) { + g_warning("Bad QUESTION message %s", Data); + return; + } + + g_strdelimit(split[1], "^", '\n'); + + Responses = split[0]; + LabelText = split[1]; + + dialog = gtk_window_new(GTK_WINDOW_DIALOG); + accel_group = gtk_accel_group_new(); + gtk_signal_connect(GTK_OBJECT(dialog), "delete_event", + GTK_SIGNAL_FUNC(DisallowDelete), NULL); + gtk_object_set_data(GTK_OBJECT(dialog), "From", (gpointer)From); + + /* Title of the 'ask player a question' dialog */ + gtk_window_set_title(GTK_WINDOW(dialog), _("Question")); + + gtk_window_add_accel_group(GTK_WINDOW(dialog), accel_group); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); + + vbox = gtk_vbox_new(FALSE, 7); + while (*LabelText == '\n') + LabelText++; + label = gtk_label_new(LabelText); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + hbbox = gtk_hbutton_box_new(); + + for (i = 0; i < strlen(Responses); i++) { + for (j = 0, trword = NULL; j < numWords && !trword; j++) { + underline = strchr(Words[j], '_'); + if (underline && toupper(underline[1]) == Responses[i]) { + trword = _(Words[j]); + } + } + button = gtk_button_new_with_label(""); + if (trword) { + SetAccelerator(button, trword, button, "clicked", accel_group); + } else { + trword = g_strdup_printf("_%c", Responses[i]); + SetAccelerator(button, trword, button, "clicked", accel_group); + g_free(trword); + } + gtk_object_set_data(GTK_OBJECT(button), "dialog", (gpointer)dialog); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(QuestionCallback), + GINT_TO_POINTER((gint)Responses[i])); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + } + gtk_box_pack_start(GTK_BOX(vbox), hbbox, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(dialog), vbox); + gtk_widget_show_all(dialog); + + g_strfreev(split); +} + +void StartGame(void) +{ + Player *Play = ClientData.Play; + + InitAbilities(Play); + SendAbilities(Play); + SendNullClientMessage(Play, C_NONE, C_NAME, NULL, GetPlayerName(Play)); + InGame = TRUE; + UpdateMenus(); + gtk_widget_show_all(ClientData.vbox); + UpdatePlayerLists(); +} + +void EndGame(void) +{ + DisplayFightMessage(NULL); + gtk_widget_hide_all(ClientData.vbox); + gtk_editable_delete_text(GTK_EDITABLE(ClientData.messages), 0, -1); + ShutdownNetwork(ClientData.Play); + UpdatePlayerLists(); + CleanUpServer(); + RestoreConfig(); + InGame = FALSE; + UpdateMenus(); +} + +static void ChangeDrugSort(GtkCList *clist, gint column, + gpointer user_data) +{ + if (column == 0) { + DrugSortMethod = (DrugSortMethod == DS_ATOZ ? DS_ZTOA : DS_ATOZ); + } else { + DrugSortMethod = (DrugSortMethod == DS_CHEAPFIRST ? DS_CHEAPLAST : + DS_CHEAPFIRST); + } + gtk_clist_sort(clist); +} + +static gint DrugSortFunc(GtkCList *clist, gconstpointer ptr1, + gconstpointer ptr2) +{ + int index1, index2; + price_t pricediff; + + index1 = GPOINTER_TO_INT(((const GtkCListRow *)ptr1)->data); + index2 = GPOINTER_TO_INT(((const GtkCListRow *)ptr2)->data); + if (index1 < 0 || index1 >= NumDrug || index2 < 0 || index2 >= NumDrug) + return 0; + + switch (DrugSortMethod) { + case DS_ATOZ: + return g_strcasecmp(Drug[index1].Name, Drug[index2].Name); + case DS_ZTOA: + return g_strcasecmp(Drug[index2].Name, Drug[index1].Name); + case DS_CHEAPFIRST: + pricediff = ClientData.Play->Drugs[index1].Price - + ClientData.Play->Drugs[index2].Price; + return pricediff == 0 ? 0 : pricediff < 0 ? -1 : 1; + case DS_CHEAPLAST: + pricediff = ClientData.Play->Drugs[index2].Price - + ClientData.Play->Drugs[index1].Price; + return pricediff == 0 ? 0 : pricediff < 0 ? -1 : 1; + } + return 0; +} + +void UpdateMenus(void) +{ + gboolean MultiPlayer; + gint Bitches; + + MultiPlayer = (FirstClient && FirstClient->next != NULL); + Bitches = InGame + && ClientData.Play ? ClientData.Play->Bitches.Carried : 0; + + gtk_widget_set_sensitive(gtk_item_factory_get_widget(ClientData.Menu, + "<main>/Talk"), + InGame && Network); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "<main>/List"), InGame); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "<main>/List/Players..."), + InGame && Network); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "<main>/Errands"), InGame); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "<main>/Errands/Spy..."), + InGame && MultiPlayer); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "<main>/Errands/Tipoff..."), + InGame && MultiPlayer); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, + "<main>/Errands/Sack Bitch..."), Bitches > 0); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, + "<main>/Errands/Get spy reports..."), InGame + && MultiPlayer); +} + +GtkWidget *CreateStatusWidgets(struct StatusWidgets *Status) +{ + GtkWidget *table, *label; + + table = gtk_table_new(3, 6, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 3); + + label = Status->Location = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1); + + label = Status->Date = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 4, 0, 1); + + /* Available space label in GTK+ client status display */ + label = Status->SpaceName = gtk_label_new(_("Space")); + + gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 5, 0, 1); + label = Status->SpaceValue = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 5, 6, 0, 1); + + /* Player's cash label in GTK+ client status display */ + label = Status->CashName = gtk_label_new(_("Cash")); + + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + label = Status->CashValue = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2); + + /* Player's debt label in GTK+ client status display */ + label = Status->DebtName = gtk_label_new(_("Debt")); + + gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 1, 2); + label = Status->DebtValue = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 3, 4, 1, 2); + + /* Player's bank balance label in GTK+ client status display */ + label = Status->BankName = gtk_label_new(_("Bank")); + + gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 5, 1, 2); + label = Status->BankValue = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 5, 6, 1, 2); + + label = Status->GunsName = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3); + label = Status->GunsValue = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 3); + + label = Status->BitchesName = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 2, 3); + label = Status->BitchesValue = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 3, 4, 2, 3); + + /* Player's health label in GTK+ client status display */ + label = Status->HealthName = gtk_label_new(_("Health")); + + gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 5, 2, 3); + label = Status->HealthValue = gtk_label_new(NULL); + gtk_table_attach_defaults(GTK_TABLE(table), label, 5, 6, 2, 3); + return table; +} + +void SetJetButtonTitle(GtkAccelGroup *accel_group) +{ + GtkWidget *button; + guint accel_key; + + button = ClientData.JetButton; + accel_key = ClientData.JetAccel; + + if (accel_key) { + gtk_widget_remove_accelerator(button, accel_group, accel_key, 0); + } + + ClientData.JetAccel = SetAccelerator(button, + (ClientData.Play + && ClientData.Play-> + Flags & FIGHTING) ? _("_Fight") : + /* Caption of 'Jet' button in main + * window */ + _("_Jet!"), button, "clicked", + accel_group); +} + +static void SetIcon(GtkWidget *window, gchar **xpmdata) +{ +#ifndef CYGWIN + GdkBitmap *mask; + GdkPixmap *icon; + GtkStyle *style; + + style = gtk_widget_get_style(window); + icon = gdk_pixmap_create_from_xpm_d(window->window, &mask, + &style->bg[GTK_STATE_NORMAL], + xpmdata); + gdk_window_set_icon(window->window, NULL, icon, mask); +#endif +} + +#ifdef CYGWIN +gboolean GtkLoop(HINSTANCE hInstance, HINSTANCE hPrevInstance, + gboolean ReturnOnFail) +{ +#else +gboolean GtkLoop(int *argc, char **argv[], gboolean ReturnOnFail) +{ +#endif + GtkWidget *window, *vbox, *vbox2, *hbox, *frame, *table, *menubar, *text, + *vpaned, *button, *clist; + GtkAccelGroup *accel_group; + GtkItemFactory *item_factory; + GtkAdjustment *adj; + gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); + +#ifdef CYGWIN + win32_init(hInstance, hPrevInstance, "mainicon"); +#else + gtk_set_locale(); + if (ReturnOnFail && !gtk_init_check(argc, argv)) + return FALSE; + else if (!ReturnOnFail) + gtk_init(argc, argv); +#endif + + /* Set up message handlers */ + ClientMessageHandlerPt = HandleClientMessage; + + /* Have the GLib log messages pop up in a nice dialog box */ + g_log_set_handler(NULL, + LogMask() | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING | + G_LOG_LEVEL_CRITICAL, LogMessage, NULL); + + if (!CheckHighScoreFileConfig()) + return TRUE; + + /* Create the main player */ + ClientData.Play = g_new(Player, 1); + FirstClient = AddPlayer(0, ClientData.Play, FirstClient); + + window = MainWindow = ClientData.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + /* Title of main window in GTK+ client */ + gtk_window_set_title(GTK_WINDOW(window), _("dopewars")); + gtk_window_set_default_size(GTK_WINDOW(window), 450, 390); + gtk_signal_connect(GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(MainDelete), NULL); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(DestroyGtk), NULL); + + accel_group = gtk_accel_group_new(); + gtk_object_set_data(GTK_OBJECT(window), "accel_group", accel_group); + item_factory = ClientData.Menu = gtk_item_factory_new(GTK_TYPE_MENU_BAR, + "<main>", + accel_group); + gtk_item_factory_set_translate_func(item_factory, MenuTranslate, NULL, + NULL); + + gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, + NULL); + gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); + menubar = gtk_item_factory_get_widget(item_factory, "<main>"); + + vbox2 = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox2), menubar, FALSE, FALSE, 0); + gtk_widget_show_all(menubar); + UpdateMenus(); + + vbox = ClientData.vbox = gtk_vbox_new(FALSE, 5); + frame = gtk_frame_new(_("Stats")); + + table = CreateStatusWidgets(&ClientData.Status); + + gtk_container_add(GTK_CONTAINER(frame), table); + + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); + + vpaned = gtk_vpaned_new(); + + adj = (GtkAdjustment *)gtk_adjustment_new(0.0, 0.0, 100.0, + 1.0, 10.0, 10.0); + text = ClientData.messages = gtk_scrolled_text_new(NULL, adj, &hbox); + gtk_widget_set_usize(text, 100, 80); + gtk_text_set_point(GTK_TEXT(text), 0); + gtk_text_set_editable(GTK_TEXT(text), FALSE); + gtk_text_set_word_wrap(GTK_TEXT(text), TRUE); + gtk_paned_pack1(GTK_PANED(vpaned), hbox, TRUE, TRUE); + + hbox = gtk_hbox_new(FALSE, 7); + CreateInventory(hbox, Names.Drugs, accel_group, TRUE, TRUE, + &ClientData.Drug, DealDrugs); + clist = ClientData.Drug.HereList; + gtk_clist_column_titles_active(GTK_CLIST(clist)); + gtk_clist_set_compare_func(GTK_CLIST(clist), DrugSortFunc); + gtk_signal_connect(GTK_OBJECT(clist), "click-column", + GTK_SIGNAL_FUNC(ChangeDrugSort), NULL); + + button = ClientData.JetButton = gtk_button_new_with_label(""); + ClientData.JetAccel = 0; + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(JetButtonPressed), NULL); + gtk_box_pack_start(GTK_BOX(ClientData.Drug.vbbox), button, TRUE, TRUE, 0); + SetJetButtonTitle(accel_group); + + gtk_paned_pack2(GTK_PANED(vpaned), hbox, TRUE, TRUE); + + gtk_box_pack_start(GTK_BOX(vbox), vpaned, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox2), vbox, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(window), vbox2); + + /* Just show the window, not the vbox - we'll do that when the game + * starts */ + gtk_widget_show(vbox2); + gtk_widget_show(window); + + gtk_widget_realize(window); + + SetIcon(window, dopewars_pill_xpm); + + gtk_main(); + + /* Free the main player */ + FirstClient = RemovePlayer(ClientData.Play, FirstClient); + + return TRUE; +} + +static void PackCentredURL(GtkWidget *vbox, gchar *title, gchar *target, + gchar *browser) +{ + GtkWidget *hbox, *label, *url; + + /* There must surely be a nicer way of making the URL centred - but I + * can't think of one... */ + hbox = gtk_hbox_new(FALSE, 0); + label = gtk_label_new(""); + gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); + + url = gtk_url_new(title, target, browser); + gtk_box_pack_start(GTK_BOX(hbox), url, FALSE, FALSE, 0); + + label = gtk_label_new(""); + gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); +} + +void display_intro(GtkWidget *widget, gpointer data) +{ + GtkWidget *dialog, *label, *table, *OKButton, *vbox, *hsep; + gchar *VersionStr, *docindex; + const int rows = 6, cols = 3; + int i, j; + gchar *table_data[6][3] = { + /* Credits labels in GTK+ 'about' dialog */ + {N_("Icons and graphics"), "Ocelot Mantis", NULL}, + {N_("Drug Dealing and Research"), "Dan Wolf", NULL}, + {N_("Play Testing"), "Phil Davis", "Owen Walsh"}, + {N_("Extensive Play Testing"), "Katherine Holt", + "Caroline Moore"}, + {N_("Constructive Criticism"), "Andrea Elliot-Smith", + "Pete Winn"}, + {N_("Unconstructive Criticism"), "James Matthews", NULL} + }; + + dialog = gtk_window_new(GTK_WINDOW_DIALOG); + + /* Title of GTK+ 'about' dialog */ + gtk_window_set_title(GTK_WINDOW(dialog), _("About dopewars")); + + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); + gtk_container_border_width(GTK_CONTAINER(dialog), 10); + + vbox = gtk_vbox_new(FALSE, 5); + + /* Main content of GTK+ 'about' dialog */ + label = gtk_label_new(_("Based on John E. Dell's old Drug Wars game, " + "dopewars is a simulation of an\nimaginary drug " + "market. dopewars is an All-American game which " + "features\nbuying, selling, and trying to get " + "past the cops!\n\nThe first thing you need to " + "do is pay off your debt to the Loan Shark. " + "After\nthat, your goal is to make as much " + "money as possible (and stay alive)! You\n" + "have one month of game time to make " + "your fortune.\n")); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + /* Version and copyright notice in GTK+ 'about' dialog */ + VersionStr = g_strdup_printf(_("Version %s " + "Copyright (C) 1998-2002 " + "Ben Webb ben@bellatrix.pcl.ox.ac.uk\n" + "dopewars is released under the " + "GNU General Public Licence\n"), VERSION); + label = gtk_label_new(VersionStr); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + g_free(VersionStr); + + table = gtk_table_new(rows, cols, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 3); + for (i = 0; i < rows; i++) + for (j = 0; j < cols; j++) + if (table_data[i][j]) { + if (j == 0) + label = gtk_label_new(_(table_data[i][j])); + else + label = gtk_label_new(table_data[i][j]); + gtk_table_attach_defaults(GTK_TABLE(table), label, j, j + 1, i, + i + 1); + } + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); + + /* Label at the bottom of GTK+ 'about' dialog */ + label = gtk_label_new(_("\nFor information on the command line " + "options, type dopewars -h at your\n" + "Unix prompt. This will display a help " + "screen, listing the available options.\n")); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + docindex = GetDocIndex(); + PackCentredURL(vbox, "Local HTML documentation", docindex, WebBrowser); + g_free(docindex); + + PackCentredURL(vbox, "http://dopewars.sourceforge.net/", + "http://dopewars.sourceforge.net/", WebBrowser); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + OKButton = gtk_button_new_with_label(_("OK")); + gtk_signal_connect_object(GTK_OBJECT(OKButton), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)dialog); + + gtk_box_pack_start(GTK_BOX(vbox), OKButton, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(dialog), vbox); + + GTK_WIDGET_SET_FLAGS(OKButton, GTK_CAN_DEFAULT); + gtk_widget_grab_default(OKButton); + + gtk_widget_show_all(dialog); +} + +static gboolean GetStartGamePlayerName(struct StartGameStruct *widgets, + gchar **PlayerName) +{ + g_free(*PlayerName); + *PlayerName = gtk_editable_get_chars(GTK_EDITABLE(widgets->name), 0, -1); + if (*PlayerName && (*PlayerName)[0]) + return TRUE; + else { + GtkMessageBox(widgets->dialog, + _("You can't start the game without giving a name first!"), + _("New Game"), MB_OK); + return FALSE; + } +} + +static void SetStartGameStatus(struct StartGameStruct *widgets, gchar *msg) +{ + gtk_label_set_text(GTK_LABEL(widgets->status), + msg ? msg : _("Status: Waiting for user input")); +} + +#ifdef NETWORKING +static void ConnectError(struct StartGameStruct *widgets, gboolean meta) +{ + GString *neterr; + gchar *text; + LastError *error; + + if (meta) + error = widgets->MetaConn->NetBuf.error; + else + error = ClientData.Play->NetBuf.error; + + neterr = g_string_new(""); + + if (error) { + g_string_assign_error(neterr, error); + } else { + g_string_assign(neterr, _("Connection closed by remote host")); + } + + if (meta) { + /* Error: GTK+ client could not connect to the metaserver */ + text = + g_strdup_printf(_("Status: Could not connect to metaserver (%s)"), + neterr->str); + } else { + /* Error: GTK+ client could not connect to the given dopewars server */ + text = + g_strdup_printf(_("Status: Could not connect (%s)"), neterr->str); + } + + SetStartGameStatus(widgets, text); + g_free(text); + g_string_free(neterr, TRUE); +} + +void FinishServerConnect(struct StartGameStruct *widgets, + gboolean ConnectOK) +{ + if (ConnectOK) { + Client = Network = TRUE; + gtk_widget_destroy(widgets->dialog); + StartGame(); + } else { + ConnectError(widgets, FALSE); + } +} + +static void DoConnect(struct StartGameStruct *widgets) +{ + gchar *text; + NetworkBuffer *NetBuf; + NBStatus oldstatus; + NBSocksStatus oldsocks; + + NetBuf = &ClientData.Play->NetBuf; + + /* Message displayed during the attempted connect to a dopewars server */ + text = g_strdup_printf(_("Status: Attempting to contact %s..."), + ServerName); + SetStartGameStatus(widgets, text); + g_free(text); + + /* Terminate any existing connection attempts */ + ShutdownNetworkBuffer(NetBuf); + if (widgets->MetaConn) { + CloseHttpConnection(widgets->MetaConn); + widgets->MetaConn = NULL; + } + + oldstatus = NetBuf->status; + oldsocks = NetBuf->sockstat; + if (StartNetworkBufferConnect(NetBuf, ServerName, Port)) { + DisplayConnectStatus(widgets, FALSE, oldstatus, oldsocks); + SetNetworkBufferUserPasswdFunc(NetBuf, SocksAuthDialog, NULL); + SetNetworkBufferCallBack(NetBuf, SocketStatus, (gpointer)widgets); + } else { + ConnectError(widgets, FALSE); + } +} + +static void ConnectToServer(GtkWidget *widget, + struct StartGameStruct *widgets) +{ + gchar *text; + + g_free(ServerName); + ServerName = gtk_editable_get_chars(GTK_EDITABLE(widgets->hostname), + 0, -1); + text = gtk_editable_get_chars(GTK_EDITABLE(widgets->port), 0, -1); + Port = atoi(text); + g_free(text); + + if (!GetStartGamePlayerName(widgets, &ClientData.Play->Name)) + return; + DoConnect(widgets); +} + +static void FillMetaServerList(struct StartGameStruct *widgets, + gboolean UseNewList) +{ + GtkWidget *metaserv; + ServerData *ThisServer; + gchar *titles[5]; + GSList *ListPt; + gint row; + + if (UseNewList && !widgets->NewMetaList) + return; + + metaserv = widgets->metaserv; + gtk_clist_freeze(GTK_CLIST(metaserv)); + gtk_clist_clear(GTK_CLIST(metaserv)); + + if (UseNewList) { + ClearServerList(&MetaList); + MetaList = widgets->NewMetaList; + widgets->NewMetaList = NULL; + } + + for (ListPt = MetaList; ListPt; ListPt = g_slist_next(ListPt)) { + ThisServer = (ServerData *)(ListPt->data); + titles[0] = ThisServer->Name; + titles[1] = g_strdup_printf("%d", ThisServer->Port); + titles[2] = ThisServer->Version; + if (ThisServer->CurPlayers == -1) { + /* Displayed if we don't know how many players are logged on to a + * server */ + titles[3] = _("Unknown"); + } else { + /* e.g. "5 of 20" means 5 players are logged on to a server, out of + * a maximum of 20 */ + titles[3] = g_strdup_printf(_("%d of %d"), ThisServer->CurPlayers, + ThisServer->MaxPlayers); + } + titles[4] = ThisServer->Comment; + row = gtk_clist_append(GTK_CLIST(metaserv), titles); + gtk_clist_set_row_data(GTK_CLIST(metaserv), row, (gpointer)ThisServer); + g_free(titles[1]); + if (ThisServer->CurPlayers != -1) + g_free(titles[3]); + } + gtk_clist_thaw(GTK_CLIST(metaserv)); +} + +void DisplayConnectStatus(struct StartGameStruct *widgets, gboolean meta, + NBStatus oldstatus, NBSocksStatus oldsocks) +{ + NBStatus status; + NBSocksStatus sockstat; + gchar *text; + + if (meta) { + status = widgets->MetaConn->NetBuf.status; + sockstat = widgets->MetaConn->NetBuf.sockstat; + } else { + status = ClientData.Play->NetBuf.status; + sockstat = ClientData.Play->NetBuf.sockstat; + } + if (oldstatus == status && sockstat == oldsocks) + return; + + switch (status) { + case NBS_PRECONNECT: + break; + case NBS_SOCKSCONNECT: + switch (sockstat) { + case NBSS_METHODS: + text = g_strdup_printf(_("Status: Connected to SOCKS server %s..."), + Socks.name); + SetStartGameStatus(widgets, text); + g_free(text); + break; + case NBSS_USERPASSWD: + SetStartGameStatus(widgets, + _("Status: Authenticating with SOCKS server")); + break; + case NBSS_CONNECT: + text = + g_strdup_printf(_("Status: Asking SOCKS for connect to %s..."), + meta ? MetaServer.Name : ServerName); + SetStartGameStatus(widgets, text); + g_free(text); + break; + } + break; + case NBS_CONNECTED: + if (meta) { + SetStartGameStatus(widgets, + _("Status: Obtaining server information " + "from metaserver...")); + } + break; + } +} + +static void MetaDone(struct StartGameStruct *widgets) +{ + if (IsHttpError(widgets->MetaConn)) { + ConnectError(widgets, TRUE); + } else { + SetStartGameStatus(widgets, NULL); + } + CloseHttpConnection(widgets->MetaConn); + widgets->MetaConn = NULL; + FillMetaServerList(widgets, TRUE); +} + +static void HandleMetaSock(gpointer data, gint socket, + GdkInputCondition condition) +{ + struct StartGameStruct *widgets; + gboolean DoneOK; + NBStatus oldstatus; + NBSocksStatus oldsocks; + + widgets = (struct StartGameStruct *)data; + if (!widgets->MetaConn) + return; + + oldstatus = widgets->MetaConn->NetBuf.status; + oldsocks = widgets->MetaConn->NetBuf.sockstat; + + if (NetBufHandleNetwork + (&widgets->MetaConn->NetBuf, condition & GDK_INPUT_READ, + condition & GDK_INPUT_WRITE, &DoneOK)) { + while (HandleWaitingMetaServerData + (widgets->MetaConn, &widgets->NewMetaList, &DoneOK)) { + } + } + + if (!DoneOK && HandleHttpCompletion(widgets->MetaConn)) { + MetaDone(widgets); + } else { + DisplayConnectStatus(widgets, TRUE, oldstatus, oldsocks); + } +} + +void MetaSocketStatus(NetworkBuffer *NetBuf, gboolean Read, gboolean Write, + gboolean CallNow) +{ + if (NetBuf->InputTag) + gdk_input_remove(NetBuf->InputTag); + NetBuf->InputTag = 0; + if (Read || Write) { + NetBuf->InputTag = gdk_input_add(NetBuf->fd, + (Read ? GDK_INPUT_READ : 0) | + (Write ? GDK_INPUT_WRITE : 0), + HandleMetaSock, NetBuf->CallBackData); + } + if (CallNow) + HandleMetaSock(NetBuf->CallBackData, NetBuf->fd, 0); +} + +static void UpdateMetaServerList(GtkWidget *widget, + struct StartGameStruct *widgets) +{ + GtkWidget *metaserv; + gchar *text; + + /* Terminate any existing connection attempts */ + ShutdownNetworkBuffer(&ClientData.Play->NetBuf); + if (widgets->MetaConn) { + CloseHttpConnection(widgets->MetaConn); + widgets->MetaConn = NULL; + } + + ClearServerList(&widgets->NewMetaList); + + /* Message displayed during the attempted connect to the metaserver */ + text = g_strdup_printf(_("Status: Attempting to contact %s..."), + MetaServer.Name); + SetStartGameStatus(widgets, text); + g_free(text); + + if (OpenMetaHttpConnection(&widgets->MetaConn)) { + metaserv = widgets->metaserv; + SetHttpAuthFunc(widgets->MetaConn, AuthDialog, NULL); + SetNetworkBufferUserPasswdFunc(&widgets->MetaConn->NetBuf, + MetaSocksAuthDialog, NULL); + SetNetworkBufferCallBack(&widgets->MetaConn->NetBuf, + MetaSocketStatus, (gpointer)widgets); + } else { + ConnectError(widgets, TRUE); + CloseHttpConnection(widgets->MetaConn); + widgets->MetaConn = NULL; + } +} + +static void MetaServerConnect(GtkWidget *widget, + struct StartGameStruct *widgets) +{ + GList *selection; + gint row; + GtkWidget *clist; + ServerData *ThisServer; + + clist = widgets->metaserv; + selection = GTK_CLIST(clist)->selection; + if (selection) { + row = GPOINTER_TO_INT(selection->data); + ThisServer = (ServerData *)gtk_clist_get_row_data(GTK_CLIST(clist), row); + AssignName(&ServerName, ThisServer->Name); + Port = ThisServer->Port; + + if (!GetStartGamePlayerName(widgets, &ClientData.Play->Name)) + return; + DoConnect(widgets); + } +} +#endif /* NETWORKING */ + +static void StartSinglePlayer(GtkWidget *widget, + struct StartGameStruct *widgets) +{ + WantAntique = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->antique)); + if (!GetStartGamePlayerName(widgets, &ClientData.Play->Name)) + return; + StartGame(); + gtk_widget_destroy(widgets->dialog); +} + +static void CloseNewGameDia(GtkWidget *widget, + struct StartGameStruct *widgets) +{ +#ifdef NETWORKING + /* Terminate any existing connection attempts */ + if (ClientData.Play->NetBuf.status != NBS_CONNECTED) { + ShutdownNetworkBuffer(&ClientData.Play->NetBuf); + } + if (widgets->MetaConn) { + CloseHttpConnection(widgets->MetaConn); + widgets->MetaConn = NULL; + } + ClearServerList(&widgets->NewMetaList); +#endif +} + +void NewGameDialog(void) +{ + GtkWidget *vbox, *vbox2, *hbox, *label, *entry, *notebook; + GtkWidget *frame, *button, *dialog; + GtkAccelGroup *accel_group; + static struct StartGameStruct widgets; + guint AccelKey; + +#ifdef NETWORKING + GtkWidget *clist, *scrollwin, *table, *hbbox; + gchar *server_titles[5], *ServerEntry, *text; + gboolean UpdateMeta = FALSE; + + /* Column titles of metaserver information */ + server_titles[0] = _("Server"); + server_titles[1] = _("Port"); + server_titles[2] = _("Version"); + server_titles[3] = _("Players"); + server_titles[4] = _("Comment"); + + widgets.MetaConn = NULL; + widgets.NewMetaList = NULL; + +#endif /* NETWORKING */ + + widgets.dialog = dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_signal_connect(GTK_OBJECT(dialog), "destroy", + GTK_SIGNAL_FUNC(CloseNewGameDia), (gpointer)&widgets); + + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); +#ifdef NETWORKING + gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300); +#endif + accel_group = gtk_accel_group_new(); + + /* Title of 'New Game' dialog */ + gtk_window_set_title(GTK_WINDOW(widgets.dialog), _("New Game")); + gtk_container_set_border_width(GTK_CONTAINER(widgets.dialog), 7); + gtk_window_add_accel_group(GTK_WINDOW(widgets.dialog), accel_group); + + vbox = gtk_vbox_new(FALSE, 7); + hbox = gtk_hbox_new(FALSE, 7); + + label = gtk_label_new(""); + + AccelKey = gtk_label_parse_uline(GTK_LABEL(label), + /* Prompt for player's name in 'New + * Game' dialog */ + _("Hey dude, what's your _name?")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + entry = widgets.name = gtk_entry_new(); + gtk_widget_add_accelerator(entry, "grab-focus", accel_group, AccelKey, 0, + GTK_ACCEL_VISIBLE | GTK_ACCEL_SIGNAL_VISIBLE); + gtk_entry_set_text(GTK_ENTRY(entry), GetPlayerName(ClientData.Play)); + gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + notebook = gtk_notebook_new(); + +#ifdef NETWORKING + frame = gtk_frame_new(_("Server")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 4); + vbox2 = gtk_vbox_new(FALSE, 7); + gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); + table = gtk_table_new(2, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 4); + + /* Prompt for hostname to connect to in GTK+ new game dialog */ + label = gtk_label_new(_("Host name")); + + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + GTK_SHRINK, GTK_SHRINK, 0, 0); + entry = widgets.hostname = gtk_entry_new(); + + ServerEntry = "localhost"; + if (g_strcasecmp(ServerName, SN_META) == 0) { + NewGameType = 2; + UpdateMeta = TRUE; + } else if (g_strcasecmp(ServerName, SN_PROMPT) == 0) + NewGameType = 0; + else if (g_strcasecmp(ServerName, SN_SINGLE) == 0) + NewGameType = 1; + else + ServerEntry = ServerName; + + gtk_entry_set_text(GTK_ENTRY(entry), ServerEntry); + gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + label = gtk_label_new(_("Port")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, + GTK_SHRINK, GTK_SHRINK, 0, 0); + entry = widgets.port = gtk_entry_new(); + text = g_strdup_printf("%d", Port); + gtk_entry_set_text(GTK_ENTRY(entry), text); + g_free(text); + gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + + gtk_box_pack_start(GTK_BOX(vbox2), table, FALSE, FALSE, 0); + + button = gtk_button_new_with_label(""); + /* Button to connect to a named dopewars server */ + SetAccelerator(button, _("_Connect"), button, "clicked", accel_group); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(ConnectToServer), (gpointer)&widgets); + gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame), vbox2); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + + label = gtk_label_new(_("Server")); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); +#endif /* NETWORKING */ + + /* Title of 'New Game' dialog notebook tab for single-player mode */ + frame = gtk_frame_new(_("Single player")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 4); + vbox2 = gtk_vbox_new(FALSE, 7); + gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); + widgets.antique = gtk_check_button_new_with_label(""); + + /* Checkbox to activate 'antique mode' in single-player games */ + SetAccelerator(widgets.antique, _("_Antique mode"), widgets.antique, + "clicked", accel_group); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widgets.antique), + WantAntique); + gtk_box_pack_start(GTK_BOX(vbox2), widgets.antique, FALSE, FALSE, 0); + button = gtk_button_new_with_label(""); + + /* Button to start a new single-player (standalone, non-network) game */ + SetAccelerator(button, _("_Start single-player game"), button, + "clicked", accel_group); + + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(StartSinglePlayer), + (gpointer)&widgets); + gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame), vbox2); + label = gtk_label_new(_("Single player")); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); + +#ifdef NETWORKING + /* Title of Metaserver frame in New Game dialog */ + frame = gtk_frame_new(_("Metaserver")); + gtk_container_set_border_width(GTK_CONTAINER(frame), 4); + + vbox2 = gtk_vbox_new(FALSE, 7); + gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); + + clist = widgets.metaserv = + gtk_scrolled_clist_new_with_titles(5, server_titles, &scrollwin); + gtk_clist_column_titles_passive(GTK_CLIST(clist)); + gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE); + gtk_clist_set_column_width(GTK_CLIST(clist), 0, 130); + gtk_clist_set_column_width(GTK_CLIST(clist), 1, 35); + + gtk_box_pack_start(GTK_BOX(vbox2), scrollwin, TRUE, TRUE, 0); + + hbbox = gtk_hbutton_box_new(); + button = gtk_button_new_with_label(""); + + /* Button to update metaserver information */ + SetAccelerator(button, _("_Update"), button, "clicked", accel_group); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(UpdateMetaServerList), + (gpointer)&widgets); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + button = gtk_button_new_with_label(""); + SetAccelerator(button, _("_Connect"), button, "clicked", accel_group); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(MetaServerConnect), + (gpointer)&widgets); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox2), hbbox, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame), vbox2); + + label = gtk_label_new(_("Metaserver")); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); +#endif /* NETWORKING */ + + gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + + /* Caption of status label in New Game dialog before anything has + * happened */ + label = widgets.status = gtk_label_new(""); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(widgets.dialog), vbox); + + gtk_widget_grab_focus(widgets.name); +#ifdef NETWORKING + if (UpdateMeta) { + UpdateMetaServerList(NULL, &widgets); + } else { + FillMetaServerList(&widgets, FALSE); + } +#endif + + SetStartGameStatus(&widgets, NULL); + gtk_widget_show_all(widgets.dialog); + gtk_notebook_set_page(GTK_NOTEBOOK(notebook), NewGameType); +} + +static void SendDoneMessage(GtkWidget *widget, gpointer data) +{ + SendClientMessage(ClientData.Play, C_NONE, C_DONE, NULL, NULL); +} + +static void TransferPayAll(GtkWidget *widget, GtkWidget *dialog) +{ + gchar *text; + + text = pricetostr(ClientData.Play->Debt); + SendClientMessage(ClientData.Play, C_NONE, C_PAYLOAN, NULL, text); + g_free(text); + gtk_widget_destroy(dialog); +} + +static void TransferOK(GtkWidget *widget, GtkWidget *dialog) +{ + gpointer Debt; + GtkWidget *deposit, *entry; + gchar *text, *title; + price_t money; + gboolean withdraw = FALSE; + + Debt = gtk_object_get_data(GTK_OBJECT(dialog), "debt"); + entry = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(dialog), "entry")); + text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); + money = strtoprice(text); + g_free(text); + + if (Debt) { + /* Title of loan shark dialog - (%Tde="The Loan Shark" by default) */ + title = dpg_strdup_printf(_("%/LoanShark window title/%Tde"), + Names.LoanSharkName); + if (money > ClientData.Play->Debt) + money = ClientData.Play->Debt; + } else { + /* Title of bank dialog - (%Tde="The Bank" by default) */ + title = dpg_strdup_printf(_("%/BankName window title/%Tde"), + Names.BankName); + deposit = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(dialog), "deposit")); + if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(deposit))) { + withdraw = TRUE; + } + } + + if (money < 0) { + GtkMessageBox(dialog, _("You must enter a positive amount of money!"), + title, MB_OK); + } else if (!Debt && withdraw && money > ClientData.Play->Bank) { + GtkMessageBox(dialog, _("There isn't that much money available..."), + title, MB_OK); + } else if (!withdraw && money > ClientData.Play->Cash) { + GtkMessageBox(dialog, _("You don't have that much money!"), + title, MB_OK); + } else { + text = pricetostr(withdraw ? -money : money); + SendClientMessage(ClientData.Play, C_NONE, + Debt ? C_PAYLOAN : C_DEPOSIT, NULL, text); + g_free(text); + gtk_widget_destroy(dialog); + } + g_free(title); +} + +void TransferDialog(gboolean Debt) +{ + GtkWidget *dialog, *button, *label, *radio, *table, *vbox; + GtkWidget *hbbox, *hsep, *entry; + GSList *group; + GString *text; + + text = g_string_new(""); + + dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_signal_connect(GTK_OBJECT(dialog), "destroy", + GTK_SIGNAL_FUNC(SendDoneMessage), NULL); + if (Debt) { + /* Title of loan shark dialog - (%Tde="The Loan Shark" by default) */ + dpg_string_sprintf(text, _("%/LoanShark window title/%Tde"), + Names.LoanSharkName); + } else { + /* Title of bank dialog - (%Tde="The Bank" by default) */ + dpg_string_sprintf(text, _("%/BankName window title/%Tde"), + Names.BankName); + } + gtk_window_set_title(GTK_WINDOW(dialog), text->str); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); + + vbox = gtk_vbox_new(FALSE, 7); + table = gtk_table_new(4, 3, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 4); + gtk_table_set_col_spacings(GTK_TABLE(table), 4); + + /* Display of player's cash in bank or loan shark dialog */ + dpg_string_sprintf(text, _("Cash: %P"), ClientData.Play->Cash); + label = gtk_label_new(text->str); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 0, 1); + + if (Debt) { + /* Display of player's debt in loan shark dialog */ + dpg_string_sprintf(text, _("Debt: %P"), ClientData.Play->Debt); + } else { + /* Display of player's bank balance in bank dialog */ + dpg_string_sprintf(text, _("Bank: %P"), ClientData.Play->Bank); + } + label = gtk_label_new(text->str); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 1, 2); + + gtk_object_set_data(GTK_OBJECT(dialog), "debt", GINT_TO_POINTER(Debt)); + if (Debt) { + /* Prompt for paying back a loan */ + label = gtk_label_new(_("Pay back:")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 4); + } else { + /* Radio button selected if you want to pay money into the bank */ + radio = gtk_radio_button_new_with_label(NULL, _("Deposit")); + gtk_object_set_data(GTK_OBJECT(dialog), "deposit", radio); + group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio)); + gtk_table_attach_defaults(GTK_TABLE(table), radio, 0, 1, 2, 3); + + /* Radio button selected if you want to withdraw money from the bank */ + radio = gtk_radio_button_new_with_label(group, _("Withdraw")); + gtk_table_attach_defaults(GTK_TABLE(table), radio, 0, 1, 3, 4); + } + label = gtk_label_new(Currency.Symbol); + entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(entry), "0"); + gtk_object_set_data(GTK_OBJECT(dialog), "entry", entry); + gtk_signal_connect(GTK_OBJECT(entry), "activate", + GTK_SIGNAL_FUNC(TransferOK), dialog); + + if (Currency.Prefix) { + gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 4); + gtk_table_attach_defaults(GTK_TABLE(table), entry, 2, 3, 2, 4); + } else { + gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 2, 4); + gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 2, 4); + } + + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + hbbox = gtk_hbutton_box_new(); + button = gtk_button_new_with_label(_("OK")); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(TransferOK), dialog); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + if (Debt && ClientData.Play->Cash >= ClientData.Play->Debt) { + /* Button to pay back the entire loan/debt */ + button = gtk_button_new_with_label(_("Pay all")); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(TransferPayAll), dialog); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + } + button = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)dialog); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(dialog), vbox); + + gtk_widget_show_all(dialog); + + g_string_free(text, TRUE); +} + +void ListPlayers(GtkWidget *widget, gpointer data) +{ + GtkWidget *dialog, *clist, *button, *vbox, *hsep; + + if (IsShowingPlayerList) + return; + dialog = gtk_window_new(GTK_WINDOW_DIALOG); + + /* Title of player list dialog */ + gtk_window_set_title(GTK_WINDOW(dialog), _("Player List")); + + gtk_window_set_default_size(GTK_WINDOW(dialog), 200, 180); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); + + IsShowingPlayerList = TRUE; + gtk_window_set_modal(GTK_WINDOW(dialog), FALSE); + gtk_object_set_data(GTK_OBJECT(dialog), "IsShowing", + (gpointer)&IsShowingPlayerList); + gtk_signal_connect(GTK_OBJECT(dialog), "destroy", + GTK_SIGNAL_FUNC(DestroyShowing), NULL); + + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); + + vbox = gtk_vbox_new(FALSE, 7); + + clist = ClientData.PlayerList = CreatePlayerList(); + UpdatePlayerList(clist, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + button = gtk_button_new_with_label(_("OK")); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)dialog); + gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(dialog), vbox); + gtk_widget_show_all(dialog); +} + +struct TalkStruct { + GtkWidget *dialog, *clist, *entry, *checkbutton; +}; + +static void TalkSend(GtkWidget *widget, struct TalkStruct *TalkData) +{ + gboolean AllPlayers; + gchar *text; + GString *msg; + GList *selection; + gint row; + Player *Play; + + AllPlayers = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON + (TalkData->checkbutton)); + text = gtk_editable_get_chars(GTK_EDITABLE(TalkData->entry), 0, -1); + gtk_editable_delete_text(GTK_EDITABLE(TalkData->entry), 0, -1); + if (!text) + return; + + msg = g_string_new(""); + + if (AllPlayers) { + SendClientMessage(ClientData.Play, C_NONE, C_MSG, NULL, text); + g_string_sprintf(msg, "%s: %s", GetPlayerName(ClientData.Play), text); + PrintMessage(msg->str); + } else { + for (selection = GTK_CLIST(TalkData->clist)->selection; selection; + selection = g_list_next(selection)) { + row = GPOINTER_TO_INT(selection->data); + Play = + (Player *)gtk_clist_get_row_data(GTK_CLIST(TalkData->clist), + row); + if (Play) { + SendClientMessage(ClientData.Play, C_NONE, C_MSGTO, Play, text); + g_string_sprintf(msg, "%s->%s: %s", GetPlayerName(ClientData.Play), + GetPlayerName(Play), text); + PrintMessage(msg->str); + } + } + } + g_free(text); + g_string_free(msg, TRUE); +} + +void TalkToAll(GtkWidget *widget, gpointer data) +{ + TalkDialog(TRUE); +} + +void TalkToPlayers(GtkWidget *widget, gpointer data) +{ + TalkDialog(FALSE); +} + +void TalkDialog(gboolean TalkToAll) +{ + GtkWidget *dialog, *clist, *button, *entry, *label, *vbox, *hsep, + *checkbutton, *hbbox; + static struct TalkStruct TalkData; + + if (IsShowingTalkList) + return; + dialog = TalkData.dialog = gtk_window_new(GTK_WINDOW_DIALOG); + + /* Title of talk dialog */ + gtk_window_set_title(GTK_WINDOW(dialog), _("Talk to player(s)")); + + gtk_window_set_default_size(GTK_WINDOW(dialog), 200, 190); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); + + IsShowingTalkList = TRUE; + gtk_window_set_modal(GTK_WINDOW(dialog), FALSE); + gtk_object_set_data(GTK_OBJECT(dialog), "IsShowing", + (gpointer)&IsShowingTalkList); + gtk_signal_connect(GTK_OBJECT(dialog), "destroy", + GTK_SIGNAL_FUNC(DestroyShowing), NULL); + + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); + + vbox = gtk_vbox_new(FALSE, 7); + + clist = TalkData.clist = ClientData.TalkList = CreatePlayerList(); + UpdatePlayerList(clist, FALSE); + gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE); + gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0); + + checkbutton = TalkData.checkbutton = + /* Checkbutton set if you want to talk to all players */ + gtk_check_button_new_with_label(_("Talk to all players")); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), TalkToAll); + gtk_box_pack_start(GTK_BOX(vbox), checkbutton, FALSE, FALSE, 0); + + /* Prompt for you to enter the message to be sent to other players */ + label = gtk_label_new(_("Message:-")); + + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + entry = TalkData.entry = gtk_entry_new(); + gtk_signal_connect(GTK_OBJECT(entry), "activate", + GTK_SIGNAL_FUNC(TalkSend), (gpointer)&TalkData); + gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + hbbox = gtk_hbutton_box_new(); + + /* Button to send a message to other players */ + button = gtk_button_new_with_label(_("Send")); + + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(TalkSend), (gpointer)&TalkData); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + button = gtk_button_new_with_label(_("Close")); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)dialog); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(dialog), vbox); + gtk_widget_show_all(dialog); +} + +GtkWidget *CreatePlayerList(void) +{ + GtkWidget *clist; + gchar *text[1]; + + text[0] = "Name"; + clist = gtk_clist_new_with_titles(1, text); + gtk_clist_column_titles_passive(GTK_CLIST(clist)); + gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE); + return clist; +} + +void UpdatePlayerList(GtkWidget *clist, gboolean IncludeSelf) +{ + GSList *list; + gchar *text[1]; + gint row; + Player *Play; + + gtk_clist_freeze(GTK_CLIST(clist)); + gtk_clist_clear(GTK_CLIST(clist)); + for (list = FirstClient; list; list = g_slist_next(list)) { + Play = (Player *)list->data; + if (IncludeSelf || Play != ClientData.Play) { + text[0] = GetPlayerName(Play); + row = gtk_clist_append(GTK_CLIST(clist), text); + gtk_clist_set_row_data(GTK_CLIST(clist), row, Play); + } + } + gtk_clist_thaw(GTK_CLIST(clist)); +} + +static void ErrandOK(GtkWidget *widget, GtkWidget *clist) +{ + GList *selection; + Player *Play; + gint row; + GtkWidget *dialog; + gint ErrandType; + + dialog = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), "dialog")); + ErrandType = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(widget), + "errandtype")); + selection = GTK_CLIST(clist)->selection; + if (selection) { + row = GPOINTER_TO_INT(selection->data); + Play = (Player *)gtk_clist_get_row_data(GTK_CLIST(clist), row); + if (ErrandType == ET_SPY) { + SendClientMessage(ClientData.Play, C_NONE, C_SPYON, Play, NULL); + } else { + SendClientMessage(ClientData.Play, C_NONE, C_TIPOFF, Play, NULL); + } + gtk_widget_destroy(dialog); + } +} + +void SpyOnPlayer(GtkWidget *widget, gpointer data) +{ + ErrandDialog(ET_SPY); +} + +void TipOff(GtkWidget *widget, gpointer data) +{ + ErrandDialog(ET_TIPOFF); +} + +void ErrandDialog(gint ErrandType) +{ + GtkWidget *dialog, *clist, *button, *vbox, *hbbox, *hsep, *label; + gchar *text; + + dialog = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 7); + + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(ClientData.window)); + + vbox = gtk_vbox_new(FALSE, 7); + + if (ErrandType == ET_SPY) { + /* Title of dialog to select a player to spy on */ + gtk_window_set_title(GTK_WINDOW(dialog), _("Spy On Player")); + + /* Informative text for "spy on player" dialog. (%tde = "bitch", + * "bitch", "guns", "drugs", respectively, by default) */ + text = dpg_strdup_printf(_("Please choose the player to spy on. " + "Your %tde will\nthen offer his " + "services to the player, and if " + "successful,\nyou will be able to " + "view the player's stats with the\n" + "\"Get spy reports\" menu. Remember " + "that the %tde will leave\nyou, so " + "any %tde or %tde that he's " + "carrying may be lost!"), Names.Bitch, + Names.Bitch, Names.Guns, Names.Drugs); + label = gtk_label_new(text); + g_free(text); + } else { + + /* Title of dialog to select a player to tip the cops off to */ + gtk_window_set_title(GTK_WINDOW(dialog), _("Tip Off The Cops")); + + /* Informative text for "tip off cops" dialog. (%tde = "bitch", + * "bitch", "guns", "drugs", respectively, by default) */ + text = dpg_strdup_printf(_("Please choose the player to tip off " + "the cops to. Your %tde will\nhelp " + "the cops to attack that player, " + "and then report back to you\non " + "the encounter. Remember that the " + "%tde will leave you temporarily,\n" + "so any %tde or %tde that he's " + "carrying may be lost!"), Names.Bitch, + Names.Bitch, Names.Guns, Names.Drugs); + label = gtk_label_new(text); + g_free(text); + } + + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + clist = ClientData.PlayerList = CreatePlayerList(); + UpdatePlayerList(clist, FALSE); + gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + hbbox = gtk_hbutton_box_new(); + button = gtk_button_new_with_label(_("OK")); + gtk_object_set_data(GTK_OBJECT(button), "dialog", dialog); + gtk_object_set_data(GTK_OBJECT(button), "errandtype", + GINT_TO_POINTER(ErrandType)); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(ErrandOK), (gpointer)clist); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + button = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)dialog); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbbox, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(dialog), vbox); + gtk_widget_show_all(dialog); +} + +void SackBitch(GtkWidget *widget, gpointer data) +{ + char *title, *text; + + /* Cannot sack bitches if you don't have any! */ + if (ClientData.Play->Bitches.Carried <= 0) + return; + + /* Title of dialog to sack a bitch (%Tde = "Bitch" by default) */ + title = dpg_strdup_printf(_("%/Sack Bitch dialog title/Sack %Tde"), + Names.Bitch); + + /* Confirmation message for sacking a bitch. (%tde = "guns", "drugs", + * "bitch", respectively, by default) */ + text = dpg_strdup_printf(_("Are you sure? (Any %tde or %tde carried\n" + "by this %tde may be lost!)"), Names.Guns, + Names.Drugs, Names.Bitch); + + if (GtkMessageBox(ClientData.window, text, title, MB_YESNO) == IDYES) { + ClientData.Play->Bitches.Carried--; + UpdateMenus(); + SendClientMessage(ClientData.Play, C_NONE, C_SACKBITCH, NULL, NULL); + } + g_free(text); + g_free(title); +} + +void CreateInventory(GtkWidget *hbox, gchar *Objects, + GtkAccelGroup *accel_group, gboolean CreateButtons, + gboolean CreateHere, struct InventoryWidgets *widgets, + GtkSignalFunc CallBack) +{ + GtkWidget *scrollwin, *clist, *vbbox, *frame[2], *button[3]; + gint i, mini; + GString *text; + gchar *titles[2][2]; + gchar *button_text[3]; + gpointer button_type[3] = { BT_BUY, BT_SELL, BT_DROP }; + + /* Column titles for display of drugs/guns carried or available for + * purchase */ + titles[0][0] = titles[1][0] = _("Name"); + titles[0][1] = _("Price"); + titles[1][1] = _("Number"); + + /* Button titles for buying/selling/dropping guns or drugs */ + button_text[0] = _("_Buy ->"); + button_text[1] = _("<- _Sell"); + button_text[2] = _("_Drop <-"); + + text = g_string_new(""); + + if (CreateHere) { + /* Title of the display of available drugs/guns (%Tde = "Guns" or + * "Drugs" by default) */ + dpg_string_sprintf(text, _("%Tde here"), Objects); + widgets->HereFrame = frame[0] = gtk_frame_new(text->str); + } + + /* Title of the display of carried drugs/guns (%Tde = "Guns" or "Drugs" + * by default) */ + dpg_string_sprintf(text, _("%Tde carried"), Objects); + + widgets->CarriedFrame = frame[1] = gtk_frame_new(text->str); + + widgets->HereList = widgets->CarriedList = NULL; + if (CreateHere) + mini = 0; + else + mini = 1; + for (i = mini; i < 2; i++) { + gtk_container_set_border_width(GTK_CONTAINER(frame[i]), 5); + + clist = gtk_scrolled_clist_new_with_titles(2, titles[i], &scrollwin); + gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE); + gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 1, TRUE); + gtk_clist_column_titles_passive(GTK_CLIST(clist)); + gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE); + gtk_clist_set_auto_sort(GTK_CLIST(clist), FALSE); + gtk_container_add(GTK_CONTAINER(frame[i]), scrollwin); + if (i == 0) + widgets->HereList = clist; + else + widgets->CarriedList = clist; + } + if (CreateHere) + gtk_box_pack_start(GTK_BOX(hbox), frame[0], TRUE, TRUE, 0); + + if (CreateButtons) { + widgets->vbbox = vbbox = gtk_vbutton_box_new(); + + for (i = 0; i < 3; i++) { + button[i] = gtk_button_new_with_label(""); + SetAccelerator(button[i], _(button_text[i]), button[i], + "clicked", accel_group); + if (CallBack) + gtk_signal_connect(GTK_OBJECT(button[i]), "clicked", + GTK_SIGNAL_FUNC(CallBack), button_type[i]); + gtk_box_pack_start(GTK_BOX(vbbox), button[i], TRUE, TRUE, 0); + } + widgets->BuyButton = button[0]; + widgets->SellButton = button[1]; + widgets->DropButton = button[2]; + gtk_box_pack_start(GTK_BOX(hbox), vbbox, FALSE, FALSE, 0); + } else + widgets->vbbox = NULL; + + gtk_box_pack_start(GTK_BOX(hbox), frame[1], TRUE, TRUE, 0); + g_string_free(text, TRUE); +} + +void DestroyShowing(GtkWidget *widget, gpointer data) +{ + gboolean *IsShowing; + + IsShowing = + (gboolean *)gtk_object_get_data(GTK_OBJECT(widget), "IsShowing"); + if (IsShowing) + *IsShowing = FALSE; +} + +static void NewNameOK(GtkWidget *widget, GtkWidget *window) +{ + GtkWidget *entry; + gchar *text; + + entry = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(window), "entry")); + text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); + if (text[0]) { + SetPlayerName(ClientData.Play, text); + SendNullClientMessage(ClientData.Play, C_NONE, C_NAME, NULL, text); + gtk_widget_destroy(window); + } + g_free(text); +} + +void NewNameDialog(void) +{ + GtkWidget *window, *button, *hsep, *vbox, *label, *entry; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + + /* Title of dialog for changing a player's name */ + gtk_window_set_title(GTK_WINDOW(window), _("Change Name")); + + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(window), + GTK_WINDOW(ClientData.window)); + gtk_container_set_border_width(GTK_CONTAINER(window), 7); + gtk_signal_connect(GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(DisallowDelete), NULL); + + vbox = gtk_vbox_new(FALSE, 7); + + /* Informational text to prompt the player to change his/her name */ + label = gtk_label_new(_("Unfortunately, somebody else is already " + "using \"your\" name. Please change it:-")); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + + entry = gtk_entry_new(); + gtk_object_set_data(GTK_OBJECT(window), "entry", entry); + gtk_signal_connect(GTK_OBJECT(entry), "activate", + GTK_SIGNAL_FUNC(NewNameOK), window); + gtk_entry_set_text(GTK_ENTRY(entry), GetPlayerName(ClientData.Play)); + gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + button = gtk_button_new_with_label(_("OK")); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(NewNameOK), window); + gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_widget_show_all(window); +} + +gint DisallowDelete(GtkWidget *widget, GdkEvent *event, gpointer data) +{ + return (TRUE); +} + +void GunShopDialog(void) +{ + GtkWidget *window, *button, *hsep, *vbox, *hbox; + GtkAccelGroup *accel_group; + gchar *text; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_default_size(GTK_WINDOW(window), 600, 190); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(SendDoneMessage), NULL); + accel_group = gtk_accel_group_new(); + gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); + + /* Title of 'gun shop' dialog in GTK+ client (%Tde="Dan's House of Guns" + * by default) */ + text = dpg_strdup_printf(_("%/GTK GunShop window title/%Tde"), + Names.GunShopName); + gtk_window_set_title(GTK_WINDOW(window), text); + g_free(text); + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(window), + GTK_WINDOW(ClientData.window)); + gtk_container_set_border_width(GTK_CONTAINER(window), 7); + IsShowingGunShop = TRUE; + gtk_object_set_data(GTK_OBJECT(window), "IsShowing", + (gpointer)&IsShowingGunShop); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(DestroyShowing), NULL); + + vbox = gtk_vbox_new(FALSE, 7); + + hbox = gtk_hbox_new(FALSE, 7); + CreateInventory(hbox, Names.Guns, accel_group, TRUE, TRUE, + &ClientData.Gun, DealGuns); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + /* Button to finish buying/selling guns in the gun shop */ + button = gtk_button_new_with_label(_("Done")); + + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)window); + gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + + UpdateInventory(&ClientData.Gun, ClientData.Play->Guns, NumGun, FALSE); + gtk_widget_show_all(window); +} + +void UpdatePlayerLists(void) +{ + if (IsShowingPlayerList) + UpdatePlayerList(ClientData.PlayerList, FALSE); + if (IsShowingTalkList) + UpdatePlayerList(ClientData.TalkList, FALSE); +} + +void GetSpyReports(GtkWidget *Widget, gpointer data) +{ + SendClientMessage(ClientData.Play, C_NONE, C_CONTACTSPY, NULL, NULL); +} + +static void DestroySpyReports(GtkWidget *widget, gpointer data) +{ + SpyReportsDialog = NULL; +} + +static void CreateSpyReports(void) +{ + GtkWidget *window, *button, *vbox, *notebook; + GtkAccelGroup *accel_group; + + SpyReportsDialog = window = gtk_window_new(GTK_WINDOW_DIALOG); + accel_group = gtk_accel_group_new(); + gtk_object_set_data(GTK_OBJECT(window), "accel_group", accel_group); + gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); + + /* Title of window to display reports from spies with other players */ + gtk_window_set_title(GTK_WINDOW(window), _("Spy reports")); + + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(window), + GTK_WINDOW(ClientData.window)); + gtk_container_set_border_width(GTK_CONTAINER(window), 7); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(DestroySpyReports), NULL); + + vbox = gtk_vbox_new(FALSE, 5); + notebook = gtk_notebook_new(); + gtk_object_set_data(GTK_OBJECT(window), "notebook", notebook); + + gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + + button = gtk_button_new_with_label(_("Close")); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)window); + gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + + gtk_widget_show_all(window); +} + +void DisplaySpyReports(Player *Play) +{ + GtkWidget *dialog, *notebook, *vbox, *hbox, *frame, *label, *table; + GtkAccelGroup *accel_group; + struct StatusWidgets Status; + struct InventoryWidgets SpyDrugs, SpyGuns; + + if (!SpyReportsDialog) + CreateSpyReports(); + dialog = SpyReportsDialog; + notebook = + GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(dialog), "notebook")); + accel_group = + (GtkAccelGroup + *)(gtk_object_get_data(GTK_OBJECT(dialog), "accel_group")); + vbox = gtk_vbox_new(FALSE, 5); + frame = gtk_frame_new("Stats"); + gtk_container_set_border_width(GTK_CONTAINER(frame), 4); + table = CreateStatusWidgets(&Status); + gtk_container_add(GTK_CONTAINER(frame), table); + gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); + + hbox = gtk_hbox_new(FALSE, 5); + CreateInventory(hbox, Names.Drugs, accel_group, FALSE, FALSE, &SpyDrugs, + NULL); + CreateInventory(hbox, Names.Guns, accel_group, FALSE, FALSE, &SpyGuns, + NULL); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); + label = gtk_label_new(GetPlayerName(Play)); + + DisplayStats(Play, &Status); + UpdateInventory(&SpyDrugs, Play->Drugs, NumDrug, TRUE); + UpdateInventory(&SpyGuns, Play->Guns, NumGun, FALSE); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label); + + gtk_widget_show_all(notebook); +} + +#ifdef NETWORKING +static void OKAuthDialog(GtkWidget *widget, GtkWidget *window) +{ + gtk_object_set_data(GTK_OBJECT(window), "authok", GINT_TO_POINTER(TRUE)); + gtk_widget_destroy(window); +} + +static void DestroyAuthDialog(GtkWidget *window, gpointer data) +{ + GtkWidget *userentry, *passwdentry; + gchar *username = NULL, *password = NULL; + gpointer proxy, authok; + HttpConnection *conn; + + authok = gtk_object_get_data(GTK_OBJECT(window), "authok"); + proxy = gtk_object_get_data(GTK_OBJECT(window), "proxy"); + userentry = + (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window), "username"); + passwdentry = + (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window), "password"); + conn = + (HttpConnection *)gtk_object_get_data(GTK_OBJECT(window), + "httpconn"); + g_assert(userentry && passwdentry && conn); + + if (authok) { + username = gtk_editable_get_chars(GTK_EDITABLE(userentry), 0, -1); + password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry), 0, -1); + } + + SetHttpAuthentication(conn, GPOINTER_TO_INT(proxy), username, password); + + g_free(username); + g_free(password); +} + +void AuthDialog(HttpConnection *conn, gboolean proxy, gchar *realm, + gpointer data) +{ + GtkWidget *window, *button, *hsep, *vbox, *label, *entry, *table, *hbbox; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(DestroyAuthDialog), NULL); + gtk_object_set_data(GTK_OBJECT(window), "proxy", GINT_TO_POINTER(proxy)); + gtk_object_set_data(GTK_OBJECT(window), "httpconn", (gpointer)conn); + + if (proxy) { + gtk_window_set_title(GTK_WINDOW(window), + /* Title of dialog for authenticating with a + * proxy server */ + _("Proxy Authentication Required")); + } else { + /* Title of dialog for authenticating with a web server */ + gtk_window_set_title(GTK_WINDOW(window), _("Authentication Required")); + } + + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(window), + GTK_WINDOW(ClientData.window)); + gtk_container_set_border_width(GTK_CONTAINER(window), 7); + + vbox = gtk_vbox_new(FALSE, 7); + + table = gtk_table_new(3, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 10); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + + label = gtk_label_new("Realm:"); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); + + label = gtk_label_new(realm); + gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1); + + label = gtk_label_new("User name:"); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + + entry = gtk_entry_new(); + gtk_object_set_data(GTK_OBJECT(window), "username", (gpointer)entry); + gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 1, 2); + + label = gtk_label_new("Password:"); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3); + + entry = gtk_entry_new(); + gtk_object_set_data(GTK_OBJECT(window), "password", (gpointer)entry); + +#ifdef HAVE_FIXED_GTK + /* GTK+ versions earlier than 1.2.10 do bad things with this */ + gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); +#endif + + gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 2, 3); + + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + hbbox = gtk_hbutton_box_new(); + + button = gtk_button_new_with_label(_("OK")); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(OKAuthDialog), (gpointer)window); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + button = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)window); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbbox, TRUE, TRUE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_widget_show_all(window); +} + +static void OKSocksAuth(GtkWidget *widget, GtkWidget *window) +{ + gtk_object_set_data(GTK_OBJECT(window), "authok", GINT_TO_POINTER(TRUE)); + gtk_widget_destroy(window); +} + +static void DestroySocksAuth(GtkWidget *window, gpointer data) +{ + GtkWidget *userentry, *passwdentry; + gchar *username = NULL, *password = NULL; + gpointer authok, meta; + NetworkBuffer *netbuf; + + authok = gtk_object_get_data(GTK_OBJECT(window), "authok"); + meta = gtk_object_get_data(GTK_OBJECT(window), "meta"); + userentry = + (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window), "username"); + passwdentry = + (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window), "password"); + netbuf = + (NetworkBuffer *)gtk_object_get_data(GTK_OBJECT(window), "netbuf"); + + g_assert(userentry && passwdentry && netbuf); + + if (authok) { + username = gtk_editable_get_chars(GTK_EDITABLE(userentry), 0, -1); + password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry), 0, -1); + } + + SendSocks5UserPasswd(netbuf, username, password); + g_free(username); + g_free(password); +} + +static void RealSocksAuthDialog(NetworkBuffer *netbuf, gboolean meta, + gpointer data) +{ + GtkWidget *window, *button, *hsep, *vbox, *label, *entry, *table, *hbbox; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(DestroySocksAuth), NULL); + gtk_object_set_data(GTK_OBJECT(window), "netbuf", (gpointer)netbuf); + gtk_object_set_data(GTK_OBJECT(window), "meta", GINT_TO_POINTER(meta)); + + /* Title of dialog for authenticating with a SOCKS server */ + gtk_window_set_title(GTK_WINDOW(window), + _("SOCKS Authentication Required")); + + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(window), + GTK_WINDOW(ClientData.window)); + gtk_container_set_border_width(GTK_CONTAINER(window), 7); + + vbox = gtk_vbox_new(FALSE, 7); + + table = gtk_table_new(2, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 10); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + + label = gtk_label_new("User name:"); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); + + entry = gtk_entry_new(); + gtk_object_set_data(GTK_OBJECT(window), "username", (gpointer)entry); + gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 0, 1); + + label = gtk_label_new("Password:"); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + + entry = gtk_entry_new(); + gtk_object_set_data(GTK_OBJECT(window), "password", (gpointer)entry); + +#ifdef HAVE_FIXED_GTK + /* GTK+ versions earlier than 1.2.10 do bad things with this */ + gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); +#endif + + gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 1, 2); + + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + + hsep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), hsep, FALSE, FALSE, 0); + + hbbox = gtk_hbutton_box_new(); + + button = gtk_button_new_with_label(_("OK")); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(OKSocksAuth), (gpointer)window); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + button = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer)window); + gtk_box_pack_start(GTK_BOX(hbbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbbox, TRUE, TRUE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_widget_show_all(window); +} + +void MetaSocksAuthDialog(NetworkBuffer *netbuf, gpointer data) +{ + RealSocksAuthDialog(netbuf, TRUE, data); +} + +void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data) +{ + RealSocksAuthDialog(netbuf, FALSE, data); +} + +#endif /* NETWORKING */ (DIR) diff --git a/src/gui_client/gtk_client.h b/src/gui_client/gtk_client.h t@@ -0,0 +1,41 @@ +/************************************************************************ + * gtk_client.h dopewars client using the GTK+ toolkit * + * Copyright (C) 1998-2002 Ben Webb * + * Email: ben@bellatrix.pcl.ox.ac.uk * + * WWW: http://dopewars.sourceforge.net/ * + * * + * 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 2 * + * 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, write to the Free Software * + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * + * MA 02111-1307, USA. * + ************************************************************************/ + +#ifndef __GTK_CLIENT_H__ +#define __GTK_CLIENT_H__ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "gtkport/gtkport.h" + +extern GtkWidget *MainWindow; + +#ifdef CYGWIN +gboolean GtkLoop(HINSTANCE hInstance, HINSTANCE hPrevInstance, + gboolean ReturnOnFail); +#else +gboolean GtkLoop(int *argc, char **argv[], gboolean ReturnOnFail); +#endif + +#endif (DIR) diff --git a/src/winmain.c b/src/winmain.c t@@ -36,13 +36,22 @@ #include "nls.h" #include "tstring.h" #include "AIPlayer.h" -#include "curses_client.h" -#include "gtk_client.h" #include "message.h" #include "serverside.h" -#include "gtkport.h" #include "winmain.h" +#ifdef CURSES_CLIENT +#include "curses_client/curses_client.h" +#endif + +#ifdef GUI_CLIENT +#include "gui_client/gtk_client.h" +#endif + +#ifdef GUI_SERVER +#include "gtkport/gtkport.h" +#endif + static void ServerLogMessage(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) t@@ -310,18 +319,24 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, g_set_print_handler(ServerPrintFunc); newterm(NULL, NULL, NULL); AIPlayerLoop(); - } else if (WantedClient == CLIENT_CURSES) { - AllocConsole(); - SetConsoleTitle(_("dopewars")); - CursesLoop(); } else { -#if GUI_CLIENT - GtkLoop(hInstance, hPrevInstance); -#else - g_print(_("No graphical client available - rebuild the binary\n" - "passing the --enable-gui-client option to configure, or\n" - "use the curses client (if available) instead!\n")); -#endif + switch (WantedClient) { + case CLIENT_AUTO: + if (!GtkLoop(hInstance, hPrevInstance, TRUE)) { + AllocConsole(); + SetConsoleTitle(_("dopewars")); + CursesLoop(); + } + break; + case CLIENT_WINDOW: + GtkLoop(hInstance, hPrevInstance, FALSE); + break; + case CLIENT_CURSES: + AllocConsole(); + SetConsoleTitle(_("dopewars")); + CursesLoop(); + break; + } } #ifdef NETWORKING StopNetworking();