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
git clone git://src.adamsgaard.dk/vaccinewars
Log
Files
Refs
README
LICENSE
---
commit ef90a6dc064a2a31b8bdbc0c52a215da6d058623
parent a449a445fedb565c9b1096a5622b3e4fb33351c3
Author: Ben Webb 
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(-)
---
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//`; \
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 , 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 , 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 , 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])
+
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 <&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 <
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 <
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 <&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 <&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 <&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 <
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 <
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 <
                    #include 
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 <&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 <&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 <
 #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 <
 #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 <
 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 <&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 <&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 <&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 <&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
 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 <&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 <
 #include 
 
+#if HAVE_SYS_TYPES_H
+# include 
+#endif
+
+#if HAVE_STDLIB_H
+# include 
+#endif
+
+#if HAVE_SYS_STAT_H
+# include 
+#endif
+
+#if HAVE_UNISTD_H
+# include 
+#endif
+
 /* This mess was copied from the GNU getpagesize.h.  */
 #ifndef HAVE_GETPAGESIZE
-# ifdef HAVE_UNISTD_H
-#  include 
-# 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 <
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
 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 <&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 <
 #include 
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 <
 #include 
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 <
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 <
 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 <
 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
 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 <
 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 <
 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 <&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 <
-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 <&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 <
 /* 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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 < "$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
           ;;
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],
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}
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
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
 
 
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 
-#endif
-
-#ifdef CURSES_CLIENT
-
-#include 
-#include 
-#include 
-#ifdef HAVE_UNISTD_H
-#include 
-#endif
-#include 
-#include 
-#include 
-#include 
-#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 
-#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 */
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}\"
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:
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 
+#endif
+
+#include 
+#include 
+#include 
+#ifdef HAVE_UNISTD_H
+#include 
+#endif
+#include 
+#include 
+#include 
+#include 
+#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();
+}
diff --git a/src/curses_client.h b/src/curses_client/curses_client.h
diff --git a/src/dopewars.c b/src/dopewars.c
t@@ -43,9 +43,7 @@
 #include 
 #include 
 #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
  */
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
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 
-#endif
-
-#ifdef GUI_CLIENT
-
-#include 
-#include 
-#include 
-
-#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, ""},
-  {N_("/Game/_New..."), "N", NewGame, 0, NULL},
-  {N_("/Game/_Quit..."), "Q", QuitGame, 0, NULL},
-  {N_("/_Talk"), NULL, NULL, 0, ""},
-  {N_("/Talk/To _All..."), NULL, TalkToAll, 0, NULL},
-  {N_("/Talk/To _Player..."), NULL, TalkToPlayers, 0, NULL},
-  {N_("/_List"), NULL, NULL, 0, ""},
-  {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, ""},
-  {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, ""},
-  {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,
-                                           "
/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, - "
/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, - "
/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, - "
/Talk"), - InGame && Network); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "
/List"), InGame); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "
/List/Players..."), - InGame && Network); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "
/Errands"), InGame); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "
/Errands/Spy..."), - InGame && MultiPlayer); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, "
/Errands/Tipoff..."), - InGame && MultiPlayer); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, - "
/Errands/Sack Bitch..."), Bitches > 0); - gtk_widget_set_sensitive(gtk_item_factory_get_widget - (ClientData.Menu, - "
/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, - "
", - 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, "
"); - - 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 -#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 */
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 
-#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
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}\"
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:
diff --git a/src/gtkport.c b/src/gtkport/gtkport.c
diff --git a/src/gtkport.h b/src/gtkport/gtkport.h
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}\"
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:
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 
+#endif
+
+#include 
+#include 
+#include 
+
+#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, ""},
+  {N_("/Game/_New..."), "N", NewGame, 0, NULL},
+  {N_("/Game/_Quit..."), "Q", QuitGame, 0, NULL},
+  {N_("/_Talk"), NULL, NULL, 0, ""},
+  {N_("/Talk/To _All..."), NULL, TalkToAll, 0, NULL},
+  {N_("/Talk/To _Player..."), NULL, TalkToPlayers, 0, NULL},
+  {N_("/_List"), NULL, NULL, 0, ""},
+  {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, ""},
+  {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, ""},
+  {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,
+                                           "
/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, + "
/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, + "
/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, + "
/Talk"), + InGame && Network); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "
/List"), InGame); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "
/List/Players..."), + InGame && Network); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "
/Errands"), InGame); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "
/Errands/Spy..."), + InGame && MultiPlayer); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, "
/Errands/Tipoff..."), + InGame && MultiPlayer); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, + "
/Errands/Sack Bitch..."), Bitches > 0); + gtk_widget_set_sensitive(gtk_item_factory_get_widget + (ClientData.Menu, + "
/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, + "
", + 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, "
"); + + 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 */
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 
+#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
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();