[Tux4kids-commits] r1674 - in branches/commonification/tuxmath/trunk: . cmake-modules data/images/status data/images/title data/images/tux data/missions/multiplay doc intl linebreak src

B. Luchen cheezmeister-guest at alioth.debian.org
Tue Nov 24 23:54:32 UTC 2009


Author: cheezmeister-guest
Date: 2009-11-24 23:54:32 +0000 (Tue, 24 Nov 2009)
New Revision: 1674

Added:
   branches/commonification/tuxmath/trunk/intl/Makefile.in
   branches/commonification/tuxmath/trunk/server/
   branches/commonification/tuxmath/trunk/src/mathcards.c
   branches/commonification/tuxmath/trunk/src/mathcards.h
   branches/commonification/tuxmath/trunk/src/network.h
   branches/commonification/tuxmath/trunk/src/server.c
   branches/commonification/tuxmath/trunk/src/server.h
   branches/commonification/tuxmath/trunk/src/servermain.c
   branches/commonification/tuxmath/trunk/src/testclient.c
   branches/commonification/tuxmath/trunk/src/testclient.h
   branches/commonification/tuxmath/trunk/src/throttle.c
   branches/commonification/tuxmath/trunk/src/throttle.h
   branches/commonification/tuxmath/trunk/src/transtruct.h
Removed:
   branches/commonification/tuxmath/trunk/intl/Makefile.in
   branches/commonification/tuxmath/trunk/src/fileops_media.h
   branches/commonification/tuxmath/trunk/src/mathcards.c
   branches/commonification/tuxmath/trunk/src/mathcards.h
Modified:
   branches/commonification/tuxmath/trunk/cmake-modules/Findt4kcommon.cmake
   branches/commonification/tuxmath/trunk/config.h.cmake
   branches/commonification/tuxmath/trunk/configure.ac
   branches/commonification/tuxmath/trunk/data/images/status/Makefile.am
   branches/commonification/tuxmath/trunk/data/images/status/left.svg
   branches/commonification/tuxmath/trunk/data/images/status/left_gray.svg
   branches/commonification/tuxmath/trunk/data/images/status/right.svg
   branches/commonification/tuxmath/trunk/data/images/status/right_gray.svg
   branches/commonification/tuxmath/trunk/data/images/status/stop.svg
   branches/commonification/tuxmath/trunk/data/images/status/tux4kids.svg
   branches/commonification/tuxmath/trunk/data/images/title/egg.svg
   branches/commonification/tuxmath/trunk/data/images/title/title1.svg
   branches/commonification/tuxmath/trunk/data/images/tux/bigtux.svg
   branches/commonification/tuxmath/trunk/data/missions/multiplay/ace
   branches/commonification/tuxmath/trunk/data/missions/multiplay/commando
   branches/commonification/tuxmath/trunk/data/missions/multiplay/scout
   branches/commonification/tuxmath/trunk/doc/
   branches/commonification/tuxmath/trunk/doc/README.txt
   branches/commonification/tuxmath/trunk/doc/changelog
   branches/commonification/tuxmath/trunk/linebreak/
   branches/commonification/tuxmath/trunk/src/
   branches/commonification/tuxmath/trunk/src/CMakeLists.txt
   branches/commonification/tuxmath/trunk/src/Makefile.am
   branches/commonification/tuxmath/trunk/src/SDL_extras.c
   branches/commonification/tuxmath/trunk/src/credits.c
   branches/commonification/tuxmath/trunk/src/factoroids.c
   branches/commonification/tuxmath/trunk/src/fileops.h
   branches/commonification/tuxmath/trunk/src/fileops_media.c
   branches/commonification/tuxmath/trunk/src/game.c
   branches/commonification/tuxmath/trunk/src/game.h
   branches/commonification/tuxmath/trunk/src/gettext.h
   branches/commonification/tuxmath/trunk/src/globals.h
   branches/commonification/tuxmath/trunk/src/highscore.c
   branches/commonification/tuxmath/trunk/src/highscore.h
   branches/commonification/tuxmath/trunk/src/menu.c
   branches/commonification/tuxmath/trunk/src/menu.h
   branches/commonification/tuxmath/trunk/src/network.c
   branches/commonification/tuxmath/trunk/src/options.c
   branches/commonification/tuxmath/trunk/src/options.h
   branches/commonification/tuxmath/trunk/src/scandir.c
   branches/commonification/tuxmath/trunk/src/scandir.h
   branches/commonification/tuxmath/trunk/src/setup.c
   branches/commonification/tuxmath/trunk/src/titlescreen.c
   branches/commonification/tuxmath/trunk/src/titlescreen.h
   branches/commonification/tuxmath/trunk/src/tuxmath.c
   branches/commonification/tuxmath/trunk/src/tuxmath.h
   branches/commonification/tuxmath/trunk/tuxmath.desktop
Log:
Beginning to messily update commonification branch from trunk

Modified: branches/commonification/tuxmath/trunk/cmake-modules/Findt4kcommon.cmake
===================================================================
--- branches/commonification/tuxmath/trunk/cmake-modules/Findt4kcommon.cmake	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/cmake-modules/Findt4kcommon.cmake	2009-11-24 23:54:32 UTC (rev 1674)
@@ -14,10 +14,13 @@
 # On OSX, this will prefer the Framework version (if found) over others.
 # People will have to manually change the cache values of 
 # T4KCOMMON_LIBRARY to override this selection.
-FIND_PATH(T4KCOMMON_INCLUDE_DIR SDL_extras.h
+FIND_PATH(T4KCOMMON_INCLUDE_DIR t4kcommon.h
   $ENV{SDLDIR}/include
   /usr/local/include
   /usr/include
+  $ENV{SDLDIR}/include/t4kcommon
+  /usr/local/include/t4kcommon
+  /usr/include/t4kcommon
   )
 # I'm not sure if I should do a special casing for Apple. It is 
 # unlikely that other Unix systems will find the framework path.

Modified: branches/commonification/tuxmath/trunk/config.h.cmake
===================================================================
--- branches/commonification/tuxmath/trunk/config.h.cmake	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/config.h.cmake	2009-11-24 23:54:32 UTC (rev 1674)
@@ -5,6 +5,7 @@
 #cmakedefine ENABLE_NLS 1
 #cmakedefine SDL_Pango 1
 #cmakedefine HAVE_RSVG 1
+#cmakedefine HAVE_LIBT4KCOMMON 1
 
 /* Stuff needed for linewrap */
 #cmakedefine LINEBREAK 1

Modified: branches/commonification/tuxmath/trunk/configure.ac
===================================================================
--- branches/commonification/tuxmath/trunk/configure.ac	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/configure.ac	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,7 +1,6 @@
 #                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
 AC_INIT([Tux Of Math Command],[1.7.3],[tuxmath-devel at lists.sourceforge.net],[tuxmath])
-AC_CONFIG_SRCDIR([src/tuxmath.c])
 
 AC_PREREQ(2.61)
 AC_CANONICAL_HOST
@@ -9,8 +8,8 @@
 AC_CANONICAL_TARGET
 
 AM_INIT_AUTOMAKE(foreign)
-AC_CONFIG_SRCDIR([config.h.in])
-AC_CONFIG_HEADER([config.h])
+AC_CONFIG_SRCDIR([src/tuxmath.c])
+AC_CONFIG_HEADERS([config.h])
 
 NAME_VERSION=$PACKAGE-$VERSION
 
@@ -89,6 +88,23 @@
              ,
              [AC_MSG_ERROR([SDL_mixer not found! http://www.libsdl.org/projects/SDL_mixer])])
 
+dnl SDL_Net is enabled by default 
+dnl unless SDL_net is disabled at configure time.
+
+AC_ARG_WITH([sdlnet],
+            [AS_HELP_STRING([--without-sdlnet],[don't use SDL_Net even if available])],
+            [with_sdlnet=no],
+            [with_sdlnet=yes])
+
+if test "x$with_sdlnet" != xno; then
+AC_CHECK_LIB([SDL_net],
+             [SDLNet_Init],
+             ,
+             [with_sdlnet=no;
+              AC_MSG_FAILURE([SDL_Net test failed (--without-sdlnet to disable LAN support)])])
+fi
+
+
 dnl SDL_Pango is enabled by default.
 dnl If SDL_Pango disabled at configure time, or if we can't find it,
 dnl we look for SDL_ttf:
@@ -143,19 +159,16 @@
   AC_DEFINE([HAVE_RSVG],[1],[Define to 1 if you have the `libRSVG` library])
 fi
 
-dnl Check for Tux4kids common routines
-
-AC_ARG_WITH([t4kcommon],
-            [AS_HELP_STRING([--without-t4kcommon],[don't use t4kcommon even if available])],
-            [with_t4kcommon=no],
-            [with_t4kcommon=yes])
-
-if test "x$with_t4kcommon" = xyes; then
-  AC_CHECK_LIB([t4kcommon],
-               [GetScreen],
-               ,
-               [with_t4kcommon=no;
-               AC_MSG_FAILURE([tux4kids-common test failed (--without-t4kcommon to disable)])])
+if test "x$with_rsvg" = xyes; then
+  CAIRO_CFLAGS=""
+  CAIRO_LIBS=""
+  PKG_CHECK_MODULES([CAIRO],
+                    [cairo >= 1.4.10],
+                    ,
+                    [AC_MSG_FAILURE([cairo test failed (--without-rsvg to disable svg support)])])
+  CFLAGS="$CFLAGS $CAIRO_CFLAGS"
+  LIBS="$LIBS $CAIRO_LIBS"
+  AC_DEFINE([HAVE_RSVG],[1],[Define to 1 if you have the `libRSVG` library])
 fi
 
 dnl Check for (somewhat) higher-level math functions - needed for SDL_extras
@@ -165,6 +178,7 @@
 dnl              [AC_MSG_ERROR([Math library not found - functions in <math.h> may not be available.])])
 
 
+
 # --------------------------------------------------------------------------------------
 # Checks for header files.
 # --------------------------------------------------------------------------------------
@@ -172,7 +186,7 @@
 AC_FUNC_ALLOCA
 AC_HEADER_DIRENT
 AC_HEADER_STDC
-AC_CHECK_HEADERS([argz.h error.h errno.h fcntl.h float.h iconv.h inttypes.h langinfo.h libgen.h libintl.h limits.h locale.h malloc.h math.h stddef.h stdint.h stdio_ext.h stdlib.h string.h strings.h sys/param.h unistd.h wchar.h])
+AC_CHECK_HEADERS([argz.h error.h errno.h fcntl.h float.h iconv.h inttypes.h langinfo.h libgen.h libintl.h limits.h locale.h malloc.h math.h pthread.h stddef.h stdint.h stdio_ext.h stdlib.h string.h strings.h sys/param.h unistd.h wchar.h])
 
 
 # --------------------------------------------------------------------------------------------
@@ -239,9 +253,8 @@
 MINGW32_PACKAGE_DATA_DIR="data"
 AC_SUBST(MINGW32_PACKAGE_DATA_DIR)
 
-NSI_DLL_DIR=~/tuxmath_dll
 AC_ARG_WITH([dll-directory],
-            AS_HELP_STRING([--with-dll-directory=path], [set the path where dll for TuxMath are [$(NSI_DLL_DIR)]]),
+            AS_HELP_STRING([--with-dll-directory=path], [provide location of DLL files needed for build  [$(NSI_DLL_DIR)]]),
             [dll_path=$withval], 
             [dll_path=no])
 
@@ -249,6 +262,8 @@
 
 if test $dll_path != no; then
 NSI_DLL_DIR=$dll_path
+else
+NSI_DLL_DIR=~/tuxmath_dll
 fi
 AC_SUBST(NSI_DLL_DIR)
 

Modified: branches/commonification/tuxmath/trunk/data/images/status/Makefile.am
===================================================================
--- branches/commonification/tuxmath/trunk/data/images/status/Makefile.am	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/data/images/status/Makefile.am	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,4 +1,3 @@
-## Makefile.am for tuxmath data/images/status:
 ## Process with AutoMake:
 
 statusdir = $(pkgdatadir)/images/status


Property changes on: branches/commonification/tuxmath/trunk/data/images/status/left.svg
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: branches/commonification/tuxmath/trunk/data/images/status/left_gray.svg
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: branches/commonification/tuxmath/trunk/data/images/status/right.svg
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: branches/commonification/tuxmath/trunk/data/images/status/right_gray.svg
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: branches/commonification/tuxmath/trunk/data/images/status/stop.svg
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: branches/commonification/tuxmath/trunk/data/images/status/tux4kids.svg
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: branches/commonification/tuxmath/trunk/data/images/title/egg.svg
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: branches/commonification/tuxmath/trunk/data/images/title/title1.svg
___________________________________________________________________
Added: svn:mergeinfo
   + 


Property changes on: branches/commonification/tuxmath/trunk/data/images/tux/bigtux.svg
___________________________________________________________________
Added: svn:mergeinfo
   + 

Modified: branches/commonification/tuxmath/trunk/data/missions/multiplay/ace
===================================================================
--- branches/commonification/tuxmath/trunk/data/missions/multiplay/ace	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/data/missions/multiplay/ace	2009-11-24 23:54:32 UTC (rev 1674)
@@ -59,4 +59,3 @@
 bonus_comet_interval = 20
 allow_pause = 0
 bonus_speed_ratio = 2.0
-

Modified: branches/commonification/tuxmath/trunk/data/missions/multiplay/commando
===================================================================
--- branches/commonification/tuxmath/trunk/data/missions/multiplay/commando	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/data/missions/multiplay/commando	2009-11-24 23:54:32 UTC (rev 1674)
@@ -58,4 +58,3 @@
 bonus_comet_interval = 20
 allow_pause = 0
 bonus_speed_ratio = 2.0
-

Modified: branches/commonification/tuxmath/trunk/data/missions/multiplay/scout
===================================================================
--- branches/commonification/tuxmath/trunk/data/missions/multiplay/scout	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/data/missions/multiplay/scout	2009-11-24 23:54:32 UTC (rev 1674)
@@ -47,4 +47,3 @@
 bonus_comet_interval = 10
 allow_pause = 0
 bonus_speed_ratio = 1.5
-


Property changes on: branches/commonification/tuxmath/trunk/doc
___________________________________________________________________
Modified: svn:ignore
   - *~
*.o
CMakeFiles
Makefile
Makefile.in

   + *~
*.o
Makefile
Makefile.in


Modified: branches/commonification/tuxmath/trunk/doc/README.txt
===================================================================
--- branches/commonification/tuxmath/trunk/doc/README.txt	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/doc/README.txt	2009-11-24 23:54:32 UTC (rev 1674)
@@ -2,9 +2,9 @@
 An educational math tutorial game starring Tux, the Linux Penguin
 -----------------------------------------------------------------
 
-March 12, 2009
+October 25, 2009
 
-For tuxmath-1.7.2
+For tuxmath-1.7.3
 
 Objective
 ---------
@@ -44,7 +44,8 @@
     documentation or help screens for details.
 
     Alternatively, simply type the command "tuxmath" at a command
-    prompt (eg, in an xterm).
+    prompt (eg, in an xterm). Many command-line options are supported,
+    e.g "tuxmath -f" for fullscreen or "tuxmath -w" to run in a window.
 
   Windows
   -------
@@ -94,12 +95,52 @@
       player's home directory (see below). At some point, the options will be 
       settable from within the game.
 
+    Network Game:
+    ------------------
+      Tuxmath now provides head-to-head competition over a local area network! All
+      players see the same questions, and whoever answers first gets the points for
+      that question. The game play is cooperative, however, in that all participating
+      players help defend all the igloos. Up to 16 players can participate in a single
+      game (this can be increased extremely simply with a recompilation, if desired).
+
+      To set up network play, the tuxmath server program needs to be started. Simply go
+      to Network Game->Run Server and follow the directions. You just need to type in a
+      name to identify the server to players (such as "Tux Server").  If we are able to
+      use threads on your platform, you will also be prompted to pick the lesson file to
+      be used by the server.
+
+      Once the server is running, players can connect by going to Network Game->Join Game.
+      TuxMath should automatically detect the server if it is running on the local network.
+      The player will be asked to enter a nickname, then click an arrow to indicate that
+      he/she is ready to start.  When everyone has indicated that they are ready, the
+      game will start.
+
+      Note that while network play is functional, it needs more testing, and some aspects
+      have not yet been addressed:
+        - If the server program is running on more than one computer on the local network,
+          TuxMath will get confused and not connect.
+        - While a network game is in progress, do not play a non-network game on the same
+          computer - this will also confuse TuxMath (because TuxMath is not yet "thread-safe").
+          However, it is fine to participate in the network game from that computer.
+          Also, don't quit the program with the server while others are still playing
+          a network game!
+          This problem actually only occurs when we use threading to run the server,
+          meaning everything except Windows. On Windows, the server runs as a separate
+          program. The drawback is that you may leave the server running by accident,
+          so you have to go into Task Manager to kill it when you don't want it 
+          running anymore.
+        - It is also possible to run the server as a separate program on all platforms
+          by typing "tuxmathserver" at the command line.  This avoids any issues with
+          thread-safety, but for now the server will only use the default question list
+          settings if launched this way.
+
+
     Play With Friends:
     ------------------
       Compete with your friends by playing in a turns-based fashion! The
       math difficulty levels are the same as for the "Arcade" games. Note that
-      this involves rotating play at a single computer rather than multiplayer
-      competition over a network (although that is an idea being considered!).
+      this involves rotating play at a single computer rather than network play,
+      as described above.
 
     Factoroids!
     -----------

Modified: branches/commonification/tuxmath/trunk/doc/changelog
===================================================================
--- branches/commonification/tuxmath/trunk/doc/changelog	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/doc/changelog	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,3 +1,23 @@
+2009.Sep.04 (svn.debian.org/tux4kids - revision 1546)
+        Data - click.wav removed due to minor concerns about whether it is really
+        under a free license (license not really known).
+
+	David Bruce <davidstuartbruce at gmail.com>
+
+2009.Sep.04 (svn.debian.org/tux4kids - revision 1489)
+        LAN project branch merged back into trunk.
+	Graphical LAN play tested and functional in branch prior to merge.
+	New menu entry code for LAN game needs to be written to actually use LAN mode
+	in trunk build.
+
+	David Bruce <davidstuartbruce at gmail.com>
+
+2009.Jul.03 (svn.debian.org/tux4kids - revision 1141)
+        LAN project - basic TCP/IP server and test client implemented in branches/lan.
+        The client and server provide multiplayer command-line tuxmath over tcp.
+        Akash Gangil <akashg1611 at gmail.com>
+	David Bruce <davidstuartbruce at gmail.com>
+
 2009.Jun.24 (svn.debian.org/tux4kids - revision xxx)
         i18n - new languages from launchpad.
         Asturian by Xuacu
@@ -10,10 +30,6 @@
 2009.Mar.12 (svn.debian.org/tux4kids - revision 954
 	one-liner tweak of campaign.c to fix display problem in scrolling text
         that strangely is only apparent in Windows and Mac
-
-	David Bruce <davidstuartbruce at gmail.com>
-
-
 2009.Mar.12 (svn.debian.org/tux4kids - revision 937)
 Version 1.7.2
         Build- some minor tweaks to tuxmath.desktop and specfiles.

Deleted: branches/commonification/tuxmath/trunk/intl/Makefile.in
===================================================================
--- branches/commonification/tuxmath/trunk/intl/Makefile.in	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/intl/Makefile.in	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,587 +0,0 @@
-# Makefile for directory with message catalog handling library of GNU gettext
-# Copyright (C) 1995-1998, 2000-2007 Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2, 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
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-PACKAGE = @PACKAGE@
-VERSION = @VERSION@
-
-SHELL = /bin/sh
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-top_builddir = ..
-
-# The VPATH variables allows builds with $builddir != $srcdir, assuming a
-# 'make' program that supports VPATH (such as GNU make). This line is removed
-# by autoconf automatically when "$(srcdir)" = ".".
-# In this directory, the VPATH handling is particular:
-# 1. If INTL_LIBTOOL_SUFFIX_PREFIX is 'l' (indicating a build with libtool),
-#    the .c -> .lo rules carefully use $(srcdir), so that VPATH can be omitted.
-# 2. If PACKAGE = gettext-tools, VPATH _must_ be omitted, because otherwise
-#    'make' does the wrong thing if GNU gettext was configured with
-#    "./configure --srcdir=`pwd`", namely it gets confused by the .lo and .la
-#    files it finds in srcdir = ../../gettext-runtime/intl.
-VPATH = $(srcdir)
-
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-transform = @program_transform_name@
-libdir = @libdir@
-includedir = @includedir@
-datarootdir = @datarootdir@
-datadir = @datadir@
-localedir = $(datadir)/locale
-gettextsrcdir = $(datadir)/gettext/intl
-aliaspath = $(localedir)
-subdir = intl
-
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-
-# We use $(mkdir_p).
-# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as
-# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions,
-# @install_sh@ does not start with $(SHELL), so we add it.
-# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined
-# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake
-# versions, $(mkinstalldirs) and $(install_sh) are unused.
-mkinstalldirs = $(SHELL) @install_sh@ -d
-install_sh = $(SHELL) @install_sh@
-MKDIR_P = @MKDIR_P@
-mkdir_p = @mkdir_p@
-
-l = @INTL_LIBTOOL_SUFFIX_PREFIX@
-
-AR = ar
-CC = @CC@
-LIBTOOL = @LIBTOOL@
-RANLIB = @RANLIB@
-YACC = @INTLBISON@ -y -d
-YFLAGS = --name-prefix=__gettext
-WINDRES = @WINDRES@
-
-# -DBUILDING_LIBINTL: Change expansion of LIBINTL_DLL_EXPORTED macro.
-# -DBUILDING_DLL: Change expansion of RELOCATABLE_DLL_EXPORTED macro.
-DEFS = -DLOCALEDIR=\"$(localedir)\" -DLOCALE_ALIAS_PATH=\"$(aliaspath)\" \
--DLIBDIR=\"$(libdir)\" -DBUILDING_LIBINTL -DBUILDING_DLL -DIN_LIBINTL \
--DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"$(libdir)\" -DNO_XMALLOC \
--Dset_relocation_prefix=libintl_set_relocation_prefix \
--Drelocate=libintl_relocate \
--DDEPENDS_ON_LIBICONV=1 @DEFS@
-CPPFLAGS = @CPPFLAGS@
-CFLAGS = @CFLAGS@ @CFLAG_VISIBILITY@
-LDFLAGS = @LDFLAGS@ $(LDFLAGS_ at WOE32DLL@)
-LDFLAGS_yes = -Wl,--export-all-symbols
-LDFLAGS_no =
-LIBS = @LIBS@
-
-COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
-
-HEADERS = \
-  gmo.h \
-  gettextP.h \
-  hash-string.h \
-  loadinfo.h \
-  plural-exp.h \
-  eval-plural.h \
-  localcharset.h \
-  lock.h \
-  relocatable.h \
-  tsearch.h tsearch.c \
-  xsize.h \
-  printf-args.h printf-args.c \
-  printf-parse.h wprintf-parse.h printf-parse.c \
-  vasnprintf.h vasnwprintf.h vasnprintf.c \
-  os2compat.h \
-  libgnuintl.h.in
-SOURCES = \
-  bindtextdom.c \
-  dcgettext.c \
-  dgettext.c \
-  gettext.c \
-  finddomain.c \
-  hash-string.c \
-  loadmsgcat.c \
-  localealias.c \
-  textdomain.c \
-  l10nflist.c \
-  explodename.c \
-  dcigettext.c \
-  dcngettext.c \
-  dngettext.c \
-  ngettext.c \
-  plural.y \
-  plural-exp.c \
-  localcharset.c \
-  lock.c \
-  relocatable.c \
-  langprefs.c \
-  localename.c \
-  log.c \
-  printf.c \
-  version.c \
-  osdep.c \
-  os2compat.c \
-  intl-exports.c \
-  intl-compat.c
-OBJECTS = \
-  bindtextdom.$lo \
-  dcgettext.$lo \
-  dgettext.$lo \
-  gettext.$lo \
-  finddomain.$lo \
-  hash-string.$lo \
-  loadmsgcat.$lo \
-  localealias.$lo \
-  textdomain.$lo \
-  l10nflist.$lo \
-  explodename.$lo \
-  dcigettext.$lo \
-  dcngettext.$lo \
-  dngettext.$lo \
-  ngettext.$lo \
-  plural.$lo \
-  plural-exp.$lo \
-  localcharset.$lo \
-  lock.$lo \
-  relocatable.$lo \
-  langprefs.$lo \
-  localename.$lo \
-  log.$lo \
-  printf.$lo \
-  version.$lo \
-  osdep.$lo \
-  intl-compat.$lo
-OBJECTS_RES_yes = libintl.res
-OBJECTS_RES_no =
-DISTFILES.common = Makefile.in \
-config.charset locale.alias ref-add.sin ref-del.sin export.h libintl.rc \
-$(HEADERS) $(SOURCES)
-DISTFILES.generated = plural.c
-DISTFILES.normal = VERSION
-DISTFILES.gettext = COPYING.LIB-2.0 COPYING.LIB-2.1 libintl.glibc README.woe32
-DISTFILES.obsolete = xopen-msg.sed linux-msg.sed po2tbl.sed.in cat-compat.c \
-COPYING.LIB-2 gettext.h libgettext.h plural-eval.c libgnuintl.h \
-libgnuintl.h_vms Makefile.vms libgnuintl.h.msvc-static \
-libgnuintl.h.msvc-shared Makefile.msvc
-
-all: all- at USE_INCLUDED_LIBINTL@
-all-yes: libintl.$la libintl.h charset.alias ref-add.sed ref-del.sed
-all-no: all-no- at BUILD_INCLUDED_LIBINTL@
-all-no-yes: libgnuintl.$la
-all-no-no:
-
-libintl.a libgnuintl.a: $(OBJECTS)
-	rm -f $@
-	$(AR) cru $@ $(OBJECTS)
-	$(RANLIB) $@
-
-libintl.la libgnuintl.la: $(OBJECTS) $(OBJECTS_RES_ at WOE32@)
-	$(LIBTOOL) --mode=link \
-	  $(CC) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ \
-	  $(OBJECTS) @LTLIBICONV@ @INTL_MACOSX_LIBS@ $(LIBS) @LTLIBTHREAD@ @LTLIBC@ \
-	  $(OBJECTS_RES_ at WOE32@) \
-	  -version-info $(LTV_CURRENT):$(LTV_REVISION):$(LTV_AGE) \
-	  -rpath $(libdir) \
-	  -no-undefined
-
-# Libtool's library version information for libintl.
-# Before making a gettext release, the gettext maintainer must change this
-# according to the libtool documentation, section "Library interface versions".
-# Maintainers of other packages that include the intl directory must *not*
-# change these values.
-LTV_CURRENT=8
-LTV_REVISION=2
-LTV_AGE=0
-
-.SUFFIXES:
-.SUFFIXES: .c .y .o .lo .sin .sed
-
-.c.o:
-	$(COMPILE) $<
-
-.y.c:
-	$(YACC) $(YFLAGS) --output $@ $<
-	rm -f $*.h
-
-bindtextdom.lo: $(srcdir)/bindtextdom.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/bindtextdom.c
-dcgettext.lo: $(srcdir)/dcgettext.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcgettext.c
-dgettext.lo: $(srcdir)/dgettext.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dgettext.c
-gettext.lo: $(srcdir)/gettext.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/gettext.c
-finddomain.lo: $(srcdir)/finddomain.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/finddomain.c
-hash-string.lo: $(srcdir)/hash-string.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/hash-string.c
-loadmsgcat.lo: $(srcdir)/loadmsgcat.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/loadmsgcat.c
-localealias.lo: $(srcdir)/localealias.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localealias.c
-textdomain.lo: $(srcdir)/textdomain.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/textdomain.c
-l10nflist.lo: $(srcdir)/l10nflist.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/l10nflist.c
-explodename.lo: $(srcdir)/explodename.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/explodename.c
-dcigettext.lo: $(srcdir)/dcigettext.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcigettext.c
-dcngettext.lo: $(srcdir)/dcngettext.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcngettext.c
-dngettext.lo: $(srcdir)/dngettext.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dngettext.c
-ngettext.lo: $(srcdir)/ngettext.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/ngettext.c
-plural.lo: $(srcdir)/plural.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural.c
-plural-exp.lo: $(srcdir)/plural-exp.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural-exp.c
-localcharset.lo: $(srcdir)/localcharset.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localcharset.c
-lock.lo: $(srcdir)/lock.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/lock.c
-relocatable.lo: $(srcdir)/relocatable.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/relocatable.c
-langprefs.lo: $(srcdir)/langprefs.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/langprefs.c
-localename.lo: $(srcdir)/localename.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localename.c
-log.lo: $(srcdir)/log.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/log.c
-printf.lo: $(srcdir)/printf.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/printf.c
-version.lo: $(srcdir)/version.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/version.c
-osdep.lo: $(srcdir)/osdep.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/osdep.c
-intl-compat.lo: $(srcdir)/intl-compat.c
-	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/intl-compat.c
-
-# This rule is executed only on Woe32 systems.
-# The following sed expressions come from the windres-options script. They are
-# inlined here, so that they can be written in a Makefile without requiring a
-# temporary file. They must contain literal newlines rather than semicolons,
-# so that they work with the sed-3.02 that is shipped with MSYS. We can use
-# GNU bash's $'\n' syntax to obtain such a newline.
-libintl.res: $(srcdir)/libintl.rc
-	nl=$$'\n'; \
-	sed_extract_major='/^[0-9]/{'$${nl}'s/^\([0-9]*\).*/\1/p'$${nl}q$${nl}'}'$${nl}'c\'$${nl}0$${nl}q; \
-	sed_extract_minor='/^[0-9][0-9]*[.][0-9]/{'$${nl}'s/^[0-9]*[.]\([0-9]*\).*/\1/p'$${nl}q$${nl}'}'$${nl}'c\'$${nl}0$${nl}q; \
-	sed_extract_subminor='/^[0-9][0-9]*[.][0-9][0-9]*[.][0-9]/{'$${nl}'s/^[0-9]*[.][0-9]*[.]\([0-9]*\).*/\1/p'$${nl}q$${nl}'}'$${nl}'c\'$${nl}0$${nl}q; \
-	$(WINDRES) \
-	  "-DPACKAGE_VERSION_STRING=\\\"$(VERSION)\\\"" \
-	  "-DPACKAGE_VERSION_MAJOR="`echo '$(VERSION)' | sed -n -e "$$sed_extract_major"` \
-	  "-DPACKAGE_VERSION_MINOR="`echo '$(VERSION)' | sed -n -e "$$sed_extract_minor"` \
-	  "-DPACKAGE_VERSION_SUBMINOR="`echo '$(VERSION)' | sed -n -e "$$sed_extract_subminor"` \
-	  -i $(srcdir)/libintl.rc -o libintl.res --output-format=coff
-
-ref-add.sed: $(srcdir)/ref-add.sin
-	sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-add.sin > t-ref-add.sed
-	mv t-ref-add.sed ref-add.sed
-ref-del.sed: $(srcdir)/ref-del.sin
-	sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-del.sin > t-ref-del.sed
-	mv t-ref-del.sed ref-del.sed
-
-INCLUDES = -I. -I$(srcdir) -I..
-
-libgnuintl.h: $(srcdir)/libgnuintl.h.in
-	sed -e '/IN_LIBGLOCALE/d' \
-	    -e 's,@''HAVE_POSIX_PRINTF''@, at HAVE_POSIX_PRINTF@,g' \
-	    -e 's,@''HAVE_ASPRINTF''@, at HAVE_ASPRINTF@,g' \
-	    -e 's,@''HAVE_SNPRINTF''@, at HAVE_SNPRINTF@,g' \
-	    -e 's,@''HAVE_WPRINTF''@, at HAVE_WPRINTF@,g' \
-	  < $(srcdir)/libgnuintl.h.in \
-	| if test '@WOE32DLL@' = yes; then \
-	    sed -e 's/extern \([^()]*\);/extern __declspec (dllimport) \1;/'; \
-	  else \
-	    cat; \
-	  fi \
-	| sed -e 's/extern \([^"]\)/extern LIBINTL_DLL_EXPORTED \1/' \
-	      -e "/#define _LIBINTL_H/r $(srcdir)/export.h" \
-	| sed -e 's,@''HAVE_VISIBILITY''@, at HAVE_VISIBILITY@,g' \
-	  > libgnuintl.h
-
-libintl.h: $(srcdir)/libgnuintl.h.in
-	sed -e '/IN_LIBGLOCALE/d' \
-	    -e 's,@''HAVE_POSIX_PRINTF''@, at HAVE_POSIX_PRINTF@,g' \
-	    -e 's,@''HAVE_ASPRINTF''@, at HAVE_ASPRINTF@,g' \
-	    -e 's,@''HAVE_SNPRINTF''@, at HAVE_SNPRINTF@,g' \
-	    -e 's,@''HAVE_WPRINTF''@, at HAVE_WPRINTF@,g' \
-	  < $(srcdir)/libgnuintl.h.in > libintl.h
-
-charset.alias: $(srcdir)/config.charset
-	$(SHELL) $(srcdir)/config.charset '@host@' > t-$@
-	mv t-$@ $@
-
-check: all
-
-# We must not install the libintl.h/libintl.a files if we are on a
-# system which has the GNU gettext() function in its C library or in a
-# separate library.
-# If you want to use the one which comes with this version of the
-# package, you have to use `configure --with-included-gettext'.
-install: install-exec install-data
-install-exec: all
-	if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \
-	   && test '@USE_INCLUDED_LIBINTL@' = yes; then \
-	  $(mkdir_p) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \
-	  $(INSTALL_DATA) libintl.h $(DESTDIR)$(includedir)/libintl.h; \
-	  $(LIBTOOL) --mode=install \
-	    $(INSTALL_DATA) libintl.$la $(DESTDIR)$(libdir)/libintl.$la; \
-	  if test "@RELOCATABLE@" = yes; then \
-	    dependencies=`sed -n -e 's,^dependency_libs=\(.*\),\1,p' < $(DESTDIR)$(libdir)/libintl.la | sed -e "s,^',," -e "s,'\$$,,"`; \
-	    if test -n "$$dependencies"; then \
-	      rm -f $(DESTDIR)$(libdir)/libintl.la; \
-	    fi; \
-	  fi; \
-	else \
-	  : ; \
-	fi
-	if test "$(PACKAGE)" = "gettext-tools" \
-	   && test '@USE_INCLUDED_LIBINTL@' = no \
-	   && test @GLIBC2@ != no; then \
-	  $(mkdir_p) $(DESTDIR)$(libdir); \
-	  $(LIBTOOL) --mode=install \
-	    $(INSTALL_DATA) libgnuintl.$la $(DESTDIR)$(libdir)/libgnuintl.$la; \
-	  rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \
-	  $(INSTALL_DATA) $(DESTDIR)$(libdir)/libgnuintl.so $(DESTDIR)$(libdir)/preloadable_libintl.so; \
-	  $(LIBTOOL) --mode=uninstall \
-	    rm -f $(DESTDIR)$(libdir)/libgnuintl.$la; \
-	else \
-	  : ; \
-	fi
-	if test '@USE_INCLUDED_LIBINTL@' = yes; then \
-	  test @GLIBC21@ != no || $(mkdir_p) $(DESTDIR)$(libdir); \
-	  temp=$(DESTDIR)$(libdir)/t-charset.alias; \
-	  dest=$(DESTDIR)$(libdir)/charset.alias; \
-	  if test -f $(DESTDIR)$(libdir)/charset.alias; then \
-	    orig=$(DESTDIR)$(libdir)/charset.alias; \
-	    sed -f ref-add.sed $$orig > $$temp; \
-	    $(INSTALL_DATA) $$temp $$dest; \
-	    rm -f $$temp; \
-	  else \
-	    if test @GLIBC21@ = no; then \
-	      orig=charset.alias; \
-	      sed -f ref-add.sed $$orig > $$temp; \
-	      $(INSTALL_DATA) $$temp $$dest; \
-	      rm -f $$temp; \
-	    fi; \
-	  fi; \
-	  $(mkdir_p) $(DESTDIR)$(localedir); \
-	  test -f $(DESTDIR)$(localedir)/locale.alias \
-	    && orig=$(DESTDIR)$(localedir)/locale.alias \
-	    || orig=$(srcdir)/locale.alias; \
-	  temp=$(DESTDIR)$(localedir)/t-locale.alias; \
-	  dest=$(DESTDIR)$(localedir)/locale.alias; \
-	  sed -f ref-add.sed $$orig > $$temp; \
-	  $(INSTALL_DATA) $$temp $$dest; \
-	  rm -f $$temp; \
-	else \
-	  : ; \
-	fi
-install-data: all
-	if test "$(PACKAGE)" = "gettext-tools"; then \
-	  $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
-	  $(INSTALL_DATA) VERSION $(DESTDIR)$(gettextsrcdir)/VERSION; \
-	  $(INSTALL_DATA) ChangeLog.inst $(DESTDIR)$(gettextsrcdir)/ChangeLog; \
-	  dists="COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common)"; \
-	  for file in $$dists; do \
-	    $(INSTALL_DATA) $(srcdir)/$$file \
-			    $(DESTDIR)$(gettextsrcdir)/$$file; \
-	  done; \
-	  chmod a+x $(DESTDIR)$(gettextsrcdir)/config.charset; \
-	  dists="$(DISTFILES.generated)"; \
-	  for file in $$dists; do \
-	    if test -f $$file; then dir=.; else dir=$(srcdir); fi; \
-	    $(INSTALL_DATA) $$dir/$$file \
-			    $(DESTDIR)$(gettextsrcdir)/$$file; \
-	  done; \
-	  dists="$(DISTFILES.obsolete)"; \
-	  for file in $$dists; do \
-	    rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
-	  done; \
-	else \
-	  : ; \
-	fi
-
-install-strip: install
-
-install-dvi install-html install-info install-ps install-pdf:
-
-installdirs:
-	if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \
-	   && test '@USE_INCLUDED_LIBINTL@' = yes; then \
-	  $(mkdir_p) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \
-	else \
-	  : ; \
-	fi
-	if test "$(PACKAGE)" = "gettext-tools" \
-	   && test '@USE_INCLUDED_LIBINTL@' = no \
-	   && test @GLIBC2@ != no; then \
-	  $(mkdir_p) $(DESTDIR)$(libdir); \
-	else \
-	  : ; \
-	fi
-	if test '@USE_INCLUDED_LIBINTL@' = yes; then \
-	  test @GLIBC21@ != no || $(mkdir_p) $(DESTDIR)$(libdir); \
-	  $(mkdir_p) $(DESTDIR)$(localedir); \
-	else \
-	  : ; \
-	fi
-	if test "$(PACKAGE)" = "gettext-tools"; then \
-	  $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
-	else \
-	  : ; \
-	fi
-
-# Define this as empty until I found a useful application.
-installcheck:
-
-uninstall:
-	if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \
-	   && test '@USE_INCLUDED_LIBINTL@' = yes; then \
-	  rm -f $(DESTDIR)$(includedir)/libintl.h; \
-	  $(LIBTOOL) --mode=uninstall \
-	    rm -f $(DESTDIR)$(libdir)/libintl.$la; \
-	else \
-	  : ; \
-	fi
-	if test "$(PACKAGE)" = "gettext-tools" \
-	   && test '@USE_INCLUDED_LIBINTL@' = no \
-	   && test @GLIBC2@ != no; then \
-	  rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \
-	else \
-	  : ; \
-	fi
-	if test '@USE_INCLUDED_LIBINTL@' = yes; then \
-	  if test -f $(DESTDIR)$(libdir)/charset.alias; then \
-	    temp=$(DESTDIR)$(libdir)/t-charset.alias; \
-	    dest=$(DESTDIR)$(libdir)/charset.alias; \
-	    sed -f ref-del.sed $$dest > $$temp; \
-	    if grep '^# Packages using this file: $$' $$temp > /dev/null; then \
-	      rm -f $$dest; \
-	    else \
-	      $(INSTALL_DATA) $$temp $$dest; \
-	    fi; \
-	    rm -f $$temp; \
-	  fi; \
-	  if test -f $(DESTDIR)$(localedir)/locale.alias; then \
-	    temp=$(DESTDIR)$(localedir)/t-locale.alias; \
-	    dest=$(DESTDIR)$(localedir)/locale.alias; \
-	    sed -f ref-del.sed $$dest > $$temp; \
-	    if grep '^# Packages using this file: $$' $$temp > /dev/null; then \
-	      rm -f $$dest; \
-	    else \
-	      $(INSTALL_DATA) $$temp $$dest; \
-	    fi; \
-	    rm -f $$temp; \
-	  fi; \
-	else \
-	  : ; \
-	fi
-	if test "$(PACKAGE)" = "gettext-tools"; then \
-	  for file in VERSION ChangeLog COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common) $(DISTFILES.generated); do \
-	    rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
-	  done; \
-	else \
-	  : ; \
-	fi
-
-info dvi ps pdf html:
-
-$(OBJECTS): ../config.h libgnuintl.h
-bindtextdom.$lo dcgettext.$lo dcigettext.$lo dcngettext.$lo dgettext.$lo dngettext.$lo finddomain.$lo gettext.$lo intl-compat.$lo loadmsgcat.$lo localealias.$lo ngettext.$lo textdomain.$lo: $(srcdir)/gettextP.h $(srcdir)/gmo.h $(srcdir)/loadinfo.h
-hash-string.$lo dcigettext.$lo loadmsgcat.$lo: $(srcdir)/hash-string.h
-explodename.$lo l10nflist.$lo: $(srcdir)/loadinfo.h
-dcigettext.$lo loadmsgcat.$lo plural.$lo plural-exp.$lo: $(srcdir)/plural-exp.h
-dcigettext.$lo: $(srcdir)/eval-plural.h
-localcharset.$lo: $(srcdir)/localcharset.h
-bindtextdom.$lo dcigettext.$lo finddomain.$lo loadmsgcat.$lo localealias.$lo lock.$lo log.$lo: $(srcdir)/lock.h
-localealias.$lo localcharset.$lo relocatable.$lo: $(srcdir)/relocatable.h
-printf.$lo: $(srcdir)/printf-args.h $(srcdir)/printf-args.c $(srcdir)/printf-parse.h $(srcdir)/wprintf-parse.h $(srcdir)/xsize.h $(srcdir)/printf-parse.c $(srcdir)/vasnprintf.h $(srcdir)/vasnwprintf.h $(srcdir)/vasnprintf.c
-
-# A bison-2.1 generated plural.c includes <libintl.h> if ENABLE_NLS.
-PLURAL_DEPS_yes = libintl.h
-PLURAL_DEPS_no =
-plural.$lo: $(PLURAL_DEPS_ at USE_INCLUDED_LIBINTL@)
-
-tags: TAGS
-
-TAGS: $(HEADERS) $(SOURCES)
-	here=`pwd`; cd $(srcdir) && etags -o $$here/TAGS $(HEADERS) $(SOURCES)
-
-ctags: CTAGS
-
-CTAGS: $(HEADERS) $(SOURCES)
-	here=`pwd`; cd $(srcdir) && ctags -o $$here/CTAGS $(HEADERS) $(SOURCES)
-
-id: ID
-
-ID: $(HEADERS) $(SOURCES)
-	here=`pwd`; cd $(srcdir) && mkid -f$$here/ID $(HEADERS) $(SOURCES)
-
-
-mostlyclean:
-	rm -f *.a *.la *.o *.obj *.lo libintl.res core core.*
-	rm -f libgnuintl.h libintl.h charset.alias ref-add.sed ref-del.sed
-	rm -f -r .libs _libs
-
-clean: mostlyclean
-
-distclean: clean
-	rm -f Makefile ID TAGS
-	if test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; then \
-	  rm -f ChangeLog.inst $(DISTFILES.normal); \
-	else \
-	  : ; \
-	fi
-
-maintainer-clean: distclean
-	@echo "This command is intended for maintainers to use;"
-	@echo "it deletes files that may require special tools to rebuild."
-
-
-# GNU gettext needs not contain the file `VERSION' but contains some
-# other files which should not be distributed in other packages.
-distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
-dist distdir: Makefile
-	if test "$(PACKAGE)" = "gettext-tools"; then \
-	  : ; \
-	else \
-	  if test "$(PACKAGE)" = "gettext-runtime"; then \
-	    additional="$(DISTFILES.gettext)"; \
-	  else \
-	    additional="$(DISTFILES.normal)"; \
-	  fi; \
-	  $(MAKE) $(DISTFILES.common) $(DISTFILES.generated) $$additional; \
-	  for file in ChangeLog $(DISTFILES.common) $(DISTFILES.generated) $$additional; do \
-	    if test -f $$file; then dir=.; else dir=$(srcdir); fi; \
-	    cp -p $$dir/$$file $(distdir) || test $$file = Makefile.in || exit 1; \
-	  done; \
-	fi
-
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-	cd $(top_builddir) && $(SHELL) ./config.status
-# This would be more efficient, but doesn't work any more with autoconf-2.57,
-# when AC_CONFIG_FILES([intl/Makefile:somedir/Makefile.in]) is used.
-#	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
-
-# Tell versions [3.59,3.63) of GNU make not to export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:

Copied: branches/commonification/tuxmath/trunk/intl/Makefile.in (from rev 1657, tuxmath/trunk/intl/Makefile.in)
===================================================================
--- branches/commonification/tuxmath/trunk/intl/Makefile.in	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/intl/Makefile.in	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,587 @@
+# Makefile for directory with message catalog handling library of GNU gettext
+# Copyright (C) 1995-1998, 2000-2007 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Library General Public License as published
+# by the Free Software Foundation; either version 2, 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = ..
+
+# The VPATH variables allows builds with $builddir != $srcdir, assuming a
+# 'make' program that supports VPATH (such as GNU make). This line is removed
+# by autoconf automatically when "$(srcdir)" = ".".
+# In this directory, the VPATH handling is particular:
+# 1. If INTL_LIBTOOL_SUFFIX_PREFIX is 'l' (indicating a build with libtool),
+#    the .c -> .lo rules carefully use $(srcdir), so that VPATH can be omitted.
+# 2. If PACKAGE = gettext-tools, VPATH _must_ be omitted, because otherwise
+#    'make' does the wrong thing if GNU gettext was configured with
+#    "./configure --srcdir=`pwd`", namely it gets confused by the .lo and .la
+#    files it finds in srcdir = ../../gettext-runtime/intl.
+VPATH = $(srcdir)
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+transform = @program_transform_name@
+libdir = @libdir@
+includedir = @includedir@
+datarootdir = @datarootdir@
+datadir = @datadir@
+localedir = $(datadir)/locale
+gettextsrcdir = $(datadir)/gettext/intl
+aliaspath = $(localedir)
+subdir = intl
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+
+# We use $(mkdir_p).
+# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as
+# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions,
+# @install_sh@ does not start with $(SHELL), so we add it.
+# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined
+# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake
+# versions, $(mkinstalldirs) and $(install_sh) are unused.
+mkinstalldirs = $(SHELL) @install_sh@ -d
+install_sh = $(SHELL) @install_sh@
+MKDIR_P = @MKDIR_P@
+mkdir_p = @mkdir_p@
+
+l = @INTL_LIBTOOL_SUFFIX_PREFIX@
+
+AR = ar
+CC = @CC@
+LIBTOOL = @LIBTOOL@
+RANLIB = @RANLIB@
+YACC = @INTLBISON@ -y -d
+YFLAGS = --name-prefix=__gettext
+WINDRES = @WINDRES@
+
+# -DBUILDING_LIBINTL: Change expansion of LIBINTL_DLL_EXPORTED macro.
+# -DBUILDING_DLL: Change expansion of RELOCATABLE_DLL_EXPORTED macro.
+DEFS = -DLOCALEDIR=\"$(localedir)\" -DLOCALE_ALIAS_PATH=\"$(aliaspath)\" \
+-DLIBDIR=\"$(libdir)\" -DBUILDING_LIBINTL -DBUILDING_DLL -DIN_LIBINTL \
+-DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"$(libdir)\" -DNO_XMALLOC \
+-Dset_relocation_prefix=libintl_set_relocation_prefix \
+-Drelocate=libintl_relocate \
+-DDEPENDS_ON_LIBICONV=1 @DEFS@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@ @CFLAG_VISIBILITY@
+LDFLAGS = @LDFLAGS@ $(LDFLAGS_ at WOE32DLL@)
+LDFLAGS_yes = -Wl,--export-all-symbols
+LDFLAGS_no =
+LIBS = @LIBS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+HEADERS = \
+  gmo.h \
+  gettextP.h \
+  hash-string.h \
+  loadinfo.h \
+  plural-exp.h \
+  eval-plural.h \
+  localcharset.h \
+  lock.h \
+  relocatable.h \
+  tsearch.h tsearch.c \
+  xsize.h \
+  printf-args.h printf-args.c \
+  printf-parse.h wprintf-parse.h printf-parse.c \
+  vasnprintf.h vasnwprintf.h vasnprintf.c \
+  os2compat.h \
+  libgnuintl.h.in
+SOURCES = \
+  bindtextdom.c \
+  dcgettext.c \
+  dgettext.c \
+  gettext.c \
+  finddomain.c \
+  hash-string.c \
+  loadmsgcat.c \
+  localealias.c \
+  textdomain.c \
+  l10nflist.c \
+  explodename.c \
+  dcigettext.c \
+  dcngettext.c \
+  dngettext.c \
+  ngettext.c \
+  plural.y \
+  plural-exp.c \
+  localcharset.c \
+  lock.c \
+  relocatable.c \
+  langprefs.c \
+  localename.c \
+  log.c \
+  printf.c \
+  version.c \
+  osdep.c \
+  os2compat.c \
+  intl-exports.c \
+  intl-compat.c
+OBJECTS = \
+  bindtextdom.$lo \
+  dcgettext.$lo \
+  dgettext.$lo \
+  gettext.$lo \
+  finddomain.$lo \
+  hash-string.$lo \
+  loadmsgcat.$lo \
+  localealias.$lo \
+  textdomain.$lo \
+  l10nflist.$lo \
+  explodename.$lo \
+  dcigettext.$lo \
+  dcngettext.$lo \
+  dngettext.$lo \
+  ngettext.$lo \
+  plural.$lo \
+  plural-exp.$lo \
+  localcharset.$lo \
+  lock.$lo \
+  relocatable.$lo \
+  langprefs.$lo \
+  localename.$lo \
+  log.$lo \
+  printf.$lo \
+  version.$lo \
+  osdep.$lo \
+  intl-compat.$lo
+OBJECTS_RES_yes = libintl.res
+OBJECTS_RES_no =
+DISTFILES.common = Makefile.in \
+config.charset locale.alias ref-add.sin ref-del.sin export.h libintl.rc \
+$(HEADERS) $(SOURCES)
+DISTFILES.generated = plural.c
+DISTFILES.normal = VERSION
+DISTFILES.gettext = COPYING.LIB-2.0 COPYING.LIB-2.1 libintl.glibc README.woe32
+DISTFILES.obsolete = xopen-msg.sed linux-msg.sed po2tbl.sed.in cat-compat.c \
+COPYING.LIB-2 gettext.h libgettext.h plural-eval.c libgnuintl.h \
+libgnuintl.h_vms Makefile.vms libgnuintl.h.msvc-static \
+libgnuintl.h.msvc-shared Makefile.msvc
+
+all: all- at USE_INCLUDED_LIBINTL@
+all-yes: libintl.$la libintl.h charset.alias ref-add.sed ref-del.sed
+all-no: all-no- at BUILD_INCLUDED_LIBINTL@
+all-no-yes: libgnuintl.$la
+all-no-no:
+
+libintl.a libgnuintl.a: $(OBJECTS)
+	rm -f $@
+	$(AR) cru $@ $(OBJECTS)
+	$(RANLIB) $@
+
+libintl.la libgnuintl.la: $(OBJECTS) $(OBJECTS_RES_ at WOE32@)
+	$(LIBTOOL) --mode=link \
+	  $(CC) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) $(LDFLAGS) -o $@ \
+	  $(OBJECTS) @LTLIBICONV@ @INTL_MACOSX_LIBS@ $(LIBS) @LTLIBTHREAD@ @LTLIBC@ \
+	  $(OBJECTS_RES_ at WOE32@) \
+	  -version-info $(LTV_CURRENT):$(LTV_REVISION):$(LTV_AGE) \
+	  -rpath $(libdir) \
+	  -no-undefined
+
+# Libtool's library version information for libintl.
+# Before making a gettext release, the gettext maintainer must change this
+# according to the libtool documentation, section "Library interface versions".
+# Maintainers of other packages that include the intl directory must *not*
+# change these values.
+LTV_CURRENT=8
+LTV_REVISION=2
+LTV_AGE=0
+
+.SUFFIXES:
+.SUFFIXES: .c .y .o .lo .sin .sed
+
+.c.o:
+	$(COMPILE) $<
+
+.y.c:
+	$(YACC) $(YFLAGS) --output $@ $<
+	rm -f $*.h
+
+bindtextdom.lo: $(srcdir)/bindtextdom.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/bindtextdom.c
+dcgettext.lo: $(srcdir)/dcgettext.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcgettext.c
+dgettext.lo: $(srcdir)/dgettext.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dgettext.c
+gettext.lo: $(srcdir)/gettext.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/gettext.c
+finddomain.lo: $(srcdir)/finddomain.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/finddomain.c
+hash-string.lo: $(srcdir)/hash-string.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/hash-string.c
+loadmsgcat.lo: $(srcdir)/loadmsgcat.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/loadmsgcat.c
+localealias.lo: $(srcdir)/localealias.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localealias.c
+textdomain.lo: $(srcdir)/textdomain.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/textdomain.c
+l10nflist.lo: $(srcdir)/l10nflist.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/l10nflist.c
+explodename.lo: $(srcdir)/explodename.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/explodename.c
+dcigettext.lo: $(srcdir)/dcigettext.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcigettext.c
+dcngettext.lo: $(srcdir)/dcngettext.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dcngettext.c
+dngettext.lo: $(srcdir)/dngettext.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/dngettext.c
+ngettext.lo: $(srcdir)/ngettext.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/ngettext.c
+plural.lo: $(srcdir)/plural.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural.c
+plural-exp.lo: $(srcdir)/plural-exp.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/plural-exp.c
+localcharset.lo: $(srcdir)/localcharset.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localcharset.c
+lock.lo: $(srcdir)/lock.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/lock.c
+relocatable.lo: $(srcdir)/relocatable.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/relocatable.c
+langprefs.lo: $(srcdir)/langprefs.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/langprefs.c
+localename.lo: $(srcdir)/localename.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/localename.c
+log.lo: $(srcdir)/log.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/log.c
+printf.lo: $(srcdir)/printf.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/printf.c
+version.lo: $(srcdir)/version.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/version.c
+osdep.lo: $(srcdir)/osdep.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/osdep.c
+intl-compat.lo: $(srcdir)/intl-compat.c
+	$(LIBTOOL) --mode=compile $(COMPILE) $(srcdir)/intl-compat.c
+
+# This rule is executed only on Woe32 systems.
+# The following sed expressions come from the windres-options script. They are
+# inlined here, so that they can be written in a Makefile without requiring a
+# temporary file. They must contain literal newlines rather than semicolons,
+# so that they work with the sed-3.02 that is shipped with MSYS. We can use
+# GNU bash's $'\n' syntax to obtain such a newline.
+libintl.res: $(srcdir)/libintl.rc
+	nl=$$'\n'; \
+	sed_extract_major='/^[0-9]/{'$${nl}'s/^\([0-9]*\).*/\1/p'$${nl}q$${nl}'}'$${nl}'c\'$${nl}0$${nl}q; \
+	sed_extract_minor='/^[0-9][0-9]*[.][0-9]/{'$${nl}'s/^[0-9]*[.]\([0-9]*\).*/\1/p'$${nl}q$${nl}'}'$${nl}'c\'$${nl}0$${nl}q; \
+	sed_extract_subminor='/^[0-9][0-9]*[.][0-9][0-9]*[.][0-9]/{'$${nl}'s/^[0-9]*[.][0-9]*[.]\([0-9]*\).*/\1/p'$${nl}q$${nl}'}'$${nl}'c\'$${nl}0$${nl}q; \
+	$(WINDRES) \
+	  "-DPACKAGE_VERSION_STRING=\\\"$(VERSION)\\\"" \
+	  "-DPACKAGE_VERSION_MAJOR="`echo '$(VERSION)' | sed -n -e "$$sed_extract_major"` \
+	  "-DPACKAGE_VERSION_MINOR="`echo '$(VERSION)' | sed -n -e "$$sed_extract_minor"` \
+	  "-DPACKAGE_VERSION_SUBMINOR="`echo '$(VERSION)' | sed -n -e "$$sed_extract_subminor"` \
+	  -i $(srcdir)/libintl.rc -o libintl.res --output-format=coff
+
+ref-add.sed: $(srcdir)/ref-add.sin
+	sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-add.sin > t-ref-add.sed
+	mv t-ref-add.sed ref-add.sed
+ref-del.sed: $(srcdir)/ref-del.sin
+	sed -e '/^#/d' -e 's/@''PACKAGE''@/@PACKAGE@/g' $(srcdir)/ref-del.sin > t-ref-del.sed
+	mv t-ref-del.sed ref-del.sed
+
+INCLUDES = -I. -I$(srcdir) -I..
+
+libgnuintl.h: $(srcdir)/libgnuintl.h.in
+	sed -e '/IN_LIBGLOCALE/d' \
+	    -e 's,@''HAVE_POSIX_PRINTF''@, at HAVE_POSIX_PRINTF@,g' \
+	    -e 's,@''HAVE_ASPRINTF''@, at HAVE_ASPRINTF@,g' \
+	    -e 's,@''HAVE_SNPRINTF''@, at HAVE_SNPRINTF@,g' \
+	    -e 's,@''HAVE_WPRINTF''@, at HAVE_WPRINTF@,g' \
+	  < $(srcdir)/libgnuintl.h.in \
+	| if test '@WOE32DLL@' = yes; then \
+	    sed -e 's/extern \([^()]*\);/extern __declspec (dllimport) \1;/'; \
+	  else \
+	    cat; \
+	  fi \
+	| sed -e 's/extern \([^"]\)/extern LIBINTL_DLL_EXPORTED \1/' \
+	      -e "/#define _LIBINTL_H/r $(srcdir)/export.h" \
+	| sed -e 's,@''HAVE_VISIBILITY''@, at HAVE_VISIBILITY@,g' \
+	  > libgnuintl.h
+
+libintl.h: $(srcdir)/libgnuintl.h.in
+	sed -e '/IN_LIBGLOCALE/d' \
+	    -e 's,@''HAVE_POSIX_PRINTF''@, at HAVE_POSIX_PRINTF@,g' \
+	    -e 's,@''HAVE_ASPRINTF''@, at HAVE_ASPRINTF@,g' \
+	    -e 's,@''HAVE_SNPRINTF''@, at HAVE_SNPRINTF@,g' \
+	    -e 's,@''HAVE_WPRINTF''@, at HAVE_WPRINTF@,g' \
+	  < $(srcdir)/libgnuintl.h.in > libintl.h
+
+charset.alias: $(srcdir)/config.charset
+	$(SHELL) $(srcdir)/config.charset '@host@' > t-$@
+	mv t-$@ $@
+
+check: all
+
+# We must not install the libintl.h/libintl.a files if we are on a
+# system which has the GNU gettext() function in its C library or in a
+# separate library.
+# If you want to use the one which comes with this version of the
+# package, you have to use `configure --with-included-gettext'.
+install: install-exec install-data
+install-exec: all
+	if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \
+	   && test '@USE_INCLUDED_LIBINTL@' = yes; then \
+	  $(mkdir_p) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \
+	  $(INSTALL_DATA) libintl.h $(DESTDIR)$(includedir)/libintl.h; \
+	  $(LIBTOOL) --mode=install \
+	    $(INSTALL_DATA) libintl.$la $(DESTDIR)$(libdir)/libintl.$la; \
+	  if test "@RELOCATABLE@" = yes; then \
+	    dependencies=`sed -n -e 's,^dependency_libs=\(.*\),\1,p' < $(DESTDIR)$(libdir)/libintl.la | sed -e "s,^',," -e "s,'\$$,,"`; \
+	    if test -n "$$dependencies"; then \
+	      rm -f $(DESTDIR)$(libdir)/libintl.la; \
+	    fi; \
+	  fi; \
+	else \
+	  : ; \
+	fi
+	if test "$(PACKAGE)" = "gettext-tools" \
+	   && test '@USE_INCLUDED_LIBINTL@' = no \
+	   && test @GLIBC2@ != no; then \
+	  $(mkdir_p) $(DESTDIR)$(libdir); \
+	  $(LIBTOOL) --mode=install \
+	    $(INSTALL_DATA) libgnuintl.$la $(DESTDIR)$(libdir)/libgnuintl.$la; \
+	  rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \
+	  $(INSTALL_DATA) $(DESTDIR)$(libdir)/libgnuintl.so $(DESTDIR)$(libdir)/preloadable_libintl.so; \
+	  $(LIBTOOL) --mode=uninstall \
+	    rm -f $(DESTDIR)$(libdir)/libgnuintl.$la; \
+	else \
+	  : ; \
+	fi
+	if test '@USE_INCLUDED_LIBINTL@' = yes; then \
+	  test @GLIBC21@ != no || $(mkdir_p) $(DESTDIR)$(libdir); \
+	  temp=$(DESTDIR)$(libdir)/t-charset.alias; \
+	  dest=$(DESTDIR)$(libdir)/charset.alias; \
+	  if test -f $(DESTDIR)$(libdir)/charset.alias; then \
+	    orig=$(DESTDIR)$(libdir)/charset.alias; \
+	    sed -f ref-add.sed $$orig > $$temp; \
+	    $(INSTALL_DATA) $$temp $$dest; \
+	    rm -f $$temp; \
+	  else \
+	    if test @GLIBC21@ = no; then \
+	      orig=charset.alias; \
+	      sed -f ref-add.sed $$orig > $$temp; \
+	      $(INSTALL_DATA) $$temp $$dest; \
+	      rm -f $$temp; \
+	    fi; \
+	  fi; \
+	  $(mkdir_p) $(DESTDIR)$(localedir); \
+	  test -f $(DESTDIR)$(localedir)/locale.alias \
+	    && orig=$(DESTDIR)$(localedir)/locale.alias \
+	    || orig=$(srcdir)/locale.alias; \
+	  temp=$(DESTDIR)$(localedir)/t-locale.alias; \
+	  dest=$(DESTDIR)$(localedir)/locale.alias; \
+	  sed -f ref-add.sed $$orig > $$temp; \
+	  $(INSTALL_DATA) $$temp $$dest; \
+	  rm -f $$temp; \
+	else \
+	  : ; \
+	fi
+install-data: all
+	if test "$(PACKAGE)" = "gettext-tools"; then \
+	  $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
+	  $(INSTALL_DATA) VERSION $(DESTDIR)$(gettextsrcdir)/VERSION; \
+	  $(INSTALL_DATA) ChangeLog.inst $(DESTDIR)$(gettextsrcdir)/ChangeLog; \
+	  dists="COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common)"; \
+	  for file in $$dists; do \
+	    $(INSTALL_DATA) $(srcdir)/$$file \
+			    $(DESTDIR)$(gettextsrcdir)/$$file; \
+	  done; \
+	  chmod a+x $(DESTDIR)$(gettextsrcdir)/config.charset; \
+	  dists="$(DISTFILES.generated)"; \
+	  for file in $$dists; do \
+	    if test -f $$file; then dir=.; else dir=$(srcdir); fi; \
+	    $(INSTALL_DATA) $$dir/$$file \
+			    $(DESTDIR)$(gettextsrcdir)/$$file; \
+	  done; \
+	  dists="$(DISTFILES.obsolete)"; \
+	  for file in $$dists; do \
+	    rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
+	  done; \
+	else \
+	  : ; \
+	fi
+
+install-strip: install
+
+install-dvi install-html install-info install-ps install-pdf:
+
+installdirs:
+	if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \
+	   && test '@USE_INCLUDED_LIBINTL@' = yes; then \
+	  $(mkdir_p) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir); \
+	else \
+	  : ; \
+	fi
+	if test "$(PACKAGE)" = "gettext-tools" \
+	   && test '@USE_INCLUDED_LIBINTL@' = no \
+	   && test @GLIBC2@ != no; then \
+	  $(mkdir_p) $(DESTDIR)$(libdir); \
+	else \
+	  : ; \
+	fi
+	if test '@USE_INCLUDED_LIBINTL@' = yes; then \
+	  test @GLIBC21@ != no || $(mkdir_p) $(DESTDIR)$(libdir); \
+	  $(mkdir_p) $(DESTDIR)$(localedir); \
+	else \
+	  : ; \
+	fi
+	if test "$(PACKAGE)" = "gettext-tools"; then \
+	  $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
+	else \
+	  : ; \
+	fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+	if { test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; } \
+	   && test '@USE_INCLUDED_LIBINTL@' = yes; then \
+	  rm -f $(DESTDIR)$(includedir)/libintl.h; \
+	  $(LIBTOOL) --mode=uninstall \
+	    rm -f $(DESTDIR)$(libdir)/libintl.$la; \
+	else \
+	  : ; \
+	fi
+	if test "$(PACKAGE)" = "gettext-tools" \
+	   && test '@USE_INCLUDED_LIBINTL@' = no \
+	   && test @GLIBC2@ != no; then \
+	  rm -f $(DESTDIR)$(libdir)/preloadable_libintl.so; \
+	else \
+	  : ; \
+	fi
+	if test '@USE_INCLUDED_LIBINTL@' = yes; then \
+	  if test -f $(DESTDIR)$(libdir)/charset.alias; then \
+	    temp=$(DESTDIR)$(libdir)/t-charset.alias; \
+	    dest=$(DESTDIR)$(libdir)/charset.alias; \
+	    sed -f ref-del.sed $$dest > $$temp; \
+	    if grep '^# Packages using this file: $$' $$temp > /dev/null; then \
+	      rm -f $$dest; \
+	    else \
+	      $(INSTALL_DATA) $$temp $$dest; \
+	    fi; \
+	    rm -f $$temp; \
+	  fi; \
+	  if test -f $(DESTDIR)$(localedir)/locale.alias; then \
+	    temp=$(DESTDIR)$(localedir)/t-locale.alias; \
+	    dest=$(DESTDIR)$(localedir)/locale.alias; \
+	    sed -f ref-del.sed $$dest > $$temp; \
+	    if grep '^# Packages using this file: $$' $$temp > /dev/null; then \
+	      rm -f $$dest; \
+	    else \
+	      $(INSTALL_DATA) $$temp $$dest; \
+	    fi; \
+	    rm -f $$temp; \
+	  fi; \
+	else \
+	  : ; \
+	fi
+	if test "$(PACKAGE)" = "gettext-tools"; then \
+	  for file in VERSION ChangeLog COPYING.LIB-2.0 COPYING.LIB-2.1 $(DISTFILES.common) $(DISTFILES.generated); do \
+	    rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
+	  done; \
+	else \
+	  : ; \
+	fi
+
+info dvi ps pdf html:
+
+$(OBJECTS): ../config.h libgnuintl.h
+bindtextdom.$lo dcgettext.$lo dcigettext.$lo dcngettext.$lo dgettext.$lo dngettext.$lo finddomain.$lo gettext.$lo intl-compat.$lo loadmsgcat.$lo localealias.$lo ngettext.$lo textdomain.$lo: $(srcdir)/gettextP.h $(srcdir)/gmo.h $(srcdir)/loadinfo.h
+hash-string.$lo dcigettext.$lo loadmsgcat.$lo: $(srcdir)/hash-string.h
+explodename.$lo l10nflist.$lo: $(srcdir)/loadinfo.h
+dcigettext.$lo loadmsgcat.$lo plural.$lo plural-exp.$lo: $(srcdir)/plural-exp.h
+dcigettext.$lo: $(srcdir)/eval-plural.h
+localcharset.$lo: $(srcdir)/localcharset.h
+bindtextdom.$lo dcigettext.$lo finddomain.$lo loadmsgcat.$lo localealias.$lo lock.$lo log.$lo: $(srcdir)/lock.h
+localealias.$lo localcharset.$lo relocatable.$lo: $(srcdir)/relocatable.h
+printf.$lo: $(srcdir)/printf-args.h $(srcdir)/printf-args.c $(srcdir)/printf-parse.h $(srcdir)/wprintf-parse.h $(srcdir)/xsize.h $(srcdir)/printf-parse.c $(srcdir)/vasnprintf.h $(srcdir)/vasnwprintf.h $(srcdir)/vasnprintf.c
+
+# A bison-2.1 generated plural.c includes <libintl.h> if ENABLE_NLS.
+PLURAL_DEPS_yes = libintl.h
+PLURAL_DEPS_no =
+plural.$lo: $(PLURAL_DEPS_ at USE_INCLUDED_LIBINTL@)
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES)
+	here=`pwd`; cd $(srcdir) && etags -o $$here/TAGS $(HEADERS) $(SOURCES)
+
+ctags: CTAGS
+
+CTAGS: $(HEADERS) $(SOURCES)
+	here=`pwd`; cd $(srcdir) && ctags -o $$here/CTAGS $(HEADERS) $(SOURCES)
+
+id: ID
+
+ID: $(HEADERS) $(SOURCES)
+	here=`pwd`; cd $(srcdir) && mkid -f$$here/ID $(HEADERS) $(SOURCES)
+
+
+mostlyclean:
+	rm -f *.a *.la *.o *.obj *.lo libintl.res core core.*
+	rm -f libgnuintl.h libintl.h charset.alias ref-add.sed ref-del.sed
+	rm -f -r .libs _libs
+
+clean: mostlyclean
+
+distclean: clean
+	rm -f Makefile ID TAGS
+	if test "$(PACKAGE)" = "gettext-runtime" || test "$(PACKAGE)" = "gettext-tools"; then \
+	  rm -f ChangeLog.inst $(DISTFILES.normal); \
+	else \
+	  : ; \
+	fi
+
+maintainer-clean: distclean
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+
+# GNU gettext needs not contain the file `VERSION' but contains some
+# other files which should not be distributed in other packages.
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: Makefile
+	if test "$(PACKAGE)" = "gettext-tools"; then \
+	  : ; \
+	else \
+	  if test "$(PACKAGE)" = "gettext-runtime"; then \
+	    additional="$(DISTFILES.gettext)"; \
+	  else \
+	    additional="$(DISTFILES.normal)"; \
+	  fi; \
+	  $(MAKE) $(DISTFILES.common) $(DISTFILES.generated) $$additional; \
+	  for file in ChangeLog $(DISTFILES.common) $(DISTFILES.generated) $$additional; do \
+	    if test -f $$file; then dir=.; else dir=$(srcdir); fi; \
+	    cp -p $$dir/$$file $(distdir) || test $$file = Makefile.in || exit 1; \
+	  done; \
+	fi
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	cd $(top_builddir) && $(SHELL) ./config.status
+# This would be more efficient, but doesn't work any more with autoconf-2.57,
+# when AC_CONFIG_FILES([intl/Makefile:somedir/Makefile.in]) is used.
+#	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:


Property changes on: branches/commonification/tuxmath/trunk/linebreak
___________________________________________________________________
Modified: svn:ignore
   - *~
*.o
.deps
CMakeFiles
Makefile
Makefile.in

   + *~
*.o
Makefile
Makefile.in



Property changes on: branches/commonification/tuxmath/trunk/src
___________________________________________________________________
Modified: svn:ignore
   - *~
*.o
.deps
CMakeFiles
Makefile
Makefile.in
tuxmath
tuxmathadmin
generate_lesson

   + *~
*.o
Makefile
Makefile.in
tuxmath
tuxmathadmin
generate-lesson


Modified: branches/commonification/tuxmath/trunk/src/CMakeLists.txt
===================================================================
--- branches/commonification/tuxmath/trunk/src/CMakeLists.txt	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/CMakeLists.txt	2009-11-24 23:54:32 UTC (rev 1674)
@@ -7,6 +7,7 @@
 find_package(SDL_ttf REQUIRED)
 find_package(SDL_mixer REQUIRED)
 find_package(SDL_gfx)
+find_package(SDL_net)
 find_package(t4kcommon)
 
 if (NOT SDLGFX_FOUND)
@@ -14,7 +15,9 @@
   set(TUXMATH_EXTRA_SRC ${TUXMATH_EXTRA_SRC} SDL_rotozoom.c)
 endif (NOT SDLGFX_FOUND)
 
+set (HAVE_LIBT4KCOMMON ${T4KCOMMON_FOUND})
 
+
 ## Define the source files used for each executable
 # tuxmath
 set(SOURCES_TUXMATH
@@ -30,11 +33,13 @@
   lessons.c
   loaders.c
   mathcards.c
+  network.c
   options.c
   pixels.c
   scandir.c
   SDL_extras.c
   setup.c
+  throttle.c
   titlescreen.c
   multiplayer.c
   campaign.c
@@ -71,6 +76,9 @@
 if (SDLGFX_FOUND)
    include_directories(${SDLGFX_INCLUDE_DIR})
 endif (SDLGFX_FOUND)
+if (T4KCOMMON_FOUND)
+   include_directories(${T4KCOMMON_INCLUDE_DIR})
+endif (T4KCOMMON_FOUND)
 
 if (TUXMATH_BUILD_INTL)
   link_directories(${INTL_BINARY_DIR})
@@ -126,6 +134,7 @@
   ${SDLIMAGE_LIBRARY}
   ${SDLTTF_LIBRARY}
   ${SDLMIXER_LIBRARY}
+  ${SDLNET_LIBRARY}
   )
 
 if (SDLPANGO_FOUND)

Modified: branches/commonification/tuxmath/trunk/src/Makefile.am
===================================================================
--- branches/commonification/tuxmath/trunk/src/Makefile.am	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/Makefile.am	2009-11-24 23:54:32 UTC (rev 1674)
@@ -19,11 +19,16 @@
 
 
 if BUILD_MINGW32
-  bin_PROGRAMS = TuxMath
+  bin_PROGRAMS = TuxMath tuxmathserver
   DATA_PREFIX=@MINGW32_PACKAGE_DATA_DIR@
 else
   TUXMATHRC =
-  bin_PROGRAMS = tuxmath tuxmathadmin generate_lesson
+  bin_PROGRAMS = tuxmath \
+                 tuxmathadmin \
+                 generate_lesson \
+                 tuxmathserver	\
+                 tuxmathtestclient
+
   DATA_PREFIX=${pkgdatadir}
 endif
 
@@ -31,6 +36,7 @@
 tuxmath_SOURCES = tuxmath.c \
 	setup.c 	\
 	titlescreen.c	\
+	menu.c		\
 	game.c 		\
 	factoroids.c    \
 	fileops_media.c \
@@ -40,7 +46,7 @@
 	linewrap.c	\
 	loaders.c	\
 	audio.c 	\
-	menu.c   	\
+        network.c       \
 	mathcards.c	\
 	campaign.c	\
 	multiplayer.c	\
@@ -50,7 +56,9 @@
 	SDL_rotozoom.c	\
 	lessons.c	\
 	scandir.c	\
-	pixels.c
+	pixels.c	\
+	server.c	\
+	throttle.c	
 
 
 # HACK "TuxMath" is the Windows program, whereas "tuxmath" is the Unix program
@@ -64,6 +72,18 @@
 		fileops.c	\
 		lessons.c
 
+tuxmathserver_SOURCES = servermain.c	\
+		server.c \
+		mathcards.c	\
+		throttle.c	\
+		options.c
+
+tuxmathtestclient_SOURCES = testclient.c \
+                            throttle.c \
+                            network.c  \
+                            options.c  \
+                            mathcards.c
+
 EXTRA_DIST = 	credits.h 	\
 	factoroids.h	\
 	fileops.h 	\
@@ -73,10 +93,12 @@
 	highscore.h 	\
 	linewrap.h	\
 	loaders.h	\
-	mathcards.h 	\
+        network.h       \
+	titlescreen.h   \
+	menu.h		\
 	options.h	\
 	setup.h		\
-	titlescreen.h	\
+	mathcards.h 	\
 	campaign.h	\
 	multiplayer.h	\
 	tuxmath.h	\
@@ -87,7 +109,12 @@
 	gettext.h	\
 	scandir.h	\
 	pixels.h	\
-	compiler.h
+	compiler.h	\
+	server.h	\
+	testclient.h	\
+	transtruct.h	\
+	throttle.h
+        
 
 
 WINDRES=@WINDRES@
@@ -95,7 +122,3 @@
 # How to make an RC file
 tuxmathrc.o: tuxmathrc.rc
 	$(WINDRES) -i $< -o $@
-
-
-
-

Modified: branches/commonification/tuxmath/trunk/src/SDL_extras.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/SDL_extras.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/SDL_extras.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1210,7 +1210,7 @@
 /* "Public" functions called from other files that use either */
 /*SDL_Pango or SDL_ttf:                                       */
 
-
+#ifndef HAVE_LIBT4KCOMMON
 /* For setup, we either initialize SDL_Pango and set its context, */
 /* or we initialize SDL_ttf:                                      */
 int Setup_SDL_Text(void)
@@ -1274,27 +1274,27 @@
 #ifdef HAVE_LIBSDL_PANGO
   if (!context)
   {
-    fprintf(stderr, "BlackOutline(): invalid SDL_Pango context - returning.");
+    fprintf(stderr, "BlackOutline(): invalid SDL_Pango context - returning.\n");
     return NULL;
   }
 #else
   TTF_Font* font = get_font(size);
   if (!font)
   {
-    fprintf(stderr, "BlackOutline(): could not load needed font - returning.");
+    fprintf(stderr, "BlackOutline(): could not load needed font - returning.\n");
     return NULL;
   }
 #endif
 
   if (!t || !c)
   {
-    fprintf(stderr, "BlackOutline(): invalid ptr parameter, returning.");
+    fprintf(stderr, "BlackOutline(): invalid ptr parameter, returning.\n");
     return NULL;
   }
 
   if (t[0] == '\0')
   {
-    fprintf(stderr, "BlackOutline(): empty string, returning");
+    fprintf(stderr, "BlackOutline(): empty string, returning\n");
     return NULL;
   }
 
@@ -1475,9 +1475,9 @@
 
   return surf;
 }
+#endif //HAVE_LIBT4KCOMMON
 
 
-
 /*-----------------------------------------------------------*/
 /* Local functions, callable only within SDL_extras, divided */
 /* according with which text lib we are using:               */

Modified: branches/commonification/tuxmath/trunk/src/credits.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/credits.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/credits.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -26,7 +26,6 @@
 #include "tuxmath.h"
 #include "options.h"
 #include "fileops.h"
-#include "fileops_media.h"
 #include "setup.h"
 #include "credits.h"
 #include "SDL_extras.h"

Modified: branches/commonification/tuxmath/trunk/src/factoroids.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/factoroids.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/factoroids.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -34,7 +34,6 @@
 
 #include "game.h"
 #include "fileops.h"
-#include "fileops_media.h"
 #include "setup.h"
 #include "mathcards.h"
 #include "loaders.h"

Modified: branches/commonification/tuxmath/trunk/src/fileops.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/fileops.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/fileops.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -16,8 +16,11 @@
 #ifndef FILEOPS_H
 #define FILEOPS_H
 
+#if HAVE_T4KCOMMON
+#include "t4kcommon.h"
+#endif
+
 #include "globals.h"
-#include "SDL.h"
 
 /* Flag basically telling whether or not to allow admin-level */
 /* settings to be changed: */
@@ -26,6 +29,172 @@
   GLOBAL_CONFIG_FILE
 };
 
+/* Names for images (formerly in images.h) */
+enum {
+  IMG_TITLE,
+  IMG_LEFT,
+  IMG_LEFT_GRAY,
+  IMG_RIGHT,
+  IMG_RIGHT_GRAY,
+  IMG_TUX4KIDS,
+  IMG_NBS,
+  IMG_CITY_BLUE,
+  IMG_CITY_BLUE_EXPL1,
+  IMG_CITY_BLUE_EXPL2,
+  IMG_CITY_BLUE_EXPL3,
+  IMG_CITY_BLUE_EXPL4,
+  IMG_CITY_BLUE_EXPL5,
+  IMG_CITY_BLUE_DEAD,
+  IMG_CITY_GREEN,
+  IMG_CITY_GREEN_EXPL1,
+  IMG_CITY_GREEN_EXPL2,
+  IMG_CITY_GREEN_EXPL3,
+  IMG_CITY_GREEN_EXPL4,
+  IMG_CITY_GREEN_EXPL5,
+  IMG_CITY_GREEN_DEAD,
+  IMG_CITY_ORANGE,
+  IMG_CITY_ORANGE_EXPL1,
+  IMG_CITY_ORANGE_EXPL2,
+  IMG_CITY_ORANGE_EXPL3,
+  IMG_CITY_ORANGE_EXPL4,
+  IMG_CITY_ORANGE_EXPL5,
+  IMG_CITY_ORANGE_DEAD,
+  IMG_CITY_RED,
+  IMG_CITY_RED_EXPL1,
+  IMG_CITY_RED_EXPL2,
+  IMG_CITY_RED_EXPL3,
+  IMG_CITY_RED_EXPL4,
+  IMG_CITY_RED_EXPL5,
+  IMG_CITY_RED_DEAD,
+  IMG_SHIELDS,
+  IMG_MINI_COMET1,
+  IMG_MINI_COMET2,
+  IMG_MINI_COMET3,
+  IMG_NUMS,
+  IMG_LEDNUMS,
+  IMG_LED_NEG_SIGN,
+  IMG_PAUSED,
+  IMG_DEMO,
+  IMG_DEMO_SMALL,
+  IMG_KEYPAD,
+  IMG_KEYPAD_NO_NEG,
+  IMG_CONSOLE_LED,
+  IMG_CONSOLE_BASH,
+  IMG_TUX_CONSOLE1,
+  IMG_TUX_CONSOLE2,
+  IMG_TUX_CONSOLE3,
+  IMG_TUX_CONSOLE4,
+  IMG_TUX_RELAX1,
+  IMG_TUX_RELAX2,
+  IMG_TUX_EGYPT1,
+  IMG_TUX_EGYPT2,
+  IMG_TUX_EGYPT3,
+  IMG_TUX_EGYPT4,
+  IMG_TUX_RELAX,
+  IMG_TUX_ALARM,
+  IMG_TUX_DRAT,
+  IMG_TUX_YIPE,
+  IMG_TUX_YAY1,
+  IMG_TUX_YAY2,
+  IMG_TUX_YES1,
+  IMG_TUX_YES2,
+  IMG_TUX_SIT,
+  IMG_TUX_FIST1,
+  IMG_TUX_FIST2,
+  IMG_PENGUIN_FLAPDOWN,
+  IMG_PENGUIN_FLAPUP,
+  IMG_PENGUIN_INCOMING,
+  IMG_PENGUIN_GRUMPY,
+  IMG_PENGUIN_WORRIED,
+  IMG_PENGUIN_STANDING_UP,
+  IMG_PENGUIN_SITTING_DOWN,
+  IMG_PENGUIN_WALK_ON1,
+  IMG_PENGUIN_WALK_ON2,
+  IMG_PENGUIN_WALK_ON3,
+  IMG_PENGUIN_WALK_OFF1,
+  IMG_PENGUIN_WALK_OFF2,
+  IMG_PENGUIN_WALK_OFF3,
+  IMG_IGLOO_MELTED3,
+  IMG_IGLOO_MELTED2,
+  IMG_IGLOO_MELTED1,
+  IMG_IGLOO_HALF,
+  IMG_IGLOO_INTACT,
+  IMG_IGLOO_REBUILDING1,
+  IMG_IGLOO_REBUILDING2,
+  IMG_STEAM1,
+  IMG_STEAM2,
+  IMG_STEAM3,
+  IMG_STEAM4,
+  IMG_STEAM5,
+  IMG_CLOUD,
+  IMG_SNOW1,
+  IMG_SNOW2,
+  IMG_SNOW3,
+  IMG_EXTRA_LIFE,
+  IMG_WAVE,
+  IMG_SCORE,
+  IMG_STOP,
+  IMG_NUMBERS,
+  IMG_GAMEOVER,
+  IMG_GAMEOVER_WON,
+  BG_STARS,
+  IMG_ASTEROID1,
+  IMG_ASTEROID2,
+  IMG_ASTEROID3,
+  IMG_SHIP01,
+  IMG_FACTOROIDS,
+  IMG_FACTORS,
+  IMG_TUX_LITTLE,
+  IMG_GOOD,
+  NUM_IMAGES
+};
+
+/* Names for animated images (sprites) */
+enum {
+  IMG_COMET,
+  IMG_BONUS_COMET,
+  IMG_COMET_EXPL,
+  IMG_BONUS_COMET_EXPL,
+  ANIM_COMET,
+  ANIM_BONUS_COMET,
+  ANIM_COMET_EXPL,
+  ANIM_BONUS_COMET_EXPL,
+  ANIM_COMET_MINI,
+  ANIM_TUX_CONSOLE,
+  ANIM_TUX_EGYPT_LEFT,
+  ANIM_TUX_EGYPT_RIGHT,
+  ANIM_TUX_YAY,
+  ANIM_TUX_YES,
+  ANIM_TUX_FIST,
+  ANIM_STEAM,
+  NUM_SPRITES
+};
+
+/* Names for game sounds (formerly in sounds.h): */
+enum {
+  SND_HARP,
+  SND_POP,
+  SND_TOCK,
+  SND_LASER,
+  SND_BUZZ,
+  SND_ALARM,
+  SND_SHIELDSDOWN,
+  SND_EXPLOSION,
+  SND_CLICK,
+  SND_SIZZLE,
+  SND_BONUS_COMET,
+  SND_EXTRA_LIFE,
+  NUM_SOUNDS
+};
+
+/* Names for background music (also formerly in sounds.h): */
+enum {
+  MUS_GAME,
+  MUS_GAME2,
+  MUS_GAME3,
+  NUM_MUSICS
+};
+
 /* Names for game summary files: */
 enum {
   SUMMARY1,
@@ -64,4 +233,15 @@
 /* These functions used by game() to record game summary: */
 int write_pregame_summary(void);
 int write_postgame_summary(void);
+
+int load_image_data();
+int            SetImage(int id, SDL_Rect* rect);
+SDL_Surface*   GetImage(int id);
+sprite*        GetSprite(int id);
+
+
+#ifndef NOSOUND
+int load_sound_data();
 #endif
+
+#endif

Modified: branches/commonification/tuxmath/trunk/src/fileops_media.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/fileops_media.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/fileops_media.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,5 +1,5 @@
 #include "tuxmath.h"
-#include "fileops_media.h"
+#include "fileops.h"
 #include "loaders.h"
 #include "options.h"
 #include "SDL_extras.h"
@@ -17,135 +17,138 @@
 /* TODO load only "igloo" or "city" files, not both.             */
 /* TODO get rid of files no longer used.                         */
 
-static char fn[PATH_MAX];
+int load_image_data()
+{
+  int i;
 
-static char* image_filenames[NUM_IMAGES] = {
-  "status/title.svg",
-  "status/left.svg",
-  "status/left_gray.svg",
-  "status/right.svg",
-  "status/right_gray.svg",
-  "status/tux4kids.svg",
-  "status/nbs.svg",
-  "cities/city-blue.svg",
-  "cities/csplode-blue-1.svg",
-  "cities/csplode-blue-2.svg",
-  "cities/csplode-blue-3.svg",
-  "cities/csplode-blue-4.svg",
-  "cities/csplode-blue-5.svg",
-  "cities/cdead-blue.svg",
-  "cities/city-green.svg",
-  "cities/csplode-green-1.svg",
-  "cities/csplode-green-2.svg",
-  "cities/csplode-green-3.svg",
-  "cities/csplode-green-4.svg",
-  "cities/csplode-green-5.svg",
-  "cities/cdead-green.svg",
-  "cities/city-orange.svg",
-  "cities/csplode-orange-1.svg",
-  "cities/csplode-orange-2.svg",
-  "cities/csplode-orange-3.svg",
-  "cities/csplode-orange-4.svg",
-  "cities/csplode-orange-5.svg",
-  "cities/cdead-orange.svg",
-  "cities/city-red.svg",
-  "cities/csplode-red-1.svg",
-  "cities/csplode-red-2.svg",
-  "cities/csplode-red-3.svg",
-  "cities/csplode-red-4.svg",
-  "cities/csplode-red-5.svg",
-  "cities/cdead-red.svg",
-  "cities/shields.svg",
-  "status/nums.svg",
-  "status/lednums.svg",
-  "status/led_neg_sign.svg",
-  "status/paused.svg",
-  "status/demo.svg",
-  "status/demo-small.svg",
-  "status/keypad.svg",
-  "status/keypad_no_neg.svg",
-  "tux/console_led.svg",
-  "tux/console_bash.svg",
-  "tux/tux-relax.svg",
-  "tux/tux-alarm.svg",
-  "tux/tux-drat.svg",
-  "tux/tux-yipe.svg",
-  "tux/tux-sit.svg",
-  "penguins/flapdown.svg",
-  "penguins/flapup.svg",
-  "penguins/incoming.svg",
-  "penguins/grumpy.svg",
-  "penguins/worried.svg",
-  "penguins/standing-up.svg",
-  "penguins/sitting-down.svg",
-  "penguins/walk-on1.svg",
-  "penguins/walk-on2.svg",
-  "penguins/walk-on3.svg",
-  "penguins/walk-off1.svg",
-  "penguins/walk-off2.svg",
-  "penguins/walk-off3.svg",
-  "igloos/melted3.svg",
-  "igloos/melted2.svg",
-  "igloos/melted1.svg",
-  "igloos/half.svg",
-  "igloos/intact.svg",
-  "igloos/rebuilding1.svg",
-  "igloos/rebuilding2.svg",
-  "igloos/cloud.svg",
-  "igloos/snow1.svg",
-  "igloos/snow2.svg",
-  "igloos/snow3.svg",
-  "igloos/extra_life.svg",
-  "status/wave.svg",
-  "status/score.svg",
-  "status/stop.svg",
-  "status/numbers.svg",
-  "status/gameover.svg",
-  "status/gameover_won.svg",
-  "factoroids/gbstars.svg",
-  "factoroids/asteroid1.svg",
-  "factoroids/asteroid2.svg",
-  "factoroids/asteroid3.svg",
-  "factoroids/ship01.svg",
-  "factoroids/factoroids.svg",
-  "factoroids/factors.svg",
-  "factoroids/tux.svg",
-  "factoroids/good.svg"
+  static char* image_filenames[NUM_IMAGES] = {
+  "status/title.png",
+  "status/left.png",
+  "status/left_gray.png",
+  "status/right.png",
+  "status/right_gray.png",
+  "status/tux4kids.png",
+  "status/nbs.png",
+  "cities/city-blue.png",
+  "cities/csplode-blue-1.png",
+  "cities/csplode-blue-2.png",
+  "cities/csplode-blue-3.png",
+  "cities/csplode-blue-4.png",
+  "cities/csplode-blue-5.png",
+  "cities/cdead-blue.png",
+  "cities/city-green.png",
+  "cities/csplode-green-1.png",
+  "cities/csplode-green-2.png",
+  "cities/csplode-green-3.png",
+  "cities/csplode-green-4.png",
+  "cities/csplode-green-5.png",
+  "cities/cdead-green.png",
+  "cities/city-orange.png",
+  "cities/csplode-orange-1.png",
+  "cities/csplode-orange-2.png",
+  "cities/csplode-orange-3.png",
+  "cities/csplode-orange-4.png",
+  "cities/csplode-orange-5.png",
+  "cities/cdead-orange.png",
+  "cities/city-red.png",
+  "cities/csplode-red-1.png",
+  "cities/csplode-red-2.png",
+  "cities/csplode-red-3.png",
+  "cities/csplode-red-4.png",
+  "cities/csplode-red-5.png",
+  "cities/cdead-red.png",
+  "cities/shields.png",
+  "comets/mini_comet1.png",
+  "comets/mini_comet2.png",
+  "comets/mini_comet3.png",
+  "status/nums.png",
+  "status/lednums.png",
+  "status/led_neg_sign.png",
+  "status/paused.png",
+  "status/demo.png",
+  "status/demo-small.png",
+  "status/keypad.png",
+  "status/keypad_no_neg.png",
+  "tux/console_led.png",
+  "tux/console_bash.png",
+  "tux/tux-console1.png",
+  "tux/tux-console2.png",
+  "tux/tux-console3.png",
+  "tux/tux-console4.png",
+  "tux/tux-relax1.png",
+  "tux/tux-relax2.png",
+  "tux/tux-egypt1.png",
+  "tux/tux-egypt2.png",
+  "tux/tux-egypt3.png",
+  "tux/tux-egypt4.png",
+  "tux/tux-drat.png",
+  "tux/tux-yipe.png",
+  "tux/tux-yay1.png",
+  "tux/tux-yay2.png",
+  "tux/tux-yes1.png",
+  "tux/tux-yes2.png",
+  "tux/tux-sit.png",
+  "tux/tux-fist1.png",
+  "tux/tux-fist2.png",
+  "penguins/flapdown.png",
+  "penguins/flapup.png",
+  "penguins/incoming.png",
+  "penguins/grumpy.png",
+  "penguins/worried.png",
+  "penguins/standing-up.png",
+  "penguins/sitting-down.png",
+  "penguins/walk-on1.png",
+  "penguins/walk-on2.png",
+  "penguins/walk-on3.png",
+  "penguins/walk-off1.png",
+  "penguins/walk-off2.png",
+  "penguins/walk-off3.png",
+  "igloos/melted3.png",
+  "igloos/melted2.png",
+  "igloos/melted1.png",
+  "igloos/half.png",
+  "igloos/intact.png",
+  "igloos/rebuilding1.png",
+  "igloos/rebuilding2.png",
+  "igloos/steam1.png",
+  "igloos/steam2.png",
+  "igloos/steam3.png",
+  "igloos/steam4.png",
+  "igloos/steam5.png",
+  "igloos/cloud.png",
+  "igloos/snow1.png",
+  "igloos/snow2.png",
+  "igloos/snow3.png",
+  "igloos/extra_life.png",
+  "status/wave.png",
+  "status/score.png",
+  "status/stop.png",
+  "status/numbers.png",
+  "status/gameover.png",
+  "status/gameover_won.png",
+  "factoroids/gbstars.png",
+  "factoroids/asteroid1.png",
+  "factoroids/asteroid2.png",
+  "factoroids/asteroid3.png",
+  "factoroids/ship01.png",
+  "factoroids/factoroids.png",
+  "factoroids/factors.png",
+  "factoroids/tux.png",
+  "factoroids/good.png"
   };
 
-static char* sprite_filenames[NUM_IMAGES] = {
+  static char* sprite_filenames[NUM_IMAGES] = {
   "comets/comet",
   "comets/bonus_comet",
   "comets/cometex",
-  "comets/bonus_cometex",
-  "comets/mini_comet",
-  "tux/tux-console",
-  "tux/tux-egypt-left",
-  "tux/tux-egypt-right",
-  "tux/tux-yay",
-  "tux/tux-yes",
-  "tux/tux-fist",
-  "igloos/steam"
+  "comets/bonus_cometex"
   };
 
-
-int load_image_data()
-{
-  int i;
-
   /* Load static images: */
   for (i = 0; i < NUM_IMAGES; i++)
   {
-    if(images[i])
-    {
-      DEBUGMSG(debug_loaders, "load_image_data(): file %s already loaded\n",
-                              image_filenames[i]);
-      continue;
-    }
+    images[i] = LoadImage(image_filenames[i], IMG_ALPHA);
 
-    sprintf(fn, "%s%s%s", DATA_PREFIX, "/images/", image_filenames[i]);
-    images[i] = LoadImage(fn, IMG_ALPHA);
-
     if (images[i] == NULL)
     {
       fprintf(stderr,
@@ -160,8 +163,7 @@
   /* Load animated graphics: */
   for (i = 0; i < NUM_SPRITES; i++)
   {
-    sprintf(fn, "%s%s%s", DATA_PREFIX, "/images/", sprite_filenames[i]);
-    sprites[i] = LoadSprite(fn, IMG_ALPHA);
+    sprites[i] = LoadSprite(sprite_filenames[i], IMG_ALPHA);
 
     if (sprites[i] == NULL)
     {
@@ -174,7 +176,6 @@
     }
   }
 
-
   glyph_offset = 0;
 
 #ifdef REPLACE_WAVESCORE
@@ -190,41 +191,10 @@
   return 1;
 }
 
-SDL_Surface* GetImage(int id)
-{
-    return images[id];
-}
 
-sprite* GetSprite(int id)
-{
-    return sprites[id];
-}
 
-int SetImage(int id, SDL_Rect* rect)
-{
-  if(images[id])
-    SDL_FreeSurface(images[id]);
-  sprintf(fn, "%s%s%s", DATA_PREFIX, "/images/", image_filenames[id]);
-  if(rect)
-    images[id] = LoadImageOfBoundingBox(fn, IMG_ALPHA, rect->w, rect->h);
-  else
-    images[id] = LoadImage(fn, IMG_ALPHA);
 
-  if(NULL == images[id])
-  {
-    fprintf(stderr,
-            "\nError: I couldn't load a graphics file:\n"
-            "%s\n"
-            "The Simple DirectMedia error that occured was:\n"
-            "%s\n\n", image_filenames[id], SDL_GetError());
-    return 0;
-  }
 
-  return 1;
-}
-
-
-
 #ifndef NOSOUND
 int load_sound_data(void)
 {
@@ -239,7 +209,6 @@
   DATA_PREFIX "/sounds/alarm.wav",
   DATA_PREFIX "/sounds/shieldsdown.wav",
   DATA_PREFIX "/sounds/explosion.wav",
-  DATA_PREFIX "/sounds/click.wav",
   DATA_PREFIX "/sounds/sizzling.wav",
   DATA_PREFIX "/sounds/towerclock.wav",
   DATA_PREFIX "/sounds/cheer.wav"

Deleted: branches/commonification/tuxmath/trunk/src/fileops_media.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/fileops_media.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/fileops_media.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,156 +0,0 @@
-#ifndef FILEOPS_MEDIA_H
-#define FILEOPS_MEDIA_H
-
-#include "globals.h"
-#include "SDL.h"
-
-/* Names for images (formerly in images.h) */
-enum {
-  IMG_TITLE,
-  IMG_LEFT,
-  IMG_LEFT_GRAY,
-  IMG_RIGHT,
-  IMG_RIGHT_GRAY,
-  IMG_TUX4KIDS,
-  IMG_NBS,
-  IMG_CITY_BLUE,
-  IMG_CITY_BLUE_EXPL1,
-  IMG_CITY_BLUE_EXPL2,
-  IMG_CITY_BLUE_EXPL3,
-  IMG_CITY_BLUE_EXPL4,
-  IMG_CITY_BLUE_EXPL5,
-  IMG_CITY_BLUE_DEAD,
-  IMG_CITY_GREEN,
-  IMG_CITY_GREEN_EXPL1,
-  IMG_CITY_GREEN_EXPL2,
-  IMG_CITY_GREEN_EXPL3,
-  IMG_CITY_GREEN_EXPL4,
-  IMG_CITY_GREEN_EXPL5,
-  IMG_CITY_GREEN_DEAD,
-  IMG_CITY_ORANGE,
-  IMG_CITY_ORANGE_EXPL1,
-  IMG_CITY_ORANGE_EXPL2,
-  IMG_CITY_ORANGE_EXPL3,
-  IMG_CITY_ORANGE_EXPL4,
-  IMG_CITY_ORANGE_EXPL5,
-  IMG_CITY_ORANGE_DEAD,
-  IMG_CITY_RED,
-  IMG_CITY_RED_EXPL1,
-  IMG_CITY_RED_EXPL2,
-  IMG_CITY_RED_EXPL3,
-  IMG_CITY_RED_EXPL4,
-  IMG_CITY_RED_EXPL5,
-  IMG_CITY_RED_DEAD,
-  IMG_SHIELDS,
-  IMG_NUMS,
-  IMG_LEDNUMS,
-  IMG_LED_NEG_SIGN,
-  IMG_PAUSED,
-  IMG_DEMO,
-  IMG_DEMO_SMALL,
-  IMG_KEYPAD,
-  IMG_KEYPAD_NO_NEG,
-  IMG_CONSOLE_LED,
-  IMG_CONSOLE_BASH,
-  IMG_TUX_RELAX,
-  IMG_TUX_ALARM,
-  IMG_TUX_DRAT,
-  IMG_TUX_YIPE,
-  IMG_TUX_SIT,
-  IMG_PENGUIN_FLAPDOWN,
-  IMG_PENGUIN_FLAPUP,
-  IMG_PENGUIN_INCOMING,
-  IMG_PENGUIN_GRUMPY,
-  IMG_PENGUIN_WORRIED,
-  IMG_PENGUIN_STANDING_UP,
-  IMG_PENGUIN_SITTING_DOWN,
-  IMG_PENGUIN_WALK_ON1,
-  IMG_PENGUIN_WALK_ON2,
-  IMG_PENGUIN_WALK_ON3,
-  IMG_PENGUIN_WALK_OFF1,
-  IMG_PENGUIN_WALK_OFF2,
-  IMG_PENGUIN_WALK_OFF3,
-  IMG_IGLOO_MELTED3,
-  IMG_IGLOO_MELTED2,
-  IMG_IGLOO_MELTED1,
-  IMG_IGLOO_HALF,
-  IMG_IGLOO_INTACT,
-  IMG_IGLOO_REBUILDING1,
-  IMG_IGLOO_REBUILDING2,
-  IMG_CLOUD,
-  IMG_SNOW1,
-  IMG_SNOW2,
-  IMG_SNOW3,
-  IMG_EXTRA_LIFE,
-  IMG_WAVE,
-  IMG_SCORE,
-  IMG_STOP,
-  IMG_NUMBERS,
-  IMG_GAMEOVER,
-  IMG_GAMEOVER_WON,
-  BG_STARS,
-  IMG_ASTEROID1,
-  IMG_ASTEROID2,
-  IMG_ASTEROID3,
-  IMG_SHIP01,
-  IMG_FACTOROIDS,
-  IMG_FACTORS,
-  IMG_TUX_LITTLE,
-  IMG_GOOD,
-  NUM_IMAGES
-};
-
-/* Names for animated images (sprites) */
-enum {
-  ANIM_COMET,
-  ANIM_BONUS_COMET,
-  ANIM_COMET_EXPL,
-  ANIM_BONUS_COMET_EXPL,
-  ANIM_COMET_MINI,
-  ANIM_TUX_CONSOLE,
-  ANIM_TUX_EGYPT_LEFT,
-  ANIM_TUX_EGYPT_RIGHT,
-  ANIM_TUX_YAY,
-  ANIM_TUX_YES,
-  ANIM_TUX_FIST,
-  ANIM_STEAM,
-  NUM_SPRITES
-};
-
-/* Names for game sounds (formerly in sounds.h): */
-enum {
-  SND_HARP,
-  SND_POP,
-  SND_TOCK,
-  SND_LASER,
-  SND_BUZZ,
-  SND_ALARM,
-  SND_SHIELDSDOWN,
-  SND_EXPLOSION,
-  SND_CLICK,
-  SND_SIZZLE,
-  SND_BONUS_COMET,
-  SND_EXTRA_LIFE,
-  NUM_SOUNDS
-};
-
-/* Names for background music (also formerly in sounds.h): */
-enum {
-  MUS_GAME,
-  MUS_GAME2,
-  MUS_GAME3,
-  NUM_MUSICS
-};
-
-
-int            load_image_data();
-int            SetImage(int id, SDL_Rect* rect);
-SDL_Surface*   GetImage(int id);
-sprite*        GetSprite(int id);
-
-#ifndef NOSOUND
-int            load_sound_data();
-#endif
-
-
-#endif

Modified: branches/commonification/tuxmath/trunk/src/game.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/game.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/game.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -15,7 +15,7 @@
   August 26, 2001 - February 18, 2004
 
   Revised by David Bruce, Tim Holy and others
-  2005-2007
+  2005-2009
 */
 
 /* put this first so we get <config.h> and <gettext.h> immediately: */
@@ -26,14 +26,21 @@
 #include <string.h>
 
 #include "SDL.h"
+#include "SDL_image.h"
+
 #ifndef NOSOUND
 #include "SDL_mixer.h"
 #endif
-#include "SDL_image.h"
 
+/* Make sure we don't try to call network code if we built without */
+/* network support:                                                */
+#ifdef HAVE_LIBSDL_NET
+#include "network.h"
+#endif
+
+#include "transtruct.h"
 #include "game.h"
 #include "fileops.h"
-#include "fileops_media.h"
 #include "setup.h"
 #include "loaders.h"
 #include "mathcards.h"
@@ -41,7 +48,10 @@
 #include "titlescreen.h"
 #include "options.h"
 #include "SDL_extras.h"
+#include "pixels.h"
+#include "throttle.h"
 
+
 #define FPS 15                     /* 15 frames per second */
 #define MS_PER_FRAME (1000 / FPS)
 
@@ -96,6 +106,7 @@
 static int gameover_counter;
 static int game_status;
 static int user_quit_received;
+static int total_questions_left;
 static int paused;
 static int wave;
 static int score;
@@ -107,7 +118,6 @@
 static int demo_countdown;
 static int tux_anim_frame;
 static int num_cities_alive;
-static int num_comets_alive;
 static int frame;
 static int neg_answer_picked;
 static int tux_pressing;
@@ -119,6 +129,8 @@
 static int bonus_comet_counter;
 static int extra_life_earned;
 static int key_pressed;
+static int game_over_other;
+static int game_over_won;
 
 static SDL_Surface* tux_img = NULL;
 static SDL_Surface* old_tux_img = NULL;
@@ -148,6 +160,14 @@
 static game_message s1, s2, s3, s4, s5;
 static int start_message_chosen = 0;
 
+/*****************************************************************/
+MC_FlashCard quest_queue[QUEST_QUEUE_SIZE];    //current questions
+int remaining_quests = 0;
+static int comet_counter = 0;
+static int lan_players = 0;
+char lan_pnames[MAX_CLIENTS][NAME_SIZE];
+int lan_pscores[MAX_CLIENTS];
+/****************************************************************/
 
 typedef struct {
   int x_is_blinking;
@@ -179,10 +199,10 @@
 static int check_extra_life(void);
 static int check_exit_conditions(void);
 
-static void game_set_message(game_message *,const char *,int x, int y);
+static void game_set_message(game_message*, const char* ,int x, int y);
 static void game_clear_message(game_message*);
 static void game_clear_messages(void);
-static void game_write_message(const game_message* msg);
+void game_write_message(const game_message* msg);
 static void game_write_messages(void);
 static void draw_led_console(void);
 static void draw_question_counter(void);
@@ -192,6 +212,7 @@
 static int add_comet(void);
 static void add_score(int inc);
 static void reset_comets(void);
+static int num_comets_alive(void);
 
 static void game_mouse_event(SDL_Event event);
 static void game_key_event(SDLKey key);
@@ -203,75 +224,64 @@
 
 void putpixel(SDL_Surface* surface, int x, int y, Uint32 pixel);
 
+/*****************************************************/
+#ifdef HAVE_LIBSDL_NET
+void game_handle_net_messages(void);
+void game_handle_net_msg(char* buf);
+int add_quest_recvd(char* buf);
+int remove_quest_recvd(char* buf);
+int connected_players_recvd(char* buf);
+int update_score_recvd(char* buf);
+int erase_comet_on_screen(comet_type* comet_ques);
+void print_current_quests(void);
+MC_FlashCard* search_queue_by_id(int id);
+comet_type* search_comets_by_id(int id);
+/******************************************************/
+#endif
+
+
 static void print_exit_conditions(void);
 static void print_status(void);
 
 
-/* load all game graphics in required sizes,
-   return 0 on failure */
-int PrerenderGraphics()
-{
-  SDL_Rect rt;
-  int i;
-
-  for(i = 0; i < POSITIONED_IMAGES; i++)
-  {
-    SetRect(&rt, img_pos[i]);
-    if(!SetImage(img_ids[i], &rt))
-      return 0;
-  }
-
-  rt.w = 10000; /* these images may be long */
-  rt.h = CONSOLE_SCREEN_H * GetImage(IMG_CONSOLE_LED)->h;
-  if(!SetImage(IMG_LEDNUMS, &rt))
-    return 0;
-  if(!SetImage(IMG_LED_NEG_SIGN, &rt))
-    return 0;
-
-  return 1;
-}
-
 /* --- MAIN GAME FUNCTION!!! --- */
 
 
 int game(void)
 {
-  Uint32 last_time, now_time;
+  Uint32 timer = 0;
   int num_frames;
 
   DEBUGMSG(debug_game, "Entering game():\n");
 
   //see if the option matches the actual screen
   if (Opts_GetGlobalOpt(FULLSCREEN) == !(GetScreen()->flags & SDL_FULLSCREEN) )
-    {
-    ;//SwitchScreenMode();
-    }
+  {
+    ;//SwitchScreenMode();  //Huh??
+  }
 
 
    /* most code moved into smaller functions (game_*()): */
   if (!game_initialize())
   {
     fprintf(stderr, "\ngame_initialize() failed!");
-    /* return 0 so we go back to Options screen - maybe */
-    /* player simply has all operations deselected */
-//    free_on_exit();
     return 0;
   }
 
+
   if (Opts_HelpMode()) {
     game_handle_help();
     game_cleanup();
     return GAME_OVER_OTHER;
   }
+ 
 
 
-
   /* --- MAIN GAME LOOP: --- */
   do
   {
     /* reset or increment various things with each loop: */
     frame++;
-    last_time = SDL_GetTicks();
     old_tux_img = tux_img;
     tux_pressing = 0;
 
@@ -280,6 +290,13 @@
       laser.alive--;
     }
 
+    /* Check for server messages if we are playing a LAN game: */
+#ifdef HAVE_LIBSDL_NET
+    if(Opts_LanMode())
+    {
+      game_handle_net_messages();
+    }
+#endif
     /* Most code now in smaller functions: */
 
     // 1. Check for user input
@@ -297,9 +314,8 @@
     // 3. Redraw:
     game_draw();
     // 4. Figure out if we should leave loop:
-    game_status = check_exit_conditions();
+    game_status = check_exit_conditions(); 
 
-
     /* If we're in "PAUSE" mode, pause! */
     if (paused)
     {
@@ -319,22 +335,15 @@
     }
 #endif
 
+
     /* Pause (keep frame-rate event) */
-    now_time = SDL_GetTicks();
-    if (now_time < last_time + MS_PER_FRAME)
-    {
-      //Prevent any possibility of a time wrap-around
-      // (this is a very unlikely problem unless there is an SDL bug
-      //  or you leave tuxmath running for 49 days...)
-      now_time = (last_time+MS_PER_FRAME) - now_time;  // this holds the delay
-      if (now_time > MS_PER_FRAME)
-        now_time = MS_PER_FRAME;
-      SDL_Delay(now_time);
-    }
+    Throttle(MS_PER_FRAME, &timer);
+
   }
   while(GAME_IN_PROGRESS == game_status);
   /* END OF MAIN GAME LOOP! */
 
+
   DEBUGCODE(debug_game) print_exit_conditions();
 
   /* TODO: need better "victory" screen with animation, special music, etc., */
@@ -361,7 +370,6 @@
       do
       {
         frame++;
-        last_time = SDL_GetTicks();
 
         while (SDL_PollEvent(&event) > 0)
         {
@@ -376,8 +384,6 @@
         if (current_bkgd() )
           SDL_BlitSurface(current_bkgd(), NULL, GetScreen(), NULL);
 
-
-
         /* draw flashing victory message: */
         if (((frame / 2) % 4))
         {
@@ -417,20 +423,14 @@
 /*        draw_console_image(tux_img);*/
 
         SDL_Flip(GetScreen());
-
-        now_time = SDL_GetTicks();
-
-        if (now_time < last_time + MS_PER_FRAME)
-          SDL_Delay(last_time + MS_PER_FRAME - now_time);
+        Throttle(MS_PER_FRAME, &timer);
       }
       while (looping);
       break;
     }
 
     case GAME_OVER_ERROR:
-    {
-      printf("\ngame() exiting with error");
-    }
+      DEBUGMSG(debug_game, "game() exiting with error:\n");
     case GAME_OVER_LOST:
     case GAME_OVER_OTHER:
     {
@@ -445,7 +445,6 @@
       do
       {
         frame++;
-        last_time = SDL_GetTicks();
 
         while (SDL_PollEvent(&event) > 0)
         {
@@ -460,10 +459,7 @@
         SDL_BlitSurface(GetImage(IMG_GAMEOVER), NULL, GetScreen(), &dest_message);
         SDL_Flip(GetScreen());
 
-        now_time = SDL_GetTicks();
-
-        if (now_time < last_time + MS_PER_FRAME)
-          SDL_Delay(last_time + MS_PER_FRAME - now_time);
+        Throttle(MS_PER_FRAME, &timer);
       }
       while (looping);
 
@@ -498,15 +494,343 @@
   {
     /* program exits: */
     cleanup();
+    DEBUGMSG(debug_game, "Leaving game() from window close\n");
     return 1;
   }
   else
   {
     /* return to title() screen: */
+    DEBUGMSG(debug_game, "Leaving game() normally\n");
     return game_status;
   }
 }
 
+
+
+
+
+
+#ifdef HAVE_LIBSDL_NET
+/*****************   Functions for LAN support  *****************/
+
+/*Examines the network messages from the buffer and calls
+  appropriate function accordingly*/
+
+void game_handle_net_messages(void)
+{
+  char buf[NET_BUF_LEN];
+  int done = 0;
+  while(!done)
+  {
+    switch(LAN_NextMsg(buf))
+    {
+      case 1:   //Message received (e.g. a new question):
+        game_handle_net_msg(buf);
+        break;
+      case 0:   //No more messages:
+        done = 1;
+        break;
+      case -1:  //Error in networking or server:
+        game_cleanup();
+        game_status = GAME_OVER_ERROR;
+      default:
+        {}
+    }
+  }
+}
+
+
+void game_handle_net_msg(char* buf)
+{
+  DEBUGMSG(debug_lan, "Received server message: %s\n", buf);
+
+  if(strncmp(buf, "PLAYER_MSG", strlen("PLAYER_MSG")) == 0)
+  {
+    printf("buf is %s\n", buf);                                                  
+  }
+
+  else if(strncmp(buf, "ADD_QUESTION", strlen("ADD_QUESTION")) == 0)
+  {
+    if(!add_quest_recvd(buf))
+      printf("ADD_QUESTION received but could not add question\n");
+    else  
+      DEBUGCODE(debug_game) print_current_quests();
+  }
+
+  else if(strncmp(buf, "REMOVE_QUESTION", strlen("REMOVE_QUESTION")) == 0)
+  {
+    if(!remove_quest_recvd(buf)) //remove the question with id in buf
+      printf("REMOVE_QUESTION received but could not remove question\n");
+    else 
+      DEBUGCODE(debug_game) print_current_quests();
+  }
+
+  else if(strncmp(buf, "TOTAL_QUESTIONS", strlen("TOTAL_QUESTIONS")) == 0)
+  {
+    sscanf(buf,"%*s %d", &total_questions_left);
+    if(!total_questions_left)
+      game_over_other = 1;
+  }
+
+  else if(strncmp(buf, "CONNECTED_PLAYERS", strlen("CONNECTED_PLAYERS")) == 0)
+  {
+    connected_players_recvd(buf);
+  }
+
+  else if(strncmp(buf, "UPDATE_SCORE", strlen("UPDATE_SCORE")) == 0)
+  {
+    update_score_recvd(buf);
+  }
+
+  else if(strncmp(buf, "MISSION_ACCOMPLISHED", strlen("MISSION_ACCOMPLISHED")) == 0)
+  {
+    game_over_won = 1;
+  }
+  else
+  {
+    DEBUGMSG(debug_game, "Unrecognized message from server: %s\n", buf);
+  }  
+}
+
+
+int add_quest_recvd(char* buf)
+{
+  /* Empty slots indicated by question_id == -1 */
+  MC_FlashCard* fc = search_queue_by_id(-1);
+
+  DEBUGMSG(debug_game, "Enter add_quest_recvd(), buf is: %s\n", buf);
+
+  // if fc = NULL means no empty slot for question
+  if(!buf)
+  {
+    printf("NULL buf\n");
+    return 0;
+  }
+
+  if(!fc)
+  {
+    printf("NULL fc - no empty slot for question\n");
+    return 0;
+  }
+
+  /* function call to parse buffer and receive question */
+  if(!Make_Flashcard(buf, fc))
+  {
+    printf("Unable to parse buffer into FlashCard\n");
+    return 0;
+  }
+
+  DEBUGCODE(debug_game) print_current_quests();
+
+  /* If we have an open comet slot, put question in: */
+  
+  if(num_attackers > 0)
+    if(add_comet())
+      num_attackers--;
+
+  return 1;
+}
+
+
+int remove_quest_recvd(char* buf)
+{
+  int id = 0;
+  char* p = NULL;
+  MC_FlashCard* fc = NULL;
+  comet_type* comet_screen;
+
+  if(!buf)
+    return 0;
+
+  p = strchr(buf, '\t');
+  if(!p)
+    return 0;
+
+  p++;
+  id = atoi(p);
+
+  DEBUGMSG(debug_game, "remove_quest_recvd() for id = %d\n", id);
+
+  if(id < 1)  // The question_id can never be negative or zero
+    return 0;
+
+  comet_screen = search_comets_by_id(id);
+  fc = search_queue_by_id(id);
+  if(!comet_screen && !fc)
+    return 0;
+
+  if(comet_screen)
+  {
+    DEBUGMSG(debug_game, "comet on screen found with question_id = %d\n", id);
+    erase_comet_on_screen(comet_screen);
+  }
+
+  //NOTE: normally the question should no longer be in the queue,
+  //so the next statement should not get executed:
+  if(fc)
+  {
+    DEBUGMSG(debug_game,
+             "Note - request to erase question still in queue: %s\n",
+             fc->formula_string);
+    MC_ResetFlashCard(fc);
+  }
+
+  return 1;
+}
+
+
+/* Here we have been told how many LAN players are still    */
+/* in the game. This should always be followed by a series  */
+/* of UPDATE_SCORE messages, each with the name and score  */
+/* of a player. We clear out the array to get rid of anyone */
+/* who has disconnected.                                    */
+int connected_players_recvd(char* buf)
+{
+  int n = 0;
+  int i = 0;
+  char* p = NULL;
+
+  if(!buf)
+    return 0;
+
+  p = strchr(buf, '\t');
+  if(!p)
+    return 0;
+  p++;
+  n = atoi(p);
+
+  DEBUGMSG(debug_game, "connected_players_recvd() for n = %d\n", n);
+
+  if(n < 0 || n > MAX_CLIENTS)
+  {
+    fprintf(stderr, "connected_players_recvd() - illegal value: %d\n", n);
+    return -1;
+  }
+  lan_players = n;
+
+  /* Reset array - we should be getting new values in immediately */
+  /* following messages.                                          */
+  for(i = 0; i < MAX_CLIENTS; i++)
+  {
+    lan_pnames[i][0] = '\0';
+    lan_pscores[i] = -1;
+  }
+  return n;
+}
+
+/* Receive the name and current score of a currently-connected */
+/* LAN player.                                                 */
+int update_score_recvd(char* buf)
+{
+  int i = 0;
+  char* p = NULL;
+
+  if(buf == NULL)
+    return 0;
+  // get i:
+  p = strchr(buf, '\t');
+  if(!p)
+    return 0;
+  p++;
+  i = atoi(p);
+
+  //get name:
+  p = strchr(p, '\t');
+  if(!p)
+    return 0;
+  p++;
+  strncpy(lan_pnames[i], p, NAME_SIZE);
+  //This has most likely copied the score field as well, so replace the
+  //tab delimiter with a null to terminate the string:
+  {
+    char* p2 = strchr(lan_pnames[i], '\t');
+    if (p2)
+      *p2 = '\0';
+  }
+
+  //Now get score:
+  p = strchr(p, '\t');
+  if(p)
+    lan_pscores[i] = atoi(p);
+
+  DEBUGMSG(debug_lan, "update_score_recvd() - buf is: %s\n", buf);
+  DEBUGMSG(debug_lan, "i is: %d\tname is: %s\tscore is: %d\n", 
+           i, lan_pnames[i], lan_pscores[i]);
+
+  return 1;
+}
+
+/* Return a pointer to an empty comet slot, */
+/* returning NULL if no vacancy found:      */
+
+MC_FlashCard* search_queue_by_id(int id)
+{
+  int i = 0;
+  for(i = 0; i < QUEST_QUEUE_SIZE; i++)
+  {
+    if(quest_queue[i].question_id == id)
+      return &quest_queue[i];
+  }
+  //if we don't find a match:
+  return NULL;
+}
+
+
+comet_type* search_comets_by_id(int id)
+{
+  int i;
+  for (i = 0; i < Opts_MaxComets(); i++)
+  {
+    if (comets[i].flashcard.question_id == id)
+     {printf("the question id is in slot %d\n",i);
+      return &comets[i];}
+  }
+
+  return NULL;
+}
+
+
+
+int erase_comet_on_screen(comet_type* comet)
+{
+  if(!comet)
+    return 0;
+  //setting expl to 0 starts comet explosion animation
+  comet->expl = 0;
+
+  //TODO consider more elaborate sound or animation
+  playsound(SND_SIZZLE);
+
+  return 1;
+}
+
+#endif
+
+/* Print the current questions and the number of remaining questions: */
+void print_current_quests(void)
+{
+  int i;
+  printf("\n------------  Current Questions:  -----------\n");
+  for(i = 0; i < Opts_MaxComets(); i++)
+  { 
+    if(comets[i].alive == 1)
+     printf("Comet %d - question %d:\t%s\n", i, comets[i].flashcard.question_id, comets[i].flashcard.formula_string);
+
+  }
+  printf("--------------Question Queue-----------------\n");
+  for(i = 0; i < QUEST_QUEUE_SIZE; i++)
+  {
+    if(quest_queue[i].question_id != -1)
+      printf("quest_queue %d - question %d:\t%s\n", i, quest_queue[i].question_id, quest_queue[i].formula_string);
+    else
+      printf("quest_queue %d:\tEmpty\n", i);
+  }
+  printf("------------------------------------------\n");
+}
+
+
+
+
 /* 
 Set one to four lines of text to display at the game's start. Eventually
 this should stylishly fade out over the first few moments of the game.
@@ -521,12 +845,14 @@
   start_message_chosen = 1;
 }
 
+
+
 int game_initialize(void)
 {
   int i,img;
   
   DEBUGMSG(debug_game,"Entering game_initialize()\n");
-
+  
   /* Clear window: */
   SDL_FillRect(GetScreen(), NULL, SDL_MapRGB(GetScreen()->format, 0, 0, 0));
   SDL_Flip(GetScreen());
@@ -535,57 +861,75 @@
   gameover_counter = -1;
   user_quit_received = 0;
 
-  /* Start MathCards backend: */
+  /* Make sure we don't try to call network code if we built without  */
+  /* network support:                                                 */
+  /* NOTE with this check it should be safe to assume we have SDL_net */
+  /* for the rest of this file if Opts_LanMode() == 1                 */
+#ifndef HAVE_LIBSDL_NET
+  Opts_SetLanMode(0);
+#endif
+
+  /* Start MathCards backend, unless we are getting questions from network: */
   /* FIXME may need to move this into tuxmath.c to accomodate option */
   /* to use MC_StartUsingWrongs() */
   /* NOTE MC_StartGame() will return 0 if the list length is zero due */
   /* (for example) to all math operations being deselected */
-  if (!MC_StartGame())
+  /* NOTE if we are playing a network game, MC_StartGame() has already */
+  /* been called on the server by the time we get to here:             */
+
+  if(!Opts_LanMode())
   {
-    fprintf(stderr, "\nMC_StartGame() failed!");
-    return 0;
+    if (!MC_StartGame())
+    {
+      fprintf(stderr, "\nMC_StartGame() failed!");
+      return 0;
+    } 
+    DEBUGMSG(debug_mathcards | debug_game,"MC_StartGame() finished.\n")
   }
-  DEBUGMSG(debug_mathcards | debug_game,"MC_StartGame() finished.\n")
+  else  
+  {
+    /* Reset question queue and player name/score lists: */
+    int i;
 
+    for(i = 0; i < QUEST_QUEUE_SIZE; i ++)
+      MC_ResetFlashCard(&(quest_queue[i]));
+
+    for(i = 0; i < MAX_CLIENTS; i++)
+    {
+      lan_pnames[i][0] = '\0';
+      lan_pscores[i] = -1;
+    }
+  }
+
   /* Allocate memory */
   comets = NULL;  // set in case allocation fails partway through
   cities = NULL;
   penguins = NULL;
   steam = NULL;
   comets = (comet_type *) malloc(MAX_MAX_COMETS * sizeof(comet_type));
-  if (comets == NULL) {
+  if (comets == NULL)
+  {
     printf("Allocation of comets failed");
     return 0;
   }
-  else {
-    for (i = 0; i < MAX_MAX_COMETS; ++i)
-      {
-      comets[i].flashcard = MC_AllocateFlashcard();
-      if (!MC_FlashCardGood(&comets[i].flashcard) ) 
-        {
-        //something's wrong
-        printf("Allocation of flashcard %d failed\n", i);
-        for (; i >= 0; --i) //free anything we've already gotten
-          MC_FreeFlashcard(&comets[i].flashcard);
-        return 0;
-        }
-      }
-  }
 
-  DEBUGMSG(debug_game,"Flashcards allocated.\n");
-
   cities = (city_type *) malloc(NUM_CITIES * sizeof(city_type));
-  if (cities == NULL) {
+  if (cities == NULL)
+  {
     printf("Allocation of cities failed");
     return 0;
   }
+
   penguins = (penguin_type *) malloc(NUM_CITIES * sizeof(penguin_type));
-  if (penguins == NULL) {
+  if (penguins == NULL)
+  {
     printf("Allocation of penguins failed");
     return 0;
   }
+
   steam = (steam_type *) malloc(NUM_CITIES * sizeof(steam_type));
-  if (steam == NULL) {
+  if (steam == NULL)
+  {
     printf("Allocation of steam failed");
     return 0;
   }
@@ -612,6 +956,7 @@
   slowdown = 0;
   score = 0;
   demo_countdown = 2000;
+  total_questions_left = 0;
   level_start_wait = LEVEL_START_WAIT_START;
   neg_answer_picked = 0;
 
@@ -645,12 +990,12 @@
   }
 
   num_cities_alive = NUM_CITIES;
-  num_comets_alive = 0;
 
   igloo_vertical_offset = GetImage(IMG_CITY_BLUE)->h - GetImage(IMG_IGLOO_INTACT)->h;
 
   /* Create and position the penguins and steam */
-  for (i = 0; i < NUM_CITIES; i++) {
+  for (i = 0; i < NUM_CITIES; i++)
+  {
     penguins[i].status = PENGUIN_HAPPY;
     penguins[i].counter = 0;
     penguins[i].x = cities[i].x;
@@ -660,10 +1005,12 @@
     steam[i].counter = 0;
   }
 
-  if (Opts_BonusCometInterval()) {
+  if (Opts_BonusCometInterval())
+  {
     bonus_comet_counter = Opts_BonusCometInterval() + 1;
-    DEBUGMSG(debug_game,"\nInitializing with bonus_comet_counter = %d\n",bonus_comet_counter)
+    DEBUGMSG(debug_game,"\nInitializing with bonus_comet_counter = %d\n",bonus_comet_counter);
   }
+
   extra_life_earned = 0;
   cloud.status = EXTRA_LIFE_OFF;
 
@@ -707,6 +1054,10 @@
 
 void game_cleanup(void)
 {
+#ifdef HAVE_LIBSDL_NET  
+  LAN_Cleanup();
+#endif
+
   /* Free background: */
   if (bkgd != NULL)
   {
@@ -736,9 +1087,10 @@
   }
 #endif
 
-  DEBUGMSG(debug_game, "Leaving game():\n");
+  DEBUGMSG(debug_game, "Leaving game_cleanup():\n");
 }
 
+
 void game_handle_help(void)
 {
   const int left_edge = 140;
@@ -855,39 +1207,51 @@
 
   help_add_comet("56 / 8 = ?", "7");
   comets[0].y = 2*(GetScreen()->h)/3;   // start it low down
+
   while (comets[0].alive && !(quit_help = help_renderframe_exit()));
+
   if (quit_help)
     return;
   frame_start = frame;
+
   while ((frame-frame_start < 3*FPS) && !(quit_help = help_renderframe_exit()));
+
   if (quit_help)
     return;
 
   help_controls.laser_enabled = 1;
-  game_set_message(&s1,_("You can fix the igloos"),left_edge,100);
-  game_set_message(&s2,_("by stopping bonus comets."),left_edge,135);
+  game_set_message(&s1,_("You can fix the igloos"), left_edge,100);
+  game_set_message(&s2,_("by stopping bonus comets."), left_edge,135);
   help_add_comet("2 + 2 = ?", "4");
   comets[0].bonus = 1;
   frame_start = frame;
+
   while (comets[0].alive && (frame-frame_start < 50) && !(quit_help = help_renderframe_exit()));
+
   if (quit_help)
     return;
   if (comets[0].alive)
     speed = 0;
   game_set_message(&s3,_("Zap it now!"),left_edge,225);
+
   while (comets[0].alive && !(quit_help = help_renderframe_exit()));
+
   if (quit_help)
     return;
   game_set_message(&s1,_("Great job!"),left_edge,100);
   game_clear_message(&s2);
   game_clear_message(&s3);
   frame_start = frame;
+
   while ((frame-frame_start < 2*FPS) && !(quit_help = help_renderframe_exit()));
+
   if (quit_help)
     return;
   check_extra_life();
   frame_start = frame;
+
   while ((frame-frame_start < 10*FPS) && !(quit_help = help_renderframe_exit()));
+
   if (quit_help)
     return;
 
@@ -898,6 +1262,7 @@
   game_set_message(&s4,_("Do it now, and then play!"),left_edge,225);
 
   help_controls.x_is_blinking = 1;
+
   while (!help_renderframe_exit());
 }
 
@@ -947,7 +1312,7 @@
   comets[0].alive = 1;
   comets[0].expl = -1;
   comets[0].answer = atoi(ans_str);
-  num_comets_alive = 1;
+//  num_comets_alive = 1;
   comets[0].city = 0;
   comets[0].x = cities[0].x;
   comets[0].y = 0;
@@ -985,10 +1350,11 @@
 
 void game_write_message(const game_message *msg)
 {
-  SDL_Surface *surf;
+  SDL_Surface* surf;
   SDL_Rect rect;
 
-  if (strlen(msg->message) > 0) {
+  if (strlen(msg->message) > 0)
+  {
     surf = BlackOutline( _(msg->message), DEFAULT_HELP_FONT_SIZE, &white);
     rect.w = surf->w;
     rect.h = surf->h;
@@ -1047,87 +1413,89 @@
 
   /* Demo mode! */
   {
-  static int demo_answer = 0;
-  static int answer_digit = 0;
-  static int picked_comet=-1;
+    static int demo_answer = 0;
+    static int answer_digit = 0;
+    static int picked_comet=-1;
 
-  if (picked_comet == -1 && (rand() % 10) < 3)
-  {
-    /* Demo mode!  Randomly pick a comet to destroy: */
-    picked_comet = (rand() % MAX_COMETS);
-
-    if (!(comets[picked_comet].alive &&
-          comets[picked_comet].expl == -1)
-        || comets[picked_comet].y < 80)
+    if (picked_comet == -1 && (rand() % 10) < 3)
     {
-      picked_comet = -1;
-    }
-    else
-    {
-      /* found a comet to blow up! */
-      demo_answer = comets[picked_comet].answer;
-      if ((rand() % 3) < 1)
-        demo_answer--;  // sometimes get it wrong on purpose
+      /* Demo mode!  Randomly pick a comet to destroy: */
+      picked_comet = (rand() % Opts_MaxComets());
 
-      DEBUGMSG(debug_game, "Demo mode, comet %d attacked with answer %d\n",picked_comet,demo_answer);
-      /* handle negative answer: */
-      if (demo_answer < 0)
+      if (!(comets[picked_comet].alive &&
+            comets[picked_comet].expl == -1)
+          || comets[picked_comet].y < 80)
       {
-        demo_answer = -demo_answer;
-        neg_answer_picked = 1;
+        picked_comet = -1;
       }
-      if (demo_answer >= 100)
-        answer_digit = 0;
-      else if (demo_answer >= 10)
-        answer_digit = 1;
       else
-        answer_digit = 2;
+      {
+        /* found a comet to blow up! */
+        demo_answer = comets[picked_comet].answer;
+        if ((rand() % 3) < 1)
+          demo_answer--;  // sometimes get it wrong on purpose
+
+        DEBUGMSG(debug_game, "Demo mode, comet %d attacked with answer %d\n", picked_comet,demo_answer);
+
+        /* handle negative answer: */
+        if (demo_answer < 0)
+        {
+          demo_answer = -demo_answer;
+          neg_answer_picked = 1;
+        }
+        if (demo_answer >= 100)
+          answer_digit = 0;
+        else if (demo_answer >= 10)
+          answer_digit = 1;
+        else
+          answer_digit = 2;
+      }
     }
-  }
 
-  /* Add a digit: */
-  if (picked_comet != -1 && (frame % 5) == 0 && (rand() % 10) < 8)
-  {
-    tux_pressing = 1;
-
-    if (answer_digit < 3)
+    /* Add a digit: */
+    if (picked_comet != -1 && (frame % 5) == 0 && (rand() % 10) < 8)
     {
-      digits[0] = digits[1];
-      digits[1] = digits[2];
+      tux_pressing = 1;
 
-      if (answer_digit == 0)
+      if (answer_digit < 3)
       {
-        digits[2] = demo_answer / 100;
+        digits[0] = digits[1];
+        digits[1] = digits[2];
+
+        if (answer_digit == 0)
+        {
+          digits[2] = demo_answer / 100;
+        }
+        else if (answer_digit == 1)
+        {
+          digits[2] = (demo_answer % 100) / 10;
+        }
+        else if (answer_digit == 2)
+        {
+          digits[2] = (demo_answer % 10);
+        }
+
+        answer_digit++;
       }
-      else if (answer_digit == 1)
+      else
       {
-        digits[2] = (demo_answer % 100) / 10;
+        /* "Press Return" */
+        DEBUGMSG(debug_game, "Demo mode firing with these digits: %d%d%d\n",
+                 digits[0], digits[1], digits[2]);
+        doing_answer = 1;
+        picked_comet = -1;
       }
-      else if (answer_digit == 2)
-      {
-        digits[2] = (demo_answer % 10);
-      }
+    }
 
-      answer_digit++;
-    }
-    else
-    {
-      /* "Press Return" */
-      DEBUGMSG(debug_game, "Demo mode firing with these digits: %d%d%d\n",digits[0],digits[1],digits[2]);
-      doing_answer = 1;
-      picked_comet = -1;
-    }
+    /* Count down counter: */
+    demo_countdown--;
   }
-
-  /* Count down counter: */
-  demo_countdown--;
 }
-}
 
 void game_handle_answer(void)
 {
   int i, j, lowest, lowest_y;
-  char ans[MC_MAX_DIGITS+2]; //extra space for negative, and for final '\0'
+  char ans[MC_MAX_DIGITS + 2]; //extra space for negative, and for final '\0'
   Uint32 ctime;
 
   if (!doing_answer)
@@ -1136,11 +1504,7 @@
   }
 
   doing_answer = 0;
-/*
-  num = (digits[0] * 100 +
-         digits[1] * 10 +
-         digits[2]);
-*/
+
   /* negative answer support DSB */
   
   ans[0] = '-'; //for math questions only, this is just replaced.
@@ -1149,36 +1513,15 @@
     ans[j] = digits[i] + '0';
   ans[j] = '\0';
   
-/*
-  if (neg_answer_picked)
-  {
-    ans[0] = '-';
-    for (i = j = 0; i < MC_MAX_DIGITS; ++i)
-    {
-      if (digits[i] == 0)
-        continue;
-      ans[++j] = digits[i] + '0';
-    }
-  }
-  else
-  {
-    for (i = j = 0; i < MC_MAX_DIGITS; ++i)
-    {
-      if (digits[i] == 0)
-        continue;
-      ans[j++] = digits[i] + '0';
-    }
-  } 
-*/
 
+
   /*  Pick the lowest comet which has the right answer: */
   /*  FIXME: do we want it to prefer bonus comets to regular comets? */
   lowest_y = 0;
   lowest = -1;
 
-  for (i = 0; i < MAX_COMETS; i++)
+  for (i = 0; i < Opts_MaxComets(); i++)
   {
-    mcdprintf("Comparing '%s' with '%s'\n", comets[i].flashcard.answer_string, ans);
     if (comets[i].alive &&
         comets[i].expl == -1 &&
         //comets[i].answer == num &&
@@ -1190,17 +1533,22 @@
     }
   }
 
-  /* If there was an comet with this answer, destroy it! */
+  /* If there was a comet with this answer, destroy it! */
   if (lowest != -1)  /* -1 means no comet had this answer */
   {
-    MC_AnsweredCorrectly(&(comets[lowest].flashcard));
-
+    float t;
     /* Store the time the question was present on GetScreen() (do this */
     /* in a way that avoids storing it if the time wrapped around */
     ctime = SDL_GetTicks();
-    if (ctime > comets[lowest].time_started) {
-      MC_AddTimeToList((float)(ctime - comets[lowest].time_started)/1000);
-    }
+    if (ctime > comets[lowest].time_started)
+      t = ((float)(ctime - comets[lowest].time_started)/1000);
+    else
+      t = -1;   //Mathcards will ignore t == -1
+    /* Tell Mathcards or the server that we answered correctly: */
+    if(Opts_LanMode())
+      LAN_AnsweredCorrectly(comets[lowest].flashcard.question_id, t);
+    else
+      MC_AnsweredCorrectly(comets[lowest].flashcard.question_id, t);
 
 
     /* Destroy comet: */
@@ -1226,8 +1574,7 @@
 #endif
     }
 
-
-    /* FIXME maybe should move this into game_handle_tux() */
+    /* Pick Tux animation: */
     /* 50% of the time.. */
     if ((rand() % 10) < 5)
     {
@@ -1284,6 +1631,7 @@
   s2.alpha -= SDL_ALPHA_OPAQUE / LEVEL_START_WAIT_START;
   s3.alpha -= SDL_ALPHA_OPAQUE / LEVEL_START_WAIT_START;
   s4.alpha -= SDL_ALPHA_OPAQUE / LEVEL_START_WAIT_START;
+  DEBUGMSG(debug_game, "alpha = %d\n", s1.alpha);
 
   level_start_wait--;
   if (level_start_wait > LEVEL_START_WAIT_START / 4)
@@ -1307,14 +1655,9 @@
   /* If Tux pressed a button, pick a new (different!) stance: */
   if (tux_pressing)
   {
-    num_frames = GetSprite(ANIM_TUX_CONSOLE)->num_frames;
-    do
-    {
-      tux_img = GetSprite(ANIM_TUX_CONSOLE)->frame[rand() % num_frames];
-    }
+    do { tux_img = IMG_TUX_CONSOLE1 + (rand() % 4); }
     while (tux_img == old_tux_img);
-
-    PlaySound(sounds[SND_CLICK]);
+    playsound(SND_TOCK);
   }
 
   /* If Tux is being animated, show the animation: */
@@ -1349,22 +1692,23 @@
   int i, this_city;
   Uint32 ctime;
 
-  num_comets_alive = 0;
+//  num_comets_alive = 0;
 
   /* Clear the threatened flag on each city */
   for (i = 0; i < NUM_CITIES; i++)
     cities[i].threatened = 0;
 
-  for (i = 0; i < MAX_COMETS; i++)
+  for (i = 0; i < Opts_MaxComets(); i++)
   {
     if (comets[i].alive)
     {
-      num_comets_alive++;
+//     num_comets_alive++;
       this_city = comets[i].city;
 
       /* Update comet position */
       comets[i].x = comets[i].x + 0; /* no lateral motion for now! */
       /* Make bonus comet move faster at chosen ratio: */
+      /* NOTE y increment scaled to make game play similar at any resolution */
       if (comets[i].bonus)
       {
         comets[i].y += speed * Opts_BonusSpeedRatio() *
@@ -1385,7 +1729,10 @@
           comets[i].expl == -1)
       {
         /* Tell MathCards about it - question not answered correctly: */
-        MC_NotAnsweredCorrectly(&(comets[i].flashcard));
+        if(Opts_LanMode())
+          LAN_NotAnsweredCorrectly(comets[i].flashcard.question_id);
+        else
+          MC_NotAnsweredCorrectly(comets[i].flashcard.question_id);
 
         /* Store the time the question was present on screen (do this */
         /* in a way that avoids storing it if the time wrapped around */
@@ -1470,14 +1817,18 @@
     }
   }
 
+  /* FIXME for the LAN game, the adding of comets needs to take place in  */
+  /* check_messages() when new questions come in from the server.  For    */
+  /* ease of understanding, we should do it at the same place in the game */
+  /* loop for the non-LAN (i.e. local MC_*() functions) game - DSB        */
   /* add more comets if needed: */
-  if (!Opts_HelpMode() && level_start_wait == 0 &&
-      (frame % 20) == 0)   /* FIXME:do we want this to vary with comet speed?*/
+  if (!Opts_HelpMode() && level_start_wait == 0) //&&
+     // (frame % 20) == 0)
   {
     /* num_attackers is how many comets are left in wave */
     if (num_attackers > 0)
     {
-      if ((rand() % 2) == 0 || num_comets_alive == 0)
+//      if ((rand() % 2) == 0 || num_comets_alive() == 0)  NOTE also caused timing issue
       {
         if (add_comet())
         {
@@ -1487,9 +1838,10 @@
     }
     else
     {
-      if (num_comets_alive == 0)
+      if (num_comets_alive() == 0)
       {
-        if (!check_extra_life()) {
+        if (!check_extra_life())
+        {
           /* Time for the next wave! */
           wave++;
           reset_level();
@@ -1729,6 +2081,7 @@
     return 1;
   DEBUGCODE(debug_game)
     print_status();
+    
   if (extra_life_earned) {
     /* Check to see if any ingloo has been hit */
     fewest_hits_left = 2;
@@ -1747,7 +2100,7 @@
     cloud.y = GetScreen()->h/3;
     cloud.city = fewest_index;
     bonus_comet_counter = Opts_BonusCometInterval()+1;
-
+    
     DEBUGMSG(debug_game, "Bonus comet counter restored to %d\n",bonus_comet_counter);
 
     if (cloud.city < NUM_CITIES/2)
@@ -1765,14 +2118,16 @@
     DEBUGCODE(debug_game)
       print_status();
     return 1;
-  } else
+  }
+  else
     return 0;
 }
 
+
 void game_handle_extra_life(void)
 {
   // This handles the animation sequence during the rebuilding of an igloo
-  int i,igloo_top,num_below_igloo,direction;
+  int i, igloo_top, num_below_igloo, direction;
 
   if (cloud.status == EXTRA_LIFE_ON) {
 
@@ -1891,7 +2246,7 @@
     fgcolor = SDL_MapRGB(GetScreen()->format, 64, 96, 64);
   if (old_wave != wave)
   {
-    DEBUGMSG(debug_game,"Wave %d\n", wave)
+    DEBUGMSG(debug_game,"Wave %d\n", wave);
     old_wave = wave;
     bgcolor = SDL_MapRGB(GetScreen()->format,
                          64,
@@ -1930,13 +2285,14 @@
 /* draw last (i.e. in front), as they can overlap          */
 void game_draw_comets(void)
 {
+
   int i;
   SDL_Surface* img = NULL;
   SDL_Rect dest;
   char* comet_str;
 
    /* First draw regular comets: */
-  for (i = 0; i < MAX_COMETS; i++)
+  for (i = 0; i < Opts_MaxComets(); i++)
   {
     if (comets[i].alive && !comets[i].bonus)
     {
@@ -1977,7 +2333,7 @@
   }
 
   /* Now draw any bonus comets: */
-  for (i = 0; i < MAX_COMETS; i++)
+  for (i = 0; i < Opts_MaxComets(); i++)
   {
     if (comets[i].alive && comets[i].bonus)
     {
@@ -2002,14 +2358,11 @@
         comet_str = comets[i].flashcard.answer_string;
       }
 
-      /* Move image index to bonus range: */
-
       /* Draw it! */
       dest.x = comets[i].x - (img->w / 2);
       dest.y = comets[i].y - img->h;
       dest.w = img->w;
       dest.h = img->h;
-
       SDL_BlitSurface(img, NULL, GetScreen(), &dest);
       if (comet_str != NULL)
       {
@@ -2019,6 +2372,8 @@
   }
 }
 
+
+
 void game_draw_cities(void)
 {
   int i, j, current_layer, max_layer;
@@ -2208,7 +2563,8 @@
   sprintf(str, "%d", wave);
   draw_numbers(str, offset+GetImage(IMG_WAVE)->w + (GetImage(IMG_NUMBERS)->w / 10), 0);
 
-  if (Opts_KeepScore() )
+  /* In LAN mode, we show the server-generated score: */
+  if (Opts_KeepScore() && !Opts_LanMode())
   {
     /* Draw "score" label: */
     dest.x = (GetScreen()->w - ((GetImage(IMG_NUMBERS)->w / 10) * 7) -
@@ -2226,9 +2582,10 @@
                  0);
   }
 
-  /* Draw other players' scores */
+  /* Draw other players' scores (turn-based single machine multiplayer) */
   if (mp_get_parameter(PLAYERS) && mp_get_parameter(MODE) == SCORE_SWEEP )
   {
+    int i;
     for (i = 0; i < mp_get_parameter(PLAYERS); ++i)
     {
       SDL_Surface* score;
@@ -2246,6 +2603,31 @@
     }
   }
 
+   /* Draw other players' scores (LAN game) */
+  if (Opts_LanMode())
+  {
+    int entries = 0;
+    for (i = 0; i < MAX_CLIENTS; i++)
+    {
+      if(lan_pscores[i] >= 0)
+      {
+        SDL_Surface* score;
+        snprintf(str, 64, "%s: %d", lan_pnames[i], lan_pscores[i]);
+        score = BlackOutline(str, DEFAULT_MENU_FONT_SIZE, &white);
+        if(score)
+        {
+          SDL_Rect loc;
+          loc.w = score->w;
+          loc.h = score->h;
+          loc.x = 0;
+          loc.y = score->h * (entries + 2);
+          SDL_BlitSurface(score, NULL, screen, &loc);
+          entries++;
+        }
+      }
+    }
+  }
+  
   /* Draw stop button: */
   if (!help_controls.x_is_blinking || (frame % 10 < 5)) {
     dest.x = (GetScreen()->w - GetImage(IMG_STOP)->w);
@@ -2259,14 +2641,16 @@
 
 int check_exit_conditions(void)
 {
+//  int x;
+
   if (user_quit_received)
   {
     if (user_quit_received != GAME_OVER_WINDOW_CLOSE &&
         user_quit_received != GAME_OVER_ESCAPE &&
         user_quit_received != GAME_OVER_CHEATER)
     {
-    	 fprintf(stderr,"Unexpected value %d for user_quit_received\n", user_quit_received);
-    	 return GAME_OVER_OTHER;
+      fprintf(stderr, "Unexpected value %d for user_quit_received\n", user_quit_received);
+      return GAME_OVER_OTHER;
     }
     return user_quit_received;    
   }
@@ -2282,30 +2666,53 @@
   }
 
   /* determine if game won (i.e. all questions in mission answered correctly): */
-  if (MC_MissionAccomplished())
+  if(Opts_LanMode())
   {
-    DEBUGMSG(debug_game,"Mission accomplished!\n");
-    return GAME_OVER_WON;
+    if(game_over_won)
+       return GAME_OVER_WON;
   }
+  else
+  {
+    if (MC_MissionAccomplished())
+    {
+      DEBUGMSG(debug_game,"Mission accomplished!\n");
+      return GAME_OVER_WON;
+    }
+  }
 
+  
   /* Could have situation where mathcards doesn't have more questions */
   /* even though not all questions answered correctly:                */
-  if (!MC_TotalQuestionsLeft())
+  if(Opts_LanMode())
   {
-    return GAME_OVER_OTHER;
+    if(game_over_other)
+       return GAME_OVER_OTHER;
   }
+  else
+  {
+    if(!MC_TotalQuestionsLeft())
+      return GAME_OVER_OTHER;
+  }
 
+
+  //NOTE can't use this check in LAN mode because we don't know if the server has 
+  //questions left
+ 
   /* Need to get out if no comets alive and MathCards has no questions left in list, */
   /* even though MathCards thinks there are still questions "in play".  */
   /* This SHOULD NOT HAPPEN and means we have a bug somewhere. */
-  if (!MC_ListQuestionsLeft() && !num_comets_alive)
+  if (!Opts_LanMode())
   {
-    DEBUGMSG(debug_game, "ListQuestionsLeft() = %d ", MC_ListQuestionsLeft());
-    DEBUGMSG(debug_game, "num_comets_alive = %d", num_comets_alive);
-    return GAME_OVER_ERROR;
-  }
+    if (!MC_ListQuestionsLeft() && !num_comets_alive())
+    {
+      fprintf(stderr, "Error - no questions left but game not over\n");
+      DEBUGMSG(debug_game, "ListQuestionsLeft() = %d ", MC_ListQuestionsLeft());
+      DEBUGMSG(debug_game, "num_comets_alive() = %d", num_comets_alive());
+      return GAME_OVER_ERROR;
+    }
+  } 
 
-  /* If using demo mode, see if counter has run out: */
+   /* If using demo mode, see if counter has run out: */
   if (Opts_DemoMode())
   {
     if (demo_countdown <= 0 )
@@ -2316,6 +2723,7 @@
   return GAME_IN_PROGRESS;
 }
 
+
 void print_exit_conditions(void)
 {
   printf("\ngame_status:\t");
@@ -2366,6 +2774,7 @@
   }
 }
 
+
 /* Reset stuff for the next level! */
 void reset_level(void)
 {
@@ -2373,16 +2782,20 @@
   int i;
   int next_wave_comets;
   int use_feedback;
-  float comet_avg_height,height_differential;
+  float comet_avg_height, height_differential;
 
 
   /* Clear all comets: */
 
-  for (i = 0; i < MAX_COMETS; i++)
+  for (i = 0; i < Opts_MaxComets(); i++)
   {
+    DEBUGCODE(debug_game)
+    {
+      if(comets[i].alive)
+        printf("Warning - resetting comets but comet[%d| still alive\n", i);
+    }
     comets[i].alive = 0;
   }
-  num_comets_alive = 0;
 
   /* Clear LED F: */
 
@@ -2390,8 +2803,6 @@
     digits[i] = 0;
   neg_answer_picked = 0;
 
-
-
   /* Load random background image, but ensure it's different from this one: */
   for (i = last_bkgd; i == last_bkgd; i = rand() % NUM_BKGDS);
 
@@ -2538,76 +2949,108 @@
 int add_comet(void)
 {
   static int prev_city = -1;
-  int i, found;
+  int i;
   float y_spacing;
 
-  /* Look for a free comet slot and see if all live comets are far */
-  /* enough down to avoid overlap and keep formulas legible:       */
-  found = -1;
+  int com_found = -1;
+  int q_found = -1;  
+
   y_spacing = (GetImage(IMG_NUMS)->h) * 1.5;
 
-  for (i = 0; i < MAX_COMETS && found == -1; i++)
+  /* Return if any previous comet too high up to create another one yet: */
+  for (i = 0; i < Opts_MaxComets(); i++)
   {
     if (comets[i].alive)
-    {
       if (comets[i].y < y_spacing)
       {
-        /* previous comet too high up to create another one yet: */
+        DEBUGMSG(debug_game,
+                 "add_comet() - returning because comet[%d] not"
+                 " far enough down: %f\n", i, comets[i].y);
         return 0;
       }
-    }
-    else  /* non-living comet so we found a free slot: */
+  }  
+    
+  /* Now look for a free comet slot: */
+  for (i = 0; i < Opts_MaxComets(); i++)
+  {
+    if (!comets[i].alive)
     {
-      found = i;
+      com_found = i;
+      break;
     }
   }
-
-  if (-1 == found)
+ 
+  if (-1 == com_found)
   {
     /* free comet slot not found - no comet added: */
+    DEBUGMSG(debug_game, "add_comet() called but no free comet slot\n");
+    DEBUGCODE(debug_game) print_current_quests();
     return 0;
   }
 
 
-  /* Get math question for new comet - the following function fills in */
-  /* the flashcard struct that is part of the comet struct:            */
-  if (!MC_NextQuestion(&(comets[found].flashcard)))
+  /* If playing in LAN mode, see if we have a question ready  in  */
+  /* our local queue:                                             */
+   
+  if(Opts_LanMode())
   {
-    /* no more questions available - cannot create comet.  */
-    return 0;
+    DEBUGCODE(debug_game) print_current_quests();
+    for (i = 0; i < QUEST_QUEUE_SIZE; i++)
+    {
+      if(quest_queue[i].question_id != -1)
+      {
+        DEBUGMSG(debug_game, "Found question_id %d, %s\n", 
+                  quest_queue[i].question_id,
+                  quest_queue[i].formula_string);
+        q_found = i;
+        break;
+      }
+    }
+
+    if(q_found == -1)
+    {
+      DEBUGMSG(debug_game, "add_comet() called but no question available in queue\n");
+      return 0;    DEBUGCODE(debug_game) print_current_quests();
+    } 
   }
 
-  /* If we make it to here, create a new comet!                  */
+  /* Now we have a vacant comet slot at com_found and (if in LAN mode) */
+  /* a question for it at q_found.  Now just copy:                     */
 
-  comets[found].answer = comets[found].flashcard.answer;
-//  /* The answer may be num1, num2, or num3, depending on format. */
-//  switch (comets[found].flashcard.format)
-//  {
-//    case MC_FORMAT_ANS_LAST:  /* e.g. num1 + num2 = ? */
-//    {
-//      comets[found].answer = comets[found].flashcard.num3;
-//      break;
-//    }
-//    case MC_FORMAT_ANS_MIDDLE:  /* e.g. num1 + ? = num3 */
-//    {
-//      comets[found].answer = comets[found].flashcard.num2;
-//      break;
-//    }
-//    case MC_FORMAT_ANS_FIRST:  /* e.g. ? + num2 = num3 */
-//    {
-//      comets[found].answer = comets[found].flashcard.num1;
-//      break;
-//    }
-//    default:  /* should not get to here if MathCards behaves correctly */
-//    {
-//      fprintf(stderr, "\nadd_comet() - invalid question format");
-//      return 0;
-//    }
-//  }
+  if(Opts_LanMode())
+  {
+    MC_CopyCard(&(quest_queue[q_found]), &(comets[com_found].flashcard));
+    MC_ResetFlashCard(&(quest_queue[q_found]));
+  }
+  else // Not LAN mode - just get question with direct call:
+  {
+    if (!MC_NextQuestion(&(comets[com_found].flashcard)))
+    {
+      /* no more questions available - cannot create comet.  */
+      return 0;
+    }
+  }
+
+  DEBUGCODE(debug_game)
+  {
+    printf("In add_comet(), card is\n");
+    print_card(comets[com_found].flashcard);
+  }
   
+  /* Make sure question is "sane" before we add it: */
+  if( (comets[com_found].flashcard.answer > 999)
+    ||(comets[com_found].flashcard.answer < -999))
+  {
+    printf("Warning, card with invalid answer encountered: %d\n",
+           comets[com_found].flashcard.answer);
+    MC_ResetFlashCard(&(comets[com_found].flashcard));
+    return 0;
+  }
 
-  comets[found].alive = 1;
-  num_comets_alive++;
+  /* If we make it to here, create a new comet!*/
+  comets[com_found].answer = comets[com_found].flashcard.answer;
+  comets[com_found].alive = 1;
+//  num_comets_alive++;
 
   /* Pick a city to attack that was not attacked last time */
   /* (so formulas are less likely to overlap). */
@@ -2620,33 +3063,35 @@
   prev_city = i;
 
   /* Set in to attack that city: */
-  comets[found].city = i;
+  comets[com_found].city = i;
   /* Start at the top, above the city in question: */
-  comets[found].x = cities[i].x;
-  comets[found].y = 0;
-  comets[found].zapped = 0;
+  comets[com_found].x = cities[i].x;
+  comets[com_found].y = 0;
+  comets[com_found].zapped = 0;
   /* Should it be a bonus comet? */
-  comets[found].bonus = 0;
+  comets[com_found].bonus = 0;
 
   DEBUGMSG(debug_game, "bonus_comet_counter is %d\n",bonus_comet_counter);
 
-  if (bonus_comet_counter == 1) {
+  if (bonus_comet_counter == 1)
+  {
     bonus_comet_counter = 0;
-    comets[found].bonus = 1;
+    comets[com_found].bonus = 1;
     PlaySound(sounds[SND_BONUS_COMET]);
-
     DEBUGMSG(debug_game, "Created bonus comet");
   }
 
-  DEBUGMSG(debug_game, "add_comet(): formula string is: %s", comets[found].flashcard.formula_string);
-
+  DEBUGMSG(debug_game, "add_comet(): formula string is: %s\n", comets[com_found].flashcard.formula_string);
+  
   /* Record the time at which this comet was created */
-  comets[found].time_started = SDL_GetTicks();
-
+  comets[com_found].time_started = SDL_GetTicks();
+   
   /* comet slot found and question found so return successfully: */
   return 1;
 }
 
+
+
 /* Draw numbers/symbols over the attacker: */
 /* This draws the numbers related to the comets */
 void draw_nums(const char* str, int x, int y)
@@ -2671,19 +3116,14 @@
   /* the following code keeps the formula at least 8 pixels inside the window: */
   if (cur_x < 8)
     cur_x = 8;
-  if (cur_x + (image_length) >=
-      (GetScreen()->w - 8))
-    cur_x = ((GetScreen()->w - 8) -
-             (image_length));
+  if (cur_x + (image_length) >= (screen->w - 8))
+    cur_x = ((screen->w - 8) - (image_length));
 
-
   /* Draw each character: */
-
   for (i = 0; i < str_length; i++)
   {
     c = -1;
 
-
     /* Determine which character to display: */
 
     if (str[i] >= '0' && str[i] <= '9')
@@ -2743,45 +3183,38 @@
   int i, cur_x, c;
   SDL_Rect src, dest;
 
-
   cur_x = x;
 
-
   /* Draw each character: */
 
   for (i = 0; i < strlen(str); i++)
-    {
-      c = -1;
+  {
+    c = -1;
 
+    /* Determine which character to display: */
+    if (str[i] >= '0' && str[i] <= '9')
+      c = str[i] - '0';
 
-      /* Determine which character to display: */
+    /* Display this character! */
+    if (c != -1)
+    {
+      src.x = c * (images[IMG_NUMBERS]->w / 10);
+      src.y = 0;
+      src.w = (images[IMG_NUMBERS]->w / 10);
+      src.h = images[IMG_NUMBERS]->h;
 
-      if (str[i] >= '0' && str[i] <= '9')
-        c = str[i] - '0';
+      dest.x = cur_x;
+      dest.y = y;
+      dest.w = src.w;
+      dest.h = src.h;
 
+      SDL_BlitSurface(images[IMG_NUMBERS], &src,
+                          screen, &dest);
 
-      /* Display this character! */
-
-      if (c != -1)
-        {
-          src.x = c * (GetImage(IMG_NUMBERS)->w / 10);
-          src.y = 0;
-          src.w = (GetImage(IMG_NUMBERS)->w / 10);
-          src.h = GetImage(IMG_NUMBERS)->h;
-
-          dest.x = cur_x;
-          dest.y = y;
-          dest.w = src.w;
-          dest.h = src.h;
-
-          SDL_BlitSurface(GetImage(IMG_NUMBERS), &src,
-                          GetScreen(), &dest);
-
-
-          /* Move the 'cursor' one character width: */
-          cur_x = cur_x + (GetImage(IMG_NUMBERS)->w / 10);
-        }
+      /* Move the 'cursor' one character width: */
+      cur_x = cur_x + (images[IMG_NUMBERS]->w / 10);
     }
+  }
 }
 
 
@@ -2814,13 +3247,11 @@
   SDL_BlitSurface(GetImage(IMG_PAUSED), NULL, GetScreen(), &dest);
   SDL_UpdateRect(GetScreen(), 0, 0, 0, 0);
 
-
 #ifndef NOSOUND
   if (Opts_UsingSound())
     Mix_PauseMusic();
 #endif
 
-
   do
   {
     while (SDL_PollEvent(&event))
@@ -2838,7 +3269,6 @@
   }
   while (!pause_done && !pause_quit);
 
-
 #ifndef NOSOUND
   if (Opts_UsingSound())
     Mix_ResumeMusic();
@@ -2849,8 +3279,9 @@
 
 
 
+/* FIXME these ought to be in SDL_extras - DSB */
+
 /* Draw a line: */
-
 void draw_line(int x1, int y1, int x2, int y2, int red, int grn, int blu)
 {
   int dx, dy, tmp;
@@ -2926,34 +3357,34 @@
   /* Assuming the X/Y values are within the bounds of this surface... */
 
   if (x >= 0 && y >= 0 && x < surface->w && y < surface->h)
-    {
+  {
       /* Set the (correctly-sized) piece of data in the surface's RAM
          to the pixel value sent in: */
 
-      if (bpp == 1)
-        *p = pixel;
-      else if (bpp == 2)
-        *(Uint16 *)p = pixel;
-      else if (bpp == 3)
-        {
-          if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
-            {
-              p[0] = (pixel >> 16) & 0xff;
-              p[1] = (pixel >> 8) & 0xff;
-              p[2] = pixel & 0xff;
-            }
-          else
-            {
-              p[0] = pixel & 0xff;
-              p[1] = (pixel >> 8) & 0xff;
-              p[2] = (pixel >> 16) & 0xff;
-            }
-        }
-      else if (bpp == 4)
-        {
-          *(Uint32 *)p = pixel;
-        }
+    if (bpp == 1)
+      *p = pixel;
+    else if (bpp == 2)
+      *(Uint16 *)p = pixel;
+    else if (bpp == 3)
+    {
+      if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+      {
+        p[0] = (pixel >> 16) & 0xff;
+        p[1] = (pixel >> 8) & 0xff;
+        p[2] = pixel & 0xff;
+      }
+      else
+      {
+        p[0] = pixel & 0xff;
+        p[1] = (pixel >> 8) & 0xff;
+        p[2] = (pixel >> 16) & 0xff;
+      }
     }
+    else if (bpp == 4)
+    {
+      *(Uint32 *)p = pixel;
+    }
+  }
 #else
   SDL_Rect dest;
 
@@ -3011,7 +3442,11 @@
   SDL_BlitSurface(comet_img, NULL, GetScreen(), &dest);
 
   /* draw number of remaining questions: */
-  questions_left = MC_TotalQuestionsLeft();
+  if(Opts_LanMode())
+    questions_left = total_questions_left;
+  else
+    questions_left = MC_TotalQuestionsLeft();
+
   sprintf(str, "%.4d", questions_left);
   draw_numbers(str, nums_x, 0);
 }
@@ -3400,15 +3835,17 @@
 void add_score(int inc)
 {
   score += inc;
-  DEBUGMSG(debug_game,"Score is now: %d\n", score)
+  DEBUGMSG(debug_game,"Score is now: %d\n", score);
 }
 
 
 
 void reset_comets(void)
 {
-  int i =0;
-  for (i = 0; i < MAX_COMETS; i++)
+  int i = 0;
+  comet_counter = 0;
+
+  for (i = 0; i < Opts_MaxComets(); i++)
   {
     comets[i].alive = 0;
     comets[i].expl = -1;
@@ -3416,13 +3853,12 @@
     comets[i].x = 0;
     comets[i].y = 0;
     comets[i].answer = 0;
-//    strncpy(comets[i].flashcard.formula_string, " ", max_formula_size);
-//    strncpy(comets[i].flashcard.answer_string, " ", max_answer_size);
     MC_ResetFlashCard(&(comets[i].flashcard) );
     comets[i].bonus = 0;
   }
 }
 
+
 void print_status(void)
 {
   int i;
@@ -3446,6 +3882,7 @@
   printf("\n");
 }
 
+
 void free_on_exit(void)
 {
   int i;
@@ -3463,8 +3900,8 @@
   int i, img;
   int old_city_expl_height = city_expl_height;
 
-  DEBUGMSG(debug_game,"Recalculating positions\n")
-
+  DEBUGMSG(debug_game,"Recalculating positions\n");
+  
   if (Opts_GetGlobalOpt(USE_IGLOOS))
     img = IMG_IGLOO_INTACT;
   else
@@ -3477,7 +3914,7 @@
     {
       cities[i].x = (((GetScreen()->w / (NUM_CITIES + 1)) * i) +
                      ((GetImage(img) -> w) / 2));
-      DEBUGMSG(debug_game,"%d,", cities[i].x)
+      DEBUGMSG(debug_game,"%d,", cities[i].x);
     }
     else
     {
@@ -3494,7 +3931,7 @@
   city_expl_height = GetScreen()->h - GetImage(IMG_CITY_BLUE)->h;
   //move comets to a location 'equivalent' to where they were
   //i.e. with the same amount of time left before impact
-  for (i = 0; i < MAX_COMETS; ++i)
+  for (i = 0; i < Opts_MaxComets(); ++i)
   {
     if (!comets[i].alive)
       continue;
@@ -3505,6 +3942,14 @@
     //else
     //  comets[i].y = comets[i].y * RES_Y / screen->h;
   }
+}
 
-
+static int num_comets_alive()
+{
+  int i = 0;
+  int living = 0;
+  for(i = 0; i < Opts_MaxComets(); i++)
+    if(comets[i].alive)
+      living++;
+  return living;
 }

Modified: branches/commonification/tuxmath/trunk/src/game.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/game.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/game.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -143,8 +143,8 @@
 int PrerenderGraphics();
 int game(void);
 void game_set_start_message(const char*, const char*, const char*, const char*);
+
 /* draw_nums() is used in options.c and factoroids.c/h so need extern linkage */
-
 void draw_nums(const char* str, int x, int y);
 
 /*used in factoroids.c/h*/

Modified: branches/commonification/tuxmath/trunk/src/gettext.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/gettext.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/gettext.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -21,7 +21,6 @@
 
 /* NLS can be disabled through the configure --disable-nls option.  */
 #if ENABLE_NLS
-
 /* Get declarations of GNU message catalog functions.  */
 # include <libintl.h>
 

Modified: branches/commonification/tuxmath/trunk/src/globals.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/globals.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/globals.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -25,9 +25,21 @@
 #ifndef GLOBALS_H
 #define GLOBALS_H
 
+//#include "config.h"
 #include "config.h"
 
-#ifndef HAVE_LIBT4KCOMMON
+// Translation stuff (now works for Mac and Win too!): 
+#include "gettext.h"
+#include <locale.h>
+#define _(String) gettext (String)
+#define gettext_noop(String) String
+#define N_(String) gettext_noop (String)
+
+#include <wchar.h>
+
+#ifdef HAVE_LIBT4KCOMMON
+#  include <t4kcommon.h>
+#else
 typedef enum { false, true } bool;
 #endif // HAVE_LIBT4KCOMMON
 
@@ -78,6 +90,7 @@
 #define DEFAULT_MENU_SOUND 1
 #define DEFAULT_MENU_MUSIC 1
 #define DEFAULT_FULLSCREEN 1
+#define DEFAULT_LAN_MODE 0
 #define DEFAULT_USE_BKGD 1
 #define DEFAULT_HELP_MODE 0
 #define DEFAULT_DEMO_MODE 0
@@ -116,6 +129,7 @@
 #define MAX_BONUS_SPEED_RATIO 3.0
 #define MIN_COMETS 1
 #define MAX_MAX_COMETS 100
+#define SCORE_COEFFICIENT 100
 
 #define DEFAULT_FONT_NAME "AndikaDesRevG.ttf"
 #define FONT_NAME_LENGTH 64

Modified: branches/commonification/tuxmath/trunk/src/highscore.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/highscore.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/highscore.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -16,11 +16,13 @@
 #include "menu.h"
 #include "titlescreen.h"
 #include "fileops.h"
-#include "fileops_media.h"
 #include "setup.h"
 #include "options.h"
 #include "SDL_extras.h"
 #include "convert_utf.h"
+#include "transtruct.h"
+#include "network.h"
+#include "throttle.h"
 
 
 typedef struct high_score_entry {
@@ -313,6 +315,12 @@
 
   DrawTitleScreen();
 
+  /* Red "Stop" circle in upper right corner to go back to main menu: */
+  if (stop_button)
+  {
+    SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
+  }
+
   /* Draw translucent background for text: */
   {
     SDL_Rect bg_rect;
@@ -480,7 +488,7 @@
   SDL_EnableUNICODE(SDL_DISABLE);
 
   /* Now copy name into location pointed to by arg: */ 
-  strncpy((char*)pl_name, (char*)UTF8_buf, HIGH_SCORE_NAME_LENGTH * 3);
+  strncpy(pl_name, UTF8_buf, HIGH_SCORE_NAME_LENGTH * 3);
 }
 
 
@@ -715,3 +723,445 @@
 
   return high_scores[diff_level][place].name;
 }
+
+
+int Ready(const char* heading)
+{
+  SDL_Rect loc;
+  SDL_Rect okRect;
+  int finished = 0;
+  Uint32 frame = 0;
+  Uint32 timer = 0;
+  const int BG_Y = 100;
+  const int BG_WIDTH = 400;
+  const int BG_HEIGHT = 200;
+
+  DEBUGMSG(debug_highscore, "Enter Ready()\n" );
+
+  DrawTitleScreen();
+
+  /* Draw translucent background for text: */
+  {
+    SDL_Rect bg_rect;
+    bg_rect.x = (screen->w)/2 - BG_WIDTH/2;
+    bg_rect.y = BG_Y;
+    bg_rect.w = BG_WIDTH;
+    bg_rect.h = BG_HEIGHT;
+    DrawButton(&bg_rect, 15, REG_RGBA);
+
+    bg_rect.x += 10;
+    bg_rect.y += 10;
+    bg_rect.w -= 20;
+    bg_rect.h = 60;
+    DrawButton(&bg_rect, 10, SEL_RGBA);
+  }
+
+  /* Draw heading: */
+  {
+    SDL_Surface* s = BlackOutline(_(heading),
+                                  DEFAULT_MENU_FONT_SIZE, &white);
+    if (s)
+    {
+      loc.x = (screen->w/2) - (s->w/2);
+      loc.y = 110;
+      SDL_BlitSurface(s, NULL, screen, &loc);
+      SDL_FreeSurface(s);
+    }
+  }
+
+  /* Red "Stop" circle in upper right corner to go back to main menu: */
+  if (stop_button)
+  {
+    SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
+  }
+
+  /* "Next_arrow" to indicate ready to proceed: */
+  if (next_arrow)
+  {
+    okRect.x = (screen->w)/2;
+    okRect.y = 240;
+    SDL_BlitSurface(next_arrow, NULL, screen, &okRect);
+  }
+
+  /* and update: */
+  SDL_UpdateRect(screen, 0, 0, 0, 0);
+
+
+  while (!finished)
+  {
+    /* Handle user events: */
+    while (SDL_PollEvent(&event))
+    {
+      switch (event.type)
+      {
+        case SDL_QUIT:
+        {
+          cleanup();
+        }
+
+        case SDL_MOUSEBUTTONDOWN:
+        /* "Stop" button - go to main menu: */
+        {
+          if (inRect(stop_rect, event.button.x, event.button.y ))
+          {
+            finished = -1;
+            playsound(SND_TOCK);
+            break;
+          } 
+          else if (inRect(okRect, event.button.x, event.button.y ))
+          {
+            finished = 1;
+            playsound(SND_TOCK);
+            break;
+          }
+
+        }
+        case SDL_KEYDOWN:
+        {
+          switch (event.key.keysym.sym)
+          {
+            case SDLK_ESCAPE:
+            case SDLK_BACKSPACE:
+            {
+              finished = -2;
+              playsound(SND_TOCK);
+              break;
+            }
+            case SDLK_RETURN:
+            case SDLK_KP_ENTER:
+            case SDLK_SPACE:
+            {
+              finished = 1;
+              playsound(SND_TOCK);
+              break;
+            }
+            default:
+            {
+              //Do nothing - event. add support for toggle fullscreen, etc.
+            }
+          } 
+        }
+      }
+    }
+
+    HandleTitleScreenAnimations();
+    Throttle(20, &timer);
+    frame++;
+  }  // End of while (!finished) loop
+
+  DEBUGMSG(debug_highscore, "Leave Ready()\n" );
+
+  /* 1 means we start game, -1 means we go back to menu */
+  return finished;
+}
+
+
+int Standby(const char* heading, const char* sub)
+{
+  SDL_Rect loc;
+  int finished = 0;
+  Uint32 frame = 0;
+  Uint32 timer = 0;
+  const int BG_Y = 100;
+  const int BG_WIDTH = 400;
+  const int BG_HEIGHT = 200;
+
+  char buf[NET_BUF_LEN];
+
+  DEBUGMSG(debug_highscore, "Enter Standby()\n" );
+
+  DrawTitleScreen();
+
+  /* Draw translucent background for text: */
+  {
+    SDL_Rect bg_rect;
+    bg_rect.x = (screen->w)/2 - BG_WIDTH/2;
+    bg_rect.y = BG_Y;
+    bg_rect.w = BG_WIDTH;
+    bg_rect.h = BG_HEIGHT;
+    DrawButton(&bg_rect, 15, REG_RGBA);
+
+    bg_rect.x += 10;
+    bg_rect.y += 10;
+    bg_rect.w -= 20;
+    bg_rect.h = 60;
+    DrawButton(&bg_rect, 10, SEL_RGBA);
+  }
+
+  /* Draw heading: */
+  {
+    SDL_Surface* s = BlackOutline(_(heading),
+                                  DEFAULT_MENU_FONT_SIZE, &white);
+    if (s)
+    {
+      loc.x = (screen->w/2) - (s->w/2);
+      loc.y = 110;
+      SDL_BlitSurface(s, NULL, screen, &loc);
+      SDL_FreeSurface(s);
+    }
+
+    s = BlackOutline(_(sub),
+                     DEFAULT_MENU_FONT_SIZE, &white);
+    if (s)
+    {
+      loc.x = (screen->w/2) - (s->w/2);
+      loc.y = 140;
+      SDL_BlitSurface(s, NULL, screen, &loc);
+      SDL_FreeSurface(s);
+    }
+  }
+
+  /* Red "Stop" circle in upper right corner to go back to main menu: */
+  if (stop_button)
+  {
+    SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
+  }
+
+  /* and update: */
+  SDL_UpdateRect(screen, 0, 0, 0, 0);
+
+
+  while (!finished)
+  {
+    /* Handle user events: */
+    while (SDL_PollEvent(&event))
+    {
+      switch (event.type)
+      {
+        case SDL_QUIT:
+        {
+          cleanup();
+        }
+
+        case SDL_MOUSEBUTTONDOWN:
+        /* "Stop" button - go to main menu: */
+        {
+          if (inRect(stop_rect, event.button.x, event.button.y ))
+          {
+            finished = 1;
+            playsound(SND_TOCK);
+            break;
+          }
+        }
+        case SDL_KEYDOWN:
+        {
+          switch (event.key.keysym.sym)
+          {
+            case SDLK_ESCAPE:
+            case SDLK_BACKSPACE:
+            {
+              finished = -2;
+              playsound(SND_TOCK);
+              break;
+            }
+
+            default:
+            {
+              //Do nothing - event. add support for toggle fullscreen, etc.
+            }
+          } 
+        }
+      }
+    }
+
+    /* Handle server messages: */
+    while(!check_messages(buf))
+    {
+      if(strncmp(buf,"GO_TO_GAME", strlen("GO_TO_GAME")) == 0)
+      {
+        finished = 1;
+        playsound(SND_TOCK);
+        break;
+      }
+      else if(strncmp(buf, "GAME_IN_PROGRESS", strlen("GAME_IN_PROGRESS")) == 0)
+      {
+        finished = -1;
+        playsound(SND_TOCK);
+        break;
+      }
+      else
+      {
+        DEBUGMSG(debug_highscore, "Unrecognized message from server: %s\n", buf);
+        continue;
+      }
+    }
+
+    HandleTitleScreenAnimations();
+    Throttle(20, &timer);
+    frame++;
+  }  // End of while (!finished) loop
+
+  DEBUGMSG(debug_highscore, "Leave Standby()\n" );
+
+  /* 1 means we start game, -1 means we go back to menu */
+  return finished;
+}
+
+
+int detecting_servers(const char* heading, const char* sub)
+{
+#ifndef HAVE_LIBSDL_NET
+  return 0;
+#else
+  SDL_Rect loc;
+  SDL_Rect TuxRect,
+           stopRect;
+
+  int finished = 0;
+  int tux_frame = 0;
+  Uint32 frame = 0;
+  Uint32 start = 0;
+  Uint32 timer = 0;
+  int servers_found = 0;  
+  sprite* Tux = NULL;
+
+  DEBUGMSG(debug_lan, "\nEnter detecting_servers()\n");
+
+  /* FIXME it takes several seconds to load this sprite on a */
+  /* Dell Mini 9 netbook, probably longer on many school     */
+  /* machines.  Perhaps we should load this ahead of time... */
+  Tux = LoadSprite("tux/bigtux", IMG_ALPHA);
+
+  /* We need to get Unicode vals from SDL keysyms */
+  SDL_EnableUNICODE(SDL_ENABLE);
+
+  /* Draw background: */
+  if (current_bkg())
+    SDL_BlitSurface(current_bkg(), NULL, screen, NULL);
+
+  /* Red "Stop" circle in upper right corner to go back to main menu: */
+  if (images[IMG_STOP])
+  {
+    stopRect.w = images[IMG_STOP]->w;
+    stopRect.h = images[IMG_STOP]->h;
+    stopRect.x = screen->w - images[IMG_STOP]->w;
+    stopRect.y = 0;
+    SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
+  }
+
+  if (Tux && Tux->frame[0]) /* make sure sprite has at least one frame */
+  {
+    TuxRect.w = Tux->frame[0]->w;
+    TuxRect.h = Tux->frame[0]->h;
+    TuxRect.x = 0;
+    TuxRect.y = screen->h - Tux->frame[0]->h;
+  }
+
+  /* Draw heading: */
+  {
+    SDL_Surface* s = BlackOutline(_(heading),
+                                  DEFAULT_MENU_FONT_SIZE, &white);
+    if (s)
+    {
+      loc.x = (screen->w/2) - (s->w/2);
+      loc.y = 110;
+      SDL_BlitSurface(s, NULL, screen, &loc);
+      SDL_FreeSurface(s);
+    }
+
+    s = BlackOutline(_(sub),
+                     DEFAULT_MENU_FONT_SIZE, &white);
+    if (s)
+    {
+      loc.x = (screen->w/2) - (s->w/2);
+      loc.y = 140;
+      SDL_BlitSurface(s, NULL, screen, &loc);
+      SDL_FreeSurface(s);
+    }
+  }
+
+  /* and update: */
+  SDL_UpdateRect(screen, 0, 0, 0, 0);
+
+  while (!finished)
+  {
+    start = SDL_GetTicks();
+
+    //Scan local network to find running server:
+    servers_found = LAN_DetectServers();
+    if(servers_found < 1)
+    {
+      printf("No server could be found - returning.\n");
+      /* Turn off SDL Unicode lookup (because has some overhead): */
+      SDL_EnableUNICODE(SDL_DISABLE);
+      FreeSprite(Tux);
+      return 0;
+    }
+    else if(servers_found  == 1)  //One server - connect without player intervention
+    {
+      printf("Single server found - connecting automatically...");
+
+      if(!LAN_AutoSetup(0))  //i.e.first (and only) entry in list
+      {
+        printf("LAN_AutoSetup() failed - returning.\n");
+        /* Turn off SDL Unicode lookup (because has some overhead): */
+        SDL_EnableUNICODE(SDL_DISABLE);
+        FreeSprite(Tux);
+        return 0;
+      }
+      
+      
+      finished = 1;
+      break;  //So we quit scanning as soon as we connect
+      printf("connected\n");
+    } else if (servers_found  > 1)
+    {
+      //TODO display list of servers for player to choose from:
+    }
+
+
+    while (SDL_PollEvent(&event)) 
+    {
+      switch (event.type)
+      {
+        case SDL_QUIT:
+        {
+          cleanup();
+        }
+
+        case SDL_MOUSEBUTTONDOWN:
+        /* "Stop" button - go to main menu: */
+        { 
+          if (inRect(stopRect, event.button.x, event.button.y ))
+          {
+            finished = 1;
+            playsound(SND_TOCK);
+            break;
+          }
+        }
+      }
+    }
+
+    /* --- make tux blink --- */
+    switch (frame % TUX6)
+    {
+      case 0:    tux_frame = 1; break;
+      case TUX1: tux_frame = 2; break;
+      case TUX2: tux_frame = 3; break;
+      case TUX3: tux_frame = 4; break;                        
+      case TUX4: tux_frame = 3; break;
+      case TUX5: tux_frame = 2; break;
+      default: tux_frame = 0;
+    }
+
+    if (Tux && tux_frame)
+    {
+      SDL_BlitSurface(Tux->frame[tux_frame - 1], NULL, screen, &TuxRect);
+      SDL_UpdateRect(screen, TuxRect.x, TuxRect.y, TuxRect.w, TuxRect.h);
+    }
+
+    /* Wait so we keep frame rate constant: */
+    Throttle(20, &timer);
+    frame++;
+  }  // End of while (!finished) loop
+
+
+  /* Turn off SDL Unicode lookup (because has some overhead): */
+  SDL_EnableUNICODE(SDL_DISABLE);
+  FreeSprite(Tux);
+
+  return 1;
+
+#endif
+}
+

Modified: branches/commonification/tuxmath/trunk/src/highscore.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/highscore.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/highscore.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -16,9 +16,15 @@
 
 #include "globals.h"
 
+
 void DisplayHighScores(int level);
 void HighScoreNameEntry(char* pl_name);
 void NameEntry(char* pl_name, const char* heading, const char* sub);
+/* FIXME the next three don't have anything to do with high scores */
+/* and don't really belong here:                                   */
+int Standby(const char* heading, const char* sub);
+int detecting_servers(const char* heading, const char* sub);
+int Ready(const char* heading);
 
 int check_score_place(int diff_level, int new_score);
 int insert_score(char* playername, int diff_level, int new_score);

Deleted: branches/commonification/tuxmath/trunk/src/mathcards.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/mathcards.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/mathcards.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,2438 +0,0 @@
-/*
-*  C Implementation: mathcards.c
-*
-*       Description: implementation of backend for a flashcard-type math game.
-        Developed as an enhancement to Bill Kendrick's "Tux of Math Command"
-        (aka tuxmath).  (If tuxmath were a C++ program, this would be a C++ class).
-        MathCards could be used as the basis for similar games using a different interface.
-
-*
-*
-* Author: David Bruce <dbruce at tampabay.rr.com>, (C) 2005
-*
-* Copyright: See COPYING file that comes with this distribution.  (Briefly, GNU GPL).
-*
-* Revised extensively in 2008 by Brendan Luchen, Tim Holy, and David Bruce
-*
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <time.h>
-
-#include "globals.h"
-#include "mathcards.h"
-
-/* extern'd constants */
-
-const char* const MC_OPTION_TEXT[NOPTS+1] = {
-"PLAY_THROUGH_LIST",
-"QUESTION_COPIES",
-"REPEAT_WRONGS",
-"COPIES_REPEATED_WRONGS",
-"ALLOW_NEGATIVES",
-"MAX_ANSWER",
-"MAX_QUESTIONS",
-"MAX_FORMULA_NUMS",
-"MIN_FORMULA_NUMS",
-
-"FORMAT_ANSWER_LAST",
-"FORMAT_ANSWER_FIRST",
-"FORMAT_ANSWER_MIDDLE",
-"FORMAT_ADD_ANSWER_LAST",
-"FORMAT_ADD_ANSWER_FIRST",
-"FORMAT_ADD_ANSWER_MIDDLE",
-"FORMAT_SUB_ANSWER_LAST",
-"FORMAT_SUB_ANSWER_FIRST",
-"FORMAT_SUB_ANSWER_MIDDLE",
-"FORMAT_MULT_ANSWER_LAST",
-"FORMAT_MULT_ANSWER_FIRST",
-"FORMAT_MULT_ANSWER_MIDDLE",
-"FORMAT_DIV_ANSWER_LAST",
-"FORMAT_DIV_ANSWER_FIRST",
-"FORMAT_DIV_ANSWER_MIDDLE",
-
-"ADDITION_ALLOWED",
-"SUBTRACTION_ALLOWED",
-"MULTIPLICATION_ALLOWED",
-"DIVISION_ALLOWED",
-"TYPING_PRACTICE_ALLOWED",
-"ARITHMETIC_ALLOWED",
-"COMPARISON_ALLOWED",
-
-"MIN_AUGEND",
-"MAX_AUGEND",
-"MIN_ADDEND",
-"MAX_ADDEND",
-
-"MIN_MINUEND",
-"MAX_MINUEND",
-"MIN_SUBTRAHEND",
-"MAX_SUBTRAHEND",
-
-"MIN_MULTIPLIER",
-"MAX_MULTIPLIER",
-"MIN_MULTIPLICAND",
-"MAX_MULTIPLICAND",
-
-"MIN_DIVISOR",
-"MAX_DIVISOR",
-"MIN_QUOTIENT",
-"MAX_QUOTIENT",
-
-"MIN_TYPING_NUM",
-"MAX_TYPING_NUM",
-
-"MIN_COMPARATOR" ,
-"MAX_COMPARATOR" ,
-"MIN_COMPARISAND",
-"MAX_COMPARISAND",
-
-"RANDOMIZE",
-
-"COMPREHENSIVE",
-"AVG_LIST_LENGTH",
-"VARY_LIST_LENGTH",
-
-"END_OF_OPTS"
-};
-
-const int MC_DEFAULTS[] = {
-  1,    //PLAY_THROUGH_LIST
-  1,    //QUESTION_COPIES
-  1,    //REPEAT_WRONGS
-  1,    //COPIES_REPEATED_WRONGS
-  0,    //ALLOW_NEGATIVES
-  999,  //MAX_ANSWER
-  5000, //MAX_QUESTIONS
-  2,    //MAX_FORMULA_NUMS
-  2,    //MIN_FORMULA_NUMS
-        //
-  1,    //FORMAT_ANSWER_LAST
-  0,    //FORMAT_ANSWER_FIRST
-  0,    //FORMAT_ANSWER_MIDDLE
-  1,    //FORMAT_ADD_ANSWER_LAST
-  0,    //FORMAT_ADD_ANSWER_FIRST
-  0,    //FORMAT_ADD_ANSWER_MIDDLE
-  1,    //FORMAT_SUB_ANSWER_LAST
-  0,    //FORMAT_SUB_ANSWER_FIRST
-  0,    //FORMAT_SUB_ANSWER_MIDDLE
-  1,    //FORMAT_MULT_ANSWER_LAST
-  0,    //FORMAT_MULT_ANSWER_FIRST
-  0,    //FORMAT_MULT_ANSWER_MIDDLE
-  1,    //FORMAT_DIV_ANSWER_LAST
-  0,    //FORMAT_DIV_ANSWER_FIRST
-  0,    //FORMAT_DIV_ANSWER_MIDDLE
-        //
-  1,    //ADDITION_ALLOWED
-  1,    //SUBTRACTION_ALLOWED
-  1,    //MULTIPLICATION_ALLOWED
-  1,    //DIVISION_ALLOWED
-
-  0,    //TYPING_PRACTICE_ALLOWED
-  1,    //ARITHMETIC_ALLOWED
-  0,    //COMPARISON_ALLOWED
-        //
-  0,    //MIN_AUGEND
-  12,   //MAX_AUGEND
-  0,    //MIN_ADDEND
-  12,   //MAX_ADDEND
-        //
-  0,    //MIN_MINUEND
-  12,   //MAX_MINUEND
-  0,    //MIN_SUBTRAHEND
-  12,   //MAX_SUBTRAHEND
-        //
-  0,    //MIN_MULTIPLIER
-  12,   //MAX_MULTIPLIER
-  0,    //MIN_MULTIPLICAND
-  12,   //MAX_MULTIPLICAND
-        //
-  0,    //MIN_DIVISOR
-  12,   //MAX_DIVISOR
-  0,    //MIN_QUOTIENT
-  12,   //MAX_QUOTIENT
-        //
-  0,    //MIN_TYPING_NUM
-  12,   //MAX_TYPING_NUM
-        //
-  0,    //MIN_COMPARATOR
-  12,   //MAX_COMPARATOR
-  0,    //MIN_COMPARISAND
-  12,   //MAX_COMPARISAND
-
-  1,    //RANDOMIZE
-
-  0,    //COMPREHENSIVE
-  100,  //AVG_LIST_LENGTH
-  1     //VARY_LIST_LENGTH
-};
-
-
-
-/* "Globals" for mathcards.c: */
-#define PI_VAL 3.1415927
-#define NPRIMES 9
-const int smallprimes[NPRIMES] = {2, 3, 5 ,7, 11, 13, 17, 19, 23};
-const char operchars[4] = "+-*/";
-
-MC_Options* math_opts = 0;
-MC_MathQuestion* question_list = 0;
-MC_MathQuestion* wrong_quests = 0;
-MC_MathQuestion* next_wrong_quest = 0;
-int initialized = 0;
-int quest_list_length = 0;
-int answered_correctly = 0;
-int answered_wrong = 0;
-int questions_pending = 0;
-int unanswered = 0;
-int starting_length = 0;
-int max_formula_size = 0; //max length in chars of a flashcard's formula
-int max_answer_size = 0; //and of its answer
-
-/* For keeping track of timing data */
-float* time_per_question_list = NULL;
-int length_time_per_question_list = 0;
-int length_alloc_time_per_question_list = 0;
-
-const MC_FlashCard DEFAULT_CARD = {NULL,NULL,0,0}; //empty card to signal error
-
-/* "private" function prototypes:                        */
-/*                                                       */
-/* these are for internal use by MathCards only - like   */
-/* the private functions of a C++ class. Declared static */
-/* to give file scope rather than extern scope.          */
-
-static MC_MathQuestion* generate_list(void);
-static void clear_negatives(void);
-//static int validate_question(int n1, int n2, int n3);
-//static MC_MathQuestion* create_node(int n1, int n2, int op, int ans, int f);
-static MC_MathQuestion* create_node_from_card(const MC_FlashCard* flashcard);
-static MC_MathQuestion* insert_node(MC_MathQuestion* first, MC_MathQuestion* current, MC_MathQuestion* new_node);
-static MC_MathQuestion* append_node(MC_MathQuestion* list, MC_MathQuestion* new_node);
-static MC_MathQuestion* remove_node(MC_MathQuestion* first, MC_MathQuestion* n);
-static MC_MathQuestion* delete_list(MC_MathQuestion* list);
-//static int copy_node(MC_MathQuestion* original, MC_MathQuestion* copy);
-static int list_length(MC_MathQuestion* list);
-static int randomize_list(MC_MathQuestion** list);
-
-int comp_randomizer(const void *a, const void *b);
-static MC_MathQuestion* pick_random(int length, MC_MathQuestion* list);
-static int compare_node(MC_MathQuestion* first, MC_MathQuestion* other);
-static int already_in_list(MC_MathQuestion* list, MC_MathQuestion* ptr);
-//static int int_to_bool(int i);
-//static int sane_value(int i);
-//static int abs_value(int i);
-static int log10i(int i);
-static int floatCompare(const void *v1,const void *v2);
-
-static void print_list(FILE* fp,MC_MathQuestion* list);
-void print_vect_list(FILE* fp, MC_MathQuestion** vect, int length);
-
-/* these functions are dead code unless compiling with debug turned on: */
-static void print_card(MC_FlashCard card);
-static void print_counters(void);
-//static MC_MathQuestion* create_node_copy(MC_MathQuestion* other);
-//static MC_FlashCard    create_card_from_node(MC_MathQuestion* node);
-
-/* Functions for new mathcards architecture */
-static void free_node(MC_MathQuestion* mq); //wrapper for free() that also frees card
-static MC_FlashCard generate_random_flashcard(void);
-static MC_FlashCard generate_random_ooo_card_of_length(int length, int reformat);
-static void copy_card(const MC_FlashCard* src, MC_FlashCard* dest); //deep copy a flashcard
-static MC_MathQuestion* allocate_node(void); //allocate space for a node
-static int compare_card(const MC_FlashCard* a, const MC_FlashCard* b); //test for identical cards
-static int find_divisor(int a); //return a random positive divisor of a
-static int calc_num_valid_questions(void);
-static MC_MathQuestion* add_all_valid(MC_ProblemType pt, MC_MathQuestion* list, MC_MathQuestion** end_of_list);
-static MC_MathQuestion* find_node(MC_MathQuestion* list, int num);
-
-/*  MC_Initialize() sets up the struct containing all of  */
-/*  settings regarding math questions.  It should be      */
-/*  called before any other function.  Many of the other  */
-/*  functions will not work properly if MC_Initialize()   */
-/*  has not been called. It only needs to be called once, */
-/*  i.e when the program is starting, not at the beginning*/
-/*  of each math game for the player. Returns 1 if        */
-/*  successful, 0 otherwise.                              */
-int MC_Initialize(void)
-{
-  int i;
-
-  mcdprintf("\nEntering MC_Initialize()");
-  /* check flag to see if we did this already */
-  if (initialized)
-  {
-
-    if (debug_status & debug_mathcards) {
-      printf("\nAlready initialized");
-      MC_PrintMathOptions(stdout, 0);
-      printf("\nLeaving MC_Initialize()\n");
-    }
-
-    return 1;
-  }
-  math_opts = malloc(sizeof(MC_Options));
-  /* bail out if no struct */
-  if (!math_opts)
-  {
-
-    mcdprintf("\nError: math_opts null or invalid");
-    mcdprintf("\nLeaving MC_Initialize()\n");
-
-    fprintf(stderr, "\nUnable to initialize math_options");
-    return 0;
-  }
-
-  /* set defaults */
-  for (i = 0; i < NOPTS; ++i)
-    {
-    math_opts->iopts[i] = MC_DEFAULTS[i];
-    }
-
-  /* if no negatives to be used, reset any negatives to 0 */
-  if (!math_opts->iopts[ALLOW_NEGATIVES])
-  {
-    clear_negatives();
-  }
-
-  initialized = 1;
-
-  if (debug_status & debug_mathcards) {
-    MC_PrintMathOptions(stdout, 0);
-    printf("\nLeaving MC_Initialize()\n");
-  }
-
-  return 1;
-}
-
-
-
-/*  MC_StartGame() generates the list of math questions   */
-/*  based on existing settings. It should be called at    */
-/*  the beginning of each math game for the player.       */
-/*  Returns 1 if resultant list contains 1 or more        */
-/*  questions, 0 if list empty or not generated           */
-/*  successfully.                                         */
-int MC_StartGame(void)
-{
-  mcdprintf("\nEntering MC_StartGame()");
-
-  /* if math_opts not set up yet, initialize it: */
-  if (!initialized)
-  {
-
-    mcdprintf("\nNot initialized - calling MC_Initialize()");
-
-    MC_Initialize();
-  }
-
-  if (!math_opts)
-  {
-    mcdprintf("\nCould not initialize - bailing out");
-    mcdprintf("\nLeaving MC_StartGame()\n");
-
-    return 0;
-  }
-  /* we know math_opts exists if we make it to here */
-  srand(time(NULL));
-
-  /* clear out old lists if starting another game: (if not done already) */
-  delete_list(question_list);
-  question_list = NULL;
-  delete_list(wrong_quests);
-  wrong_quests = NULL;
-
-  /* clear the time list */
-  if (time_per_question_list != NULL) {
-    free(time_per_question_list);
-    time_per_question_list = NULL;
-    length_time_per_question_list = 0;
-    length_alloc_time_per_question_list = 0;
-  }
-
-  /* determine how much space needed for strings, based on user options */
-  max_formula_size = MC_GetOpt(MAX_FORMULA_NUMS)
-                   * (log10i(MC_GLOBAL_MAX) + 4) //sign/operator/spaces
-                   + 1; //question mark for answer
-  max_answer_size = (int)(log10i(MC_GLOBAL_MAX) ) + 2; //negative sign + digit
-
-  mcdprintf("max answer, formula size: %d, %d\n",
-            max_answer_size, max_formula_size);
-  /* set up new list with pointer to top: */
-  question_list = generate_list();
-
-  next_wrong_quest = 0;
-  /* initialize counters for new game: */
-  quest_list_length = list_length(question_list);
-  /* Note: the distinction between quest_list_length and  */
-  /* unanswered is that the latter includes questions     */
-  /* that are currently "in play" by the user interface - */
-  /* it is only decremented when an answer to the question*/
-  /* is received.                                         */
-  unanswered = starting_length = quest_list_length;
-  answered_correctly = 0;
-  answered_wrong = 0;
-  questions_pending = 0;
-
-  if (debug_status & debug_mathcards) {
-    print_counters();
-  }
-
-  /* make sure list now exists and has non-zero length: */
-  if (question_list && quest_list_length)
-  {
-    mcdprintf("\nGame set up successfully");
-    mcdprintf("\nLeaving MC_StartGame()\n");
-
-    return 1;
-  }
-  else
-  {
-    mcdprintf("\nGame NOT set up successfully - no valid list");
-    mcdprintf("\nLeaving MC_StartGame()\n");
-
-    return 0;
-  }
-}
-
-/*  MC_StartGameUsingWrongs() is like MC_StartGame(),     */
-/*  but uses the incorrectly answered questions from the  */
-/*  previous game for the question list as a review form  */
-/*  of learning. If there were no wrong answers (or no    */
-/*  previous game), it behaves just like MC_StartGame().  */
-/*  FIXME wonder if it should return a different value if */
-/*  the list is created from settings because there is no */
-/*  valid wrong question list?                            */
-int MC_StartGameUsingWrongs(void)
-{
-  mcdprintf("\nEntering MC_StartGameUsingWrongs()");
-
-  /* Note: if not initialized, control will pass to       */
-  /* MC_StartGame() via else clause so don't need to test */
-  /* for initialization here                              */
-  if (wrong_quests &&
-      list_length(wrong_quests))
-  {
-    mcdprintf("\nNon-zero length wrong_quests list found, will");
-    mcdprintf("\nuse for new game list:");
-
-    /* initialize lists for new game: */
-    delete_list(question_list);
-    if(!randomize_list(&wrong_quests)) {
-      fprintf(stderr, "Error during randomization of wrong_quests!\n");
-      /* Punt on trying wrong question list, just run normal game */
-      return MC_StartGame();
-    }
-    question_list = wrong_quests;
-    wrong_quests = 0;
-    next_wrong_quest = 0;
-   /* initialize counters for new game: */
-    quest_list_length = list_length(question_list);
-    unanswered = starting_length = quest_list_length;
-    answered_correctly = 0;
-    answered_wrong = 0;
-    questions_pending = 0;
-
-    if (debug_status & debug_mathcards) {
-      print_counters();
-      print_list(stdout, question_list);
-      printf("\nLeaving MC_StartGameUsingWrongs()\n");
-    }
-
-    return 1;
-  }
-  else /* if no wrong_quests list, go to MC_StartGame()   */
-       /* to set up list based on math_opts               */
-  {
-    mcdprintf("\nNo wrong questions to review - generate list from math_opts\n");
-    mcdprintf("\nLeaving MC_StartGameUsingWrongs()\n");
-
-    return MC_StartGame();
-  }
-}
-
-
-/*  MC_NextQuestion() takes a pointer to an allocated     */
-/*  MC_MathQuestion struct and fills in the fields for    */
-/*  use by the user interface program. It basically is    */
-/*  like taking the next flashcard from the pile. The     */
-/*  node containing the question is removed from the list.*/
-/*  Returns 1 if question found, 0 if list empty/invalid  */
-/*  or if argument pointer is invalid.                    */
-int MC_NextQuestion(MC_FlashCard* fc)
-{
-  mcdprintf("\nEntering MC_NextQuestion()\n");
-
-  /* (so we can free the node after removed from list:) */
-  MC_MathQuestion* ptr;
-  ptr = question_list;
-
-  if (!fc )
-  {
-    fprintf(stderr, "\nNull MC_FlashCard* argument!\n");
-    mcdprintf("\nLeaving MC_NextQuestion()\n");
-    return 0;
-  }
-
-  if (!question_list ||
-/*      !next_question || */
-      !list_length(question_list) )
-  {
-    mcdprintf("\nquestion_list invalid or empty");
-    mcdprintf("\nLeaving MC_NextQuestion()\n");
-
-    return 0;
-  }
-
-  /* 'draw' - copy over the first question */
-  copy_card(&question_list->card, fc);
-
-  /* 'discard' - take first question node out of list and free it */
-  question_list = remove_node(question_list, question_list);
-  free_node(ptr);
-  quest_list_length--;
-  questions_pending++;
-
-  if (debug_status & debug_mathcards) {
-    printf("\nnext question is:");
-    print_card(*fc);
-    print_counters();
-    printf("\n\nLeaving MC_NextQuestion()\n");
-  }
-
-  return 1;
-}
-
-/*  MC_AnsweredCorrectly() is how the user interface      */
-/*  tells MathCards that the question has been answered   */
-/*  correctly. Returns 1 if no errors.                    */
-int MC_AnsweredCorrectly(MC_FlashCard* fc)
-{
-  mcdprintf("\nEntering MC_AnsweredCorrectly()");
-
-  if (!fc)
-  {
-    fprintf(stderr, "\nMC_AnsweredCorrectly() passed invalid pointer as argument!\n");
-
-    mcdprintf("\nInvalid MC_FlashCard* argument!");
-    mcdprintf("\nLeaving MC_AnsweredCorrectly()\n");
-
-    return 0;
-  }
-
-  if (debug_status & debug_mathcards) {
-    printf("\nQuestion was:");
-    print_card(*fc);
-  }
-
-  answered_correctly++;
-  questions_pending--;
-
-  if (!math_opts->iopts[PLAY_THROUGH_LIST])
-  /* reinsert question into question list at random location */
-  {
-    mcdprintf("\nReinserting question into list");
-
-    MC_MathQuestion* ptr1;
-    MC_MathQuestion* ptr2;
-    /* make new node using values from flashcard */
-    ptr1 = create_node_from_card(fc);
-    /* put it into list */
-    ptr2 = pick_random(quest_list_length, question_list);
-    question_list = insert_node(question_list, ptr2, ptr1);
-    quest_list_length++;
-    /* unanswered does not change - was not decremented when */
-    /* question allocated!                                   */
-  }
-  else
-  {
-    mcdprintf("\nNot reinserting question into list");
-    /* not recycling questions so fewer questions remain:      */
-    unanswered--;
-  }
-
-  if (debug_status & debug_mathcards) {
-    print_counters();
-    printf("\nLeaving MC_AnsweredCorrectly()\n");
-  }
-
-  return 1;
-}
-
-/*  MC_NotAnsweredCorrectly() is how the user interface    */
-/*  tells MathCards that the player failed to answer the  */
-/*  question correctly. Returns 1 if no errors.           */
-/*  Note: this gets triggered only if a player's city     */
-/*  gets hit by a question, not if they "miss".           */
-int MC_NotAnsweredCorrectly(MC_FlashCard* fc)
-{
-  mcdprintf("\nEntering MC_NotAnsweredCorrectly()");
-
-  if (!fc)
-  {
-    fprintf(stderr, "\nMC_NotAnsweredCorrectly() passed invalid pointer as argument!\n");
-
-    mcdprintf("\nInvalid MC_FlashCard* argument!");
-    mcdprintf("\nLeaving MC_NotAnsweredCorrectly()\n");
-
-    return 0;
-  }
-
-  if (debug_status & debug_mathcards) {
-    printf("\nQuestion was:");
-    print_card(*fc);
-  }
-
-  answered_wrong++;
-  questions_pending--;
-
-  /* add question to wrong_quests list: */
-
-  MC_MathQuestion* ptr1;
-  MC_MathQuestion* ptr2;
-
-  ptr1 = create_node_from_card(fc);
-
-  if (!already_in_list(wrong_quests, ptr1)) /* avoid duplicates */
-  {
-    mcdprintf("\nAdding to wrong_quests list");
-    wrong_quests = append_node(wrong_quests, ptr1);
-  }
-  else /* avoid memory leak */
-  {
-    free(ptr1);
-  }
-
-  /* if desired, put question back in list so student sees it again */
-  if (math_opts->iopts[REPEAT_WRONGS])
-  {
-    int i;
-
-    mcdprintf("\nAdding %d copies to question_list:", math_opts->iopts[COPIES_REPEATED_WRONGS]);
-
-    /* can put in more than one copy (to drive the point home!) */
-    for (i = 0; i < math_opts->iopts[COPIES_REPEATED_WRONGS]; i++)
-    {
-      ptr1 = create_node_from_card(fc);
-      ptr2 = pick_random(quest_list_length, question_list);
-      question_list = insert_node(question_list, ptr2, ptr1);
-      quest_list_length++;
-    }
-    /* unanswered stays the same if a single copy recycled or */
-    /* increases by 1 for each "extra" copy reinserted:       */
-    unanswered += (math_opts->iopts[COPIES_REPEATED_WRONGS] - 1);
-  }
-  else
-  {
-    mcdprintf("\nNot repeating wrong answers\n");
-
-    /* not repeating questions so list gets shorter:      */
-    unanswered--;
-  }
-
-  if (debug_status & debug_mathcards) {
-    print_counters();
-    printf("\nLeaving MC_NotAnswered_Correctly()\n");
-  }
-
-  return 1;
-
-}
-
-/* Tells user interface if all questions have been answered correctly! */
-/* Requires that at list contained at least one question to start with */
-/* and that wrongly answered questions have been recycled.             */
-int MC_MissionAccomplished(void)
-{
-  if (starting_length
-    && math_opts->iopts[REPEAT_WRONGS]
-    && !unanswered)
-  {
-    return 1;
-  }
-  else
-  {
-    return 0;
-  }
-}
-
-/*  Returns number of questions left (either in list       */
-/*  or "in play")                                          */
-int MC_TotalQuestionsLeft(void)
-{
-  return unanswered;
-}
-
-/*  Returns number of questions left in list, NOT       */
-/*  including questions currently "in play".            */
-int MC_ListQuestionsLeft(void)
-{
-  return quest_list_length;
-}
-
-
-/*  Store the amount of time a given flashcard was      */
-/*  visible on the screen. Returns 1 if the request     */
-/*  succeeds, 0 otherwise.                              */
-int MC_AddTimeToList(float t)
-{
-  int newsize = 0;
-  float *newlist;
-
-  /* This list will be allocated in an STL-like manner: when the       */
-  /* list gets full, allocate an additional amount of storage equal    */
-  /* to the current size of the list, so that only O(logN) allocations */
-  /* will ever be needed. We therefore have to keep track of 2 sizes:  */
-  /* the allocated size, and the actual number of items currently on   */
-  /* the list.                                                         */
-  if (length_time_per_question_list >= length_alloc_time_per_question_list) {
-    /* The list is full, allocate more space */
-    newsize = 2*length_time_per_question_list;
-    if (newsize == 0)
-      newsize = 100;
-    newlist = realloc(time_per_question_list, newsize*sizeof(float));
-    if (newlist == NULL) {
-      DEBUGMSG(debug_mathcards,"\nError: allocation for time_per_question_list failed\n");
-      return 0;
-    }
-    time_per_question_list = newlist;
-    length_alloc_time_per_question_list = newsize;
-  }
-
-  /* Append the time to the list */
-  time_per_question_list[length_time_per_question_list++] = t;
-  return 1;
-}
-
-/* Frees heap memory used in program:                   */
-void MC_EndGame(void)
-{
-  delete_list(question_list);
-  question_list = 0;
-  delete_list(wrong_quests);
-  wrong_quests = 0;
-
-  if (math_opts)
-  {
-    free(math_opts);
-    math_opts = 0;
-  }
-
-  free(time_per_question_list);
-  time_per_question_list = NULL;
-  length_alloc_time_per_question_list = 0;
-  length_time_per_question_list = 0;
-
-  initialized = 0;
-}
-
-
-
-/* prints struct to file */
-void MC_PrintMathOptions(FILE* fp, int verbose)
-{
-  int i, vcommentsprimed = 0;
-  //comments when writing out verbose...perhaps they can go somewhere less conspicuous
-  static char* vcomments[NOPTS];
-  if (!vcommentsprimed) //we only want to initialize these once
-  {
-    vcommentsprimed = 1;
-    for (i = 0; i < NOPTS; ++i)
-      vcomments[i] = NULL;
-    vcomments[PLAY_THROUGH_LIST] =
-      "\n############################################################\n"
-      "#                                                          #\n"
-      "#                  General Math Options                    #\n"
-      "#                                                          #\n"
-      "# If 'play_through_list' is true, Tuxmath will ask each    #\n"
-      "# question in an internally-generated list. The list is    #\n"
-      "# generated based on the question ranges selected below.   #\n"
-      "# The game ends when no questions remain.                  #\n"
-      "# If 'play_through_list' is false, the game continues      #\n"
-      "# until all cities are destroyed.                          #\n"
-      "# Default is 1 (i.e. 'true' or 'yes').                     #\n"
-      "#                                                          #\n"
-      "# 'question_copies' is the number of times each question   #\n"
-      "# will be asked. It can be 1 to 10 - Default is 1.         #\n"
-      "#                                                          #\n"
-      "# 'repeat_wrongs' tells Tuxmath whether to reinsert        #\n"
-      "# incorrectly answered questions into the list to be       #\n"
-      "# asked again. Default is 1 (yes).                         #\n"
-      "#                                                          #\n"
-      "# 'copies_repeated_wrongs' gives the number of times an    #\n"
-      "# incorrectly answered question will reappear. Default     #\n"
-      "# is 1.                                                    #\n"
-      "#                                                          #\n"
-      "# The defaults for these values result in a 'mission'      #\n"
-      "# for Tux that is accomplished by answering all            #\n"
-      "# questions correctly with at least one surviving city.    #\n"
-      "############################################################\n\n";
-
-    vcomments[FORMAT_ADD_ANSWER_LAST] =
-      "\n############################################################\n"
-      "# The 'format_<op>_answer_<place>  options control         #\n"
-      "# generation of questions with the answer in different     #\n"
-      "# places in the equation.  i.e.:                           #\n"
-      "#                                                          #\n"
-      "#    format_add_answer_last:    2 + 2 = ?                  #\n"
-      "#    format_add_answer_first:   ? + 2 = 4                  #\n"
-      "#    format_add_answer_middle:  2 + ? = 4                  #\n"
-      "#                                                          #\n"
-      "# By default, 'format_answer_first' is enabled and the     #\n"
-      "# other two formats are disabled.  Note that the options   #\n"
-      "# are not mutually exclusive - the question list may       #\n"
-      "# contain questions with different formats.                #\n"
-      "#                                                          #\n"
-      "# The formats are set independently for each of the four   #\n"
-      "# math operations.                                         #\n"
-      "############################################################\n\n";
-
-    vcomments[ALLOW_NEGATIVES] =
-      "\n############################################################\n"
-      "# 'allow_negatives' allows or disallows use of negative    #\n"
-      "# numbers as both operands and answers.  Default is 0      #\n"
-      "# (no), which disallows questions like:                    #\n"
-      "#          2 - 4 = ?                                       #\n"
-      "# Note: this option must be enabled in order to set the    #\n"
-      "# operand ranges to include negatives (see below). If it   #\n"
-      "# is changed from 1 (yes) to 0 (no), any negative          #\n"
-      "# operand limits will be reset to 0.                       #\n"
-      "############################################################\n\n";
-
-    vcomments[MAX_ANSWER] =
-      "\n############################################################\n"
-      "# 'max_answer' is the largest absolute value allowed in    #\n"
-      "# any value in a question (not only the answer). Default   #\n"
-      "# is 144. It can be set as high as 999.                    #\n"
-      "############################################################\n\n";
-
-    vcomments[MAX_QUESTIONS] =
-      "\n############################################################\n"
-      "# 'max_questions' is limit of the length of the question   #\n"
-      "# list. Default is 5000 - only severe taskmasters will     #\n"
-      "# need to raise it.                                        #\n"
-      "############################################################\n\n";
-
-    vcomments[RANDOMIZE] =
-      "\n############################################################\n"
-      "# If 'randomize' selected, the list will be shuffled       #\n"
-      "# at the start of the game.  Default is 1 (yes).           #\n"
-      "############################################################\n\n";
-
-    vcomments[ADDITION_ALLOWED] =
-      "\n############################################################\n"
-      "#                                                          #\n"
-      "#                 Math Operations Allowed                  #\n"
-      "#                                                          #\n"
-      "# These options enable questions for each of the four math #\n"
-      "# operations.  All are 1 (yes) by default.                 #\n"
-      "############################################################\n\n";
-
-    vcomments[MIN_AUGEND] =
-      "\n############################################################\n"
-      "#                                                          #\n"
-      "#      Minimum and Maximum Values for Operand Ranges       #\n"
-      "#                                                          #\n"
-      "# Operand limits can be set to any integer up to the       #\n"
-      "# value of 'max_answer'.  If 'allow_negatives' is set to 1 #\n"
-      "# (yes), either negative or positive values can be used.   #\n"
-      "# Tuxmath will generate questions for every value in the   #\n"
-      "# specified range. The maximum must be greater than or     #\n"
-      "# equal to the corresponding minimum for any questions to  #\n"
-      "# be generated for that operation.                         #\n"
-      "############################################################\n\n";
-
-  }
-
-
-  mcdprintf("\nEntering MC_PrintMathOptions()\n");
-
-  /* bail out if no struct */
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMath Options struct does not exist!\n");
-    return;
-  }
-
-  for (i = 0; i < NOPTS; ++i)
-    {
-    if (verbose && vcomments[i] != NULL)
-      fprintf(fp, "%s", vcomments[i]);
-    fprintf(fp, "%s = %d\n", MC_OPTION_TEXT[i], math_opts->iopts[i]);
-    }
-  mcdprintf("\nLeaving MC_PrintMathOptions()\n");
-}
-
-
-
-int MC_PrintQuestionList(FILE* fp)
-{
-  if (fp && question_list)
-  {
-    print_list(fp, question_list);
-    return 1;
-  }
-  else
-  {
-    fprintf(stderr, "\nFile pointer and/or question list invalid\n");
-    return 0;
-  }
-}
-
-int MC_PrintWrongList(FILE* fp)
-{
-  if (!fp)
-  {
-    fprintf(stderr, "File pointer invalid\n");
-    return 0;
-  }
-
-  if (wrong_quests)
-  {
-    print_list(fp, wrong_quests);
-  }
-  else
-  {
-    fprintf(fp, "\nNo wrong questions!\n");
-  }
-
-  return 1;
-}
-
-
-int MC_StartingListLength(void)
-{
-  return starting_length;
-}
-
-
-int MC_WrongListLength(void)
-{
-  return list_length(wrong_quests);
-}
-
-int MC_NumAnsweredCorrectly(void)
-{
-  return answered_correctly;
-}
-
-
-int MC_NumNotAnsweredCorrectly(void)
-{
-  return answered_wrong;
-}
-
-
-/* Report the median time per question */
-float MC_MedianTimePerQuestion(void)
-{
-  if (length_time_per_question_list == 0)
-    return 0;
-
-  qsort(time_per_question_list,length_time_per_question_list,sizeof(float),floatCompare);
-  return time_per_question_list[length_time_per_question_list/2];
-}
-
-/* Implementation of "private methods" - (cannot be called from outside
-of this file) */
-
-
-
-/* Resets negative values to zero - used when allow_negatives deselected. */
-void clear_negatives(void)
-{
-  int i;
-  for (i = MIN_AUGEND; i <= MAX_TYPING_NUM; ++i)
-    if (math_opts->iopts[i]< 0)
-      math_opts->iopts[i]= 0;
-}
-
-// /* this is used by generate_list to see if a possible question */
-// /* meets criteria to be added to the list or not:              */
-// int validate_question(int n1, int n2, int n3)
-// {
-//   /* make sure none of values exceeds max_answer using absolute */
-//   /* value comparison:                                          */
-//   if (abs_value(n1) > abs_value(math_opts->iopts[MAX_ANSWER])
-//    || abs_value(n2) > abs_value(math_opts->iopts[MAX_ANSWER])
-//    || abs_value(n3) > abs_value(math_opts->iopts[MAX_ANSWER]))
-//   {
-//     return 0;
-//   }
-//   /* make sure none of values are negative if negatives not allowed: */
-//   if (!math_opts->iopts[ALLOW_NEGATIVES])
-//   {
-//     if (n1 < 0 || n2 < 0 || n3 < 0)
-//     {
-//       return 0;
-//     }
-//   }
-//   return 1;
-// }
-
-#if 0 //this code is probably on the way out...
-/* create a new node and return a pointer to it */
-MC_MathQuestion* create_node(int n1, int n2, int op, int ans, int f)
-{
-  MC_MathQuestion* ptr = NULL;
-
-  ptr = (MC_MathQuestion*)malloc(sizeof(MC_MathQuestion));
-
-  if (!ptr)
-  {
-    fprintf(stderr, "create_node() - malloc() failed!\n");
-    return NULL;
-  }
-
-  ptr->card = MC_AllocateFlashcard();
-  ptr->next = NULL;
-  ptr->previous = NULL;
-
-  snprintf(ptr->card.formula_string, max_formula_size, "%d %c %d = ?",
-           n1, op < MC_NUM_OPERS ? operchars[op] : '\0', n2);
-  snprintf(ptr->card.answer_string, max_formula_size, "%d", ans);
-  ptr->card.difficulty = 25 * (op + 1);
-
-
-  /* ptr should now point to a properly constructed node: */
-  return ptr;
-}
-#endif
-
-MC_MathQuestion* create_node_from_card(const MC_FlashCard* flashcard)
-{
-  MC_MathQuestion* ret = allocate_node();
-  copy_card(flashcard, &(ret->card));
-  return ret;
-}
-
-// /* FIXME take care of strings */
-// /* this one copies the contents, including pointers; both nodes must be allocated */
-// int copy_node(MC_MathQuestion* original, MC_MathQuestion* copy)
-// {
-//   if (!original)
-//   {
-//     fprintf(stderr, "\nIn copy_node(): invalid 'original' pointer arg.\n");
-//     return 0;
-//   }
-//   if (!copy)
-//   {
-//     fprintf(stderr, "\nIn copy_node(): invalid 'copy' pointer arg.\n");
-//     return 0;
-//   }
-// 
-//   copy_card(&(original->card), &(copy->card) );
-// 
-//   copy->next = original->next;
-//   copy->previous = original->previous;
-//   copy->randomizer = original->randomizer;
-//   return 1;
-// }
-
-
-
-
-/* this puts the node into the list AFTER the node pointed to by current */
-/* and returns a pointer to the top of the modified list  */
-MC_MathQuestion* insert_node(MC_MathQuestion* first, MC_MathQuestion* current, MC_MathQuestion* new_node)
-{
-  /* return pointer to list unchanged if new_node doesn't exist*/
-  if (!new_node)
-    return first;
-  /* if current doesn't exist, new_node is first */
-  if (!current)
-  {
-    new_node->previous = 0;
-    new_node->next =0;
-    first = new_node;
-    return first;
-  }
-
-  if (current->next)  /* avoid error if at end of list */
-    current->next->previous = new_node;
-  new_node->next = current->next;
-  current->next = new_node;
-  new_node->previous = current;
-  return first;
-}
-
-
-
-/* adds the new node to the end of the list */
-MC_MathQuestion* append_node(MC_MathQuestion* list, MC_MathQuestion* new_node)
-{
-  MC_MathQuestion* ptr;
-  /* return pointer to list unchanged if new_node doesn't exist*/
-  if (!new_node)
-  {
-    return list;
-  }
-
-  /* if list does not exist, new_node is the first (and only) node */
-  if (!list)
-  {
-    return new_node;
-  }
-  /* otherwise, go to end of list */
-  ptr = list;
-  while (ptr->next)
-  {
-    ptr = ptr->next;
-  }
-
-  ptr->next = new_node;
-  new_node->previous = ptr;
-  new_node->next = 0;
-  return list;
-}
-
-
-
-/* this takes the node out of the list but does not delete it */
-/* and returns a pointer to the top of the modified list  */
-MC_MathQuestion* remove_node(MC_MathQuestion* first, MC_MathQuestion* n)
-{
-  if (!n || !first)
-    return first;
-  /* special case if first node being removed */
-  if (n == first)
-     first = first->next;
-
-  if (n->previous)
-    n->previous->next = n->next;
-  if (n->next)
-      n->next->previous = n->previous;
-  n->previous = 0;
-  n->next = 0;
-  return first;
-}
-
-
-
-/* frees memory for entire list and returns null pointer */
-MC_MathQuestion* delete_list(MC_MathQuestion* list)
-{
-  MC_MathQuestion* tmp_ptr;
-  while (list)
-  {
-    tmp_ptr = list->next;
-    free_node (list);
-    list = tmp_ptr;
-  }
-  return list;
-}
-
-
-
-void print_list(FILE* fp, MC_MathQuestion* list)
-{
-  if (!list)
-  {
-    fprintf(stderr, "\nprint_list(): list empty or pointer invalid\n");
-    return;
-  }
-
-  MC_MathQuestion* ptr = list;
-  while (ptr)
-  {
-    fprintf(fp, "%s\n", ptr->card.formula_string);
-    ptr = ptr->next;
-  }
-}
-
-void print_vect_list(FILE* fp, MC_MathQuestion** vect, int length)
-{
-  if (!vect)
-  {
-    fprintf(fp, "\nprint_vect_list(): list empty or pointer invalid\n");
-    return;
-  }
-
-  int i = 0;
-  mcdprintf("Entering print_vect_list()\n");
-  for(i = 0; i < length; i++)
-    fprintf(fp, "%s\n", vect[i]->card.formula_string);
-
-  mcdprintf("Leaving print_vect_list()\n");
-}
-
-void print_card(MC_FlashCard card)
-{
-  printf("\nprint_card():");
-  printf("formula_string = %s\nanswer_string = %s\ndifficulty = %d\n\n",
-         card.formula_string,
-         card.answer_string,
-         card.difficulty);
-}
-
-/* This sends the values of all "global" counters and the */
-/* lengths of the question lists to stdout - for debugging */
-void print_counters(void)
-{
-  printf("\nquest_list_length = \t%d", quest_list_length);
-  printf("\nlist_length(question_list) = \t%d", list_length(question_list));
-  printf("\nstarting_length = \t%d", starting_length);
-  printf("\nunanswered = \t%d", unanswered);
-  printf("\nanswered_correctly = \t%d", answered_correctly);
-  printf("\nanswered_wrong = \t%d", answered_wrong);
-  printf("\nlist_length(wrong_quests) = \t%d", list_length(wrong_quests));
-  printf("\nquestions_pending = \t%d", questions_pending);
-}
-
-// /* a "copy constructor", so to speak */
-// /* FIXME should properly return newly allocated list if more than one node DSB */
-// MC_MathQuestion* create_node_copy(MC_MathQuestion* other)
-// {
-//   MC_MathQuestion* ret = allocate_node();
-//   if (ret)
-//     copy_card(&(other->card), &(ret->card) );
-//   return ret;
-// }
-// 
-// /* FIXME take care of strings */
-// 
-// MC_FlashCard create_card_from_node(MC_MathQuestion* node)
-// {
-//   MC_FlashCard fc;
-//   if (!node)
-//     return DEFAULT_CARD;
-//   fc = MC_AllocateFlashcard();
-//   copy_card(&(node->card), &fc);
-//   return fc;
-// }
-
-int list_length(MC_MathQuestion* list)
-{
-  int length = 0;
-  while (list)
-  {
-    length++;
-    list = list->next;
-  }
-  return length;
-}
-
-
-
-
-
-
-/* This is a new implementation written in an attempt to avoid       */
-/* the O(n^2) performance problems seen with the old randomization   */
-/* function. The list is created as a vector, but is for now still   */
-/* made a linked list to minimize changes needed elsewhere.          */
-/* The argument is a pointer to the top of the old list.  This extra */
-/* level of indirection allows the list to be shuffled "in-place".   */
-/* The function returns 1 if successful, 0 on errors.                */
-
-static int randomize_list(MC_MathQuestion** old_list)
-{
-  MC_MathQuestion* old_tmp = *old_list;
-  MC_MathQuestion** tmp_vect = NULL;
-
-  int i = 0;
-  if (!old_list || !*old_list) //invalid/empty list
-    return 0;
-  
-  int old_length = list_length(old_tmp);
-
-  /* set random seed: */
-  srand(time(0));
-
-
-  /* Allocate vector and set ptrs to nodes in old list: */
-
-  /* Allocate a list of pointers, not space for the nodes themselves: */
-  tmp_vect = (MC_MathQuestion**)malloc(sizeof(MC_MathQuestion*) * old_length);
-  /* Set each pointer in the vector to the corresponding node: */
-  for (i = 0; i < old_length; i++)
-  {
-    tmp_vect[i] = old_tmp;
-    tmp_vect[i]->randomizer = rand();
-    old_tmp = old_tmp->next;
-  }
-
-  /* Now simply sort on 'tmp_vect[i]->randomizer' to shuffle list: */
-  qsort(tmp_vect, old_length,
-        sizeof(MC_MathQuestion*),
-        comp_randomizer);
-
-  /* Re-create pointers to provide linked-list functionality:      */
-  /* (stop at 'old_length-1' because we dereference tmp_vect[i+1]) */
-  for(i = 0; i < old_length - 1; i++)
-  {
-    if (!tmp_vect[i])
-    {
-      fprintf(stderr, "Invalid pointer!\n");
-      return 0;
-    }
-    tmp_vect[i]->next = tmp_vect[i+1];
-    tmp_vect[i+1]->previous = tmp_vect[i];
-  }
-  /* Handle end cases: */
-  tmp_vect[0]->previous = NULL;
-  tmp_vect[old_length-1]->next = NULL;
-
-  /* Now arrange for arg pointer to indirectly point to first element! */
-  *old_list = tmp_vect[0];
-  free(tmp_vect);
-  return 1;
-}
-
-
-
-/* This is needed for qsort(): */
-int comp_randomizer (const void* a, const void* b)
-{
-
-  int int1 = (*(const struct MC_MathQuestion **) a)->randomizer;
-  int int2 = (*(const struct MC_MathQuestion **) b)->randomizer;
-
-  if (int1 > int2)
-    return 1;
-  else if (int1 == int2)
-    return 0;
-  else
-    return -1;
-}
-
-MC_MathQuestion* pick_random(int length, MC_MathQuestion* list)
-{
-  int i;
-  int rand_node;
-
-  /* set random seed DSB */
-  srand(time(0));
-
-  /* if length is zero, get out to avoid divide-by-zero error */
-  if (0 == length)
-  {
-    return list;
-  }
-
-  rand_node = rand() % length;
-
-  for (i=1; i < rand_node; i++)
-  {
-    if (list)
-     list = list->next;
-  }
-
-  return list;
-}
-
-/* compares fields other than pointers */
-int compare_node(MC_MathQuestion* first, MC_MathQuestion* other)
-{
-  if (!first || !other)
-    return 0;
-  if (compare_card(&(first->card), &(first->card) ) ) //cards are equal
-    return 1;
-  else
-    return 0;
-}
-
-/* check to see if list already contains an identical node */
-int already_in_list(MC_MathQuestion* list, MC_MathQuestion* ptr)
-{
-  if (!list || !ptr)
-    return 0;
-
-  while (list)
-  {
-    if (compare_node(list, ptr))
-      return 1;
-    list = list->next;
-  }
-  return 0;
-}
-
-// /* to prevent option settings in math_opts from getting set to */
-// /* values other than 0 or 1                                    */
-// int int_to_bool(int i)
-// {
-//   if (i)
-//     return 1;
-//   else
-//     return 0;
-// }
-
-// /* prevent values from getting into math_opts that are outside */
-// /* the range that can be handled by the program (i.e. more     */
-// /* than three digits; also disallow negatives if that has been */
-// /* selected.                                                   */
-// int sane_value(int i)
-// {
-//   if (i > MC_GLOBAL_MAX)
-//     i = MC_GLOBAL_MAX;
-//   else if (i < -MC_GLOBAL_MAX)
-//     i = -MC_GLOBAL_MAX;
-// 
-//   if (i < 0
-//    && math_opts
-//    && !math_opts->iopts[ALLOW_NEGATIVES])
-//   {
-//     i = 0;
-//   }
-// 
-//   return i;
-// }
-
-// int abs_value(int i)
-// {
-//   if (i > 0)
-//     return i;
-//   else
-//     return -i;
-// }
-
-int log10i(int i) //base 10 logarithm for ints
-{
-  int j;
-  for (j = 0; i > 0; i /= 10, ++j);
-  return j;
-}
-
-/* Compares two floats (needed for sorting in MC_MedianTimePerQuestion) */
-int floatCompare(const void *v1,const void *v2)
-{
-  float f1,f2;
-
-  f1 = *((float *) v1);
-  f2 = *((float *) v2);
-
-  if (f1 < f2)
-    return -1;
-  else if (f1 > f2)
-    return 1;
-  else
-    return 0;
-}
-
-
-
-/****************************************************
-Functions for new mathcards architecture
-****************************************************/
-
-void copy_card(const MC_FlashCard* src, MC_FlashCard* dest)
-{
-  if (!src || !dest)
-    return;
-  mcdprintf("Copying '%s' to '%s', ", src->formula_string,dest->formula_string);
-  mcdprintf("copying '%s' to '%s'\n", src->answer_string, dest->answer_string);
-  strncpy(dest->formula_string, src->formula_string, max_formula_size);
-  strncpy(dest->answer_string, src->answer_string, max_answer_size);
-  mcdprintf("Card is: '%s', '%s'\n", dest->formula_string, dest->answer_string);
-  dest->answer = src->answer;
-  dest->difficulty = src->difficulty;
-}
-
-void free_node(MC_MathQuestion* mq) //no, not that freenode.
-{
-  if (!mq)
-    return;
-  MC_FreeFlashcard(&(mq->card) );
-  free(mq);
-}
-
-MC_MathQuestion* allocate_node()
-{
-  MC_MathQuestion* ret = NULL;
-  ret = malloc(sizeof(MC_MathQuestion) );
-  if (!ret)
-  {
-    printf("Could not allocate space for a new node!\n");
-    return NULL;
-  }
-
-  ret->card = MC_AllocateFlashcard();
-  ret->next = ret->previous = NULL;
-  
-  return ret;
-}
-
-/*
-The function that does the central dirty work pertaining to flashcard
-creation. Extensible to just about any kind of math problem, perhaps
-with the exception of those with multiple answers, such as "8 + 2 > ?"
-Simply specify how the problem is presented to the user, and the
-answer the game should look for, as strings.
-*/
-MC_FlashCard generate_random_flashcard(void)
-{
-  int num;
-  int length;
-  MC_ProblemType pt;
-  MC_FlashCard ret;
-
-  mcdprintf("Entering generate_random_flashcard()\n");
-
-  do
-    pt = rand() % MC_NUM_PTYPES;
-  while ( (pt == MC_PT_TYPING && !MC_GetOpt(TYPING_PRACTICE_ALLOWED) ) ||
-          (pt == MC_PT_ARITHMETIC && !MC_GetOpt(ADDITION_ALLOWED) &&
-                                   !MC_GetOpt(SUBTRACTION_ALLOWED) &&
-                                   !MC_GetOpt(MULTIPLICATION_ALLOWED) &&
-                                   !MC_GetOpt(DIVISION_ALLOWED) ) ||
-          (pt == MC_PT_COMPARISON && !MC_GetOpt(COMPARISON_ALLOWED) )
-        );
-
-  if (pt == MC_PT_TYPING) //typing practice
-  {
-    mcdprintf("Generating typing question\n");
-    ret = MC_AllocateFlashcard();
-    num = rand() % (MC_GetOpt(MAX_TYPING_NUM)-MC_GetOpt(MIN_TYPING_NUM) + 1)
-                  + MC_GetOpt(MIN_TYPING_NUM);
-    snprintf(ret.formula_string, max_formula_size, "%d", num);
-    snprintf(ret.answer_string, max_answer_size, "%d", num);
-    ret.answer = num;
-    ret.difficulty = 10;
-  }
-  else //if (pt == MC_PT_ARITHMETIC)
-  {
-    mcdprintf("Generating arithmetic question");
-    length = rand() % (MC_GetOpt(MAX_FORMULA_NUMS) -
-                       MC_GetOpt(MIN_FORMULA_NUMS) + 1) //avoid div by 0
-                    +  MC_GetOpt(MIN_FORMULA_NUMS);
-    mcdprintf(" of length %d", length);
-    ret = generate_random_ooo_card_of_length(length, 1);
-    if (debug_status & debug_mathcards) {
-      print_card(ret);
-    }
-  }
-  //TODO comparison problems (e.g. "6 ? 9", "<")
-
-  mcdprintf("Exiting generate_random_flashcard()\n");
-
-  return ret;
-}
-
-/*
-Recursively generate an order of operations problem. Hopefully this won't
-raise performance issues. Difficulty is calculated based on the length of
-the formula and on the operators used. Problems have a 'base' difficulty of
-1 for binary operations, 3 for 3 numbers, 6, 10, etc. Each operator adds to
-the score: 0, 1, 2, and 3 respectively for addition, subtraction,
-multiplication and division.If reformat is 0, FORMAT_ANS_LAST will be used,
-otherwise a format is chosen at random.
-*/
-MC_FlashCard generate_random_ooo_card_of_length(int length, int reformat)
-{
-  int format = 0;
-  int r1 = 0;
-  int r2 = 0;
-  int ans = 0;
-  char tempstr[max_formula_size];
-  MC_FlashCard ret;
-  MC_Operation op;
-
-  printf(".");
-  if (length > MAX_FORMULA_NUMS)
-    return DEFAULT_CARD;
-  if (length <= 2)
-  {
-    mcdprintf("\n");
-    ret = MC_AllocateFlashcard();
-    for (op = rand() % MC_NUM_OPERS; //pick a random operation
-         MC_GetOpt(op + ADDITION_ALLOWED) == 0; //make sure it's allowed
-         op = rand() % MC_NUM_OPERS);
-
-    mcdprintf("Operation is %c\n", operchars[op]);
-    /*
-    if (op == MC_OPER_ADD)
-    {
-      r1 = rand() % (math_opts->iopts[MAX_AUGEND] - math_opts->iopts[MIN_AUGEND] + 1) + math_opts->iopts[MIN_AUGEND];
-      r2 = rand() % (math_opts->iopts[MAX_ADDEND] - math_opts->iopts[MIN_ADDEND] + 1) + math_opts->iopts[MIN_ADDEND];
-      ans = r1 + r2;
-    }
-    else if (op == MC_OPER_SUB)
-    {
-      r1 = rand() % (math_opts->iopts[MAX_MINUEND] - math_opts->iopts[MIN_MINUEND] + 1) + math_opts->iopts[MIN_MINUEND];
-      r2 = rand() % (math_opts->iopts[MAX_SUBTRAHEND] - math_opts->iopts[MIN_SUBTRAHEND] + 1) + math_opts->iopts[MIN_SUBTRAHEND];
-      ans = r1 - r2;
-    }
-    else if (op == MC_OPER_MULT)
-    {
-      r1 = rand() % (math_opts->iopts[MAX_MULTIPLIER] - math_opts->iopts[MIN_MULTIPLIER] + 1) + math_opts->iopts[MIN_MULTIPLIER];
-      r2 = rand() % (math_opts->iopts[MAX_MULTIPLICAND] - math_opts->iopts[MIN_MULTIPLICAND] + 1) + math_opts->iopts[MIN_MULTIPLICAND];
-      ans = r1 * r2;
-    }
-    else if (op == MC_OPER_DIV)
-    {
-      ans = rand() % (math_opts->iopts[MAX_QUOTIENT] - math_opts->iopts[MIN_QUOTIENT] + 1) + math_opts->iopts[MIN_QUOTIENT];
-      r2 = rand() % (math_opts->iopts[MAX_DIVISOR] - math_opts->iopts[MIN_DIVISOR] + 1) + math_opts->iopts[MIN_DIVISOR];
-      if (r2 == 0)
-        r2 = 1;
-      r1 = ans * r2;
-    }
-    */
-    if (op > MC_OPER_DIV || op < MC_OPER_ADD)
-    {
-      mcdprintf("Invalid operator: value %d\n", op);
-      return DEFAULT_CARD;
-    }
-    //choose two numbers in the proper range and get their result
-    
-    else do
-    {
-      r1 = rand() % (math_opts->iopts[MAX_AUGEND+4*op] - math_opts->iopts[MIN_AUGEND+4*op] + 1) + math_opts->iopts[MIN_AUGEND+4*op];    
-      r2 = rand() % (math_opts->iopts[MAX_ADDEND+4*op] - math_opts->iopts[MIN_ADDEND+4*op] + 1) + math_opts->iopts[MIN_ADDEND+4*op]; 
-
-      if (op == MC_OPER_ADD)
-        ans = r1 + r2;
-      if (op == MC_OPER_SUB)
-        ans = r1 - r2;
-      if (op == MC_OPER_MULT)
-        ans = r1 * r2;
-      if (op == MC_OPER_DIV)  
-      {
-        if (r2 == 0)
-          r2 = 1;
-        ret.difficulty = r1;
-        r1 *= r2;
-        ans = ret.difficulty;
-      }
-    } while ( (ans < 0 && !MC_GetOpt(ALLOW_NEGATIVES)) || ans > MC_GetOpt(MAX_ANSWER) );
-
-
-    mcdprintf("Constructing answer_string\n");
-    snprintf(ret.answer_string, max_answer_size+1, "%d", ans);
-    mcdprintf("Constructing formula_string\n");
-    snprintf(ret.formula_string, max_formula_size, "%d %c %d",
-             r1, operchars[op], r2);
-    ret.answer = ans;
-    ret.difficulty = op + 1;
-
-  }
-  else //recurse
-  {
-    ret = generate_random_ooo_card_of_length(length - 1, 0);
-
-    if (strchr(ret.formula_string, '+') || strchr(ret.formula_string, '-') )
-    {
-      //if the expression has addition or subtraction, we can't assume that
-      //introducing multiplication or division will produce a predictable
-      //result, so we'll limit ourselves to more addition/subtraction
-      for (op = rand() % 2 ? MC_OPER_ADD : MC_OPER_SUB;
-           MC_GetOpt(op + ADDITION_ALLOWED) == 0;
-           op = rand() % 2 ? MC_OPER_ADD : MC_OPER_SUB);
-
-    }
-    else
-    {
-      //the existing expression can be treated as a number in itself, so we
-      //can do anything to it and be confident of the result.
-      for (op = rand() % MC_NUM_OPERS; //pick a random operation
-         MC_GetOpt(op + ADDITION_ALLOWED) == 0; //make sure it's allowed
-         op = rand() % MC_NUM_OPERS);
-    }
-    mcdprintf("Next operation is %c,",  operchars[op]);
-
-    //pick the next operand
-    if (op == MC_OPER_ADD)
-    {
-      r1 = rand() % (math_opts->iopts[MAX_AUGEND] - math_opts->iopts[MIN_AUGEND] + 1) + math_opts->iopts[MIN_AUGEND];
-      ret.answer += r1;
-    }
-    else if (op == MC_OPER_SUB)
-    {
-      r1 = rand() % (math_opts->iopts[MAX_SUBTRAHEND] - math_opts->iopts[MIN_SUBTRAHEND] + 1) + math_opts->iopts[MIN_SUBTRAHEND];
-      ret.answer -= r1;
-    }
-    else if (op == MC_OPER_MULT)
-    {
-      r1 = rand() % (math_opts->iopts[MAX_MULTIPLICAND] - math_opts->iopts[MIN_MULTIPLICAND] + 1) + math_opts->iopts[MIN_AUGEND];
-      ret.answer *= r1;
-    }
-    else if (op == MC_OPER_DIV)
-    {
-      r1 = find_divisor(ret.answer);
-      ret.answer /= r1;
-    }
-    else
-    {
-      ; //invalid operator
-    }
-    mcdprintf(" operand is %d\n", r1);
-    mcdprintf("Answer: %d\n", ret.answer);
-
-    //next append or prepend the new number (might need optimization)
-    if (op == MC_OPER_SUB || op == MC_OPER_DIV || //noncommutative, append only
-        rand() % 2)
-    {
-      snprintf(tempstr, max_formula_size, "%s %c %d", //append
-               ret.formula_string, operchars[op], r1);
-      strncpy(ret.formula_string, tempstr, max_formula_size);
-    }
-    else //we're prepending
-    {
-      snprintf(tempstr, max_formula_size, "%d %c %s", //append
-               r1, operchars[op], ret.formula_string);
-      strncpy(ret.formula_string, tempstr, max_formula_size);
-    }
-
-    //finally update the answer and score
-    snprintf(ret.answer_string, max_answer_size, "%d", ret.answer);
-    ret.difficulty += (length - 1) + op;
-  }
-  
-  if (reformat)
-  {
-    mcdprintf("Reformatting...\n");
-    do {
-      format = rand() % MC_NUM_FORMATS;
-    } while (!MC_GetOpt(FORMAT_ANSWER_LAST + format) && 
-             !MC_GetOpt(FORMAT_ADD_ANSWER_LAST + op * 3 + format) );
-   
-    strncat(ret.formula_string, " = ?", max_formula_size - strlen(ret.formula_string) );
-    reformat_arithmetic(&ret, format );     
-  }
-  return ret;
-}
-
-
-
-MC_MathQuestion* generate_list(void)
-{
-  int i, j;
-  int length = MC_GetOpt(AVG_LIST_LENGTH);
-  int cl; //raw length
-  double r1, r2, delta, var; //randomizers for list length
-  MC_MathQuestion* list = NULL;
-  MC_MathQuestion* end_of_list = NULL;
-  MC_MathQuestion* tnode = NULL;
-
-  if (debug_status & debug_mathcards)
-    MC_PrintMathOptions(stdout, 0);
-  if (!(MC_GetOpt(ARITHMETIC_ALLOWED) ||
-      MC_GetOpt(TYPING_PRACTICE_ALLOWED) ||
-      MC_GetOpt(COMPARISON_ALLOWED) ) )
-    return NULL;
-
-  //randomize list length by a "bell curve" centered on average
-  if (length && MC_GetOpt(VARY_LIST_LENGTH) )
-  {
-    r1 = (double)rand() / RAND_MAX / 2 + 0.5; //interval (0, 1)
-    r2 = (double)rand() / RAND_MAX / 2 + 0.5; //interval (0, 1)
-    mcdprintf("Randoms chosen: %5f, %5f\n", r1, r2);
-    delta = sqrt(-2 * log(r1) ) * cos(2 * PI_VAL * r2); //standard normal dist.
-    var = length / 10.0; //variance
-    delta = delta * var;
-    mcdprintf("Delta of average is %5f\n", delta);
-    length += delta;
-    if (length < 0)
-      length = 1; //just in case...
-  }
-
-  if (MC_GetOpt(COMPREHENSIVE)) //generate all
-  {
-    int num_valid_questions; //How many questions the COMPREHENSIVE list specifies
-    int cycles_needed;       //How many times we need to generate it to get enough
-
-    num_valid_questions = calc_num_valid_questions();
-    if(num_valid_questions == 0)
-    {
-      fprintf(stderr, "generate_list() - no valid questions\n");
-      return NULL;
-    }
-
-    cycles_needed = length/num_valid_questions;
-
-    if((cycles_needed * num_valid_questions) < length)
-      cycles_needed++;
-
-    mcdprintf("In generate_list() - COMPREHENSIVE method requested\n");
-    mcdprintf("num_valid_questions = %d\t cycles_needed = %d\n",
-              num_valid_questions, cycles_needed);
-
-    for (i = MC_PT_TYPING; i < MC_NUM_PTYPES; ++i)
-    {
-      if (!MC_GetOpt(i + TYPING_PRACTICE_ALLOWED))
-          continue;
-      for (j = 0; j < cycles_needed; j++)
-        list = add_all_valid(i, list, &end_of_list);
-    }
-
-
-    if (MC_GetOpt(RANDOMIZE) )
-    {
-      mcdprintf("Randomizing list\n");
-      randomize_list(&list);
-    }
-
-    if (length)
-    {
-      cl = list_length(list);
-      // NOTE this should no longer happen - we run the COMPREHENSIVE
-      // generation until we have enough questions.
-      if (length > cl) //if not enough questions, pad out with randoms
-      {
-        mcdprintf("Padding out list from %d to %d questions\n", cl, length);
-        for (i = cl; i < length; ++i)
-        {
-          tnode = malloc(sizeof(MC_MathQuestion) );
-          if(!tnode)
-          {
-            fprintf(stderr, "In generate_list() - allocation failed!\n");
-            delete_list(list);
-            return NULL;
-          }
-
-          tnode->card = generate_random_flashcard();
-          list = insert_node(list, end_of_list, tnode);
-          end_of_list = tnode;
-          mcdprintf("%d...", list_length(list) );
-        }
-      }
-      else if (length < cl) //if too many questions, chop off tail end of list
-      {
-        mcdprintf("Cutting list to %d questions\n", length);
-        end_of_list = find_node(list, length);
-        delete_list(end_of_list->next);
-        end_of_list->next = NULL;
-      }
-    }
-  }
-
-  /* Here we are just generating random questions, one at a */
-  /* time until we have enough                              */
-  else 
-  {
-    mcdprintf("In generate_list() - COMPREHENSIVE method NOT requested\n");
-
-    for (i = 0; i < length; ++i)
-    {
-      tnode = malloc(sizeof(MC_MathQuestion) );
-      if(!tnode)
-      {
-        fprintf(stderr, "In generate_list() - allocation failed!\n");
-        delete_list(list);
-        return NULL;
-      }
-
-      tnode->card = generate_random_flashcard();
-      list = insert_node(list, end_of_list, tnode);
-      end_of_list = tnode;
-    }
-  }
-  return list;
-}
-
-static int compare_card(const MC_FlashCard* a, const MC_FlashCard* b)
-{
-  if (strncmp(a->formula_string, b->formula_string, max_formula_size) )
-    return 1;
-  if (strncmp(a->answer_string, b->answer_string, max_answer_size) )
-    return 1;
-  if (a->answer != b->answer);
-    return 1;
-
-  return 0; //the cards are identical
-}
-
-/* Public functions */
-
-/* allocate space for an MC_Flashcard */
-MC_FlashCard MC_AllocateFlashcard(void)
-{
-  MC_FlashCard ret;
-  mcdprintf("Allocating %d + %d bytes for flashcard\n",
-            max_formula_size + 1, max_answer_size + 1);
-  ret.formula_string = malloc( (max_formula_size + 1) * sizeof(char));
-  ret.answer_string = malloc( (max_answer_size + 1) * sizeof(char));
-  if (!ret.formula_string || !ret.answer_string)
-    {
-    free(ret.formula_string);
-    free(ret.answer_string);
-    printf("Couldn't allocate space for a new flashcard!\n");
-    ret = DEFAULT_CARD;
-    }
-  return ret;
-}
-
-void MC_FreeFlashcard(MC_FlashCard* fc)
-{
-  if (!fc)
-    return;
-//  mcdprintf("Freeing formula_string\n");
-  if (fc->formula_string)
-  {
-    free(fc->formula_string);
-    fc->formula_string = NULL;
-  }
-//  mcdprintf("Freeing answer_string\n");
-  if (fc->answer_string)
-  {
-    free(fc->answer_string);
-    fc->answer_string = NULL;
-  }
-}
-
-unsigned int MC_MapTextToIndex(const char* text)
-{
-  int i;
-  for (i = 0; i < NOPTS; ++i)
-  {
-    if (!strcasecmp(text, MC_OPTION_TEXT[i]) )
-      return i;
-  }
-  mcdprintf("'%s' isn't a math option\n", text);
-  return NOT_VALID_OPTION;
-}
-
-
-//TODO more intuitive function names for access by index vs. by text
-void MC_SetOpt(unsigned int index, int val)
-{
-  if (index >= NOPTS)
-  {
-    mcdprintf("Invalid math option index: %d\n", index);
-    return;
-  }
-
-  /* Do some sanity checks before we throw val into the struct: */
-  switch(index)
-  {
-    /* All the booleans must be 0 or 1: */
-    case PLAY_THROUGH_LIST:
-    case REPEAT_WRONGS:
-    case ALLOW_NEGATIVES:
-    case FORMAT_ANSWER_LAST:
-    case FORMAT_ANSWER_FIRST:
-    case FORMAT_ANSWER_MIDDLE:
-    case FORMAT_ADD_ANSWER_LAST:
-    case FORMAT_ADD_ANSWER_FIRST:
-    case FORMAT_ADD_ANSWER_MIDDLE:
-    case FORMAT_SUB_ANSWER_LAST:
-    case FORMAT_SUB_ANSWER_FIRST:
-    case FORMAT_SUB_ANSWER_MIDDLE:
-    case FORMAT_MULT_ANSWER_LAST:
-    case FORMAT_MULT_ANSWER_FIRST:
-    case FORMAT_MULT_ANSWER_MIDDLE:
-    case FORMAT_DIV_ANSWER_LAST:
-    case FORMAT_DIV_ANSWER_FIRST:
-    case FORMAT_DIV_ANSWER_MIDDLE:
-    case ADDITION_ALLOWED:
-    case SUBTRACTION_ALLOWED:
-    case MULTIPLICATION_ALLOWED:
-    case DIVISION_ALLOWED:
-    case TYPING_PRACTICE_ALLOWED:
-    case ARITHMETIC_ALLOWED:
-    case COMPARISON_ALLOWED:
-    case RANDOMIZE:
-    case COMPREHENSIVE:
-    case VARY_LIST_LENGTH:
-    {
-      /* Reset all non-zero values to one: */
-      if(val)
-      {
-        if(val != 1)
-        {
-          fprintf(stderr, "Warning - parameter %s with invalid value %d, "
-                          "resetting to 1\n", MC_OPTION_TEXT[index], val);
-          val = 1;
-        }
-      }
-      break;
-    }
-
-    /* Parameters concerning numbers of questions */
-    /* must be greater than or equal to zero:     */
-    /* TODO some additional checks would make sense */
-    case QUESTION_COPIES:
-    case COPIES_REPEATED_WRONGS:
-    case MAX_QUESTIONS:
-    case MAX_FORMULA_NUMS:
-    case MIN_FORMULA_NUMS:
-    case AVG_LIST_LENGTH:
-    {
-      /* Reset all negative values to zero: */
-      if(val < 0)
-      {
-        fprintf(stderr, "Warning - parameter %s with invalid value %d, "
-                        "resetting to 0\n", MC_OPTION_TEXT[index], val);
-        val = 0;
-      }
-      break;
-    }
-
-    /* Operand values - make sure they are in displayable range */
-    /* i.e. -999 to 999                                         */ 
-    case MAX_ANSWER:
-    case MIN_AUGEND:
-    case MAX_AUGEND:
-    case MIN_ADDEND:
-    case MAX_ADDEND:
-    case MIN_MINUEND:
-    case MAX_MINUEND:
-    case MIN_SUBTRAHEND:
-    case MAX_SUBTRAHEND:
-    case MIN_MULTIPLIER:
-    case MAX_MULTIPLIER:
-    case MIN_MULTIPLICAND:
-    case MAX_MULTIPLICAND:
-    case MIN_DIVISOR:
-    case MAX_DIVISOR:
-    case MIN_QUOTIENT:
-    case MAX_QUOTIENT:
-    case MIN_TYPING_NUM:
-    case MAX_TYPING_NUM:
-    case MIN_COMPARATOR:
-    case MAX_COMPARATOR:
-    case MIN_COMPARISAND:
-    case MAX_COMPARISAND:
-    {
-      if(val > MC_GLOBAL_MAX)
-      {
-        fprintf(stderr, "Warning - parameter %s with invalid value %d, "
-                       "resetting to %d\n", MC_OPTION_TEXT[index],
-                       val, MC_GLOBAL_MAX);
-        val = MC_GLOBAL_MAX;
-      }
-
-      if(val < (0 - MC_GLOBAL_MAX))
-      {
-        fprintf(stderr, "Warning - parameter %s with invalid value %d, "
-                        "resetting to %d\n", MC_OPTION_TEXT[index],
-                       val, (0 - MC_GLOBAL_MAX));
-        val = (0 - MC_GLOBAL_MAX);
-      }
-
-      break;
-    }
-
-    default:
-        fprintf(stderr, "Warning - in MC_SetOpt() - unrecognized index %d\n",
-                index);
-  }
-  /* Should now be safe to put "sanitized" value into struct: */
-  math_opts->iopts[index] = val;
-}
-
-void MC_SetOp(const char* param, int val)
-{
-  MC_SetOpt(MC_MapTextToIndex(param), val);
-}
-
-int MC_GetOpt(unsigned int index)
-{
-  if (index >= NOPTS)
-  {
-    mcdprintf("Invalid option index: %d\n", index);
-    return MC_MATH_OPTS_INVALID;
-  }
-  if (!math_opts)
-  {
-    printf("Invalid options list!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->iopts[index];
-}
-
-int MC_GetOp(const char* param)
-{
-  return MC_GetOpt(MC_MapTextToIndex(param) );
-}
-
-int MC_VerifyOptionListSane(void)
-{
-  return strcmp(MC_OPTION_TEXT[NOPTS], "END_OF_OPTS") == 0;
-}
-
-int MC_MaxFormulaSize(void)
-{
-  return max_formula_size;
-}
-
-int MC_MaxAnswerSize(void)
-{
-  return max_answer_size;
-}
-
-void MC_ResetFlashCard(MC_FlashCard* fc)
-{
-  if (!fc || !fc->formula_string || !fc->answer_string)
-    return;
-  strncpy(fc->formula_string, " ", max_formula_size);
-  strncpy(fc->answer_string, " ", max_answer_size);
-  fc->answer = 0;
-  fc->difficulty = 0;
-}
-
-int MC_FlashCardGood(const MC_FlashCard* fc)
-{
-  return fc && fc->formula_string && fc->answer_string;
-}
-
-int find_divisor(int a)
-{
-  int div = 1; //the divisor to return
-  int realisticpasses = 3; //reasonable time after which a minimum should be met
-  int i;
-  do
-    for (i = 0; i < NPRIMES; ++i) //test each prime
-      if (a % smallprimes[i] == 0)  //if it is a prime factor,
-        if (rand() % (i + 1) == 0) //maybe we'll keep it
-          if (div * smallprimes[i] <= MC_GetOpt(MAX_DIVISOR) ) //if we can,
-            div *= smallprimes[i]; //update our real divisor
-  //keep going if the divisor is too small
-  while (div < MC_GetOpt(MIN_DIVISOR) && --realisticpasses); 
-  
-  return div;
-}
-
-
-//Computes (approximately) the number of questions that will be returned
-//by add_all_valid() as specified by the current options. This does not 
-//take into account screening out of invalid questions, such
-//as divide-by-zero and questions like "0 x ? = 0".
-static int calc_num_valid_questions(void)
-{
-  int total_questions = 0;
-  int k = 0;
-  //First add the number of typing questions
-  if (MC_GetOpt(TYPING_PRACTICE_ALLOWED))
-    total_questions += (MC_GetOpt(MAX_TYPING_NUM) - MC_GetOpt(MIN_TYPING_NUM));
-
-  //Now add how many questions we will have for each operation:
-  for (k = MC_OPER_ADD; k < MC_NUM_OPERS; ++k)
-  {
-    int num_this_oper = 0;
-    int formats_this_oper = 0;
-
-    if (!MC_GetOpt(k + ADDITION_ALLOWED) )
-      continue;
-
-    //calculate number of ordered pairs of first and second operands:
-    //note the "+ 1" is due to the ranges being inclusive
-    num_this_oper = (MC_GetOpt(MAX_AUGEND + 4 * k) - MC_GetOpt(MIN_AUGEND + 4 * k) + 1)
-                    *
-                    (MC_GetOpt(MAX_ADDEND + 4 * k) - MC_GetOpt(MIN_ADDEND + 4 * k) + 1);
-    //check what formats are allowed
-    if (MC_GetOpt(FORMAT_ANSWER_LAST) && MC_GetOpt(FORMAT_ADD_ANSWER_LAST + k * 3))
-      formats_this_oper++;
-    if (MC_GetOpt(FORMAT_ANSWER_FIRST) && MC_GetOpt(FORMAT_ADD_ANSWER_FIRST + k * 3))
-      formats_this_oper++;
-    if (MC_GetOpt(FORMAT_ANSWER_MIDDLE) && MC_GetOpt(FORMAT_ADD_ANSWER_MIDDLE + k * 3))
-      formats_this_oper++;
-    //Get total of e.g. addition questions:
-    num_this_oper *= formats_this_oper;
-    //add to overall total:
-    total_questions += num_this_oper;
-  }
-
-  //TODO will also need to count up the COMPARISON questions once
-  //they are implemented
-  {
-  }
-
-  mcdprintf("calc_num_valid_questions():\t%d\n", total_questions);
-  return total_questions;
-}
-
-
-//NOTE end_of_list** needs to be doubly indirect because otherwise the end does not
-//get updated in the calling code
-//NOTE the difficulty is set as add = 1, sub = 2, mult = 3, div = 4, plus a 2 point
-//bonus if the format is a "missing number".
-MC_MathQuestion* add_all_valid(MC_ProblemType pt, MC_MathQuestion* list, MC_MathQuestion** end_of_list)
-{
-  int i, j;
-  int ans = 0, tmp;
-  MC_Operation k;
-  MC_MathQuestion* tnode;
-
-  mcdprintf("Entering add_all_valid(%d)\n", pt);
-  mcdprintf("List already has %d questions\n", list_length(list));
-
-  //make sure this problem type is actually allowed
-  if (!MC_GetOpt(pt + TYPING_PRACTICE_ALLOWED) )
-    return list;
-
-  //add all typing questions in range
-  if (pt == MC_PT_TYPING)
-  {
-    mcdprintf("Adding typing...\n");
-    for (i = MC_GetOpt(MIN_TYPING_NUM); i <= MC_GetOpt(MAX_TYPING_NUM); ++i)
-    {
-      mcdprintf("(%d)\n", i);
-      tnode = allocate_node();
-      if(!tnode)
-      {
-        fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
-        delete_list(list);
-        return NULL;
-      }
-
-      snprintf(tnode->card.formula_string, max_formula_size, "%d", i);
-      snprintf(tnode->card.answer_string, max_formula_size, "%d", i);
-      tnode->card.difficulty = 1;
-      list = insert_node(list, *end_of_list, tnode);
-      *end_of_list = tnode;
-    }
-  }
-
-  //add all allowed arithmetic questions
-  else if (MC_PT_ARITHMETIC)
-  {
-    mcdprintf("Adding arithmetic...\n");
-
-    // The k loop iterates through the four arithmetic operations:
-    // k = 0 means addition
-    // k = 1 means subtraction
-    // k = 2 means multiplication
-    // k = 3 means division
-    for (k = MC_OPER_ADD; k < MC_NUM_OPERS; ++k)
-    {
-      if (!MC_GetOpt(k + ADDITION_ALLOWED) )
-        continue;
-      mcdprintf("\n*%d*\n", k);
-
-      // The i loop iterates through the first value in the question:
-      for (i = MC_GetOpt(MIN_AUGEND + 4 * k); i <= MC_GetOpt(MAX_AUGEND + 4 * k); ++i)
-      {
-        mcdprintf("\n%d:\n", i);
-
-        // The j loop iterates through the second value in the question:
-        for (j = MC_GetOpt(MIN_ADDEND + 4 * k); j <= MC_GetOpt(MAX_ADDEND + 4 * k); ++j)
-        {
-          // Generate the third number according to the operation.
-          // Although it is called "ans", it will not be the actual
-          // answer if it is a "missing number" type problem
-          // (e.g. "3 x ? = 12")
-          // We also filter out invalid questions here
-          switch (k)
-          {
-            case MC_OPER_ADD:
-            {
-              ans = i + j;
-              // throw anything over MAX_ANSWER
-              if (ans > MC_GetOpt(MAX_ANSWER))
-                continue;
-              break;
-            }
-            case MC_OPER_SUB:
-            {
-              ans = i - j;
-              // throw out negatives if they aren't allowed:
-              if (ans < 0 && !MC_GetOpt(ALLOW_NEGATIVES))
-                continue;
-              // throw anything over MAX_ANSWER
-              if (ans > MC_GetOpt(MAX_ANSWER))
-                continue;
-              break;
-            }
-            case MC_OPER_MULT:
-            {
-              ans = i * j;
-              // throw anything over MAX_ANSWER
-              if (ans > MC_GetOpt(MAX_ANSWER))
-                continue;
-              break;
-            }
-            case MC_OPER_DIV:
-            {
-               // throw anything over MAX_ANSWER
-              if (i * j > MC_GetOpt(MAX_ANSWER))
-                continue;
-
-              tmp = i;
-              i *= j;
-              ans = j;
-              j = tmp;
-              break;
-            }
-            default:
-              fprintf(stderr, "Unrecognized operation type: %d\n", k);
-              continue;
-          }
-
-          mcdprintf("Generating: %d %c %d = %d\n", i, operchars[k], j, ans);
-
-          //add each format, provided it's allowed in general and for this op
-
-          // Questions like "a + b = ?"
-          if (MC_GetOpt(FORMAT_ANSWER_LAST) && MC_GetOpt(FORMAT_ADD_ANSWER_LAST + k * 3))
-          {
-            // Avoid division by zero:
-            if (k == MC_OPER_DIV && j == 0)
-            {
-              // need to restore i and j to original values so loop works:
-              j = ans;
-              i = tmp;
-              continue;
-            }
-
-            tnode = allocate_node();
-            if(!tnode)
-            {
-              fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
-              delete_list(list);
-              return NULL;
-            }
-
-            snprintf(tnode->card.answer_string, max_formula_size, "%d", ans);
-            snprintf(tnode->card.formula_string, max_formula_size,
-                     "%d %c %d = ?", i, operchars[k], j);
-            tnode->card.difficulty = k + 1;
-            list = insert_node(list, *end_of_list, tnode);
-            *end_of_list = tnode;
-          }
-
-
-          // Questions like "? + b = c"
-          if (MC_GetOpt(FORMAT_ANSWER_FIRST) && MC_GetOpt(FORMAT_ADD_ANSWER_FIRST + k * 3) )
-          {
-            // Avoid questions with indeterminate answer:
-            // e.g. "? x 0 = 0"
-            if (k == MC_OPER_MULT && j == 0)
-            {
-              continue;
-            }
-            // Avoid division by zero:
-            if (k == MC_OPER_DIV && j == 0)
-            {
-              // need to restore i and j to original values so loop works:
-              j = ans;
-              i = tmp;
-              continue;
-            }
-
-            tnode = allocate_node();
-            if(!tnode)
-            {
-              fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
-              delete_list(list);
-              return NULL;
-            }
-
-            snprintf(tnode->card.answer_string, max_formula_size, "%d", i);
-            snprintf(tnode->card.formula_string, max_formula_size,
-                     "? %c %d = %d", operchars[k], j, ans);
-            tnode->card.difficulty = k + 3;
-            list = insert_node(list, *end_of_list, tnode);
-            *end_of_list = tnode;
-          }
-
-
-          // Questions like "a + ? = c"
-          if (MC_GetOpt(FORMAT_ANSWER_MIDDLE) && MC_GetOpt(FORMAT_ADD_ANSWER_MIDDLE + k * 3))
-          {
-            // Avoid questions with indeterminate answer:
-            // e.g. "0 x ? = 0"
-            if (k == MC_OPER_MULT && i == 0)
-              continue;
-
-            // e.g. "0 / ? = 0"
-            if (k == MC_OPER_DIV && i == 0)
-            {
-              // need to restore i and j to original values so loop works:
-              j = ans;
-              i = tmp;
-              continue;
-            }
-
-            tnode = allocate_node();
-            if(!tnode)
-            {
-              fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
-              delete_list(list);
-              return NULL;
-            }
-
-            snprintf(tnode->card.answer_string, max_formula_size, "%d", j);
-            snprintf(tnode->card.formula_string, max_formula_size,
-                     "%d %c ? = %d", i, operchars[k], ans);
-            tnode->card.difficulty = k + 3;
-            list = insert_node(list, *end_of_list, tnode);
-            *end_of_list = tnode;
-          }
-          //If we divided, reset i and j so loop works correctly
-          if (k == MC_OPER_DIV)
-          {
-            j = ans;
-            i = tmp;
-            mcdprintf("resetting to %d %d\n", j, i);
-          }
-        }
-      }
-    }
-  }
-  //add all comparison questions (TODO implement them!)
-  else if (pt == MC_PT_COMPARISON)
-  {
-    for (i = MC_GetOpt(MIN_COMPARATOR); i < MC_GetOpt(MAX_COMPARATOR); ++i)
-    {
-      for (j = MC_GetOpt(MIN_COMPARISAND); j < MC_GetOpt(MAX_COMPARISAND); ++j)
-      {
-        tnode = allocate_node();
-        if(!tnode)
-        {
-          fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
-          delete_list(list);
-          return NULL;
-        }
-
-        snprintf(tnode->card.formula_string, max_formula_size, "%d ? %d", i,j);
-        snprintf(tnode->card.answer_string, max_formula_size,
-                 i < j ? "<" : 
-                 i > j ? ">" : 
-                         "=");
-        tnode->card.difficulty = 1;
-        list = insert_node(list, *end_of_list, tnode);
-        *end_of_list = tnode;
-      }
-    }
-  }
-  mcdprintf("Exiting add_all_valid()\n");  
-  mcdprintf("List now has %d questions\n\n", list_length(list));
-
-  return list;
-}
-
-MC_MathQuestion* find_node(MC_MathQuestion* list, int num)
-{
-  while (--num > 0 && list)
-    list = list->next;
-  return list;
-}
-
-void reformat_arithmetic(MC_FlashCard* card, MC_Format f)
-{
-  int i, j;
-  char* beg = 0;
-  char* end = 0;
-  char nans[max_answer_size];
-  char nformula[max_formula_size + max_answer_size]; //gets a bit larger than usual in the meantime
-  
-  {
-    //snprintf(nans, max_answer_size, "%s", card->answer_string);
-   
-    //insert old answer where question mark was
-    for (i = 0, j = 0; card->formula_string[j] != '?'; ++i, ++j)
-      nformula[i] = card->formula_string[j];
-    i += snprintf(nformula + i, max_answer_size - 1, "%s", card->answer_string);
-    snprintf(nformula + i, max_formula_size - i, "%s", card->formula_string + j + 1);
-
-    //replace the new answer with a question mark
-    if (f == MC_FORMAT_ANS_LAST)
-      beg = strrchr(nformula, ' ') + 1;
-    if (f == MC_FORMAT_ANS_FIRST)
-      beg = nformula;
-    if (f == MC_FORMAT_ANS_MIDDLE)
-      beg = strchr(nformula, ' ') + 3;
-    end = strchr(beg + 1, ' ');
-    if (!end)
-      end = "";
-    //we now have beg = first digit of number to replace, end = the char after
-    sscanf(beg, "%s", nans);
-    *beg = 0; //sequester the first half of the string
-    snprintf(card->formula_string, max_formula_size, "%s?%s", nformula, end);
-    snprintf(card->answer_string, max_answer_size, "%s", nans);
-    card->answer = atoi(card->answer_string);
-  }
-}

Copied: branches/commonification/tuxmath/trunk/src/mathcards.c (from rev 1657, tuxmath/trunk/src/mathcards.c)
===================================================================
--- branches/commonification/tuxmath/trunk/src/mathcards.c	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/mathcards.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,2554 @@
+/*
+*  C Implementation: mathcards.c
+*
+*       Description: implementation of backend for a flashcard-type math game.
+        Developed as an enhancement to Bill Kendrick's "Tux of Math Command"
+        (aka tuxmath).  (If tuxmath were a C++ program, this would be a C++ class).
+        MathCards could be used as the basis for similar games using a different interface.
+
+*
+*
+* Author: David Bruce <davidstuartbruce at gmail.com>, (C) 2005
+*
+* Copyright: See COPYING file that comes with this distribution.  (Briefly, GNU GPL).
+*
+* Revised extensively in 2008 by Brendan Luchen, Tim Holy, and David Bruce
+* Revised more in 2009 by David Bruce
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+
+#include "transtruct.h"
+#include "mathcards.h"
+#include "globals.h"
+
+/* extern'd constants */
+
+const char* const MC_OPTION_TEXT[NOPTS+1] = {
+"PLAY_THROUGH_LIST",
+"QUESTION_COPIES",
+"REPEAT_WRONGS",
+"COPIES_REPEATED_WRONGS",
+"ALLOW_NEGATIVES",
+"MAX_ANSWER",
+"MAX_QUESTIONS",
+"MAX_FORMULA_NUMS",
+"MIN_FORMULA_NUMS",
+
+"FORMAT_ANSWER_LAST",
+"FORMAT_ANSWER_FIRST",
+"FORMAT_ANSWER_MIDDLE",
+"FORMAT_ADD_ANSWER_LAST",
+"FORMAT_ADD_ANSWER_FIRST",
+"FORMAT_ADD_ANSWER_MIDDLE",
+"FORMAT_SUB_ANSWER_LAST",
+"FORMAT_SUB_ANSWER_FIRST",
+"FORMAT_SUB_ANSWER_MIDDLE",
+"FORMAT_MULT_ANSWER_LAST",
+"FORMAT_MULT_ANSWER_FIRST",
+"FORMAT_MULT_ANSWER_MIDDLE",
+"FORMAT_DIV_ANSWER_LAST",
+"FORMAT_DIV_ANSWER_FIRST",
+"FORMAT_DIV_ANSWER_MIDDLE",
+
+"ADDITION_ALLOWED",
+"SUBTRACTION_ALLOWED",
+"MULTIPLICATION_ALLOWED",
+"DIVISION_ALLOWED",
+"TYPING_PRACTICE_ALLOWED",
+"ARITHMETIC_ALLOWED",
+"COMPARISON_ALLOWED",
+
+"MIN_AUGEND",
+"MAX_AUGEND",
+"MIN_ADDEND",
+"MAX_ADDEND",
+
+"MIN_MINUEND",
+"MAX_MINUEND",
+"MIN_SUBTRAHEND",
+"MAX_SUBTRAHEND",
+
+"MIN_MULTIPLIER",
+"MAX_MULTIPLIER",
+"MIN_MULTIPLICAND",
+"MAX_MULTIPLICAND",
+
+"MIN_DIVISOR",
+"MAX_DIVISOR",
+"MIN_QUOTIENT",
+"MAX_QUOTIENT",
+
+"MIN_TYPING_NUM",
+"MAX_TYPING_NUM",
+
+"MIN_COMPARATOR" ,
+"MAX_COMPARATOR" ,
+"MIN_COMPARISAND",
+"MAX_COMPARISAND",
+
+"RANDOMIZE",
+
+"COMPREHENSIVE",
+"AVG_LIST_LENGTH",
+"VARY_LIST_LENGTH",
+
+"END_OF_OPTS"
+};
+
+
+  
+const int MC_DEFAULTS[] = {
+  1,    //PLAY_THROUGH_LIST
+  1,    //QUESTION_COPIES
+  1,    //REPEAT_WRONGS
+  1,    //COPIES_REPEATED_WRONGS
+  0,    //ALLOW_NEGATIVES
+  999,  //MAX_ANSWER
+  5000, //MAX_QUESTIONS
+  2,    //MAX_FORMULA_NUMS
+  2,    //MIN_FORMULA_NUMS
+        //
+  1,    //FORMAT_ANSWER_LAST
+  0,    //FORMAT_ANSWER_FIRST
+  0,    //FORMAT_ANSWER_MIDDLE
+  1,    //FORMAT_ADD_ANSWER_LAST
+  0,    //FORMAT_ADD_ANSWER_FIRST
+  0,    //FORMAT_ADD_ANSWER_MIDDLE
+  1,    //FORMAT_SUB_ANSWER_LAST
+  0,    //FORMAT_SUB_ANSWER_FIRST
+  0,    //FORMAT_SUB_ANSWER_MIDDLE
+  1,    //FORMAT_MULT_ANSWER_LAST
+  0,    //FORMAT_MULT_ANSWER_FIRST
+  0,    //FORMAT_MULT_ANSWER_MIDDLE
+  1,    //FORMAT_DIV_ANSWER_LAST
+  0,    //FORMAT_DIV_ANSWER_FIRST
+  0,    //FORMAT_DIV_ANSWER_MIDDLE
+        //
+  1,    //ADDITION_ALLOWED
+  1,    //SUBTRACTION_ALLOWED
+  1,    //MULTIPLICATION_ALLOWED
+  1,    //DIVISION_ALLOWED
+
+  0,    //TYPING_PRACTICE_ALLOWED
+  1,    //ARITHMETIC_ALLOWED
+  0,    //COMPARISON_ALLOWED
+        //
+  0,    //MIN_AUGEND
+  12,   //MAX_AUGEND
+  0,    //MIN_ADDEND
+  12,   //MAX_ADDEND
+        //
+  0,    //MIN_MINUEND
+  12,   //MAX_MINUEND
+  0,    //MIN_SUBTRAHEND
+  12,   //MAX_SUBTRAHEND
+        //
+  0,    //MIN_MULTIPLIER
+  12,   //MAX_MULTIPLIER
+  0,    //MIN_MULTIPLICAND
+  12,   //MAX_MULTIPLICAND
+        //
+  0,    //MIN_DIVISOR
+  12,   //MAX_DIVISOR
+  0,    //MIN_QUOTIENT
+  12,   //MAX_QUOTIENT
+        //
+  0,    //MIN_TYPING_NUM
+  12,   //MAX_TYPING_NUM
+        //
+  0,    //MIN_COMPARATOR
+  12,   //MAX_COMPARATOR
+  0,    //MIN_COMPARISAND
+  12,   //MAX_COMPARISAND
+
+  1,    //RANDOMIZE
+
+  0,    //COMPREHENSIVE
+  100,  //AVG_LIST_LENGTH
+  0     //VARY_LIST_LENGTH  FIXME what is the purpose of this?
+};
+
+
+
+/* "Globals" for mathcards.c: */
+#define PI_VAL 3.1415927
+#define NPRIMES 9
+const int smallprimes[NPRIMES] = {2, 3, 5 ,7, 11, 13, 17, 19, 23};
+const char operchars[4] = "+-*/";
+
+MC_Options* math_opts = NULL;
+MC_MathQuestion* question_list = NULL;
+MC_MathQuestion* wrong_quests = NULL;
+MC_MathQuestion* active_quests = NULL;
+MC_MathQuestion* next_wrong_quest = NULL;
+int initialized = 0;
+int quest_list_length = 0;
+int answered_correctly = 0;
+int answered_wrong = 0;
+int questions_pending = 0;
+int unanswered = 0;
+int starting_length = 0;
+static int id = 0;
+
+/* For keeping track of timing data */
+float* time_per_question_list = NULL;
+int length_time_per_question_list = 0;
+int length_alloc_time_per_question_list = 0;
+
+const MC_FlashCard DEFAULT_CARD = {{'\0'}, {'\0'}, 0, 0, 0}; //empty card to signal error
+
+/* "private" function prototypes:                        */
+/*                                                       */
+/* these are for internal use by MathCards only - like   */
+/* the private functions of a C++ class. Declared static */
+/* to give file scope rather than extern scope.          */
+
+static MC_MathQuestion* generate_list(void);
+static void clear_negatives(void);
+//static int validate_question(int n1, int n2, int n3);
+//static MC_MathQuestion* create_node(int n1, int n2, int op, int ans, int f);
+//static MC_MathQuestion* create_node_from_card(const MC_FlashCard* flashcard);
+static MC_MathQuestion* create_node_copy(MC_MathQuestion* other);
+static MC_MathQuestion* insert_node(MC_MathQuestion* first, MC_MathQuestion* current, MC_MathQuestion* new_node);
+static MC_MathQuestion* append_node(MC_MathQuestion* list, MC_MathQuestion* new_node);
+static MC_MathQuestion* remove_node(MC_MathQuestion* first, MC_MathQuestion* n);
+static MC_MathQuestion* delete_list(MC_MathQuestion* list);
+//static int copy_node(MC_MathQuestion* original, MC_MathQuestion* copy);
+static int list_length(MC_MathQuestion* list);
+static int randomize_list(MC_MathQuestion** list);
+
+int comp_randomizer(const void* a, const void* b);
+static MC_MathQuestion* pick_random(int length, MC_MathQuestion* list);
+static int compare_node(MC_MathQuestion* first, MC_MathQuestion* other);
+static int already_in_list(MC_MathQuestion* list, MC_MathQuestion* ptr);
+//static int int_to_bool(int i);
+//static int sane_value(int i);
+//static int abs_value(int i);
+static int floatCompare(const void* v1,const void* v2);
+
+static void print_list(FILE* fp,MC_MathQuestion* list);
+void print_vect_list(FILE* fp, MC_MathQuestion** vect, int length);
+
+static void print_counters(void);
+//static MC_FlashCard    create_card_from_node(MC_MathQuestion* node);
+
+
+/* Functions for new mathcards architecture */
+static void free_node(MC_MathQuestion* mq); //wrapper for free() that also frees card
+static MC_FlashCard generate_random_flashcard(void);
+static MC_FlashCard generate_random_ooo_card_of_length(int length, int reformat);
+static MC_MathQuestion* allocate_node(void); //allocate space for a node
+static int compare_card(const MC_FlashCard* a, const MC_FlashCard* b); //test for identical cards
+static int find_divisor(int a); //return a random positive divisor of a
+static int calc_num_valid_questions(void);
+static MC_MathQuestion* add_all_valid(MC_ProblemType pt, MC_MathQuestion* list, MC_MathQuestion** end_of_list);
+static MC_MathQuestion* find_node(MC_MathQuestion* list, int num);
+//Determine how many points to give player based on question
+//difficulty and how fast it was answered.
+//TODO we may want to play with this a bit
+static int calc_score(int difficulty, float t);
+
+
+
+
+
+
+/*  MC_Initialize() sets up the struct containing all of  */
+/*  settings regarding math questions.  It should be      */
+/*  called before any other function.  Many of the other  */
+/*  functions will not work properly if MC_Initialize()   */
+/*  has not been called. It only needs to be called once, */
+/*  i.e when the program is starting, not at the beginning*/
+/*  of each math game for the player. Returns 1 if        */
+/*  successful, 0 otherwise.                              */
+int MC_Initialize(void)
+{
+  int i;
+
+  DEBUGMSG(debug_mathcards,"\nEntering MC_Initialize()");
+  /* check flag to see if we did this already */
+  if (initialized)
+  {
+
+    DEBUGCODE(debug_mathcards)
+    {
+      printf("\nAlready initialized");
+      MC_PrintMathOptions(stdout, 0);
+      printf("\nLeaving MC_Initialize()\n");
+    }
+
+    return 1;
+  }
+  math_opts = malloc(sizeof(MC_Options));
+  /* bail out if no struct */
+  if (!math_opts)
+  {
+    DEBUGMSG(debug_mathcards,"\nError: malloc couldn't allocate math_opts for some reason\n");
+    DEBUGMSG(debug_mathcards,"\nLeaving MC_Initialize()\n");
+
+    fprintf(stderr, "\nUnable to initialize math_options");
+    return 0;
+  }
+
+  /* set defaults */
+  for (i = 0; i < NOPTS; ++i)
+    {
+      math_opts->iopts[i] = MC_DEFAULTS[i];
+    }
+
+  /* if no negatives to be used, reset any negatives to 0 */
+  if (!math_opts->iopts[ALLOW_NEGATIVES])
+  {
+    clear_negatives();
+  }
+
+  initialized = 1;
+
+  DEBUGCODE(debug_mathcards)
+  {
+    MC_PrintMathOptions(stdout, 0);
+    printf("\nLeaving MC_Initialize()\n");
+  }
+
+  return 1;
+}
+
+
+
+/*  MC_StartGame() generates the list of math questions   */
+/*  based on existing settings. It should be called at    */
+/*  the beginning of each math game for the player.       */
+/*  Returns 1 if resultant list contains 1 or more        */
+/*  questions, 0 if list empty or not generated           */
+/*  successfully.                                         */
+int MC_StartGame(void)
+{
+
+  DEBUGMSG(debug_mathcards,"\nEntering MC_StartGame()");
+
+  /* if math_opts not set up yet, initialize it: */
+  if (!initialized)
+  {
+
+    DEBUGMSG(debug_mathcards, "\nNot initialized - calling MC_Initialize()");
+
+    MC_Initialize();
+  }
+
+  if (!math_opts)
+  {
+    DEBUGMSG(debug_mathcards, "\nCould not initialize - bailing out");
+    DEBUGMSG(debug_mathcards, "\nLeaving MC_StartGame()\n");
+
+    return 0;
+  }
+  /* we know math_opts exists if we make it to here */
+  srand(time(NULL));
+
+  /* clear out old lists if starting another game: (if not done already) */
+  delete_list(question_list);
+  question_list = NULL;
+  delete_list(wrong_quests);
+  wrong_quests = NULL;
+  delete_list(active_quests);
+  active_quests = NULL;
+  
+  /* clear the time list */
+  if (time_per_question_list != NULL) {
+    free(time_per_question_list);
+    time_per_question_list = NULL;
+    length_time_per_question_list = 0;
+    length_alloc_time_per_question_list = 0;
+  }
+
+  question_list = generate_list();
+  next_wrong_quest = NULL;
+  /* initialize counters for new game: */
+  quest_list_length = list_length(question_list);
+  
+
+  /* Note: the distinction between quest_list_length and  */
+  /* unanswered is that the latter includes questions     */
+  /* that are currently "in play" by the user interface - */
+  /* it is only decremented when an answer to the question*/
+  /* is received.                                         */
+  unanswered = starting_length = quest_list_length;
+  answered_correctly = 0;
+  answered_wrong = 0;
+  questions_pending = 0;
+
+  if (debug_status & debug_mathcards) {
+    print_counters();
+  }
+
+/* make sure list now exists and has non-zero length: */
+  if (question_list && quest_list_length)
+  {
+    DEBUGMSG(debug_mathcards, "\nGame set up successfully");
+    DEBUGMSG(debug_mathcards, "\nLeaving MC_StartGame()\n");
+
+    return 1;
+  }
+  else
+  {
+    DEBUGMSG(debug_mathcards, "\nGame NOT set up successfully - no valid list");
+    DEBUGMSG(debug_mathcards, "\nLeaving MC_StartGame()\n");
+
+    return 0;
+  }
+}
+
+/*  MC_StartGameUsingWrongs() is like MC_StartGame(),     */
+/*  but uses the incorrectly answered questions from the  */
+/*  previous game for the question list as a review form  */
+/*  of learning. If there were no wrong answers (or no    */
+/*  previous game), it behaves just like MC_StartGame().  */
+/*  FIXME wonder if it should return a different value if */
+/*  the list is created from settings because there is no */
+/*  valid wrong question list?                            */
+int MC_StartGameUsingWrongs(void)
+{
+  DEBUGMSG(debug_mathcards, "\nEntering MC_StartGameUsingWrongs()");
+
+  /* Note: if not initialized, control will pass to       */
+  /* MC_StartGame() via else clause so don't need to test */
+  /* for initialization here                              */
+  if (wrong_quests &&
+      list_length(wrong_quests))
+  {
+    DEBUGMSG(debug_mathcards, "\nNon-zero length wrong_quests list found, will");
+    DEBUGMSG(debug_mathcards, "\nuse for new game list:");
+
+    /* initialize lists for new game: */
+    delete_list(question_list);
+    if(!randomize_list(&wrong_quests))
+    {
+      fprintf(stderr, "Error during randomization of wrong_quests!\n");
+      /* Punt on trying wrong question list, just run normal game */
+      return MC_StartGame();
+    }
+    question_list = wrong_quests;
+    wrong_quests = 0;
+    next_wrong_quest = 0;
+    delete_list(active_quests);
+    active_quests = 0;
+   /* initialize counters for new game: */
+    quest_list_length = list_length(question_list);
+    unanswered = starting_length = quest_list_length;
+    answered_correctly = 0;
+    answered_wrong = 0;
+    questions_pending = 0;
+
+    if (debug_status & debug_mathcards) {
+      print_counters();
+      print_list(stdout, question_list);
+      printf("\nLeaving MC_StartGameUsingWrongs()\n");
+    }
+
+    return 1;
+  }
+  else /* if no wrong_quests list, go to MC_StartGame()   */
+       /* to set up list based on math_opts               */
+  {
+    DEBUGMSG(debug_mathcards, "\nNo wrong questions to review - generate list from math_opts\n");
+    DEBUGMSG(debug_mathcards, "\nLeaving MC_StartGameUsingWrongs()\n");
+
+    return MC_StartGame();
+  }
+}
+
+
+/*  MC_NextQuestion() takes a pointer to an allocated      */
+/*  MC_FlashCard struct and fills in the fields for     */
+/*  use by the user interface program. It basically is     */
+/*  like taking the next flashcard from the pile. The      */
+/*  node containing the question is removed from the list. */
+/*  Returns 1 if question found, 0 if list empty/invalid   */
+/*  or if argument pointer is invalid.                     */
+int MC_NextQuestion(MC_FlashCard* fc)
+{
+  DEBUGMSG(debug_mathcards, "\nEntering MC_NextQuestion()\n");
+
+  /* (so we can move the node into active_quests:) */
+  MC_MathQuestion* ptr;
+
+  if (!fc )
+  {
+    fprintf(stderr, "\nNull MC_FlashCard* argument!\n");
+    DEBUGMSG(debug_mathcards, "\nLeaving MC_NextQuestion()\n");
+    return 0;
+  }
+
+  if (!question_list ||
+/*      !next_question || */
+      !list_length(question_list) )
+  {
+    DEBUGMSG(debug_mathcards, "\nquestion_list invalid or empty");
+    DEBUGMSG(debug_mathcards, "\nLeaving MC_NextQuestion()\n");
+    
+    return 0;
+  }
+
+  /* 'draw' - copy over the first question */
+  MC_CopyCard(&question_list->card, fc);
+ 
+  /* take first question node out of list and move it into active_quests list: */
+  ptr = question_list;
+  question_list = remove_node(question_list, ptr);
+//  free_node(ptr);
+  quest_list_length--;
+  questions_pending++;
+  active_quests = append_node(active_quests, ptr);
+
+  if (debug_status & debug_mathcards) {
+    printf("\nnext question is:");
+    print_card(*fc);
+    print_counters();
+    printf("\n\nLeaving MC_NextQuestion()\n");
+  }
+
+  return 1;
+}
+
+
+
+/*  MC_AnsweredCorrectly() is how the user interface      */
+/*  tells MathCards that the question has been answered   */
+/*  correctly. Returns the number of points earned.       */
+int MC_AnsweredCorrectly(int id, float t)
+{
+  DEBUGMSG(debug_mathcards, "\nEntering MC_AnsweredCorrectly()");
+
+  MC_MathQuestion* quest = NULL;
+  int points = 0;
+
+  if(!active_quests) // No questions currently "in play" - something is wrong:
+  {
+    fprintf(stderr, "MC_AnsweredCorrectly() - active_quests empty\n");
+    return 0;
+  }
+
+  DEBUGMSG(debug_mathcards, "\nQuestion id was: %d\n", id);
+
+  //First take the question out of the active_quests list
+  quest = active_quests;  
+  // Loop until quest is NULL or we find card with same id:
+  while(quest && (id != quest->card.question_id))
+    quest = quest->next;
+  if(!quest) // Means we didn't find matching card - something is wrong:
+  {
+    fprintf(stderr, "MC_AnsweredCorrectly() - matching question not found!\n");
+    return 0;
+  }
+
+  /* Calculate how many points the player should receive, based on */
+  /* difficulty and time required to answer it:                    */
+  points = calc_score(quest->card.difficulty, t);
+
+  DEBUGCODE(debug_mathcards)
+  {
+    printf("\nQuestion was:");
+    print_card(quest->card);
+    printf("Player recieves %d points\n", points);
+  }
+
+
+  //We found a matching question, now we take it out of the 
+  //"active_quests" list and either put it back into the 
+  //main question list in a random location, or delete it:
+  active_quests = remove_node(active_quests, quest);
+  questions_pending--;  //the length of the 'active_quests' list
+  answered_correctly++;
+
+  if (!math_opts->iopts[PLAY_THROUGH_LIST])
+  /* reinsert question into question list at random location */
+  {
+    DEBUGMSG(debug_mathcards, "\nReinserting question into list");
+
+    MC_MathQuestion* rand_spot;
+    /* put it into list */
+    rand_spot = pick_random(quest_list_length, question_list);
+    question_list = insert_node(question_list, rand_spot, quest);
+    quest_list_length++;
+    /* unanswered does not change - was not decremented when */
+    /* question allocated!                                   */
+  }
+  else
+  {
+    DEBUGMSG(debug_mathcards, "\nNot reinserting question into list");
+    free_node(quest);
+    /* not recycling questions so fewer questions remain:      */
+    unanswered--;
+  }
+
+  DEBUGCODE(debug_mathcards)
+  {
+    print_counters();
+    printf("\nLeaving MC_AnsweredCorrectly()\n");
+  }
+
+  /* Record the time it took to answer: */ 
+  MC_AddTimeToList(t);
+
+  return points;
+}
+
+
+
+
+
+/*  MC_NotAnsweredCorrectly() is how the user interface    */
+/*  tells MathCards that the player failed to answer the  */
+/*  question correctly. Returns 1 if no errors.           */
+/*  Note: this gets triggered only if a player's igloo/city */
+/*  gets hit by a question, not if they "miss".             */
+int MC_NotAnsweredCorrectly(int id)
+{
+  DEBUGMSG(debug_mathcards, "\nEntering MC_NotAnsweredCorrectly()");
+
+  MC_MathQuestion* quest = NULL;
+
+  if(!active_quests) // No questions currently "in play" - something is wrong:
+  {
+    fprintf(stderr, "MC_NotAnsweredCorrectly() - active_quests empty\n");
+    return 0;
+  }
+
+  DEBUGMSG(debug_mathcards, "\nQuestion id was: %d\n", id);
+
+  //First take the question out of the active_quests list
+  quest = active_quests;  
+  // Loop until quest is NULL or we find card with same id:
+  while(quest && (id != quest->card.question_id))
+    quest = quest->next;
+  if(!quest) // Means we didn't find matching card - something is wrong:
+  {
+    fprintf(stderr, "MC_NotAnsweredCorrectly() - matching question not found!\n");
+    return 0;
+  }
+
+  DEBUGMSG(debug_mathcards, "\nMatching question is:");
+  print_card(quest->card);
+
+
+  /* if desired, put question back in list so student sees it again */
+  if (math_opts->iopts[REPEAT_WRONGS])
+  {
+    int i;
+    MC_MathQuestion* quest_copy;
+    MC_MathQuestion* rand_loc;
+
+    DEBUGMSG(debug_mathcards, "\nAdding %d copies to question_list:", math_opts->iopts[COPIES_REPEATED_WRONGS]);
+
+    DEBUGCODE(debug_mathcards)
+    {
+      print_counters();
+      printf("\nLeaving MC_AnsweredCorrectly()\n");
+    }
+
+    /* can put in more than one copy (to drive the point home!) */
+    for (i = 0; i < math_opts->iopts[COPIES_REPEATED_WRONGS]; i++)
+    {
+      quest_copy = create_node_copy(quest);
+      rand_loc = pick_random(quest_list_length, question_list);
+      question_list = insert_node(question_list, rand_loc, quest_copy);
+      quest_list_length++;
+    }
+    /* unanswered stays the same if a single copy recycled or */
+    /* increases by 1 for each "extra" copy reinserted:       */
+    unanswered += (math_opts->iopts[COPIES_REPEATED_WRONGS] - 1);
+  }
+  else
+  {
+    DEBUGMSG(debug_mathcards, "\nNot repeating wrong answers\n");
+    /* not repeating questions so list gets shorter:      */
+    unanswered--;
+  }
+
+  //Take the question out of the active_quests list and add it to
+  //the wrong_quests list, unless an identical question is already
+  //in the wrong_quests list:
+  active_quests = remove_node(active_quests, quest);
+  questions_pending--;  //the length of the 'active_quests' list
+  answered_wrong++;
+
+  /* add question to wrong_quests list: */
+  if (!already_in_list(wrong_quests, quest)) /* avoid duplicates */
+  {
+    DEBUGMSG(debug_mathcards, "\nAdding to wrong_quests list");
+    wrong_quests = append_node(wrong_quests, quest);
+  }
+  else /* avoid memory leak */
+  {
+    free_node(quest);
+  }
+
+  DEBUGCODE(debug_mathcards)
+ {
+    print_counters();
+    printf("\nLeaving MC_NotAnswered_Correctly()\n");
+  }
+
+  return 1;
+}
+
+
+
+
+
+
+/* Tells user interface if all questions have been answered correctly! */
+/* Requires that at list contained at least one question to start with */
+/* and that wrongly answered questions have been recycled.             */
+int MC_MissionAccomplished(void)
+{
+  if (starting_length
+    && math_opts->iopts[REPEAT_WRONGS]
+    && !unanswered)
+  {
+    return 1;
+  }
+  else
+  {
+    return 0;
+  }
+}
+
+
+/*  Returns number of questions left (either in list       */
+/*  or "in play")                                          */
+int MC_TotalQuestionsLeft(void)
+{
+  return unanswered;
+}
+
+/*  Returns number of questions left in list, NOT       */
+/*  including questions currently "in play".            */
+int MC_ListQuestionsLeft(void)
+{
+  return quest_list_length;
+}
+
+
+/*  Store the amount of time a given flashcard was      */
+/*  visible on the screen. Returns 1 if the request     */
+/*  succeeds, 0 otherwise.                              */
+int MC_AddTimeToList(float t)
+{
+  int newsize = 0;
+  float *newlist;
+
+  //Bail if time invalid:
+  if(t < 0)
+    return 0;
+
+  /* This list will be allocated in an STL-like manner: when the       */
+  /* list gets full, allocate an additional amount of storage equal    */
+  /* to the current size of the list, so that only O(logN) allocations */
+  /* will ever be needed. We therefore have to keep track of 2 sizes:  */
+  /* the allocated size, and the actual number of items currently on   */
+  /* the list.                                                         */
+  if (length_time_per_question_list >= length_alloc_time_per_question_list) {
+    /* The list is full, allocate more space */
+    newsize = 2*length_time_per_question_list;
+    if (newsize == 0)
+      newsize = 100;
+    newlist = realloc(time_per_question_list, newsize*sizeof(float));
+    if (newlist == NULL)
+    {
+      DEBUGMSG(debug_mathcards,"\nError: allocation for time_per_question_list failed\n");
+      return 0;
+    }
+    time_per_question_list = newlist;
+    length_alloc_time_per_question_list = newsize;
+  }
+
+  /* Append the time to the list */
+  time_per_question_list[length_time_per_question_list++] = t;
+  return 1;
+}
+
+/* Frees heap memory used in program:                   */
+void MC_EndGame(void)
+{
+  delete_list(question_list);
+  question_list = 0;
+  delete_list(wrong_quests);
+  wrong_quests = 0;
+
+  if (math_opts)
+  {
+    free(math_opts);
+    math_opts = 0;
+  }
+
+  free(time_per_question_list);
+  time_per_question_list = NULL;
+  length_alloc_time_per_question_list = 0;
+  length_time_per_question_list = 0;
+
+  initialized = 0;
+}
+
+
+
+/* prints struct to file */
+void MC_PrintMathOptions(FILE* fp, int verbose)
+{
+  int i, vcommentsprimed = 0;
+  //comments when writing out verbose...perhaps they can go somewhere less conspicuous
+  static char* vcomments[NOPTS];
+  if (!vcommentsprimed) //we only want to initialize these once
+  {
+    vcommentsprimed = 1;
+    for (i = 0; i < NOPTS; ++i)
+      vcomments[i] = NULL;
+    vcomments[PLAY_THROUGH_LIST] =
+      "\n############################################################\n"
+      "#                                                          #\n"
+      "#                  General Math Options                    #\n"
+      "#                                                          #\n"
+      "# If 'play_through_list' is true, Tuxmath will ask each    #\n"
+      "# question in an internally-generated list. The list is    #\n"
+      "# generated based on the question ranges selected below.   #\n"
+      "# The game ends when no questions remain.                  #\n"
+      "# If 'play_through_list' is false, the game continues      #\n"
+      "# until all cities are destroyed.                          #\n"
+      "# Default is 1 (i.e. 'true' or 'yes').                     #\n"
+      "#                                                          #\n"
+      "# 'question_copies' is the number of times each question   #\n"
+      "# will be asked. It can be 1 to 10 - Default is 1.         #\n"
+      "#                                                          #\n"
+      "# 'repeat_wrongs' tells Tuxmath whether to reinsert        #\n"
+      "# incorrectly answered questions into the list to be       #\n"
+      "# asked again. Default is 1 (yes).                         #\n"
+      "#                                                          #\n"
+      "# 'copies_repeated_wrongs' gives the number of times an    #\n"
+      "# incorrectly answered question will reappear. Default     #\n"
+      "# is 1.                                                    #\n"
+      "#                                                          #\n"
+      "# The defaults for these values result in a 'mission'      #\n"
+      "# for Tux that is accomplished by answering all            #\n"
+      "# questions correctly with at least one surviving city.    #\n"
+      "############################################################\n\n";
+
+    vcomments[FORMAT_ADD_ANSWER_LAST] =
+      "\n############################################################\n"
+      "# The 'format_<op>_answer_<place>  options control         #\n"
+      "# generation of questions with the answer in different     #\n"
+      "# places in the equation.  i.e.:                           #\n"
+      "#                                                          #\n"
+      "#    format_add_answer_last:    2 + 2 = ?                  #\n"
+      "#    format_add_answer_first:   ? + 2 = 4                  #\n"
+      "#    format_add_answer_middle:  2 + ? = 4                  #\n"
+      "#                                                          #\n"
+      "# By default, 'format_answer_first' is enabled and the     #\n"
+      "# other two formats are disabled.  Note that the options   #\n"
+      "# are not mutually exclusive - the question list may       #\n"
+      "# contain questions with different formats.                #\n"
+      "#                                                          #\n"
+      "# The formats are set independently for each of the four   #\n"
+      "# math operations.                                         #\n"
+      "############################################################\n\n";
+
+    vcomments[ALLOW_NEGATIVES] =
+      "\n############################################################\n"
+      "# 'allow_negatives' allows or disallows use of negative    #\n"
+      "# numbers as both operands and answers.  Default is 0      #\n"
+      "# (no), which disallows questions like:                    #\n"
+      "#          2 - 4 = ?                                       #\n"
+      "# Note: this option must be enabled in order to set the    #\n"
+      "# operand ranges to include negatives (see below). If it   #\n"
+      "# is changed from 1 (yes) to 0 (no), any negative          #\n"
+      "# operand limits will be reset to 0.                       #\n"
+      "############################################################\n\n";
+
+    vcomments[MAX_ANSWER] =
+      "\n############################################################\n"
+      "# 'max_answer' is the largest absolute value allowed in    #\n"
+      "# any value in a question (not only the answer). Default   #\n"
+      "# is 144. It can be set as high as 999.                    #\n"
+      "############################################################\n\n";
+
+    vcomments[MAX_QUESTIONS] =
+      "\n############################################################\n"
+      "# 'max_questions' is limit of the length of the question   #\n"
+      "# list. Default is 5000 - only severe taskmasters will     #\n"
+      "# need to raise it.                                        #\n"
+      "############################################################\n\n";
+
+    vcomments[RANDOMIZE] =
+      "\n############################################################\n"
+      "# If 'randomize' selected, the list will be shuffled       #\n"
+      "# at the start of the game.  Default is 1 (yes).           #\n"
+      "############################################################\n\n";
+
+    vcomments[ADDITION_ALLOWED] =
+      "\n############################################################\n"
+      "#                                                          #\n"
+      "#                 Math Operations Allowed                  #\n"
+      "#                                                          #\n"
+      "# These options enable questions for each of the four math #\n"
+      "# operations.  All are 1 (yes) by default.                 #\n"
+      "############################################################\n\n";
+
+    vcomments[MIN_AUGEND] =
+      "\n############################################################\n"
+      "#                                                          #\n"
+      "#      Minimum and Maximum Values for Operand Ranges       #\n"
+      "#                                                          #\n"
+      "# Operand limits can be set to any integer up to the       #\n"
+      "# value of 'max_answer'.  If 'allow_negatives' is set to 1 #\n"
+      "# (yes), either negative or positive values can be used.   #\n"
+      "# Tuxmath will generate questions for every value in the   #\n"
+      "# specified range. The maximum must be greater than or     #\n"
+      "# equal to the corresponding minimum for any questions to  #\n"
+      "# be generated for that operation.                         #\n"
+      "############################################################\n\n";
+
+  }
+
+
+  DEBUGMSG(debug_mathcards, "\nEntering MC_PrintMathOptions()\n");
+
+  /* bail out if no struct */
+  if (!math_opts)
+  {
+    fprintf(stderr, "\nMath Options struct does not exist!\n");
+    return;
+  }
+
+  for (i = 0; i < NOPTS; ++i)
+    {
+    if (verbose && vcomments[i] != NULL)
+      fprintf(fp, "%s", vcomments[i]);
+    fprintf(fp, "%s = %d\n", MC_OPTION_TEXT[i], math_opts->iopts[i]);
+    }
+  DEBUGMSG(debug_mathcards, "\nLeaving MC_PrintMathOptions()\n");
+}
+
+
+
+int MC_PrintQuestionList(FILE* fp)
+{
+  if (fp && question_list)
+  {
+    print_list(fp, question_list);
+    return 1;
+  }
+  else
+  {
+    fprintf(stderr, "\nFile pointer and/or question list invalid\n");
+    return 0;
+  }
+}
+
+int MC_PrintWrongList(FILE* fp)
+{
+  if (!fp)
+  {
+    fprintf(stderr, "File pointer invalid\n");
+    return 0;
+  }
+
+  if (wrong_quests)
+  {
+    print_list(fp, wrong_quests);
+  }
+  else
+  {
+    fprintf(fp, "\nNo wrong questions!\n");
+  }
+
+  return 1;
+}
+
+
+int MC_StartingListLength(void)
+{
+  return starting_length;
+}
+
+
+int MC_WrongListLength(void)
+{
+  return list_length(wrong_quests);
+}
+
+int MC_NumAnsweredCorrectly(void)
+{
+  return answered_correctly;
+}
+
+
+int MC_NumNotAnsweredCorrectly(void)
+{
+  return answered_wrong;
+}
+
+
+/* Report the median time per question */
+float MC_MedianTimePerQuestion(void)
+{
+  if (length_time_per_question_list == 0)
+    return 0;
+
+  qsort(time_per_question_list,length_time_per_question_list,sizeof(float),floatCompare);
+  return time_per_question_list[length_time_per_question_list/2];
+}
+
+
+
+
+/* Implementation of "private methods" - (cannot be called from outside
+of this file) */
+
+
+
+/* Resets negative values to zero - used when allow_negatives deselected. */
+void clear_negatives(void)
+{
+  int i;
+  for (i = MIN_AUGEND; i <= MAX_TYPING_NUM; ++i)
+    if (math_opts->iopts[i]< 0)
+      math_opts->iopts[i]= 0;
+}
+
+// /* this is used by generate_list to see if a possible question */
+// /* meets criteria to be added to the list or not:              */
+// int validate_question(int n1, int n2, int n3)
+// {
+//   /* make sure none of values exceeds max_answer using absolute */
+//   /* value comparison:                                          */
+//   if (abs_value(n1) > abs_value(math_opts->iopts[MAX_ANSWER])
+//    || abs_value(n2) > abs_value(math_opts->iopts[MAX_ANSWER])
+//    || abs_value(n3) > abs_value(math_opts->iopts[MAX_ANSWER]))
+//   {
+//     return 0;
+//   }
+//   /* make sure none of values are negative if negatives not allowed: */
+//   if (!math_opts->iopts[ALLOW_NEGATIVES])
+//   {
+//     if (n1 < 0 || n2 < 0 || n3 < 0)
+//     {
+//       return 0;
+//     }
+//   }
+//   return 1;
+// }
+
+
+
+// MC_MathQuestion* create_node_from_card(const MC_FlashCard* flashcard)
+// {
+//   MC_MathQuestion* ret = allocate_node();
+//   MC_CopyCard(flashcard, &(ret->card));
+//   return ret;
+// }
+
+// /* FIXME take care of strings */
+// /* this one copies the contents, including pointers; both nodes must be allocated */
+// int copy_node(MC_MathQuestion* original, MC_MathQuestion* copy)
+// {
+//   if (!original)
+//   {
+//     fprintf(stderr, "\nIn copy_node(): invalid 'original' pointer arg.\n");
+//     return 0;
+//   }
+//   if (!copy)
+//   {
+//     fprintf(stderr, "\nIn copy_node(): invalid 'copy' pointer arg.\n");
+//     return 0;
+//   }
+// 
+//   copy_card(&(original->card), &(copy->card) );
+// 
+//   copy->next = original->next;
+//   copy->previous = original->previous;
+//   copy->randomizer = original->randomizer;
+//   return 1;
+// }
+
+
+
+
+/* this puts the node into the list AFTER the node pointed to by current */
+/* and returns a pointer to the top of the modified list  */
+MC_MathQuestion* insert_node(MC_MathQuestion* first,
+                             MC_MathQuestion* current,
+                             MC_MathQuestion* new_node)
+{
+  /* return pointer to list unchanged if new_node doesn't exist*/
+  if (!new_node)
+    return first;
+  /* if current doesn't exist, new_node is first */
+  if (!current)
+  {
+    new_node->previous = 0;
+    new_node->next =0;
+    first = new_node;
+    return first;
+  }
+
+  if (current->next)  /* avoid error if at end of list */
+    current->next->previous = new_node;
+  new_node->next = current->next;
+  current->next = new_node;
+  new_node->previous = current;
+  return first;
+}
+
+
+
+/* adds the new node to the end of the list */
+MC_MathQuestion* append_node(MC_MathQuestion* list, MC_MathQuestion* new_node)
+{
+  MC_MathQuestion* ptr;
+  /* return pointer to list unchanged if new_node doesn't exist*/
+  if (!new_node)
+  {
+    return list;
+  }
+
+  /* if list does not exist, new_node is the first (and only) node */
+  if (!list)
+  {
+    return new_node;
+  }
+  /* otherwise, go to end of list */
+  ptr = list;
+  while (ptr->next)
+  {
+    ptr = ptr->next;
+  }
+
+  ptr->next = new_node;
+  new_node->previous = ptr;
+  new_node->next = 0;
+  return list;
+}
+
+
+
+/* this takes the node out of the list but does not delete it */
+/* and returns a pointer to the top of the modified list  */
+MC_MathQuestion* remove_node(MC_MathQuestion* first, MC_MathQuestion* n)
+{
+  if (!n || !first)
+    return first;
+  /* special case if first node being removed */
+  if (n == first)
+     first = first->next;
+
+  if (n->previous)
+    n->previous->next = n->next;
+  if (n->next)
+      n->next->previous = n->previous;
+  n->previous = 0;
+  n->next = 0;
+  return first;
+}
+
+
+
+/* frees memory for entire list and returns null pointer */
+MC_MathQuestion* delete_list(MC_MathQuestion* list)
+{
+  MC_MathQuestion* tmp_ptr;
+  while (list)
+  {
+    tmp_ptr = list->next;
+    free_node (list);
+    list = tmp_ptr;
+  }
+  return list;
+}
+
+
+
+void print_list(FILE* fp, MC_MathQuestion* list)
+{
+  if (!list)
+  {
+    fprintf(fp, "\nprint_list(): list empty or pointer invalid\n");
+    return;
+  }
+
+  MC_MathQuestion* ptr = list;
+  while (ptr)
+  {
+    fprintf(stderr, "%s\n", ptr->card.formula_string);
+    ptr = ptr->next;
+  }
+}
+
+
+void print_vect_list(FILE* fp, MC_MathQuestion** vect, int length)
+{
+  if (!vect)
+  {
+    fprintf(fp, "\nprint_vect_list(): list empty or pointer invalid\n");
+    return;
+  }
+
+  int i = 0;
+  DEBUGMSG(debug_mathcards, "Entering print_vect_list()\n");
+  for(i = 0; i < length; i++)
+    fprintf(fp, "%s\n", vect[i]->card.formula_string);
+
+  DEBUGMSG(debug_mathcards, "Leaving print_vect_list()\n");
+}
+
+
+
+void print_card(MC_FlashCard card)
+{
+  printf("\nprint_card():\n");
+  printf("question_id: %d\nformula_string: %s\nanswer_string: %s\n"
+         "answer: %d\ndifficulty: %d\n\n",
+         card.question_id,
+         card.formula_string,
+         card.answer_string,
+         card.answer,
+         card.difficulty);
+}
+
+/* This sends the values of all "global" counters and the */
+/* lengths of the question lists to stdout - for debugging */
+void print_counters(void)
+{
+  printf("\nquest_list_length = \t%d", quest_list_length);
+  printf("\nlist_length(question_list) = \t%d", list_length(question_list));
+  printf("\nstarting_length = \t%d", starting_length);
+  printf("\nunanswered = \t%d", unanswered);
+  printf("\nanswered_correctly = \t%d", answered_correctly);
+  printf("\nanswered_wrong = \t%d", answered_wrong);
+  printf("\nlist_length(wrong_quests) = \t%d", list_length(wrong_quests));
+  printf("\nquestions_pending = \t%d", questions_pending);
+  printf("\nlist_length(active_quests) = \t%d", list_length(active_quests));
+}
+
+
+
+
+
+
+// 
+// /* FIXME take care of strings */
+// 
+// MC_FlashCard create_card_from_node(MC_MathQuestion* node)
+// {
+//   MC_FlashCard fc;
+//   if (!node)
+//     return DEFAULT_CARD;
+//   fc = MC_AllocateFlashcard();
+//   copy_card(&(node->card), &fc);
+//   return fc;
+// }
+
+
+
+/* a "copy constructor", so to speak */
+/* FIXME perhaps should return newly allocated list if more than one node DSB */
+MC_MathQuestion* create_node_copy(MC_MathQuestion* other)
+{
+  MC_MathQuestion* ret = allocate_node();
+  if (ret)
+    MC_CopyCard(&(other->card), &(ret->card) );
+  return ret;
+}
+
+
+int list_length(MC_MathQuestion* list)
+{
+  int length = 0;
+  while (list)
+  {
+    length++;
+    list = list->next;
+  }
+  return length;
+}
+
+
+
+
+
+
+/* This is a new implementation written in an attempt to avoid       */
+/* the O(n^2) performance problems seen with the old randomization   */
+/* function. The list is created as a vector, but is for now still   */
+/* made a linked list to minimize changes needed elsewhere.          */
+/* The argument is a pointer to the top of the old list.  This extra */
+/* level of indirection allows the list to be shuffled "in-place".   */
+/* The function returns 1 if successful, 0 on errors.                */
+
+static int randomize_list(MC_MathQuestion** old_list)
+{
+  MC_MathQuestion* old_tmp = *old_list;
+  MC_MathQuestion** tmp_vect = NULL;
+
+  int i = 0;
+  if (!old_list || !*old_list) //invalid/empty list
+    return 0;
+  
+  int old_length = list_length(old_tmp);
+
+  /* set random seed: */
+  srand(time(0));
+
+
+  /* Allocate vector and set ptrs to nodes in old list: */
+
+  /* Allocate a list of pointers, not space for the nodes themselves: */
+  tmp_vect = (MC_MathQuestion**)malloc(sizeof(MC_MathQuestion*) * old_length);
+  /* Set each pointer in the vector to the corresponding node: */
+  for (i = 0; i < old_length; i++)
+  {
+    tmp_vect[i] = old_tmp;
+    tmp_vect[i]->randomizer = rand();
+    old_tmp = old_tmp->next;
+  }
+
+  /* Now simply sort on 'tmp_vect[i]->randomizer' to shuffle list: */
+  qsort(tmp_vect, old_length,
+        sizeof(MC_MathQuestion*),
+        comp_randomizer);
+
+  /* Re-create pointers to provide linked-list functionality:      */
+  /* (stop at 'old_length-1' because we dereference tmp_vect[i+1]) */
+  for(i = 0; i < old_length - 1; i++)
+  {
+    if (!tmp_vect[i])
+    {
+      fprintf(stderr, "Invalid pointer!\n");
+      return 0;
+    }
+    tmp_vect[i]->next = tmp_vect[i+1];
+    tmp_vect[i+1]->previous = tmp_vect[i];
+  }
+  /* Handle end cases: */
+  tmp_vect[0]->previous = NULL;
+  tmp_vect[old_length-1]->next = NULL;
+
+  /* Now arrange for arg pointer to indirectly point to first element! */
+  *old_list = tmp_vect[0];
+  free(tmp_vect);
+  return 1;
+}
+
+
+
+/* This is needed for qsort(): */
+int comp_randomizer (const void* a, const void* b)
+{
+
+  int int1 = (*(const struct MC_MathQuestion **) a)->randomizer;
+  int int2 = (*(const struct MC_MathQuestion **) b)->randomizer;
+
+  if (int1 > int2)
+    return 1;
+  else if (int1 == int2)
+    return 0;
+  else
+    return -1;
+}
+
+MC_MathQuestion* pick_random(int length, MC_MathQuestion* list)
+{
+  int i;
+  int rand_node;
+
+  /* set random seed DSB */
+  srand(time(0));
+
+  /* if length is zero, get out to avoid divide-by-zero error */
+  if (0 == length)
+  {
+    return list;
+  }
+
+  rand_node = rand() % length;
+
+  for (i=1; i < rand_node; i++)
+  {
+    if (list)
+     list = list->next;
+  }
+
+  return list;
+}
+
+/* compares fields other than pointers */
+int compare_node(MC_MathQuestion* first, MC_MathQuestion* other)
+{
+  if (!first || !other)
+    return 0;
+  if (compare_card(&(first->card), &(first->card) ) ) //cards are equal
+    return 1;
+  else
+    return 0;
+}
+
+/* check to see if list already contains an identical node */
+int already_in_list(MC_MathQuestion* list, MC_MathQuestion* ptr)
+{
+  if (!list || !ptr)
+    return 0;
+
+  while (list)
+  {
+    if (compare_node(list, ptr))
+      return 1;
+    list = list->next;
+  }
+  return 0;
+}
+
+// /* to prevent option settings in math_opts from getting set to */
+// /* values other than 0 or 1                                    */
+// int int_to_bool(int i)
+// {
+//   if (i)
+//     return 1;
+//   else
+//     return 0;
+// }
+
+// /* prevent values from getting into math_opts that are outside */
+// /* the range that can be handled by the program (i.e. more     */
+// /* than three digits; also disallow negatives if that has been */
+// /* selected.                                                   */
+// int sane_value(int i)
+// {
+//   if (i > MC_GLOBAL_MAX)
+//     i = MC_GLOBAL_MAX;
+//   else if (i < -MC_GLOBAL_MAX)
+//     i = -MC_GLOBAL_MAX;
+// 
+//   if (i < 0
+//    && math_opts
+//    && !math_opts->iopts[ALLOW_NEGATIVES])
+//   {
+//     i = 0;
+//   }
+// 
+//   return i;
+// }
+
+// int abs_value(int i)
+// {
+//   if (i > 0)
+//     return i;
+//   else
+//     return -i;
+// }
+
+
+/* Compares two floats (needed for sorting in MC_MedianTimePerQuestion) */
+int floatCompare(const void *v1,const void *v2)
+{
+  float f1,f2;
+
+  f1 = *((float *) v1);
+  f2 = *((float *) v2);
+
+  if (f1 < f2)
+    return -1;
+  else if (f1 > f2)
+    return 1;
+  else
+    return 0;
+}
+
+
+
+/****************************************************
+Functions for new mathcards architecture
+****************************************************/
+
+void MC_CopyCard(const MC_FlashCard* src, MC_FlashCard* dest)
+{
+  if (!src || !dest)
+    return;
+  DEBUGMSG(debug_mathcards, "Copying '%s' to '%s', ", src->formula_string,dest->formula_string);
+  DEBUGMSG(debug_mathcards, "copying '%s' to '%s'\n", src->answer_string, dest->answer_string);
+  strncpy(dest->formula_string, src->formula_string, MC_FORMULA_LEN);
+  strncpy(dest->answer_string, src->answer_string, MC_ANSWER_LEN);
+  DEBUGMSG(debug_mathcards, "Card is: '%s', '%s'\n", dest->formula_string, dest->answer_string);
+  dest->answer = src->answer;
+  dest->difficulty = src->difficulty;
+  dest->question_id = src->question_id;
+}
+
+void free_node(MC_MathQuestion* mq) //no, not that freenode.
+{
+  if (!mq)
+    return;
+  MC_FreeFlashcard(&(mq->card) );
+  free(mq);
+}
+
+MC_MathQuestion* allocate_node()
+{
+  MC_MathQuestion* ret = NULL;
+  ret = malloc(sizeof(MC_MathQuestion) );
+  if (!ret)
+  {
+    printf("Could not allocate space for a new node!\n");
+    return NULL;
+  }
+
+  ret->card = MC_AllocateFlashcard();
+  ret->next = ret->previous = NULL;
+  
+  return ret;
+}
+
+/*
+The function that does the central dirty work pertaining to flashcard
+creation. Extensible to just about any kind of math problem, perhaps
+with the exception of those with multiple answers, such as "8 + 2 > ?"
+Simply specify how the problem is presented to the user, and the
+answer the game should look for, as strings.
+*/
+MC_FlashCard generate_random_flashcard(void)
+{
+  int num;
+  int length;
+  MC_ProblemType pt;
+  MC_FlashCard ret;
+  static int generate_random_flashcard_id=0;
+
+  generate_random_flashcard_id+=1;
+  DEBUGMSG(debug_mathcards, "Entering generate_random_flashcard()\n");
+  DEBUGMSG(debug_mathcards, "%d\n",generate_random_flashcard_id);
+  do
+    pt = rand() % MC_NUM_PTYPES;
+  while ( (pt == MC_PT_TYPING && !MC_GetOpt(TYPING_PRACTICE_ALLOWED) ) ||
+          (pt == MC_PT_ARITHMETIC && !MC_GetOpt(ADDITION_ALLOWED) &&
+                                   !MC_GetOpt(SUBTRACTION_ALLOWED) &&
+                                   !MC_GetOpt(MULTIPLICATION_ALLOWED) &&
+                                   !MC_GetOpt(DIVISION_ALLOWED) ) ||
+          (pt == MC_PT_COMPARISON && !MC_GetOpt(COMPARISON_ALLOWED) )
+        );
+
+  if (pt == MC_PT_TYPING) //typing practice
+  {
+    DEBUGMSG(debug_mathcards, "Generating typing question\n");
+    ret = MC_AllocateFlashcard();
+    num = rand() % (MC_GetOpt(MAX_TYPING_NUM)-MC_GetOpt(MIN_TYPING_NUM) + 1)
+                  + MC_GetOpt(MIN_TYPING_NUM);
+    snprintf(ret.formula_string, MC_FORMULA_LEN, "%d", num);
+    snprintf(ret.answer_string, MC_ANSWER_LEN, "%d", num);
+    ret.answer = num;
+    ret.difficulty = 10;
+    ret.question_id=generate_random_flashcard_id;
+  }
+  else //if (pt == MC_PT_ARITHMETIC)
+  {
+    DEBUGMSG(debug_mathcards, "Generating arithmetic question");
+    length = rand() % (MC_GetOpt(MAX_FORMULA_NUMS) -
+                       MC_GetOpt(MIN_FORMULA_NUMS) + 1) //avoid div by 0
+                    +  MC_GetOpt(MIN_FORMULA_NUMS);
+    DEBUGMSG(debug_mathcards, " of length %d", length);
+    ret = generate_random_ooo_card_of_length(length, 1);
+    
+    if (debug_status & debug_mathcards) {
+      print_card(ret);
+    }
+  }
+  //TODO comparison problems (e.g. "6 ? 9", "<")
+
+  DEBUGMSG(debug_mathcards, "Exiting generate_random_flashcard()\n");
+
+  return ret;
+}
+
+/*
+Recursively generate an order of operations problem. Hopefully this won't
+raise performance issues. Difficulty is calculated based on the length of
+the formula and on the operators used. Problems have a 'base' difficulty of
+1 for binary operations, 3 for 3 numbers, 6, 10, etc. Each operator adds to
+the score: 0, 1, 2, and 3 respectively for addition, subtraction,
+multiplication and division.If reformat is 0, FORMAT_ANS_LAST will be used,
+otherwise a format is chosen at random.
+*/
+
+/* FIXME we should consider rewriting this - it currently generates some
+questions with indeterminate answers (e.g. ? * 0 = 0) that seem to be 
+impossible to prevent using the current scheme with recursive string
+operations.
+*/
+
+MC_FlashCard generate_random_ooo_card_of_length(int length, int reformat)
+{
+  int format = 0;
+  int r1 = 0;
+  int r2 = 0;
+  int ans = 0;
+  char tempstr[MC_FORMULA_LEN];
+  MC_FlashCard ret;
+  MC_Operation op;
+
+  id += 1;
+  DEBUGMSG(debug_mathcards, ".");
+  if (length > MAX_FORMULA_NUMS)
+    return DEFAULT_CARD;
+  if (length <= 2)
+  {
+    DEBUGMSG(debug_mathcards, "\n");
+    ret = MC_AllocateFlashcard();
+    for (op = rand() % MC_NUM_OPERS; //pick a random operation
+         MC_GetOpt(op + ADDITION_ALLOWED) == 0; //make sure it's allowed
+         op = rand() % MC_NUM_OPERS);
+
+    DEBUGMSG(debug_mathcards, "Operation is %c\n", operchars[op]);
+    /*
+    if (op == MC_OPER_ADD)
+    {
+      r1 = rand() % (math_opts->iopts[MAX_AUGEND] - math_opts->iopts[MIN_AUGEND] + 1) + math_opts->iopts[MIN_AUGEND];
+      r2 = rand() % (math_opts->iopts[MAX_ADDEND] - math_opts->iopts[MIN_ADDEND] + 1) + math_opts->iopts[MIN_ADDEND];
+      ans = r1 + r2;
+    }
+    else if (op == MC_OPER_SUB)
+    {
+      r1 = rand() % (math_opts->iopts[MAX_MINUEND] - math_opts->iopts[MIN_MINUEND] + 1) + math_opts->iopts[MIN_MINUEND];
+      r2 = rand() % (math_opts->iopts[MAX_SUBTRAHEND] - math_opts->iopts[MIN_SUBTRAHEND] + 1) + math_opts->iopts[MIN_SUBTRAHEND];
+      ans = r1 - r2;
+    }
+    else if (op == MC_OPER_MULT)
+    {
+      r1 = rand() % (math_opts->iopts[MAX_MULTIPLIER] - math_opts->iopts[MIN_MULTIPLIER] + 1) + math_opts->iopts[MIN_MULTIPLIER];
+      r2 = rand() % (math_opts->iopts[MAX_MULTIPLICAND] - math_opts->iopts[MIN_MULTIPLICAND] + 1) + math_opts->iopts[MIN_MULTIPLICAND];
+      ans = r1 * r2;
+    }
+    else if (op == MC_OPER_DIV)
+    {
+      ans = rand() % (math_opts->iopts[MAX_QUOTIENT] - math_opts->iopts[MIN_QUOTIENT] + 1) + math_opts->iopts[MIN_QUOTIENT];
+      r2 = rand() % (math_opts->iopts[MAX_DIVISOR] - math_opts->iopts[MIN_DIVISOR] + 1) + math_opts->iopts[MIN_DIVISOR];
+      if (r2 == 0)
+        r2 = 1;
+      r1 = ans * r2;
+    }
+    */
+    if (op > MC_OPER_DIV || op < MC_OPER_ADD)
+    {
+      DEBUGMSG(debug_mathcards, "Invalid operator: value %d\n", op);
+      return DEFAULT_CARD;
+    }
+    //choose two numbers in the proper range and get their result
+    
+    else do
+    {
+      r1 = rand() % (math_opts->iopts[MAX_AUGEND+4*op] - math_opts->iopts[MIN_AUGEND+4*op] + 1) + math_opts->iopts[MIN_AUGEND+4*op];    
+      r2 = rand() % (math_opts->iopts[MAX_ADDEND+4*op] - math_opts->iopts[MIN_ADDEND+4*op] + 1) + math_opts->iopts[MIN_ADDEND+4*op]; 
+
+      if (op == MC_OPER_ADD)
+        ans = r1 + r2;
+      if (op == MC_OPER_SUB)
+        ans = r1 - r2;
+      if (op == MC_OPER_MULT)
+        ans = r1 * r2;
+      if (op == MC_OPER_DIV)  
+      {
+        if (r2 == 0)
+          r2 = 1;
+        ret.difficulty = r1;
+        r1 *= r2;
+        ans = ret.difficulty;
+      }
+    } while ( (ans < 0 && !MC_GetOpt(ALLOW_NEGATIVES)) || ans > MC_GetOpt(MAX_ANSWER) );
+
+
+    DEBUGMSG(debug_mathcards, "Constructing answer_string\n");
+    snprintf(ret.answer_string, MC_ANSWER_LEN, "%d", ans);
+    DEBUGMSG(debug_mathcards, "Constructing formula_string\n");
+    snprintf(ret.formula_string, MC_FORMULA_LEN, "%d %c %d",
+             r1, operchars[op], r2);
+    ret.answer = ans;
+    DEBUGMSG(debug_mathcards, "int answer is %d\n", ret.answer);
+    ret.difficulty = op + 1;
+
+  }
+  else //recurse
+  {
+    ret = generate_random_ooo_card_of_length(length - 1, 0);
+
+    if (strchr(ret.formula_string, '+') || strchr(ret.formula_string, '-') )
+    {
+      //if the expression has addition or subtraction, we can't assume that
+      //introducing multiplication or division will produce a predictable
+      //result, so we'll limit ourselves to more addition/subtraction
+      for (op = rand() % 2 ? MC_OPER_ADD : MC_OPER_SUB;
+           MC_GetOpt(op + ADDITION_ALLOWED) == 0;
+           op = rand() % 2 ? MC_OPER_ADD : MC_OPER_SUB);
+
+    }
+    else
+    {
+      //the existing expression can be treated as a number in itself, so we
+      //can do anything to it and be confident of the result.
+      for (op = rand() % MC_NUM_OPERS; //pick a random operation
+         MC_GetOpt(op + ADDITION_ALLOWED) == 0; //make sure it's allowed
+         op = rand() % MC_NUM_OPERS);
+    }
+    DEBUGMSG(debug_mathcards, "Next operation is %c,",  operchars[op]);
+
+    //pick the next operand
+    if (op == MC_OPER_ADD)
+    {
+      r1 = rand() % (math_opts->iopts[MAX_AUGEND] - math_opts->iopts[MIN_AUGEND] + 1) + math_opts->iopts[MIN_AUGEND];
+      ret.answer += r1;
+    }
+    else if (op == MC_OPER_SUB)
+    {
+      r1 = rand() % (math_opts->iopts[MAX_SUBTRAHEND] - math_opts->iopts[MIN_SUBTRAHEND] + 1) + math_opts->iopts[MIN_SUBTRAHEND];
+      ret.answer -= r1;
+    }
+    else if (op == MC_OPER_MULT)
+    {
+      r1 = rand() % (math_opts->iopts[MAX_MULTIPLICAND] - math_opts->iopts[MIN_MULTIPLICAND] + 1) + math_opts->iopts[MIN_AUGEND];
+      ret.answer *= r1;
+    }
+    else if (op == MC_OPER_DIV)
+    {
+      r1 = find_divisor(ret.answer);
+      ret.answer /= r1;
+    }
+    else
+    {
+      ; //invalid operator
+    }
+    DEBUGMSG(debug_mathcards, " operand is %d\n", r1);
+    DEBUGMSG(debug_mathcards, "Answer: %d\n", ret.answer);
+
+    //next append or prepend the new number (might need optimization)
+    if (op == MC_OPER_SUB || op == MC_OPER_DIV || //noncommutative, append only
+        rand() % 2)
+    {
+      snprintf(tempstr, MC_FORMULA_LEN, "%s %c %d", //append
+               ret.formula_string, operchars[op], r1);
+      strncpy(ret.formula_string, tempstr, MC_FORMULA_LEN);
+    }
+    else //we're prepending
+    {
+      snprintf(tempstr, MC_FORMULA_LEN, "%d %c %s", //append
+               r1, operchars[op], ret.formula_string);
+      strncpy(ret.formula_string, tempstr, MC_FORMULA_LEN);
+    }
+
+    //finally update the answer and score
+    snprintf(ret.answer_string, MC_ANSWER_LEN, "%d", ret.answer);
+    ret.difficulty += (length - 1) + op;
+  }
+  
+  if (reformat)
+  {
+    DEBUGMSG(debug_mathcards, "Reformatting...\n");
+    do {
+      format = rand() % MC_NUM_FORMATS;
+    } while (!MC_GetOpt(FORMAT_ANSWER_LAST + format) && 
+             !MC_GetOpt(FORMAT_ADD_ANSWER_LAST + op * 3 + format) );
+   
+    strncat(ret.formula_string, " = ?", MC_FORMULA_LEN - strlen(ret.formula_string) );
+    reformat_arithmetic(&ret, format );     
+  }
+  ret.question_id = id;
+
+  DEBUGMSG(debug_mathcards, "At end of generate_rand_ooo_card_of_length():\n");
+  print_card(ret);
+
+  return ret;
+}
+
+
+
+MC_MathQuestion* generate_list(void)
+{
+  int i, j;
+  int length = MC_GetOpt(AVG_LIST_LENGTH);
+  int cl; //raw length
+  double r1, r2, delta, var; //randomizers for list length
+  MC_MathQuestion* list = NULL;
+  MC_MathQuestion* end_of_list = NULL;
+  MC_MathQuestion* tnode = NULL;
+
+  if (debug_status & debug_mathcards)
+    MC_PrintMathOptions(stdout, 0);
+
+  if (!(MC_GetOpt(ARITHMETIC_ALLOWED) ||
+      MC_GetOpt(TYPING_PRACTICE_ALLOWED) ||
+      MC_GetOpt(COMPARISON_ALLOWED) ) )
+    return NULL;
+
+  //FIXME - remind me, why are we doing this??
+  //randomize list length by a "bell curve" centered on average
+  if (length && MC_GetOpt(VARY_LIST_LENGTH) )
+  {
+    r1 = (double)rand() / RAND_MAX / 2 + 0.5; //interval (0, 1)
+    r2 = (double)rand() / RAND_MAX / 2 + 0.5; //interval (0, 1)
+    DEBUGMSG(debug_mathcards, "Randoms chosen: %5f, %5f\n", r1, r2);
+    delta = sqrt(-2 * log(r1) ) * cos(2 * PI_VAL * r2); //standard normal dist.
+    var = length / 10.0; //variance
+    delta = delta * var;
+    DEBUGMSG(debug_mathcards, "Delta of average is %5f\n", delta);
+    length += delta;
+    if (length < 0)
+      length = 1; //just in case...
+  }
+
+  if (MC_GetOpt(COMPREHENSIVE)) //generate all
+  {
+    int num_valid_questions; //How many questions the COMPREHENSIVE list specifies
+    int cycles_needed;       //How many times we need to generate it to get enough
+
+    num_valid_questions = calc_num_valid_questions();
+    if(num_valid_questions == 0)
+    {
+      fprintf(stderr, "generate_list() - no valid questions\n");
+      return NULL;
+    }
+
+    cycles_needed = length/num_valid_questions;
+
+    if((cycles_needed * num_valid_questions) < length)
+      cycles_needed++;
+
+    DEBUGMSG(debug_mathcards, "In generate_list() - COMPREHENSIVE method requested\n");
+    DEBUGMSG(debug_mathcards, "num_valid_questions = %d\t cycles_needed = %d\n",
+              num_valid_questions, cycles_needed);
+
+    for (i = MC_PT_TYPING; i < MC_NUM_PTYPES; ++i)
+    {
+      if (!MC_GetOpt(i + TYPING_PRACTICE_ALLOWED))
+          continue;
+      for (j = 0; j < cycles_needed; j++)
+        list = add_all_valid(i, list, &end_of_list);
+    }
+
+
+    if (MC_GetOpt(RANDOMIZE) )
+    {
+      DEBUGMSG(debug_mathcards, "Randomizing list\n");
+      randomize_list(&list);
+    }
+
+    if (length)
+    {
+      cl = list_length(list);
+      // NOTE this should no longer happen - we run the COMPREHENSIVE
+      // generation until we have enough questions.
+      if (length > cl) //if not enough questions, pad out with randoms
+      {
+        DEBUGMSG(debug_mathcards, "Padding out list from %d to %d questions\n", cl, length);
+        for (i = cl; i < length; ++i)
+        {
+          tnode = malloc(sizeof(MC_MathQuestion) );
+          if(!tnode)
+          {
+            fprintf(stderr, "In generate_list() - allocation failed!\n");
+            delete_list(list);
+            return NULL;
+          }
+
+          tnode->card = generate_random_flashcard();
+          list = insert_node(list, end_of_list, tnode);
+          end_of_list = tnode;
+//          DEBUGMSG(debug_mathcards, "%d.", list_length(list) );
+        }
+      }
+      else if (length < cl) //if too many questions, chop off tail end of list
+      {
+        DEBUGMSG(debug_mathcards, "Cutting list to %d questions\n", length);
+        end_of_list = find_node(list, length);
+        delete_list(end_of_list->next);
+        end_of_list->next = NULL;
+      }
+    }
+  }
+
+  /* Here we are just generating random questions, one at a */
+  /* time until we have enough                              */
+  /* NOTE generate_random_flashcard() has some bugs, so only */
+  /* use this method if we need multiple operand questions   */
+  else 
+  {
+    DEBUGMSG(debug_mathcards, "In generate_list() - COMPREHENSIVE method NOT requested\n");
+
+    for (i = 0; i < length; ++i)
+    {
+      tnode = malloc(sizeof(MC_MathQuestion) );
+      if(!tnode)
+      {
+        fprintf(stderr, "In generate_list() - allocation failed!\n");
+        delete_list(list);
+        return NULL;
+      }
+
+      tnode->card = generate_random_flashcard();
+      list = insert_node(list, end_of_list, tnode);
+      end_of_list = tnode;
+    }
+  }
+  /* Now just put the question_id values in: */
+
+  {
+    int i = 1;
+    MC_MathQuestion* ptr = list;
+    while(ptr->next)
+    {
+      ptr->card.question_id = i;
+      ptr = ptr->next;
+      i++;
+    }
+  }
+
+  return list;
+}
+
+/* NOTE - returns 0 (i.e. "false") if *identical*, and */
+/* 1 (i.e. "true") if *different* - counterintuitive,  */
+/* but same behavior as e.g. strcmp()                  */
+
+static int compare_card(const MC_FlashCard* a, const MC_FlashCard* b)
+{
+  if (strncmp(a->formula_string, b->formula_string, MC_FORMULA_LEN) )
+    return 1;
+  if (strncmp(a->answer_string, b->answer_string, MC_ANSWER_LEN) )
+    return 1;
+  if (a->answer != b->answer);
+    return 1;
+
+  return 0; //the cards are identical
+}
+
+/* Public functions */
+
+/* allocate space for an MC_Flashcard */
+MC_FlashCard MC_AllocateFlashcard(void)
+{
+  MC_FlashCard ret;
+
+//NOTE strings now simply hard-coded to MC_FORMULA_LEN (= 40) and
+//MC_ANSWER_LEN (= 5) instead of tailoring them to save a few bytes - DSB
+//  DEBUGMSG(debug_mathcards, "Allocating %d + %d bytes for flashcard\n",
+//            max_formula_size + 1, max_answer_size + 1);
+//  ret.formula_string = malloc( (max_formula_size + 1) * sizeof(char));
+//  ret.answer_string = malloc( (max_answer_size + 1) * sizeof(char));
+//   if (!ret.formula_string || !ret.answer_string)
+//     {
+//     free(ret.formula_string);
+//     free(ret.answer_string);
+//     printf("Couldn't allocate space for a new flashcard!\n");
+//     ret = DEFAULT_CARD;
+//     }
+  return ret;
+}
+
+//Now a no-op - MC_FlashCard no longer has dynamically allocated strings
+void MC_FreeFlashcard(MC_FlashCard* fc)
+{
+  return;
+//   if (!fc)
+//     return;
+// //  DEBUGMSG(debug_mathcards, "Freeing formula_string\n");
+//   if (fc->formula_string)
+//   {
+//     free(fc->formula_string);
+//     fc->formula_string = NULL;
+//   }
+// //  DEBUGMSG(debug_mathcards, "Freeing answer_string\n");
+//   if (fc->answer_string)
+//   {
+//     free(fc->answer_string);
+//     fc->answer_string = NULL;
+//   }
+}
+
+unsigned int MC_MapTextToIndex(const char* text)
+{
+  int i;
+  for (i = 0; i < NOPTS; ++i)
+  {
+    if (!strcasecmp(text, MC_OPTION_TEXT[i]) )
+      return i;
+  }
+  DEBUGMSG(debug_mathcards, "'%s' isn't a math option\n", text);
+  return NOT_VALID_OPTION;
+}
+
+
+//TODO more intuitive function names for access by index vs. by text
+void MC_SetOpt(unsigned int index, int val)
+{
+  if (index >= NOPTS)
+  {
+    DEBUGMSG(debug_mathcards, "Invalid math option index: %d\n", index);
+    return;
+  }
+
+  /* Do some sanity checks before we throw val into the struct: */
+  switch(index)
+  {
+    /* All the booleans must be 0 or 1: */
+    case PLAY_THROUGH_LIST:
+    case REPEAT_WRONGS:
+    case ALLOW_NEGATIVES:
+    case FORMAT_ANSWER_LAST:
+    case FORMAT_ANSWER_FIRST:
+    case FORMAT_ANSWER_MIDDLE:
+    case FORMAT_ADD_ANSWER_LAST:
+    case FORMAT_ADD_ANSWER_FIRST:
+    case FORMAT_ADD_ANSWER_MIDDLE:
+    case FORMAT_SUB_ANSWER_LAST:
+    case FORMAT_SUB_ANSWER_FIRST:
+    case FORMAT_SUB_ANSWER_MIDDLE:
+    case FORMAT_MULT_ANSWER_LAST:
+    case FORMAT_MULT_ANSWER_FIRST:
+    case FORMAT_MULT_ANSWER_MIDDLE:
+    case FORMAT_DIV_ANSWER_LAST:
+    case FORMAT_DIV_ANSWER_FIRST:
+    case FORMAT_DIV_ANSWER_MIDDLE:
+    case ADDITION_ALLOWED:
+    case SUBTRACTION_ALLOWED:
+    case MULTIPLICATION_ALLOWED:
+    case DIVISION_ALLOWED:
+    case TYPING_PRACTICE_ALLOWED:
+    case ARITHMETIC_ALLOWED:
+    case COMPARISON_ALLOWED:
+    case RANDOMIZE:
+    case COMPREHENSIVE:
+    case VARY_LIST_LENGTH:
+    {
+      /* Reset all non-zero values to one: */
+      if(val)
+      {
+        if(val != 1)
+        {
+          fprintf(stderr, "Warning - parameter %s with invalid value %d, "
+                          "resetting to 1\n", MC_OPTION_TEXT[index], val);
+          val = 1;
+        }
+      }
+      break;
+    }
+
+    /* Parameters concerning numbers of questions */
+    /* must be greater than or equal to zero:     */
+    /* TODO some additional checks would make sense */
+    case QUESTION_COPIES:
+    case COPIES_REPEATED_WRONGS:
+    case MAX_QUESTIONS:
+    case MAX_FORMULA_NUMS:
+    case MIN_FORMULA_NUMS:
+    case AVG_LIST_LENGTH:
+    {
+      /* Reset all negative values to zero: */
+      if(val < 0)
+      {
+        fprintf(stderr, "Warning - parameter %s with invalid value %d, "
+                        "resetting to 0\n", MC_OPTION_TEXT[index], val);
+        val = 0;
+      }
+      break;
+    }
+
+    /* Operand values - make sure they are in displayable range */
+    /* i.e. -999 to 999                                         */ 
+    case MAX_ANSWER:
+    case MIN_AUGEND:
+    case MAX_AUGEND:
+    case MIN_ADDEND:
+    case MAX_ADDEND:
+    case MIN_MINUEND:
+    case MAX_MINUEND:
+    case MIN_SUBTRAHEND:
+    case MAX_SUBTRAHEND:
+    case MIN_MULTIPLIER:
+    case MAX_MULTIPLIER:
+    case MIN_MULTIPLICAND:
+    case MAX_MULTIPLICAND:
+    case MIN_DIVISOR:
+    case MAX_DIVISOR:
+    case MIN_QUOTIENT:
+    case MAX_QUOTIENT:
+    case MIN_TYPING_NUM:
+    case MAX_TYPING_NUM:
+    case MIN_COMPARATOR:
+    case MAX_COMPARATOR:
+    case MIN_COMPARISAND:
+    case MAX_COMPARISAND:
+    {
+      if(val > MC_GLOBAL_MAX)
+      {
+        fprintf(stderr, "Warning - parameter %s with invalid value %d, "
+                       "resetting to %d\n", MC_OPTION_TEXT[index],
+                       val, MC_GLOBAL_MAX);
+        val = MC_GLOBAL_MAX;
+      }
+
+      if(val < (0 - MC_GLOBAL_MAX))
+      {
+        fprintf(stderr, "Warning - parameter %s with invalid value %d, "
+                        "resetting to %d\n", MC_OPTION_TEXT[index],
+                       val, (0 - MC_GLOBAL_MAX));
+        val = (0 - MC_GLOBAL_MAX);
+      }
+
+      break;
+    }
+
+    default:
+        fprintf(stderr, "Warning - in MC_SetOpt() - unrecognized index %d\n",
+                index);
+  }
+  /* Should now be safe to put "sanitized" value into struct: */
+  math_opts->iopts[index] = val;
+}
+
+void MC_SetOp(const char* param, int val)
+{
+  MC_SetOpt(MC_MapTextToIndex(param), val);
+}
+
+int MC_GetOpt(unsigned int index)
+{
+  if (index >= NOPTS)
+  {
+    DEBUGMSG(debug_mathcards, "Invalid option index: %d\n", index);
+    return MC_MATH_OPTS_INVALID;
+  }
+  if (!math_opts)
+  {
+    printf("Invalid options list!\n");
+    return MC_MATH_OPTS_INVALID;
+  }
+  return math_opts->iopts[index];
+}
+
+int MC_GetOp(const char* param)
+{
+  return MC_GetOpt(MC_MapTextToIndex(param) );
+}
+
+int MC_VerifyOptionListSane(void)
+{
+  return strcmp(MC_OPTION_TEXT[NOPTS], "END_OF_OPTS") == 0;
+}
+
+int MC_MaxFormulaSize(void)
+{
+  return MC_FORMULA_LEN;
+}
+
+int MC_MaxAnswerSize(void)
+{
+  return MC_ANSWER_LEN;
+}
+
+void MC_ResetFlashCard(MC_FlashCard* fc)
+{
+  if (!fc || !fc->formula_string || !fc->answer_string)
+    return;
+  fc->formula_string[0] = '\0';
+  fc->answer_string[0] = '\0';
+  fc->answer = -9999;
+  fc->difficulty = 0;
+  fc->question_id = -1;
+}
+
+int MC_FlashCardGood(const MC_FlashCard* fc)
+{
+  return fc && fc->formula_string && fc->answer_string;
+}
+
+int find_divisor(int a)
+{
+  int div = 1; //the divisor to return
+  int realisticpasses = 3; //reasonable time after which a minimum should be met
+  int i;
+  do
+    for (i = 0; i < NPRIMES; ++i) //test each prime
+      if (a % smallprimes[i] == 0)  //if it is a prime factor,
+        if (rand() % (i + 1) == 0) //maybe we'll keep it
+          if (div * smallprimes[i] <= MC_GetOpt(MAX_DIVISOR) ) //if we can,
+            div *= smallprimes[i]; //update our real divisor
+  //keep going if the divisor is too small
+  while (div < MC_GetOpt(MIN_DIVISOR) && --realisticpasses); 
+  
+  return div;
+}
+
+
+//Computes (approximately) the number of questions that will be returned
+//by add_all_valid() as specified by the current options. This does not 
+//take into account screening out of invalid questions, such
+//as divide-by-zero and questions like "0 x ? = 0".
+static int calc_num_valid_questions(void)
+{
+  int total_questions = 0;
+  int k = 0;
+  //First add the number of typing questions
+  if (MC_GetOpt(TYPING_PRACTICE_ALLOWED))
+    total_questions += (MC_GetOpt(MAX_TYPING_NUM) - MC_GetOpt(MIN_TYPING_NUM));
+
+  //Now add how many questions we will have for each operation:
+  for (k = MC_OPER_ADD; k < MC_NUM_OPERS; ++k)
+  {
+    int num_this_oper = 0;
+    int formats_this_oper = 0;
+
+    if (!MC_GetOpt(k + ADDITION_ALLOWED) )
+      continue;
+
+    //calculate number of ordered pairs of first and second operands:
+    //note the "+ 1" is due to the ranges being inclusive
+    num_this_oper = (MC_GetOpt(MAX_AUGEND + 4 * k) - MC_GetOpt(MIN_AUGEND + 4 * k) + 1)
+                    *
+                    (MC_GetOpt(MAX_ADDEND + 4 * k) - MC_GetOpt(MIN_ADDEND + 4 * k) + 1);
+    //check what formats are allowed
+    if (MC_GetOpt(FORMAT_ANSWER_LAST) && MC_GetOpt(FORMAT_ADD_ANSWER_LAST + k * 3))
+      formats_this_oper++;
+    if (MC_GetOpt(FORMAT_ANSWER_FIRST) && MC_GetOpt(FORMAT_ADD_ANSWER_FIRST + k * 3))
+      formats_this_oper++;
+    if (MC_GetOpt(FORMAT_ANSWER_MIDDLE) && MC_GetOpt(FORMAT_ADD_ANSWER_MIDDLE + k * 3))
+      formats_this_oper++;
+    //Get total of e.g. addition questions:
+    num_this_oper *= formats_this_oper;
+    //add to overall total:
+    total_questions += num_this_oper;
+  }
+
+  //TODO will also need to count up the COMPARISON questions once
+  //they are implemented
+  {
+  }
+
+  DEBUGMSG(debug_mathcards, "calc_num_valid_questions():\t%d\n", total_questions);
+  return total_questions;
+}
+
+
+
+
+//NOTE end_of_list** needs to be doubly indirect because otherwise the end does not
+//get updated in the calling code
+//NOTE the difficulty is set as add = 1, sub = 2, mult = 3, div = 4, plus a 2 point
+//bonus if the format is a "missing number".
+MC_MathQuestion* add_all_valid(MC_ProblemType pt,
+                               MC_MathQuestion* list,
+                               MC_MathQuestion** end_of_list)
+{
+  int i, j;
+  int ans = 0, tmp;
+  MC_Operation k;
+  MC_MathQuestion* tnode;
+
+  DEBUGMSG(debug_mathcards, "Entering add_all_valid(%d)\n", pt);
+  DEBUGMSG(debug_mathcards, "List already has %d questions\n", list_length(list));
+
+  //make sure this problem type is actually allowed
+  if (!MC_GetOpt(pt + TYPING_PRACTICE_ALLOWED) )
+    return list;
+
+  //add all typing questions in range
+  if (pt == MC_PT_TYPING)
+  {
+    DEBUGMSG(debug_mathcards, "Adding typing...\n");
+    for (i = MC_GetOpt(MIN_TYPING_NUM); i <= MC_GetOpt(MAX_TYPING_NUM); ++i)
+    {
+      DEBUGMSG(debug_mathcards, "(%d)\n", i);
+      tnode = allocate_node();
+      if(!tnode)
+      {
+        fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
+        delete_list(list);
+        return NULL;
+      }
+
+      snprintf(tnode->card.formula_string, MC_FORMULA_LEN, "%d", i);
+      snprintf(tnode->card.answer_string, MC_ANSWER_LEN, "%d", i);
+      tnode->card.answer = i;
+      tnode->card.difficulty = 1;
+      list = insert_node(list, *end_of_list, tnode);
+      *end_of_list = tnode;
+    }
+  }
+
+  //add all allowed arithmetic questions
+  else if (MC_PT_ARITHMETIC)
+  {
+    DEBUGMSG(debug_mathcards, "Adding arithmetic...\n");
+
+    // The k loop iterates through the four arithmetic operations:
+    // k = 0 means addition
+    // k = 1 means subtraction
+    // k = 2 means multiplication
+    // k = 3 means division
+    for (k = MC_OPER_ADD; k < MC_NUM_OPERS; ++k)
+    {
+      if (!MC_GetOpt(k + ADDITION_ALLOWED) )
+        continue;
+      DEBUGMSG(debug_mathcards, "\n*%d*\n", k);
+
+      // The i loop iterates through the first value in the question:
+      for (i = MC_GetOpt(MIN_AUGEND + 4 * k); i <= MC_GetOpt(MAX_AUGEND + 4 * k); ++i)
+      {
+        DEBUGMSG(debug_mathcards, "\n%d:\n", i);
+
+        // The j loop iterates through the second value in the question:
+        for (j = MC_GetOpt(MIN_ADDEND + 4 * k); j <= MC_GetOpt(MAX_ADDEND + 4 * k); ++j)
+        {
+          // Generate the third number according to the operation.
+          // Although it is called "ans", it will not be the actual
+          // answer if it is a "missing number" type problem
+          // (e.g. "3 x ? = 12")
+          // We also filter out invalid questions here
+          switch (k)
+          {
+            case MC_OPER_ADD:
+            {
+              ans = i + j;
+              // throw anything over MAX_ANSWER
+              if (ans > MC_GetOpt(MAX_ANSWER))
+                continue;
+              break;
+            }
+            case MC_OPER_SUB:
+            {
+              ans = i - j;
+              // throw out negatives if they aren't allowed:
+              if (ans < 0 && !MC_GetOpt(ALLOW_NEGATIVES))
+                continue;
+              // throw anything over MAX_ANSWER
+              if (ans > MC_GetOpt(MAX_ANSWER))
+                continue;
+              break;
+            }
+            case MC_OPER_MULT:
+            {
+              ans = i * j;
+              // throw anything over MAX_ANSWER
+              if (ans > MC_GetOpt(MAX_ANSWER))
+                continue;
+              break;
+            }
+            case MC_OPER_DIV:
+            {
+               // throw anything over MAX_ANSWER
+              if (i * j > MC_GetOpt(MAX_ANSWER))
+                continue;
+
+              tmp = i;
+              i *= j;
+              ans = j;
+              j = tmp;
+              break;
+            }
+            default:
+              fprintf(stderr, "Unrecognized operation type: %d\n", k);
+              continue;
+          }
+
+          DEBUGMSG(debug_mathcards, "Generating: %d %c %d = %d\n", i, operchars[k], j, ans);
+
+          //add each format, provided it's allowed in general and for this op
+
+          // Questions like "a + b = ?"
+          if (MC_GetOpt(FORMAT_ANSWER_LAST) && MC_GetOpt(FORMAT_ADD_ANSWER_LAST + k * 3))
+          {
+            // Avoid division by zero:
+            if (k == MC_OPER_DIV && j == 0)
+            {
+              // need to restore i and j to original values so loop works:
+              j = ans;
+              i = tmp;
+              continue;
+            }
+
+            tnode = allocate_node();
+            if(!tnode)
+            {
+              fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
+              delete_list(list);
+              return NULL;
+            }
+
+            snprintf(tnode->card.answer_string, MC_ANSWER_LEN, "%d", ans);
+            snprintf(tnode->card.formula_string, MC_FORMULA_LEN,
+                     "%d %c %d = ?", i, operchars[k], j);
+            tnode->card.difficulty = k + 1;
+            tnode->card.answer = ans;
+            list = insert_node(list, *end_of_list, tnode);
+            *end_of_list = tnode;
+          }
+
+
+          // Questions like "? + b = c"
+          if (MC_GetOpt(FORMAT_ANSWER_FIRST) && MC_GetOpt(FORMAT_ADD_ANSWER_FIRST + k * 3) )
+          {
+            // Avoid questions with indeterminate answer:
+            // e.g. "? x 0 = 0"
+            if (k == MC_OPER_MULT && j == 0)
+            {
+              continue;
+            }
+            // Avoid division by zero:
+            if (k == MC_OPER_DIV && j == 0)
+            {
+              // need to restore i and j to original values so loop works:
+              j = ans;
+              i = tmp;
+              continue;
+            }
+
+            tnode = allocate_node();
+            if(!tnode)
+            {
+              fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
+              delete_list(list);
+              return NULL;
+            }
+
+            snprintf(tnode->card.answer_string, MC_ANSWER_LEN, "%d", i);
+            snprintf(tnode->card.formula_string, MC_FORMULA_LEN,
+                     "? %c %d = %d", operchars[k], j, ans);
+            tnode->card.answer = ans;
+            tnode->card.difficulty = k + 3;
+            list = insert_node(list, *end_of_list, tnode);
+            *end_of_list = tnode;
+          }
+
+
+          // Questions like "a + ? = c"
+          if (MC_GetOpt(FORMAT_ANSWER_MIDDLE) && MC_GetOpt(FORMAT_ADD_ANSWER_MIDDLE + k * 3))
+          {
+            // Avoid questions with indeterminate answer:
+            // e.g. "0 x ? = 0"
+            if (k == MC_OPER_MULT && i == 0)
+              continue;
+
+            // e.g. "0 / ? = 0"
+            if (k == MC_OPER_DIV && i == 0)
+            {
+              // need to restore i and j to original values so loop works:
+              j = ans;
+              i = tmp;
+              continue;
+            }
+
+            tnode = allocate_node();
+            if(!tnode)
+            {
+              fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
+              delete_list(list);
+              return NULL;
+            }
+
+            snprintf(tnode->card.answer_string, MC_ANSWER_LEN, "%d", j);
+            snprintf(tnode->card.formula_string, MC_FORMULA_LEN,
+                     "%d %c ? = %d", i, operchars[k], ans);
+            tnode->card.answer = ans;
+            tnode->card.difficulty = k + 3;
+            list = insert_node(list, *end_of_list, tnode);
+            *end_of_list = tnode;
+          }
+          //If we divided, reset i and j so loop works correctly
+          if (k == MC_OPER_DIV)
+          {
+            j = ans;
+            i = tmp;
+            DEBUGMSG(debug_mathcards, "resetting to %d %d\n", j, i);
+          }
+        }
+      }
+    }
+  }
+  //add all comparison questions (TODO implement them!)
+  else if (pt == MC_PT_COMPARISON)
+  {
+    for (i = MC_GetOpt(MIN_COMPARATOR); i < MC_GetOpt(MAX_COMPARATOR); ++i)
+    {
+      for (j = MC_GetOpt(MIN_COMPARISAND); j < MC_GetOpt(MAX_COMPARISAND); ++j)
+      {
+        tnode = allocate_node();
+        if(!tnode)
+        {
+          fprintf(stderr, "In add_all_valid() - allocate_node() failed!\n");
+          delete_list(list);
+          return NULL;
+        }
+
+        snprintf(tnode->card.formula_string, MC_FORMULA_LEN, "%d ? %d", i,j);
+        snprintf(tnode->card.answer_string, MC_ANSWER_LEN,
+                 i < j ? "<" : 
+                 i > j ? ">" : 
+                         "=");
+        tnode->card.difficulty = 1;
+        list = insert_node(list, *end_of_list, tnode);
+        *end_of_list = tnode;
+      }
+    }
+  }
+  DEBUGMSG(debug_mathcards, "Exiting add_all_valid()\n");  
+  DEBUGMSG(debug_mathcards, "List now has %d questions\n\n", list_length(list));
+
+  return list;
+}
+
+MC_MathQuestion* find_node(MC_MathQuestion* list, int num)
+{
+  while (--num > 0 && list)
+    list = list->next;
+  return list;
+}
+
+void reformat_arithmetic(MC_FlashCard* card, MC_Format f)
+{
+  int i, j;
+  char* beg = 0;
+  char* end = 0;
+  char nans[MC_ANSWER_LEN];
+  char nformula[MC_FORMULA_LEN + MC_ANSWER_LEN]; //gets a bit larger than usual in the meantime
+  
+  {
+    //snprintf(nans, max_answer_size, "%s", card->answer_string);
+   
+    //insert old answer where question mark was
+    for (i = 0, j = 0; card->formula_string[j] != '?'; ++i, ++j)
+      nformula[i] = card->formula_string[j];
+    i += snprintf(nformula + i, MC_ANSWER_LEN - 1, "%s", card->answer_string);
+    snprintf(nformula + i, MC_FORMULA_LEN - i, "%s", card->formula_string + j + 1);
+
+    //replace the new answer with a question mark
+    if (f == MC_FORMAT_ANS_LAST)
+      beg = strrchr(nformula, ' ') + 1;
+    if (f == MC_FORMAT_ANS_FIRST)
+      beg = nformula;
+    if (f == MC_FORMAT_ANS_MIDDLE)
+      beg = strchr(nformula, ' ') + 3;
+    end = strchr(beg + 1, ' ');
+    if (!end)
+      end = "";
+    //we now have beg = first digit of number to replace, end = the char after
+    sscanf(beg, "%s", nans);
+    *beg = 0; //sequester the first half of the string
+    snprintf(card->formula_string, MC_FORMULA_LEN, "%s?%s", nformula, end);
+    snprintf(card->answer_string, MC_ANSWER_LEN, "%s", nans);
+    card->answer = atoi(card->answer_string);
+  }
+}
+
+static int calc_score(int difficulty, float t)
+{
+  if (t < 0 || difficulty < 1)
+    return 0;
+  return (difficulty * SCORE_COEFFICIENT)/t;
+}
\ No newline at end of file

Deleted: branches/commonification/tuxmath/trunk/src/mathcards.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/mathcards.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/mathcards.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,296 +0,0 @@
-/*
-
-        mathcards.h
-
-        Description: contains headers for a flashcard-type math game.
-        This is a sort of interface-independent backend that could be used with a different
-        user interface. Developed as an enhancement to Bill Kendrick's "Tux of Math Command"
-        (aka tuxmath).  If tuxmath were a C++ program, this would be a C++ class.
-
-        Author: David Bruce <dbruce at tampabay.rr.com>, (C) 2006
-
-        Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
-
-*/
-#ifndef MATHCARDS_H
-#define MATHCARDS_H
-
-//#define MC_DEBUG
-//#ifdef MC_DEBUG
-#define mcdprintf(...) DEBUGMSG(debug_mathcards,__VA_ARGS__)
-//#else
-//#define mcdprintf(...) 0
-//#endif
-
-#define MC_USE_NEWARC
-
-/* different classes of problems TuxMath will ask */
-typedef enum _MC_ProblemType {
-  MC_PT_TYPING,
-  MC_PT_ARITHMETIC,
-  MC_PT_COMPARISON,
-  MC_NUM_PTYPES
-} MC_ProblemType;
-
-/* type of math operation used in an arithmetic question */
-typedef enum _MC_Operation {
-  MC_OPER_ADD,
-  MC_OPER_SUB,
-  MC_OPER_MULT,
-  MC_OPER_DIV,
-  MC_NUM_OPERS
-} MC_Operation;
-
-/* math question formats: */
-typedef enum _MC_Format {
-  MC_FORMAT_ANS_LAST,     /* a + b = ? */
-  MC_FORMAT_ANS_FIRST,    /* ? + b = c */
-  MC_FORMAT_ANS_MIDDLE,    /* a + ? = c */
-  MC_NUM_FORMATS
-} MC_Format;
-
-
-/*
-Indices for the various integer options. These are NOT the actual values!
-Actual values are accessed as such: options.iopts[PLAY_THROUGH_LIST] = val;
-Creating additional [integral] options is now centralized--it should only
-be necessary to add to this list, the list of text, and the list of
-defaults. (Besides actually using the new options!)
-*/
-enum {
-  NOT_VALID_OPTION = -1     ,
-  PLAY_THROUGH_LIST = 0     , /* play until all questions answered correctly */
-  QUESTION_COPIES           , /* # times each question is put in list */
-  REPEAT_WRONGS             , /* reuse incorrectly answered questions or not */
-  COPIES_REPEATED_WRONGS    , /* how many copies of an incorrectly answered question to re-insert*/
-  ALLOW_NEGATIVES           ,
-  MAX_ANSWER                ,
-  MAX_QUESTIONS             ,
-  MAX_FORMULA_NUMS          ,
-  MIN_FORMULA_NUMS          ,
-
-  //NOTE: Do _not_ rearrange the FORMAT values because the functions
-  //rely on index arithmetic to iterate through these, and will be
-  //broken if the relative position changes!
-  FORMAT_ANSWER_LAST        , /* question format is: a + b = ? */
-  FORMAT_ANSWER_FIRST       , /* question format is: ? + b = c */
-  FORMAT_ANSWER_MIDDLE      , /* question format is: a + ? = c */
-  FORMAT_ADD_ANSWER_LAST    , /* a + b = ?    */
-  FORMAT_ADD_ANSWER_FIRST   , /* ? + b = c    */
-  FORMAT_ADD_ANSWER_MIDDLE  , /* a + ? = c    */
-  FORMAT_SUB_ANSWER_LAST    , /* a - b = ?    */
-  FORMAT_SUB_ANSWER_FIRST   , /* ? - b = c    */
-  FORMAT_SUB_ANSWER_MIDDLE  , /* a - ? = c    */
-  FORMAT_MULT_ANSWER_LAST   , /* a * b = ?    */
-  FORMAT_MULT_ANSWER_FIRST  , /* ? * b = c    */
-  FORMAT_MULT_ANSWER_MIDDLE , /* a * ? = c    */
-  FORMAT_DIV_ANSWER_LAST    , /* a / b = ?    */
-  FORMAT_DIV_ANSWER_FIRST   , /* ? / b = c    */
-  FORMAT_DIV_ANSWER_MIDDLE  , /* a / ? = c    */
-
-  ADDITION_ALLOWED          ,
-  SUBTRACTION_ALLOWED       ,
-  MULTIPLICATION_ALLOWED    ,
-  DIVISION_ALLOWED          ,
-  TYPING_PRACTICE_ALLOWED   ,
-  ARITHMETIC_ALLOWED        ,
-  COMPARISON_ALLOWED        ,
-
-  MIN_AUGEND                , /* augend + addend = sum */
-  MAX_AUGEND                ,
-  MIN_ADDEND                ,
-  MAX_ADDEND                ,
-
-  MIN_MINUEND               , /* minuend - subtrahend = difference */
-  MAX_MINUEND               ,
-  MIN_SUBTRAHEND            ,
-  MAX_SUBTRAHEND            ,
-
-  MIN_MULTIPLIER            , /* multiplier * multiplicand = product */
-  MAX_MULTIPLIER            ,
-  MIN_MULTIPLICAND          ,
-  MAX_MULTIPLICAND          ,
-
-  MIN_DIVISOR               , /* dividend/divisor = quotient */
-  MAX_DIVISOR               , /* note - generate_list() will prevent */
-  MIN_QUOTIENT              , /* questions with division by zero.    */
-  MAX_QUOTIENT              ,
-
-  MIN_TYPING_NUM            , /* range for "typing tutor" mode, for  */
-  MAX_TYPING_NUM            , /* kids just learning to use keyboard. */
-
-  MIN_COMPARATOR            , /* left comparison operand */
-  MAX_COMPARATOR            ,
-  MIN_COMPARISAND           , /* right comparison operannd */
-  MAX_COMPARISAND           ,
-
-  RANDOMIZE                 , /* whether to shuffle cards */
-
-  COMPREHENSIVE             , /* whether to generate all questions 'in order' */
-  AVG_LIST_LENGTH           , /* the average number of questions in a list */
-  VARY_LIST_LENGTH          , /* whether to randomly adjust list length */
-
-  NOPTS
-};
-
-extern const char* const MC_OPTION_TEXT[];
-extern const int MC_DEFAULTS[];
-extern const char operchars[MC_NUM_OPERS];
-
-/* default values for math_options */
-#define MC_MAX_DIGITS 3 
-#define MC_GLOBAL_MAX 999          /* This is the largest absolute value that */
-                                   /* can be entered for math question values.*/
-#define MC_MATH_OPTS_INVALID -9999 /* Return value for accessor functions     */
-                                   /* if math_opts not valid                  */
-//#define DEFAULT_FRACTION_TO_KEEP 1
-
-
-typedef struct _MC_Options
-{
-  int iopts[NOPTS];
-} MC_Options;
-
-#ifndef MC_USE_NEWARC
-/* struct for individual "flashcard" */
-typedef struct MC_FlashCard {
-  int num1;
-  int num2;
-  int num3;
-  int operation;
-  int format;
-  char formula_string[MC_FORMULA_LEN];
-  char answer_string[MC_ANSWER_LEN];
-} MC_FlashCard;
-#else
-/* experimental struct for a more generalized flashcard */
-typedef struct _MC_FlashCard {
-  char* formula_string;
-  char* answer_string;
-  int answer;
-  int difficulty;
-} MC_FlashCard;
-#endif
-
-/* struct for node in math "flashcard" list */
-typedef struct MC_MathQuestion {
-  MC_FlashCard card;
-  struct MC_MathQuestion* next;
-  struct MC_MathQuestion* previous;
-  int randomizer;
-} MC_MathQuestion;
-
-
-/* "public" function prototypes: these functions are how */
-/* a user interface communicates with MathCards:         */
-/* TODO provide comments thoroughly explaining these functions */
-
-/*  MC_Initialize() sets up the struct containing all of  */
-/*  settings regarding math questions.  It should be      */
-/*  called before any other function.  Many of the other  */
-/*  functions will not work properly if MC_Initialize()   */
-/*  has not been called. It only needs to be called once, */
-/*  i.e when the program is starting, not at the beginning*/
-/*  of each math game for the player. Returns 1 if        */
-/*  successful, 0 otherwise.                              */
-int MC_Initialize(void);
-
-/*  MC_StartGame() generates the list of math questions   */
-/*  based on existing settings. It should be called at    */
-/*  the beginning of each math game for the player.       */
-/*  Returns 1 if resultant list contains 1 or more        */
-/*  questions, 0 if list empty or not generated           */
-/*  successfully.                                         */
-int MC_StartGame(void);
-
-/*  MC_StartGameUsingWrongs() is like MC_StartGame(),     */
-/*  but uses the incorrectly answered questions from the  */
-/*  previous game for the question list as a review form  */
-/*  of learning. If there were no wrong answers (or no    */
-/*  previous game), it behaves just like MC_StartGame().  */
-/*  FIXME wonder if it should generate a message if the   */
-/*  list is created from settings because there is no     */
-/*  valid wrong question list?                            */
-int MC_StartGameUsingWrongs(void);
-
-/*  MC_NextQuestion() takes a pointer to an allocated     */
-/*  MC_MathQuestion struct and fills in the fields for    */
-/*  use by the user interface program. It basically is    */
-/*  like taking the next flashcard from the pile.         */
-/*  Returns 1 if question found, 0 if list empty/invalid  */
-/*  or if argument pointer is invalid                     */
-int MC_NextQuestion(MC_FlashCard* q);
-
-/*  MC_AnsweredCorrectly() is how the user interface      */
-/*  tells MathCards that the question has been answered   */
-/*  correctly. Returns 1 if no errors.                    */
-int MC_AnsweredCorrectly(MC_FlashCard* q);
-
-/*  MC_NotAnsweredCorrectly() is how the user interface    */
-/*  tells MathCards that the question has not been        */
-/*  answered correctly. Returns 1 if no errors.           */
-int MC_NotAnsweredCorrectly(MC_FlashCard* q);
-
-/*  Like MC_NextQuestion(), but takes "flashcard" from    */
-/*  pile of incorrectly answered questions.               */
-/*  Returns 1 if question found, 0 if list empty/invalid  */
-int MC_NextWrongQuest(MC_FlashCard* q);
-
-/*  Returns 1 if all have been answered correctly,        */
-/* 0 otherwise.                                           */
-int MC_MissionAccomplished(void);
-
-/*  Returns number of questions left (either in list      */
-/*  or "in play")                                         */
-int MC_TotalQuestionsLeft(void);
-
-/*  Returns questions left in list, NOT                   */
-/*  including questions currently "in play".              */
-int MC_ListQuestionsLeft(void);
-
-/*  To keep track of how long students take to answer the */
-/*  questions, one can report the time needed to answer   */
-/*  an individual question:                               */
-int MC_AddTimeToList(float t);
-/*  Note that initialization of the list is handled by    */
-/*  MC_StartGame.                                         */
-
-/*  Tells MathCards to clean up - should be called when   */
-/*  user interface program exits.                         */
-void MC_EndGame(void);
-
-/*  Prints contents of math_opts struct in human-readable   */
-/*  form to given file. "verbose" tells the function to     */
-/*  write a lot of descriptive "help"-type info for each    */
-/*  option (intended to make config files self-documenting).*/
-void MC_PrintMathOptions(FILE* fp, int verbose);
-
-/* Additional functions used to generate game summary files: */
-int MC_PrintQuestionList(FILE* fp);
-int MC_PrintWrongList(FILE* fp);
-int MC_StartingListLength(void);
-int MC_WrongListLength(void);
-int MC_NumAnsweredCorrectly(void);
-int MC_NumNotAnsweredCorrectly(void);
-float MC_MedianTimePerQuestion(void);
-
-/********************************************
-Public functions for new mathcards architecture
-*********************************************/
-/* Return the array index of the given text, e.g. randomize->47 */
-unsigned int MC_MapTextToIndex(const char* text);
-void MC_SetOpt(unsigned int index, int val); //access directly,for internal use
-int MC_GetOpt(unsigned int index);
-void MC_SetOp(const char* param, int val); //access by text, for config reading
-int MC_GetOp(const char* param);
-int MC_VerifyOptionListSane(void);
-int MC_MaxFormulaSize(void); //amount of memory needed to safely hold strings
-int MC_MaxAnswerSize(void);
-MC_FlashCard MC_AllocateFlashcard();
-void MC_FreeFlashcard(MC_FlashCard* fc);
-void MC_ResetFlashCard(MC_FlashCard* fc); //empty flashcard of strings & values
-int MC_FlashCardGood(const MC_FlashCard* fc); //verifies a flashcard is valid
-/* Reorganize formula_string and answer_string to render the same equation
-   in a different format */
-void reformat_arithmetic(MC_FlashCard* card, MC_Format f);
-#endif

Copied: branches/commonification/tuxmath/trunk/src/mathcards.h (from rev 1657, tuxmath/trunk/src/mathcards.h)
===================================================================
--- branches/commonification/tuxmath/trunk/src/mathcards.h	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/mathcards.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,282 @@
+/*
+
+        mathcards.h
+
+        Description: contains headers for a flashcard-type math game.
+        This is a sort of interface-independent backend that could be used with a different
+        user interface. Developed as an enhancement to Bill Kendrick's "Tux of Math Command"
+        (aka tuxmath).  If tuxmath were a C++ program, this would be a C++ class.
+
+        Author: David Bruce <dbruce at tampabay.rr.com>, (C) 2006
+
+        Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
+
+*/
+
+
+#ifndef MATHCARDS_H
+#define MATHCARDS_H
+
+#include "transtruct.h"
+
+
+/* different classes of problems TuxMath will ask */
+typedef enum _MC_ProblemType {
+  MC_PT_TYPING,
+  MC_PT_ARITHMETIC,
+  MC_PT_COMPARISON,
+  MC_NUM_PTYPES
+} MC_ProblemType;
+
+/* type of math operation used in an arithmetic question */
+typedef enum _MC_Operation {
+  MC_OPER_ADD,
+  MC_OPER_SUB,
+  MC_OPER_MULT,
+  MC_OPER_DIV,
+  MC_NUM_OPERS
+} MC_Operation;
+
+/* math question formats: */
+typedef enum _MC_Format {
+  MC_FORMAT_ANS_LAST,     /* a + b = ? */
+  MC_FORMAT_ANS_FIRST,    /* ? + b = c */
+  MC_FORMAT_ANS_MIDDLE,    /* a + ? = c */
+  MC_NUM_FORMATS
+} MC_Format;
+
+
+/*
+Indices for the various integer options. These are NOT the actual values!
+Actual values are accessed as such: options.iopts[PLAY_THROUGH_LIST] = val;
+Creating additional [integral] options is now centralized--it should only
+be necessary to add to this list, the list of text, and the list of
+defaults. (Besides actually using the new options!)
+*/
+enum {
+  NOT_VALID_OPTION = -1     ,
+  PLAY_THROUGH_LIST = 0     , /* play until all questions answered correctly */
+  QUESTION_COPIES           , /* # times each question is put in list */
+  REPEAT_WRONGS             , /* reuse incorrectly answered questions or not */
+  COPIES_REPEATED_WRONGS    , /* how many copies of an incorrectly answered question to re-insert*/
+  ALLOW_NEGATIVES           ,
+  MAX_ANSWER                ,
+  MAX_QUESTIONS             ,
+  MAX_FORMULA_NUMS          ,
+  MIN_FORMULA_NUMS          ,
+
+  //NOTE: Do _not_ rearrange the FORMAT values because the functions
+  //rely on index arithmetic to iterate through these, and will be
+  //broken if the relative position changes!
+  FORMAT_ANSWER_LAST        , /* question format is: a + b = ? */
+  FORMAT_ANSWER_FIRST       , /* question format is: ? + b = c */
+  FORMAT_ANSWER_MIDDLE      , /* question format is: a + ? = c */
+  FORMAT_ADD_ANSWER_LAST    , /* a + b = ?    */
+  FORMAT_ADD_ANSWER_FIRST   , /* ? + b = c    */
+  FORMAT_ADD_ANSWER_MIDDLE  , /* a + ? = c    */
+  FORMAT_SUB_ANSWER_LAST    , /* a - b = ?    */
+  FORMAT_SUB_ANSWER_FIRST   , /* ? - b = c    */
+  FORMAT_SUB_ANSWER_MIDDLE  , /* a - ? = c    */
+  FORMAT_MULT_ANSWER_LAST   , /* a * b = ?    */
+  FORMAT_MULT_ANSWER_FIRST  , /* ? * b = c    */
+  FORMAT_MULT_ANSWER_MIDDLE , /* a * ? = c    */
+  FORMAT_DIV_ANSWER_LAST    , /* a / b = ?    */
+  FORMAT_DIV_ANSWER_FIRST   , /* ? / b = c    */
+  FORMAT_DIV_ANSWER_MIDDLE  , /* a / ? = c    */
+
+  ADDITION_ALLOWED          ,
+  SUBTRACTION_ALLOWED       ,
+  MULTIPLICATION_ALLOWED    ,
+  DIVISION_ALLOWED          ,
+  TYPING_PRACTICE_ALLOWED   ,
+  ARITHMETIC_ALLOWED        ,
+  COMPARISON_ALLOWED        ,
+
+  MIN_AUGEND                , /* augend + addend = sum */
+  MAX_AUGEND                ,
+  MIN_ADDEND                ,
+  MAX_ADDEND                ,
+
+  MIN_MINUEND               , /* minuend - subtrahend = difference */
+  MAX_MINUEND               ,
+  MIN_SUBTRAHEND            ,
+  MAX_SUBTRAHEND            ,
+
+  MIN_MULTIPLIER            , /* multiplier * multiplicand = product */
+  MAX_MULTIPLIER            ,
+  MIN_MULTIPLICAND          ,
+  MAX_MULTIPLICAND          ,
+
+  MIN_DIVISOR               , /* dividend/divisor = quotient */
+  MAX_DIVISOR               , /* note - generate_list() will prevent */
+  MIN_QUOTIENT              , /* questions with division by zero.    */
+  MAX_QUOTIENT              ,
+
+  MIN_TYPING_NUM            , /* range for "typing tutor" mode, for  */
+  MAX_TYPING_NUM            , /* kids just learning to use keyboard. */
+
+  MIN_COMPARATOR            , /* left comparison operand */
+  MAX_COMPARATOR            ,
+  MIN_COMPARISAND           , /* right comparison operannd */
+  MAX_COMPARISAND           ,
+
+  RANDOMIZE                 , /* whether to shuffle cards */
+
+  COMPREHENSIVE             , /* whether to generate all questions 'in order' */
+  AVG_LIST_LENGTH           , /* the average number of questions in a list */
+  VARY_LIST_LENGTH          , /* whether to randomly adjust list length */
+
+  NOPTS
+};
+
+extern const char* const MC_OPTION_TEXT[];
+extern const int MC_DEFAULTS[];
+extern const char operchars[MC_NUM_OPERS];
+
+/* default values for math_options */
+#define MC_MAX_DIGITS 3 
+#define MC_GLOBAL_MAX 999          /* This is the largest absolute value that */
+                                   /* can be entered for math question values.*/
+#define MC_MATH_OPTS_INVALID -9999 /* Return value for accessor functions     */
+                                   /* if math_opts not valid                  */
+//#define DEFAULT_FRACTION_TO_KEEP 1
+
+
+/* FIXME I think this array-based options system is *much* more error-prone */
+/* and confusing than the old struct with a named field for each option,    */
+/* albeit more compact. I think it would be worth the effort to change the  */
+/* code back to the old system - DSB                                        */
+typedef struct _MC_Options
+{
+  int iopts[NOPTS];
+} MC_Options;
+
+
+
+/* struct for node in math "flashcard" list */
+typedef struct MC_MathQuestion {
+  MC_FlashCard card;
+  struct MC_MathQuestion* next;
+  struct MC_MathQuestion* previous;
+  int randomizer;
+} MC_MathQuestion;
+
+
+/* "public" function prototypes: these functions are how */
+/* a user interface communicates with MathCards:         */
+/* TODO provide comments thoroughly explaining these functions */
+
+/*  MC_Initialize() sets up the struct containing all of  */
+/*  settings regarding math questions.  It should be      */
+/*  called before any other function.  Many of the other  */
+/*  functions will not work properly if MC_Initialize()   */
+/*  has not been called. It only needs to be called once, */
+/*  i.e when the program is starting, not at the beginning*/
+/*  of each math game for the player. Returns 1 if        */
+/*  successful, 0 otherwise.                              */
+int MC_Initialize(void);
+
+/*  MC_StartGame() generates the list of math questions   */
+/*  based on existing settings. It should be called at    */
+/*  the beginning of each math game for the player.       */
+/*  Returns 1 if resultant list contains 1 or more        */
+/*  questions, 0 if list empty or not generated           */
+/*  successfully.                                         */
+int MC_StartGame(void);
+
+/*  MC_StartGameUsingWrongs() is like MC_StartGame(),     */
+/*  but uses the incorrectly answered questions from the  */
+/*  previous game for the question list as a review form  */
+/*  of learning. If there were no wrong answers (or no    */
+/*  previous game), it behaves just like MC_StartGame().  */
+/*  FIXME wonder if it should generate a message if the   */
+/*  list is created from settings because there is no     */
+/*  valid wrong question list?                            */
+int MC_StartGameUsingWrongs(void);
+
+/*  MC_NextQuestion() takes a pointer to an allocated     */
+/*  MC_MathQuestion struct and fills in the fields for    */
+/*  use by the user interface program. It basically is    */
+/*  like taking the next flashcard from the pile.         */
+/*  Returns 1 if question found, 0 if list empty/invalid  */
+/*  or if argument pointer is invalid                     */
+int MC_NextQuestion(MC_FlashCard* q);
+
+/*  MC_AnsweredCorrectly() is how the user interface      */
+/*  tells MathCards that the question has been answered   */
+/*  correctly, and how long the student took to answer.   */
+/*  Returns 1 if no errors.                               */
+int MC_AnsweredCorrectly(int id, float t);
+//int MC_AnsweredCorrectly_id(int id);
+
+/*  MC_NotAnsweredCorrectly() is how the user interface    */
+/*  tells MathCards that the question has not been        */
+/*  answered correctly. Returns 1 if no errors.           */
+int MC_NotAnsweredCorrectly(int id);
+
+/*  Like MC_NextQuestion(), but takes "flashcard" from    */
+/*  pile of incorrectly answered questions.               */
+/*  Returns 1 if question found, 0 if list empty/invalid  */
+int MC_NextWrongQuest(MC_FlashCard* q);
+
+/*  Returns 1 if all have been answered correctly,        */
+/*  0 otherwise.                                          */
+int MC_MissionAccomplished(void);
+
+/*  Returns number of questions left (either in list      */
+/*  or "in play")                                         */
+int MC_TotalQuestionsLeft(void);
+
+/*  Returns questions left in list, NOT                   */
+/*  including questions currently "in play".              */
+int MC_ListQuestionsLeft(void);
+
+/*  To keep track of how long students take to answer the */
+/*  questions, one can report the time needed to answer   */
+/*  an individual question:                               */
+int MC_AddTimeToList(float t);
+/*  Note that initialization of the list is handled by    */
+/*  MC_StartGame.                                         */
+
+/*  Tells MathCards to clean up - should be called when   */
+/*  user interface program exits.                         */
+void MC_EndGame(void);
+
+/*  Prints contents of math_opts struct in human-readable   */
+/*  form to given file. "verbose" tells the function to     */
+/*  write a lot of descriptive "help"-type info for each    */
+/*  option (intended to make config files self-documenting).*/
+void MC_PrintMathOptions(FILE* fp, int verbose);
+
+/* Additional functions used to generate game summary files: */
+int MC_PrintQuestionList(FILE* fp);
+int MC_PrintWrongList(FILE* fp);
+int MC_StartingListLength(void);
+int MC_WrongListLength(void);
+int MC_NumAnsweredCorrectly(void);
+int MC_NumNotAnsweredCorrectly(void);
+float MC_MedianTimePerQuestion(void);
+void print_card(MC_FlashCard card);
+
+/********************************************
+Public functions for new mathcards architecture
+*********************************************/
+/* Return the array index of the given text, e.g. randomize->47 */
+unsigned int MC_MapTextToIndex(const char* text);
+void MC_SetOpt(unsigned int index, int val); //access directly,for internal use
+int MC_GetOpt(unsigned int index);
+void MC_SetOp(const char* param, int val); //access by text, for config reading
+int MC_GetOp(const char* param);
+int MC_VerifyOptionListSane(void);
+int MC_MaxFormulaSize(void); //amount of memory needed to safely hold strings
+int MC_MaxAnswerSize(void);
+MC_FlashCard MC_AllocateFlashcard();
+void MC_CopyCard(const MC_FlashCard* src, MC_FlashCard* dest);
+void MC_FreeFlashcard(MC_FlashCard* fc);
+void MC_ResetFlashCard(MC_FlashCard* fc); //empty flashcard of strings & values
+int MC_FlashCardGood(const MC_FlashCard* fc); //verifies a flashcard is valid
+/* Reorganize formula_string and answer_string to render the same equation
+   in a different format */
+void reformat_arithmetic(MC_FlashCard* card, MC_Format f);
+
+#endif

Modified: branches/commonification/tuxmath/trunk/src/menu.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/menu.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/menu.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -22,6 +22,11 @@
 #include "SDL_extras.h"
 #include "titlescreen.h"
 
+#ifdef HAVE_LIBSDL_NET
+#include "network.h"
+#include "server.h"
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -132,6 +137,16 @@
 MenuNode*       load_menu_from_file(FILE* xml_file, MenuNode* parent);
 void            free_menu(MenuNode* menu);
 
+int             handle_activity(int act, int param);
+int             run_academy(void);
+int             run_arcade(int choice);
+int             run_custom_game(void);
+void            run_multiplayer(int mode, int difficulty);
+int             run_factoroids(int choice);
+int             run_lan_join(void);
+int             run_lan_host(void);
+
+int             run_menu(MenuNode* menu, bool return_choice);
 SDL_Surface**   render_buttons(MenuNode* menu, bool selected);
 char*           find_longest_text(MenuNode* menu, int* length);
 int             find_longest_menu_page(MenuNode* menu);
@@ -352,12 +367,101 @@
 
   if(menus[index])
   {
-    free_menu(menus[index]);
-    menus[index] = NULL;
+    case RUN_CAMPAIGN:
+      start_campaign();
+      break;
+
+    case RUN_ACADEMY:
+      if(run_academy() == QUIT)
+        return QUIT;
+      break;
+
+    case RUN_ARCADE:
+      run_arcade(param);
+      break;
+
+    case RUN_LAN_HOST:
+      run_lan_host();
+      break;
+
+    case RUN_LAN_JOIN:
+      run_lan_join();
+      break;
+
+    case RUN_CUSTOM:
+      run_custom_game();
+      break;
+
+    case RUN_HALL_OF_FAME:
+      DisplayHighScores(CADET_HIGH_SCORE);
+      break;
+
+    case RUN_SCORE_SWEEP:
+      run_multiplayer(0, param);
+      break;
+
+    case RUN_ELIMINATION:
+      run_multiplayer(1, param);
+      break;
+
+    case RUN_HELP:
+      Opts_SetHelpMode(1);
+      Opts_SetDemoMode(0);
+      if (Opts_GetGlobalOpt(MENU_MUSIC))  //Turn menu music off for game
+        {audioMusicUnload();}
+      game();
+      if (Opts_GetGlobalOpt(MENU_MUSIC)) //Turn menu music back on
+        audioMusicLoad( "tuxi.ogg", -1 );
+      Opts_SetHelpMode(0);
+      break;
+
+    case RUN_FACTORS:
+      run_factoroids(0);
+      break;
+
+    case RUN_FRACTIONS:
+      run_factoroids(1);
+      break;
+
+    case RUN_DEMO:
+      if(read_named_config_file("demo"))
+      {
+        audioMusicUnload();
+        game();
+        if (Opts_GetGlobalOpt(MENU_MUSIC))
+          audioMusicLoad( "tuxi.ogg", -1 );
+      }
+      else
+        fprintf(stderr, "\nCould not find demo config file\n");
+      break;
+
+    case RUN_INFO:
+      ShowMessage(DEFAULT_MENU_FONT_SIZE,
+                  _("TuxMath is free and open-source!"),
+                  _("You can help make it better."),
+                  _("Suggestions, artwork, and code are all welcome!"),
+                  _("Discuss TuxMath at tuxmath-devel at lists.sourceforge.net"));
+      break;
+
+    case RUN_CREDITS:
+      credits();
+      break;
+
+    case RUN_QUIT:
+      return QUIT;
   }
 
-  menu_file = fopen(file_name, "r");
-  if(menu_file == NULL)
+  DEBUGMSG(debug_menu, "Leaving handle_activity\n");
+
+  return 0;
+}
+
+int run_academy(void)
+{
+  int chosen_lesson = -1;
+
+  chosen_lesson = run_menu(menus[MENU_LESSONS], true);
+  while (chosen_lesson >= 0)
   {
     DEBUGMSG(debug_menu, "LoadMenu(): Could not load %s !\n", file_name);
   }
@@ -371,7 +475,12 @@
 /* free all loaded menu trees */
 void UnloadMenus(void)
 {
-  int i;
+  const char *s1, *s2, *s3, *s4;
+  s1 = _("Edit 'options' file in your home directory");
+  s2 = _("to create customized game!");
+  s3 = _("Press a key or click your mouse to start game.");
+  s4 = _("See README.txt for more information");
+  ShowMessage(DEFAULT_MENU_FONT_SIZE, s1, s2, s3, s4);
 
   DEBUGMSG(debug_menu, "entering UnloadMenus()\n");
 
@@ -387,11 +496,46 @@
     prev_arrow = NULL;
   }
 
-  if(next_arrow)
-  {
-    SDL_FreeSurface(next_arrow);
-    next_arrow = NULL;
+  mp_set_parameter(PLAYERS, nplayers);
+  mp_set_parameter(MODE, mode);
+  mp_set_parameter(DIFFICULTY, difficulty);
+  mp_run_multiplayer();
+}
+
+int run_factoroids(int choice)
+{
+  const int factoroids_high_score_tables[2] =
+    {FACTORS_HIGH_SCORE, FRACTIONS_HIGH_SCORE};
+  int hs_table;
+
+  audioMusicUnload();
+  if(choice == 0)
+    factors();
+  else
+    fractions();
+
+  if (Opts_GetGlobalOpt(MENU_MUSIC))
+    audioMusicLoad( "tuxi.ogg", -1 );
+
+  hs_table = factoroids_high_score_tables[choice];
+  if (check_score_place(hs_table, Opts_LastScore()) < HIGH_SCORES_SAVED){
+    char player_name[HIGH_SCORE_NAME_LENGTH * 3];
+    /* Get name from player: */
+    HighScoreNameEntry(&player_name[0]);
+    insert_score(player_name, hs_table, Opts_LastScore());
+    /* Show the high scores. Note the user will see his/her */
+    /* achievement even if (in the meantime) another player */
+    /* has in fact already bumped this score off the table. */
+    DisplayHighScores(hs_table);
+    /* save to disk: */
+    /* See "On File Locking" in fileops.c */
+    append_high_score(hs_table,Opts_LastScore(),&player_name[0]);
+    DEBUGCODE(debug_titlescreen)
+    print_high_scores(stderr);
   }
+  else {
+    fprintf(stderr, "\nCould not find config file\n");
+  }
 
   for(i = 0; i < N_OF_MENUS; i++)
     if(menus[i] != NULL)
@@ -404,8 +548,136 @@
 }
 
 
-/*
-   RunMenu - main function to display the menu and run the event loop
+/* If pthreads available, we launch server in own thread.  Otherwise, we use  */
+/* the C system() call to launch the server as a standalone program.          */
+int run_lan_host(void)
+{
+#ifdef HAVE_LIBSDL_NET
+  char buf[256];
+  char server_name[150];
+  char* argv[3];
+  int chosen_lesson = -1;
+
+  /* For now, only allow one server instance: */
+  if(ServerRunning())
+  {
+    ShowMessage(DEFAULT_MENU_FONT_SIZE, _("The server is already running"),
+                NULL, NULL, NULL);
+    return 0;
+  }
+
+  NameEntry(server_name, _("Enter Server Name:"), _("(limit 50 characters)"));
+  argv[0] = "tuxmathserver";
+  argv[1] = "--name";
+  snprintf(buf, 256, "\"%s\"", server_name);
+  argv[2] = buf;
+
+
+  /* If we have POSIX threads available (Linux), we launch server in a thread within  */
+  /* our same process. The server will use the currently selected Mathcards settings, */
+  /* so we can let the user select the lesson for the server to use.                  */
+
+#ifdef HAVE_PTHREAD_H
+
+  ShowMessage(DEFAULT_MENU_FONT_SIZE, 
+              _("Click or press key to select server lesson file"),
+              NULL, NULL, NULL);
+
+  {
+    chosen_lesson = run_menu(menus[MENU_LESSONS], true);
+
+    while (chosen_lesson >= 0)
+    {
+      if (Opts_GetGlobalOpt(MENU_SOUND))
+        playsound(SND_POP);
+
+      /* Re-read global settings first in case any settings were */
+      /* clobbered by other lesson or arcade games this session: */
+      read_global_config_file();
+      /* Now read the selected file and play the "mission": */
+      if (read_named_config_file(lesson_list_filenames[chosen_lesson]))
+        break;
+      else    
+      {  // Something went wrong - could not read lesson config file:
+        fprintf(stderr, "\nCould not find file: %s\n", lesson_list_filenames[chosen_lesson]);
+        chosen_lesson = -1;
+      }
+      // Let the user choose another lesson; start with the screen and
+      // selection that we ended with
+      chosen_lesson = run_menu(menus[MENU_LESSONS], true);
+    }
+  }
+
+  ShowMessage(DEFAULT_MENU_FONT_SIZE,
+              _("Server Name:"),
+              server_name,
+              _("Selected Lesson:"),
+              lesson_list_titles[chosen_lesson]);
+
+  RunServer_pthread(3, argv);
+
+
+  /* Without pthreads, we just launch standalone server, which for now only     */
+  /* supports the hardcoded default settings.                                   */
+#else
+  RunServer_prog(3, argv);
+#endif
+
+#endif
+  return 0;
+}
+
+
+
+int run_lan_join(void)
+{
+#ifdef HAVE_LIBSDL_NET
+  if(detecting_servers(_("Detecting servers"), _("Please wait")))
+  {
+    int stdby;
+    char buf[256];
+    char player_name[HIGH_SCORE_NAME_LENGTH * 3];
+
+    snprintf(buf, 256, _("Connected to server: %s"), LAN_ConnectedServerName());
+    NameEntry(player_name, buf, _("Enter your name:"));
+    LAN_SetName(player_name);
+    Ready(_("Click when ready"));
+    LAN_StartGame();
+    stdby = Standby(_("Waiting for other players"), NULL);
+    if (stdby == 1)
+    {
+      audioMusicUnload();
+      Opts_SetLanMode(1);  // Tells game() we are playing over network
+      game();
+      Opts_SetLanMode(0);  // Go back to local play
+      if (Opts_GetGlobalOpt(MENU_MUSIC))
+          audioMusicLoad( "tuxi.ogg", -1 );
+    }
+    else
+    {
+      ShowMessage(DEFAULT_MENU_FONT_SIZE,
+                  NULL, _("Sorry, game already in progress."), NULL, NULL);
+      printf(_("Sorry, game already in progress.\n"));
+    }  
+  }
+  else
+  {
+    ShowMessage(DEFAULT_MENU_FONT_SIZE, 
+                NULL, _("Sorry, no server could be found."), NULL, NULL);
+    printf(_("Sorry, no server could be found.\n"));
+  }
+#else
+  ShowMessage(DEFAULT_MENU_FONT_SIZE, 
+              NULL, _("Sorry, this version built without network support"), NULL, NULL);
+  printf( _("Sorry, this version built without network support.\n"));
+#endif
+
+  DEBUGMSG(debug_menu, "Leaving run_lan_join()\n"); 
+  return 0;
+}
+
+
+/* Display the menu and run the event loop.
    if return_choice = true then return chosen value instead of
    running handle_activity()
    this function is a modified copy of choose_menu_item()
@@ -845,11 +1117,17 @@
         tmp_sprite = menu->submenu[menu->first_entry + loc]->icon;
         if(tmp_sprite)
         {
-          SDL_BlitSurface(menu_item_selected[loc], NULL, GetScreen(), &menu->submenu[menu->first_entry + loc]->icon_rect);
-          SDL_BlitSurface(tmp_sprite->frame[tmp_sprite->cur], NULL, GetScreen(), &menu->submenu[menu->first_entry + loc]->icon_rect);
-          UpdateRect(GetScreen(), &menu->submenu[menu->first_entry + loc]->icon_rect);
+          DEBUGMSG(debug_menu, "run_menu(): incrementing sprite for entry %d\n", loc);
+
+          SDL_BlitSurface(menu_item_selected[loc], NULL, screen,
+                          &menu->submenu[menu->first_entry + loc]->icon_rect);
+          SDL_BlitSurface(tmp_sprite->frame[tmp_sprite->cur], NULL, screen,
+                          &menu->submenu[menu->first_entry + loc]->icon_rect);
+          UpdateRect(screen, &menu->submenu[menu->first_entry + loc]->icon_rect);
           NextFrame(tmp_sprite);
         }
+        else
+          DEBUGMSG(debug_menu, "run_menu(): entry %d has no valid sprite\n", loc);
       }
 
       /* handle titlescreen animations */
@@ -914,6 +1192,11 @@
     SDL_FreeSurface(tmp_surf);
 
     /* text */
+    DEBUGMSG(debug_menu, "render_buttons(): English string is: %s\n",
+             menu->submenu[menu->first_entry + i]->title);
+    DEBUGMSG(debug_menu, "render_buttons(): NLS string is: %s\n",
+             _(menu->submenu[menu->first_entry + i]->title));
+
     tmp_surf = BlackOutline(_(menu->submenu[menu->first_entry + i]->title),
                             curr_font_size, selected ? &yellow : &white);
     SDL_BlitSurface(tmp_surf, NULL, menu_items[i], &menu->submenu[menu->first_entry + i]->text_rect);

Modified: branches/commonification/tuxmath/trunk/src/menu.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/menu.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/menu.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -15,9 +15,15 @@
 #ifndef MENU_H
 #define MENU_H
 
-#include "tuxmath.h"
+#include "globals.h"
+#include "loaders.h"
 
 #ifndef HAVE_LIBT4KCOMMON
+#include "SDL.h"
+/* titlescreen & menu frame rate */
+#define MAX_FPS                    30
+/* number of "real" frames per one sprite frame */
+#define SPRITE_FRAME_DELAY         6
 
 #define MAX_FPS 30
 /* special values used by RunMenu. RUN_MAIN_MENU is a special

Modified: branches/commonification/tuxmath/trunk/src/network.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/network.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/network.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,136 +1,503 @@
+/*
+*  C Implementation: network.c
+*
+*       Description: Contains all the network realted functions , for LAN-based play in Tux,of Math Command.
+*
+*
+* Author: Akash Gangil, David Bruce, and the TuxMath team, (C) 2009
+* Developers list: <tuxmath-devel at lists.sourceforge.net>
+*
+* Copyright: See COPYING file that comes with this distribution.  (Briefly, GNU GPL).
+*/
 
-//** this file would contain all the network related functions**
-
-
-
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
 #include <unistd.h>
-#include "SDL.h"
-#include "SDL_net.h"
+#include <fcntl.h> 
 
-//*** ipaddress of the server and the port would be taken by the user @ the time he selects "LAN multiplayer" from the options menu..
+#include "globals.h"
+#include "mathcards.h"
+#include "transtruct.h"
+#include "network.h"
+#include "throttle.h"
+//#include "testclient.h"
 
-//***also should I fix the port beforehand or ask it from the user...
 
-int lan_client_connect(char *host,int port)            //here "host" is either the hostname or the ipaddress(of the server) in string
+TCPsocket sd;           /* Server socket descriptor */
+SDLNet_SocketSet set;
+IPaddress serv_ip;
+ServerEntry servers[MAX_SERVERS];
+static int connected_server = -1;
+
+/* Local function prototypes: */
+int say_to_server(char *statement);
+int evaluate(char *statement);
+int add_to_server_list(UDPpacket* pkt);
+
+
+int LAN_DetectServers(void)
 {
-IPaddress ip;
-TCPsocket sock;
-Uint16 portnum;
+  UDPsocket udpsock = NULL;  
+  UDPpacket* out;
+  UDPpacket* in;
+  IPaddress bcast_ip;
+  int sent = 0;
+  int done = 0;
+  int seconds = 0;
+  int num_servers = 0;
+  int i = 0;
+  Uint32 timer = 0;
+  //zero out old server list
+  for(i = 0; i < MAX_SERVERS; i++)
+    servers[i].ip.host = 0;
 
-portnum=(Uint16) strtol(port,NULL,0);
+  /* Docs say we are supposed to call SDL_Init() before SDLNet_Init(): */
+  if(SDL_Init(0) == -1)
+  {
+    printf("SDL_Init: %s\n", SDL_GetError());
+    return 0;;
+  }
 
-// initialize SDL
-if(SDL_Init(0)==-1)
+  /* Initialize SDL_net */
+  if (SDLNet_Init() < 0)
+  {
+    fprintf(stderr, "SDLNet_Init: %s\n", SDLNet_GetError());
+    exit(EXIT_FAILURE);
+  }
+
+  //NOTE we can't open a UDP socket on the same port if both client
+  //and server are running on the same machine, so for now we let
+  //it be auto-assigned:
+  udpsock = SDLNet_UDP_Open(0);
+  if(!udpsock)
+  {
+    printf("SDLNet_UDP_Open: %s\n", SDLNet_GetError());
+    return 0;
+  }
+  
+  out = SDLNet_AllocPacket(NET_BUF_LEN);
+  in = SDLNet_AllocPacket(NET_BUF_LEN);
+
+  SDLNet_ResolveHost(&bcast_ip, "255.255.255.255", DEFAULT_PORT);
+  out->address.host = bcast_ip.host;
+  sprintf(out->data, "TUXMATH_CLIENT");
+  out->address.port = bcast_ip.port;
+  out->len = strlen("TUXMATH_CLIENT") + 1;
+
+  //Here we will need to send every few seconds until we hear back from server
+  //and get its ip address:  IPaddress bcast_ip;
+  printf("\nAutodetecting TuxMath servers:");
+  fflush(stdout);
+  while(!done)
+  {
+    printf(".");
+    fflush(stdout);
+
+    sent = SDLNet_UDP_Send(udpsock, -1, out);
+    if(!sent)
+    {
+      printf("broadcast failed - network inaccessible.\nTrying localhost (for testing)\n");
+      SDLNet_ResolveHost(&bcast_ip, "localhost", DEFAULT_PORT);
+      out->address.host = bcast_ip.host;
+    }
+    SDL_Delay(250);  //give server chance to answer
+
+    while(SDLNet_UDP_Recv(udpsock, in))
+    {
+      if(strncmp((char*)in->data, "TUXMATH_SERVER", strlen("TUXMATH_SERVER")) == 0)
+      {
+        done = 1;
+        //add to list, checking for duplicates
+        num_servers = add_to_server_list(in);
+      }
+    }
+    //Make sure we always scan at least one but not more than five seconds:
+    Throttle(1000, &timer); //repeat once per second
+    seconds++;
+    if(seconds < 1)
+      done = 0;
+    if(seconds > 5)
+      done = 1;
+
+  }
+
+  printf("done\n\n");
+
+  SDLNet_FreePacket(out); 
+  SDLNet_FreePacket(in); 
+  print_server_list();
+  return num_servers;
+}
+
+
+char* LAN_ServerName(int i)
 {
-printf("SDL_Init: %s\n",SDL_GetError());
-exit(1);
+  if(i < 0 || i > MAX_SERVERS)
+    return NULL;
+  if(servers[i].ip.host != 0)
+    return servers[i].name;
+  else
+    return NULL; 
 }
 
-// initialize SDL_net
-if(SDLNet_Init()==-1)
+char* LAN_ConnectedServerName(void)
 {
-printf("SDLNet_Init: %s\n",SDLNet_GetError());
-exit(2);
+   return servers[connected_server].name;
 }
 
+//For the simple case where a single server is found, i is 
+//always 0. Otherwise the player has to review the choices
+//via LAN_ServerName(i) to get the index 
+int LAN_AutoSetup(int i)
+{
+  if(i < 0 || i > MAX_SERVERS)
+    return 0;
 
-// Resolve the argument into an IPaddress type
-if(SDLNet_ResolveHost(&ip,*host,portnum)==-1)
+  /* Open a connection based on autodetection routine: */
+  if (!(sd = SDLNet_TCP_Open(&servers[i].ip)))
+  {
+    fprintf(stderr, "SDLNet_TCP_Open: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+  /* We create a socket set so we can check for activity: */
+  set = SDLNet_AllocSocketSet(1);
+  if(!set)
+  {
+    printf("SDLNet_AllocSocketSet: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+  if(SDLNet_TCP_AddSocket(set, sd) == -1)
+  {
+    printf("SDLNet_AddSocket: %s\n", SDLNet_GetError());
+    // perhaps you need to restart the set and make it bigger...
+  }
+
+  // Success - record the index for future reference:
+  connected_server = i;
+  return 1;
+}
+
+
+
+// int LAN_Setup(char *host, int port)
+// {
+//   IPaddress ip;           /* Server address */
+// 
+//   if(SDL_Init(0)==-1)
+//   {
+//     printf("SDL_Init: %s\n", SDL_GetError());
+//     return 0;;
+//   }
+// 
+//   if (SDLNet_Init() < 0)
+//   {
+//     fprintf(stderr, "SDLNet_Init: %s\n", SDLNet_GetError());
+//     return 0;
+//   } 
+// 
+//    /* Resolve the host we are connecting to */
+//   if (SDLNet_ResolveHost(&ip, host, port) < 0)
+//   {
+//     fprintf(stderr, "SDLNet_ResolveHost: %s\n", SDLNet_GetError());
+//     return 0;
+//   }
+//  
+//   /* Open a connection with the IP provided (listen on the host's port) */
+//   if (!(sd = SDLNet_TCP_Open(&ip)))
+//   {
+//     fprintf(stderr, "SDLNet_TCP_Open: %s\n", SDLNet_GetError());
+//     return 0;
+//   }
+// 
+//   /* We create a socket set so we can check for activity: */
+//   set = SDLNet_AllocSocketSet(1);
+//   if(!set)
+//   {
+//     printf("SDLNet_AllocSocketSet: %s\n", SDLNet_GetError());
+//     return 0;
+//   }
+// 
+//   if(SDLNet_TCP_AddSocket(set, sd) == -1)
+//   {
+//     printf("SDLNet_AddSocket: %s\n", SDLNet_GetError());
+//     // perhaps you need to restart the set and make it bigger...
+//   }
+// 
+// 
+//   return 1;
+// }
+
+
+void LAN_Cleanup(void)
 {
-printf("SDLNet_ResolveHost: %s\n",SDLNet_GetError());
-exit(3);
+  if(sd)
+  {
+    SDLNet_TCP_Close(sd);
+    sd = NULL;
+  }
+
+  if(set)
+  {
+    SDLNet_FreeSocketSet(set);
+    set = NULL;
+  }
+  SDLNet_Quit();
 }
 
-//connect to the "host" @ port "portnum"
-sock=SDLNet_TCP_Open(&ip);
-if(!sock)
+
+
+int LAN_SetName(char* name)
 {
-printf("SDLNet_TCP_Open: %s\n",SDLNet_GetError());
-exit(4);
+  char buf[NET_BUF_LEN];
+  if(!name)
+    return 0;
+  snprintf(buf, NET_BUF_LEN, "%s\t%s", "SET_NAME", name);
+  return say_to_server(buf);
 }
 
 
 
-return(0);
+
+
+
+/* Appears a return value of 0 means message received, 1 means no socket activity */
+int check_messages(char buf[NET_BUF_LEN])
+{ 
+  int numready;
+  
+  //This is supposed to check to see if there is activity:
+  numready = SDLNet_CheckSockets(set, 0);
+  if(numready == -1)
+  {
+    printf("SDLNet_CheckSockets: %s\n", SDLNet_GetError());
+    //most of the time this is a system error, where perror might help you.
+    perror("SDLNet_CheckSockets");
+    return -1;
+  }
+  else if(numready > 0)
+  {
+    // check socket with SDLNet_SocketReady and handle if active:
+    if(SDLNet_SocketReady(sd))
+    {
+      buf[0] = '\0';
+      if(SDLNet_TCP_Recv(sd, buf, NET_BUF_LEN) <= 0)
+      {
+        fprintf(stderr, "In check_messages(), SDLNet_TCP_Recv() failed!\n");
+        return -1;
+      }
+      return 0;
+    }
+  }
+  return 1;
 }
 
 
-/***      server connection function    ****/
+/* Here we get the next message from the server if one is available. */
+/* We return 1 if a message received, 0 if no activity, -1 on errors */
+/* or if connection is lost:                                         */
+int LAN_NextMsg(char* buf)
+{ 
+  int numready = 0;
 
-int lan_server_connect(int port)
+  /* Make sure we have place to put message: */
+  if(buf == NULL)
+  {
+    printf("get_next_msg() passed NULL buffer\n");
+    return -1;
+  }
+  
+  //Check to see if there is socket activity:
+  numready = SDLNet_CheckSockets(set, 0);
+  if(numready == -1)
+  {
+    printf("SDLNet_CheckSockets: %s\n", SDLNet_GetError());
+    //most of the time this is a system error, where perror might help you.
+    perror("SDLNet_CheckSockets");
+    return -1;
+  }
+  else if(numready > 0)
+  {
+   // check with SDLNet_SocketReady():
+    if(SDLNet_SocketReady(sd))
+    {
+      buf[0] = '\0';
+      
+      if(SDLNet_TCP_Recv(sd, buf, NET_BUF_LEN) > 0)
+      {
+        //Success - message is now in buffer
+        return 1;
+      }
+      else
+      {
+        fprintf(stderr, "In get_next_msg(), SDLNet_TCP_Recv() failed!\n");
+        SDLNet_TCP_DelSocket(set, sd);
+        if(sd != NULL)
+          SDLNet_TCP_Close(sd);
+        sd = NULL;
+        return -1;
+      }
+    }
+    else
+    {
+      fprintf(stderr, "In get_next_msg(), socket set reported active but no activity found\n");
+      SDLNet_TCP_DelSocket(set, sd);
+      if(sd != NULL)
+        SDLNet_TCP_Close(sd);
+      sd = NULL;
+      return -1;
+    }
+  }
+  // No socket activity - just return 0:
+  return 0;
+}
+
+
+
+
+int Make_Flashcard(char* buf, MC_FlashCard* fc)
 {
-IPaddress ip; //int *remoteip;
-TCPsocket server,client;
-//Uint32 ipaddr;
-Uint16 portnum;
+  int i = 0,tab = 0, s = 0;
+  char formula[MC_FORMULA_LEN];
+  sscanf (buf,"%*s%d%d%d%s",
+              &fc->question_id,
+              &fc->difficulty,
+              &fc->answer,
+              fc->answer_string); /* can't formula_string in sscanf in here cause it includes spaces*/
+ 
+  /*doing all this cause sscanf will break on encountering space in formula_string*/
+  /* NOTE changed to index notation so we keep within NET_BUF_LEN */
+  while(buf[i]!='\n' && i < NET_BUF_LEN)
+  {
+    if(buf[i]=='\t')
+      tab++; 
+    i++;
+    if(tab == 5)
+      break;
+  }
 
+  while((buf[i] != '\n') 
+    && (s < MC_FORMULA_LEN - 1)) //Must leave room for terminating null
+  {
+    formula[s] = buf[i] ;
+    i++;
+    s++;
+  }
+  formula[s]='\0';
+  strcpy(fc->formula_string, formula); 
 
-// initialize SDL
-if(SDL_Init(0)==-1)
+  DEBUGMSG(debug_lan, "In Make_Flashcard, new card is:\n");
+  DEBUGCODE(debug_lan) print_card(*fc); 
+
+return 1;
+} 
+
+
+int LAN_StartGame(void)
 {
-printf("SDL_Init: %s\n",SDL_GetError());
-exit(1);
+  char buffer[NET_BUF_LEN];
+  snprintf(buffer, NET_BUF_LEN, "%s", "START_GAME");
+  return say_to_server(buffer);
 }
 
-// initialize SDL_net
-if(SDLNet_Init()==-1)
+
+int LAN_AnsweredCorrectly(int id, float t)
 {
-printf("SDLNet_Init: %s\n",SDLNet_GetError());
-exit(2);
+  char buffer[NET_BUF_LEN];
+  snprintf(buffer, NET_BUF_LEN, "%s\t%d\t%f", "CORRECT_ANSWER", id, t);
+  return say_to_server(buffer);
 }
 
 
-portnum=(Uint16)strtol(port,NULL,0);
-
-// Resolve the argument into an IPaddress type
-if(SDLNet_ResolveHost(&ip,NULL,portum)==-1)
+int LAN_NotAnsweredCorrectly(int id)
 {
-printf("SDLNet_ResolveHost: %s\n",SDLNet_GetError());
-exit(3);
+  char buffer[NET_BUF_LEN];
+  snprintf(buffer, NET_BUF_LEN, "%s\t%d", "WRONG_ANSWER", id);
+  return say_to_server(buffer);
 }
 
-// open the server socket
-server=SDLNet_TCP_Open(&ip);
-if(!server)
+
+/* This tells the server we are quitting the current math game, but */
+/* not disconnecting our socket:                                    */
+int LAN_LeaveGame(void)
 {
-printf("SDLNet_TCP_Open: %s\n",SDLNet_GetError());
-exit(4);
+  char buf[NET_BUF_LEN];
+  snprintf(buf, NET_BUF_LEN, "%s", "LEAVE_GAME");
+  return say_to_server(buf);
 }
 
-while(1)
+
+
+/*private to network.c functions*/
+
+int say_to_server(char* statement)
 {
-// try to accept a connection
-client=SDLNet_TCP_Accept(server);
-if(!client)
-{ // no connection accepted
-//printf("SDLNet_TCP_Accept: %s\n",SDLNet_GetError());
-SDL_Delay(100); //sleep 1/10th of a second
-continue;
+  char buffer[NET_BUF_LEN];
+
+  if(!statement)
+    return 0;
+
+  snprintf(buffer, NET_BUF_LEN, 
+                  "%s",
+                  statement);
+  if (SDLNet_TCP_Send(sd, (void *)buffer, NET_BUF_LEN) < NET_BUF_LEN)
+  {
+    fprintf(stderr, "SDLNet_TCP_Send: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+  return 1;
 }
 
-/// get the clients IP and port number
-//remoteip=SDLNet_TCP_GetPeerAddress(client);
-//if(!remoteip)
-//{
-//printf("SDLNet_TCP_GetPeerAddress: %s\n",SDLNet_GetError());
-//continue;
-//}
+//add name to list, checking for duplicates:
+int add_to_server_list(UDPpacket* pkt)
+{
+  int i = 0;
+  int already_in = 0;
+  char* p = NULL;
 
-/*for testing purpose to check if it is connected to the desired client
-// print out the clients IP and port number
-ipaddr=SDL_SwapBE32(remoteip->host);
-printf("Accepted a connection from %d.%d.%d.%d port %hu\n",
-ipaddr>>24,
-(ipaddr>>16)&0xff,
-(ipaddr>>8)&0xff,
-ipaddr&0xff,
-remoteip->port);
+  if(!pkt)
+    return 0;
+ 
+  //first see if it is already in list:
+  while((i < MAX_SERVERS)
+      && (servers[i].ip.host != 0))
+  {
+    if(pkt->address.host == servers[i].ip.host)
+      already_in = 1;
+    i++;
+  }
 
-*/
+  //Copy it in unless it's already there, or we are out of room:
+  if(!already_in && i < MAX_SERVERS)
+  {
+    servers[i].ip.host = pkt->address.host;
+    servers[i].ip.port = pkt->address.port;
+    // not using sscanf() because server_name could contain whitespace:
+    p = strchr(pkt->data, '\t');
+    p++;
+    if(p)
+      strncpy(servers[i].name, p, NAME_SIZE);
 
-return(0);
+    i++;
+  }
+
+  return i;  //i should be the number of items in the list
 }
 
+void print_server_list(void)
+{
+  int i = 0;
+  printf("Detected servers:\n");
+  while(i < MAX_SERVERS && servers[i].ip.host != 0)
+  {
+    printf("SERVER NUMBER %d: %s\n", i, servers[i].name);
+    i++;
+  }
+}
 
+
+

Copied: branches/commonification/tuxmath/trunk/src/network.h (from rev 1657, tuxmath/trunk/src/network.h)
===================================================================
--- branches/commonification/tuxmath/trunk/src/network.h	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/network.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,59 @@
+/*
+
+        network.h
+
+        Description: Provides routines for various networking functions to be used
+                     in the LAN multiplayer game.
+        Author: David Bruce ,Akash Gangil and the TuxMath team, (C) 2009
+
+        Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
+
+*/
+
+
+
+
+#ifndef NETWORK_H
+#define NETWORK_H
+
+#include "transtruct.h"
+#include "SDL_net.h"
+
+
+typedef struct {
+    IPaddress ip;            /* 32-bit IPv4 host address */
+    char name[NAME_SIZE];
+}ServerEntry;
+
+
+/* Networking setup and cleanup: */
+int LAN_DetectServers(void);
+int LAN_AutoSetup(int i);
+char* LAN_ServerName(int i);
+char* LAN_ConnectedServerName(void);
+void print_server_list(void);
+
+//int LAN_Setup(char* host, int port);
+void LAN_Cleanup(void);
+int LAN_SetName(char* name);
+
+/* Network replacement functions for mathcards "API": */
+/* These functions are how the client tells things to the server: */
+int LAN_StartGame(void);
+int LAN_AnsweredCorrectly(int id, float t);
+int LAN_NotAnsweredCorrectly(int id);
+int LAN_LeaveGame(void);
+/* This is how the client receives messages from the server: */
+int LAN_NextMsg(char* buf);
+
+/* NOTE probably won't have this in multiplayer - new quests determined by server */
+//int LAN_NextQuestion(void);
+
+
+
+/* FIXME appears this one is basically the same as LAN_NextMsg() */
+int check_messages(char *);
+/* FIXME this should be local to network.c */
+int Make_Flashcard(char* buf, MC_FlashCard* fc);
+
+#endif // NETWORK_H

Modified: branches/commonification/tuxmath/trunk/src/options.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/options.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/options.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -123,7 +123,9 @@
   global_options->iopts[FULLSCREEN] = DEFAULT_FULLSCREEN;
   global_options->iopts[USE_KEYPAD] = DEFAULT_USE_KEYPAD;
   global_options->iopts[USE_IGLOOS] = DEFAULT_USE_IGLOOS;
-  strncpy(game_options->current_font_name, DEFAULT_FONT_NAME, sizeof(game_options->current_font_name));
+  strncpy(game_options->current_font_name, DEFAULT_FONT_NAME,
+          sizeof(game_options->current_font_name));
+  game_options->lan_mode = DEFAULT_LAN_MODE;
   game_options->use_bkgd = DEFAULT_USE_BKGD;
   game_options->help_mode = DEFAULT_HELP_MODE;
   game_options->demo_mode = DEFAULT_DEMO_MODE;
@@ -246,6 +248,12 @@
 //  global_options->iopts[FULLSCREEN] = int_to_bool(val);
 //}
 
+void Opts_SetLanMode(int val)
+{
+  game_options->lan_mode = int_to_bool(val);
+}
+ 
+
 void Opts_SetFontName(char* font_name)
 {
   if (font_name && font_name[0] != '\0')
@@ -613,6 +621,18 @@
 //  return global_options->iopts[FULLSCREEN];
 //}
 
+
+int Opts_LanMode(void)
+{
+  if (!game_options)
+  {
+    fprintf(stderr, "\nOpts_LanMode(): game_options not valid!\n");
+    return GAME_OPTS_INVALID;
+  }
+  return game_options->lan_mode;
+}
+ 
+
 const char* Opts_FontName(void)
 {
   if (!game_options)

Modified: branches/commonification/tuxmath/trunk/src/options.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/options.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/options.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -49,6 +49,7 @@
 typedef struct game_option_type {
   /* general game options */
   char current_font_name[FONT_NAME_LENGTH];
+  int lan_mode;
   int use_bkgd;
   int help_mode;
   int demo_mode;
@@ -63,7 +64,7 @@
   int slow_after_wrong;
   int starting_comets;
   int extra_comets_per_wave;
-  int max_comets;  
+  int max_comets;
   char next_mission[PATH_MAX];
   int save_summary;
   int use_feedback;
@@ -121,6 +122,7 @@
 void Opts_SetGlobalOpt(unsigned int index, int val);
 
 void Opts_SetFontName(char* font_name);
+void Opts_SetLanMode(int val);
 void Opts_SetUseBkgd(int val);
 void Opts_SetHelpMode(int val);
 void Opts_SetDemoMode(int val);
@@ -154,6 +156,7 @@
 
 /* "Get" functions for tuxmath options struct: */
 const char* Opts_FontName(void);
+int Opts_LanMode(void);
 int Opts_UseBkgd(void);
 int Opts_HelpMode(void);
 int Opts_DemoMode(void);

Modified: branches/commonification/tuxmath/trunk/src/scandir.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/scandir.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/scandir.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -29,9 +29,9 @@
 #include "scandir.h"
 
 /*-----------------------------------------------------------------------
- * Here come alphasort and scandir for BeOS and SunOS
+ * Here come alphasort and scandir for BeOS/Haiku and SunOS
  *-----------------------------------------------------------------------*/
-#if defined(__BEOS__) || (defined(__sun) && defined(__SVR4))
+#if defined(__BEOS__) || defined(__HAIKU__) || (defined(__sun) && defined(__SVR4))
 
 #undef DIRSIZ
 

Modified: branches/commonification/tuxmath/trunk/src/scandir.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/scandir.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/scandir.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -19,7 +19,7 @@
 #define dirent direct
 #endif
 
-#if defined(__BEOS__) || (defined(__sun) && defined(__SVR4)) || defined(WIN32)
+#if defined(__BEOS__) || defined(__HAIKU__) || (defined(__sun) && defined(__SVR4)) || defined(WIN32)
 extern int alphasort(const void *d1, const void *d2);
 extern int scandir(const char *dirname, struct dirent ***namelist, int (*sdfilter)(struct dirent *), int (*dcomp)(const void *, const void *));
 #endif

Copied: branches/commonification/tuxmath/trunk/src/server.c (from rev 1657, tuxmath/trunk/src/server.c)
===================================================================
--- branches/commonification/tuxmath/trunk/src/server.c	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/server.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,1241 @@
+/*
+*  C Implementation: server.c
+*
+*       Description: Server program for LAN-based play in Tux,of Math Command.
+*
+*
+* Author: Akash Gangil, David Bruce, and the TuxMath team, (C) 2009
+* Developers list: <tuxmath-devel at lists.sourceforge.net>
+*
+* Copyright: See COPYING file that comes with this distribution.  (Briefly, GNU GPL).
+*
+* NOTE: This file was initially based on example code from The Game Programming Wiki
+* (http://gpwiki.org), in a tutorial covered by the GNU Free Documentation License 1.2.
+* No invariant sections were indicated, and no separate license for the example code
+* was listed. The author was also not listed. AFAICT,this scenario allows incorporation of
+* derivative works into a GPLv2+ project like TuxMath.  FWIW, virtually none of
+* the tutorial code is still present here - David Bruce 
+*/
+
+#include "globals.h"
+#include "server.h" 
+#include "transtruct.h"
+#include "mathcards.h"
+#include "throttle.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h> 
+#include <sys/types.h>  
+#include <unistd.h>
+
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+
+#define MAX_ARGS 16
+
+
+/*  -----------  Local function prototypes:   ------------  */
+
+// setup and cleanup:
+int setup_server(void);
+void cleanup_server(void);
+void server_handle_command_args(int argc, char* argv[]);
+void* run_server_local_args(void);
+
+// top level functions in main loop:
+void check_UDP(void);
+void update_clients(void);
+int server_check_messages(void);
+
+// client management utilities:
+int find_vacant_client(void);
+void remove_client(int i);
+void check_game_clients(void);
+
+// message reception:
+int handle_client_game_msg(int i, char* buffer);
+void handle_client_nongame_msg(int i, char* buffer);
+int msg_set_name(int i, char* buf);
+void start_game(void);
+void game_msg_correct_answer(int i, char* inbuf);
+void game_msg_wrong_answer(int i, char* inbuf);
+void game_msg_quit(int i);
+void game_msg_exit(int i);
+int calc_score(int difficulty, float t);
+
+//message sending:
+int add_question(MC_FlashCard* fc);
+int remove_question(int id);
+int send_counter_updates(void);
+int send_score_updates(void);
+//int SendQuestion(MC_FlashCard flash, TCPsocket client_sock);
+int SendMessage(int message, int ques_id, char* name, TCPsocket client_sock);
+int player_msg(int i, char* msg);
+void broadcast_msg(char* msg);
+int transmit(int i, char* msg);
+int transmit_all(char* msg);
+
+// For non-blocking input:
+int read_stdin_nonblock(char* buf, size_t max_length);
+
+
+// not really deprecated but not done in response to 
+// client message --needs better name:
+void game_msg_next_question(void);
+
+
+
+/*  ------------   "Local globals" for server.c: ----------  */
+char server_name[NAME_SIZE];  /* User-visible name for server selection  */
+int need_server_name = 1;
+UDPsocket udpsock = NULL;     /* Used to listen for client's server autodetection           */
+TCPsocket server_sock = NULL; /* Socket descriptor for server to accept client TCP sockets. */
+IPaddress ip;
+SDLNet_SocketSet client_set = NULL, temp_set = NULL;
+static client_type client[MAX_CLIENTS];
+static int num_clients = 0;
+static int game_in_progress = 0;
+static int server_running = 0;
+static int quit = 0;
+MC_FlashCard flash;
+int local_argc;
+char* local_argv[MAX_ARGS];
+
+
+
+
+
+
+
+
+/* The previous contents of main() are wrapped into this function to   */
+/* allow the server to be run as a function in a process or thread     */
+/* within another program.  main() is now in a separate file,          */
+/* servermain.c, that consists solely of a call to RunServer().        */
+
+/* FIXME this isn't thread-safe - we need to return gracefully if we     */
+/* find that the server is already running, instead of calling cleanup() */
+/* and crashing the program. Some of the setup and cleanup will have to  */
+/* be called from main() rather than from here.                          */
+int RunServer(int argc, char* argv[])
+{ 
+  Uint32 timer = 0;
+
+  printf("Started tuxmathserver, waiting for client to connect:\n>\n");
+
+  server_handle_command_args(argc, argv);
+
+  /*     ---------------- Setup: ---------------------------   */
+  if (!setup_server())
+  {
+    fprintf(stderr, "setup_server() failed - exiting.\n");
+    cleanup_server();
+    return EXIT_FAILURE;
+  }
+
+  server_running = 1;
+
+  printf("Waiting for clients to connect:\n>");
+  fflush(stdout);
+
+ /*    ------------- Main server loop:  ------------------   */
+  while (!quit)
+  {
+    /* Respond to any clients pinging us to find the server: */
+    check_UDP();
+    /* Now we check to see if anyone is trying to connect. */
+    update_clients();
+    /* Check for any pending messages from clients already connected: */
+    server_check_messages();
+
+    /* Limit frame rate to keep from eating all CPU: */
+    /* NOTE almost certainly could make this longer wtihout noticably */
+    /* affecting performance, but even throttling to 1 msec/loop cuts */
+    /* CPU from 100% to ~2% on my desktop - DSB                       */
+    Throttle(5, &timer);  //min loop time 5 msec
+  }
+
+  server_running = 0;
+   
+  /*   -----  Free resources before exiting: -------    */
+  cleanup_server();
+
+  return EXIT_SUCCESS;
+}
+
+/* If we can't use pthreads, we use this function   */
+/* to launch the server as a separate program using */
+/* the C library system() call                      */
+int RunServer_prog(int argc, char* argv[])
+{
+  char buf[256];
+  int i;
+
+  /* Construct command-line argument string from argc and argv:   */
+  /* NOTE this is not safe from buffer overflow - do              */
+  /* not use with user-supplied arguments.                        */
+  snprintf(buf, 256, "tuxmathserver ");
+  for(i = 1; i < argc; i++)
+  {
+    strncat(buf, argv[i], 256);
+    strncat(buf, " ", 256);
+  }
+  /* Add '&' to make it non-blocking: */
+  strncat(buf, "&", 256);
+
+  return system(buf);
+}
+
+
+int RunServer_pthread(int argc, char* argv[])
+{
+  pthread_t server_thread;
+  int i;
+
+  /* We can only pass a single arg into the new thread, but it shares  */
+  /* the same address space, so we save argc and argv locally instead: */
+  local_argc = argc;
+  for(i = 0; i < argc && i < MAX_ARGS; i++)
+  {
+    local_argv[i] = argv[i];
+  }
+
+  if(pthread_create(&server_thread, NULL, run_server_local_args, NULL))
+  {
+    printf("Error creating thread\n");
+    return -1;
+  }
+  return 0;
+}
+
+
+void* run_server_local_args(void)
+{
+
+  RunServer(local_argc, local_argv);
+  pthread_exit(NULL);
+  return NULL;
+}
+
+/*********************************************************************/
+/*  "Private" (to server.c) functions                                */
+/*********************************************************************/
+
+
+/*  ----- Setup and Cleanup:  ------------------- */
+
+
+// setup_server() - all the things needed to get server running:
+int setup_server(void)
+{
+  Uint32 timer = 0;
+
+  //Initialize SDL and SDL_net:
+  if(SDL_Init(0) == -1)
+  {
+    printf("SDL_Init: %s\n", SDL_GetError());
+    return 0;;
+  }
+      
+  if (SDLNet_Init() < 0)
+  {
+    fprintf(stderr, "SDLNet_Init: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+ 
+  /* Resolving the host using NULL make network interface to listen */
+  if (SDLNet_ResolveHost(&ip, NULL, DEFAULT_PORT) < 0)
+  {
+    fprintf(stderr, "SDLNet_ResolveHost: %s\n", SDLNet_GetError());
+    return 0;
+  }
+ 
+  /* Open a connection with the IP provided (listen on the host's port) */
+  if (!(server_sock = SDLNet_TCP_Open(&ip)))
+  {
+    fprintf(stderr, "SDLNet_TCP_Open: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+  client_set = SDLNet_AllocSocketSet(MAX_CLIENTS);
+  if(!client_set)
+  { 
+    printf("SDLNet_AllocSocketSet: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+  //this sets up our mathcards "library" with hard-coded defaults - no
+  //settings read from config file here as of yet:
+  if (!MC_Initialize())
+  {
+    fprintf(stderr, "Could not initialize MathCards\n");
+    return 0;
+  }
+
+  /* Get server name: */
+  /* We use default name after 30 sec timeout if no name entered. */
+  /* FIXME we should save this to disc so it doesn't */
+  /* have to be entered every time.                  */
+  if(need_server_name)
+  {
+    Uint32 timeout = SDL_GetTicks() + SERVER_NAME_TIMEOUT;
+    int name_recvd = 0;
+    server_name[0] = '\0';
+    fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
+
+    printf("Enter the SERVER's NAME: \n>");
+    fflush(stdout);
+
+    while(!name_recvd && (SDL_GetTicks() < timeout))
+    {
+      if(read_stdin_nonblock(server_name, NAME_SIZE))
+        name_recvd = 1;
+      Throttle(10, &timer);
+    }
+    if(!name_recvd)
+      printf("No name entered within timeout, will use default: %s\n",
+             DEFAULT_SERVER_NAME);
+  
+    /* If no nickname received, use default: */
+    if(strlen(server_name) == 0)
+      strncpy(server_name, DEFAULT_SERVER_NAME, NAME_SIZE);
+  }
+
+
+  // Zero out our client list:
+  {
+    int i = 0;
+    for(i = 0; i < MAX_CLIENTS; i++)
+    {
+      client[i].game_ready = 0;   /* waiting for user to OK game start */
+      client[i].name[0] = '\0';   /* no nicknames yet                  */
+      client[i].sock = NULL;      /* sockets start out unconnected     */
+      client[i].score = 0;
+    }
+  }
+
+
+  //Now open a UDP socket to listen for clients broadcasting to find the server:
+  udpsock = SDLNet_UDP_Open(DEFAULT_PORT);
+  if(!udpsock)
+  {
+    printf("SDLNet_UDP_Open: %s\n", SDLNet_GetError());
+    return 0;
+  }
+
+  // Indicates success:
+  return 1;
+}
+
+
+
+//Free resources, closing sockets, call MC_EndGame(), and so forth:
+void cleanup_server(void)
+{
+  int i;
+  /* Close the client socket(s) */
+  
+  for(i = 0; i < MAX_CLIENTS; i++)
+  {
+    if(client[i].sock != NULL)
+    {
+      SDLNet_TCP_Close(client[i].sock);    //close all the client sockets one by one
+      client[i].sock = NULL;               // So we don't segfault in case cleanup()
+    }                                      // somehow gets called more than once.
+  } 
+
+  if (client_set != NULL)
+  {
+    SDLNet_FreeSocketSet(client_set);    //releasing the memory of the client socket set
+    client_set = NULL;                   //this helps us remember that this set is not allocated
+  } 
+
+  if(server_sock != NULL)
+  {
+    SDLNet_TCP_Close(server_sock);
+    server_sock = NULL;
+  }
+
+  SDLNet_Quit();
+
+  /* Clean up mathcards heap memory */
+  MC_EndGame();
+}
+
+
+/* Handle any arguments passed from command line */
+void server_handle_command_args(int argc, char* argv[])
+{
+  int i;
+
+  for (i = 1; i < argc; i++)
+  {
+    if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
+    {
+      /* Display help message: */
+      printf("\n");
+      cleanup_server();
+      exit(0);
+    }
+    else if (strcmp(argv[i], "--debug-lan") == 0)
+    {
+      debug_status |= debug_lan;
+    }
+
+    else if (strcmp(argv[i], "--copyright") == 0 ||
+             strcmp(argv[i], "-c") == 0)
+    {
+      printf(
+        "\n\"Tux, of Math Command Server\" version " VERSION ", Copyright (C) 2009,\n"
+        "David Bruce, Akash Gangil, and the Tux4Kids Project.\n"
+        "This program is free software; you can redistribute it and/or\n"
+        "modify it under the terms of the GNU General Public License\n"
+        "as published by the Free Software Foundation.  See COPYING.txt\n"
+        "\n"
+        "This program is distributed in the hope that it will be useful,\n"
+        "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+        "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
+        "\n");
+
+      cleanup_server();
+      exit(0);
+    }
+    else if (strcmp(argv[i], "--usage") == 0 ||
+             strcmp(argv[i], "-u") == 0)
+    {
+      /* Display (happy) usage: */
+
+//      usage(0, argv[0]);
+    }
+    else if ((strcmp(argv[i], "--name") == 0 || strcmp(argv[i], "-n") == 0)
+           && (i + 1 < argc))
+    {
+      strncpy(server_name, argv[i + 1], NAME_SIZE);
+      need_server_name = 0;
+    }
+  }
+}
+
+
+// ----------- Top level functions in main loop ---------------:
+
+//check_UDP() is the server side of the client-server autodetection system.
+//When a client wants to connect, it sends a UDP broadcast to the local
+//network on this port, and the server sends a response.
+void check_UDP(void)
+{
+  int recvd = 0;
+  UDPpacket* in = SDLNet_AllocPacket(NET_BUF_LEN);
+  recvd = SDLNet_UDP_Recv(udpsock, in);
+
+  // See if packet contains identifying string:
+  if(strncmp((char*)in->data, "TUXMATH_CLIENT", strlen("TUXMATH_CLIENT")) == 0)
+  {
+    UDPpacket* out;
+    int sent = 0;
+    char buf[NET_BUF_LEN];
+    // Send "I am here" reply so client knows where to connect socket,
+    // with configurable identifying string so user can distinguish 
+    // between multiple servers on same network (e.g. "Mrs. Adams' Class");
+    out = SDLNet_AllocPacket(NET_BUF_LEN); 
+    snprintf(buf, NET_BUF_LEN, "%s\t%s", "TUXMATH_SERVER", server_name);
+    snprintf(out->data, NET_BUF_LEN, "%s", buf);
+    out->len = strlen(buf) + 1;
+    out->address.host = in->address.host;
+    out->address.port = in->address.port;
+
+    sent = SDLNet_UDP_Send(udpsock, -1, out);
+
+    SDLNet_FreePacket(out); 
+  }
+}
+
+
+
+
+//update_clients() sees if anyone is trying to connect, and connects if a slot
+//is open and the game is not in progress. The purpose is to make sure our
+//client set accurately reflects the current state.
+void update_clients(void)
+{
+  TCPsocket temp_sock = NULL;        /* Just used when client can't be accepted */
+  int slot = 0;
+  int sockets_used = 0;
+  char buffer[NET_BUF_LEN];
+
+
+  /* See if we have a pending connection: */
+  temp_sock = SDLNet_TCP_Accept(server_sock);
+  if (!temp_sock)  /* No one waiting to join - do nothing */
+  {
+    return;   // Leave num_clients unchanged
+  }
+
+  // See if any slots are available:
+  slot = find_vacant_client();
+  if (slot == -1) /* No vacancies: */
+  {
+    snprintf(buffer, NET_BUF_LEN, 
+             "%s\t%s",
+             "PLAYER_MSG",
+             "Sorry, already have maximum number of clients connected");
+    SDLNet_TCP_Send(temp_sock, buffer, NET_BUF_LEN);
+    //hang up:
+    SDLNet_TCP_Close(temp_sock);
+    temp_sock = NULL;
+
+    DEBUGMSG(debug_lan, "update_clients() - no vacant slot found\n");
+
+    return;   // Leave num_clients unchanged
+  }
+
+  //If everyone is disconnected, game no longer in progress:
+  check_game_clients(); 
+
+  // If game already started, send our regrets:
+  if(game_in_progress)
+  {
+    snprintf(buffer, NET_BUF_LEN, 
+             "%s",
+             "GAME_IN_PROGRESS");
+    SDLNet_TCP_Send(temp_sock, buffer, NET_BUF_LEN);
+    //hang up:
+    SDLNet_TCP_Close(temp_sock);
+    temp_sock = NULL;
+
+    DEBUGMSG(debug_lan, "update_clients() - game already started\n");
+
+    return;   // Leave num_clients unchanged
+  }
+
+  // If we get to here, we have room for the new connection and the
+  // game is not in progress, so we connect:
+  DEBUGMSG(debug_lan, "creating connection for client[%d].sock:\n", slot);
+
+  client[slot].sock = temp_sock;
+
+  /* Add client socket to set: */
+  sockets_used = SDLNet_TCP_AddSocket(client_set, client[slot].sock);
+  if(sockets_used == -1) //No way this should happen
+  {
+    printf("SDLNet_AddSocket: %s\n", SDLNet_GetError());
+    cleanup_server();
+    exit(EXIT_FAILURE);
+  }
+
+  /* At this point num_clients can be updated: */
+  num_clients = sockets_used;
+
+  /* Now we can communicate with the client using client[i].sock socket */
+  /* serv_sock will remain opened waiting other connections */
+    
+
+  /* Get the remote address */
+  DEBUGCODE(debug_lan)
+  {
+    IPaddress* client_ip = NULL;
+    client_ip = SDLNet_TCP_GetPeerAddress(client[slot].sock);
+
+    printf("num_clients = %d\n", num_clients);
+    if (client_ip != NULL)
+    /* Print the address, converting in the host format */
+    {
+      printf("Client connected\n>\n");
+      printf("Client: IP = %x, Port = %d\n",
+             SDLNet_Read32(&client_ip->host),
+             SDLNet_Read16(&client_ip->port));
+    }
+    else
+      fprintf(stderr, "SDLNet_TCP_GetPeerAddress: %s\n", SDLNet_GetError());
+  }
+
+  return;
+}
+
+
+
+// check_messages() is where we look at the client socket set to see which 
+// have sent us messages. This function is used in each server loop whether
+// or not a math game is in progress (although we expect different messages
+// during a game from those encountered outside of a game)
+
+int server_check_messages(void)
+{
+  int actives = 0, i = 0;
+  int ready_found = 0;
+  char buffer[NET_BUF_LEN];
+
+
+  /* Check the client socket set for activity: */
+  actives = SDLNet_CheckSockets(client_set, 0);
+//  printf("in check_messages(), actives = %d\n", actives);
+  if(actives == -1)
+  {
+    printf("SDLNet_CheckSockets: %s\n", SDLNet_GetError());
+    //most of the time this is a system error, where perror might help you.
+    perror("SDLNet_CheckSockets");
+  }
+
+  else if(actives) 
+  {
+    DEBUGMSG(debug_lan, "There are %d sockets with activity\n", actives);
+
+    // check all sockets with SDLNet_SocketReady and handle the active ones.
+    // NOTE we have to check all the slots in the set because
+    // the set will become discontinuous if someone disconnects
+    // NOTE this will only pick up the first message for each socket each time
+    // check_messages() called - probably OK if we just get it next time through.
+    for(i = 0; i < MAX_CLIENTS; i++)
+    {
+      if((client[i].sock != NULL)
+        && (SDLNet_SocketReady(client[i].sock))) 
+      { 
+        ready_found++;
+
+        DEBUGMSG(debug_lan, "client socket %d is ready\n", i);
+
+        if (SDLNet_TCP_Recv(client[i].sock, buffer, NET_BUF_LEN) > 0)
+        {
+          DEBUGMSG(debug_lan, "buffer received from client %d is: %s\n", i, buffer);
+
+          /* Here we pass the client number and the message buffer */
+          /* to a suitable function for further action:                */
+          if(game_in_progress)
+          {
+            handle_client_game_msg(i, buffer);
+          }
+          else
+          {
+            handle_client_nongame_msg(i, buffer);
+          }
+          // See if game is ended because everyone has left:
+          check_game_clients(); 
+        }
+        else  // Socket activity but cannot receive - client invalid
+        {
+          printf("Client %d active but receive failed - apparently disconnected\n>\n", i);
+          remove_client(i);
+        }
+      }
+    }  // end of for() loop - all client sockets checked
+    // Make sure all the active sockets reported by SDLNet_CheckSockets()
+    // are accounted for:
+
+    if(actives > ready_found)
+    {
+      printf("Warning: SDLNet_CheckSockets() reported %d active sockets,\n"
+             "but only %d detected by SDLNet_SocketReady()\n", actives, ready_found);
+      //Presently, this just runs ping_client() on all the sockets:
+      //test_connections();
+    }
+  } 
+  return 1;
+}
+
+
+
+
+// client management utilities:
+
+//Returns the index of the first vacant client, or -1 if all clients full
+int find_vacant_client(void)
+{
+  int i = 0;
+  while (client[i].sock && i < MAX_CLIENTS)
+    i++;
+  if (i == MAX_CLIENTS)
+  {
+    fprintf(stderr, "All clients checked, none vacant\n");
+    i = -1;
+  }
+  return i;
+}
+
+
+void remove_client(int i)
+{
+  printf("Removing client[%d] - name: %s\n>\n", i, client[i].name);
+
+  SDLNet_TCP_DelSocket(client_set, client[i].sock);
+
+  if(client[i].sock != NULL)
+    SDLNet_TCP_Close(client[i].sock);
+
+  client[i].sock = NULL;  
+  client[i].game_ready = 0;
+  client[i].name[0] = '\0';
+}
+
+
+// check_game_clients() reviews the game_ready flags of all the connected
+// clients to determine if a new game is started, or if an old game needs
+// to be ended because all the players have left.  If it finds both "playing"
+// and "nonplaying clients", it leaves game_in_progress unchanged.
+
+// TODO this is not very sophisticated, and only supports one game at a time.
+// We may want to make this extensible to multiple simultaneous games, perhaps
+// with each game in its own thread with its own socket set and mathcards instance.
+// FIXME we need to do more than just toggle game_in_progress - should have
+// start_game() and end_game() functions that make sure mathcards is 
+// properly set up or cleaned up.
+void check_game_clients(void)
+{
+  int i = 0;
+
+  //If the game is already started, we leave it running as long as at least
+  //one client is both connected and willing to play:
+  if(game_in_progress)
+  {
+    int someone_still_playing = 0;
+    for(i = 0; i < MAX_CLIENTS; i++)
+    {
+      if((client[i].sock != NULL)
+       && client[i].game_ready)
+      {
+        someone_still_playing = 1;
+        break;
+      }
+    }
+
+    if(!someone_still_playing)
+    {
+      printf("All the clients have left the game, setting game_in_progress = 0.\n");
+      game_in_progress = 0;
+    }
+  }
+  //If the game hasn't started yet, we only start it 
+  //if all connected clients are ready:
+  //FIXME should add a timeout so the game eventually starts without
+  //those who don't answer
+  else
+  {
+    int someone_connected = 0;
+    int someone_not_ready = 0;
+    for(i = 0; i < MAX_CLIENTS; i++)
+    {
+      if(client[i].sock != NULL)
+      { 
+        someone_connected = 1;
+        if (!client[i].game_ready)
+        {
+          someone_not_ready = 1;
+        }
+      }
+    }
+    if(someone_connected && !someone_not_ready)
+      start_game(); 
+  }
+}
+
+
+
+void handle_client_nongame_msg(int i, char* buffer)
+{
+  char buf[NET_BUF_LEN];
+
+  if(strncmp(buffer, "START_GAME", strlen("START_GAME")) == 0)
+  {
+    snprintf(buf, NET_BUF_LEN,
+                "Player %s ready to start math game",
+                client[i].name);
+    broadcast_msg(buf);
+    client[i].game_ready = 1;
+    //This will call start_game() if all the other clients are ready:
+    check_game_clients();
+  }
+  else if(strncmp(buffer, "SET_NAME", strlen("SET_NAME")) == 0)
+  {
+    msg_set_name(i, buffer);
+  }
+}
+
+
+int handle_client_game_msg(int i , char* buffer)
+{
+  DEBUGMSG(debug_lan, "Buffer received from client: %s\n", buffer);
+
+  if(strncmp(buffer, "CORRECT_ANSWER", strlen("CORRECT_ANSWER")) == 0)
+  {
+    game_msg_correct_answer(i, buffer);
+  }                            
+
+  else if(strncmp(buffer, "WRONG_ANSWER",strlen("WRONG_ANSWER")) == 0) /* Player answered the question incorrectly , meaning comet crashed into a city or an igloo */
+  {
+    game_msg_wrong_answer(i, buffer);
+  }
+
+  else if(strncmp(buffer, "LEAVE_GAME", strlen("LEAVE_GAME")) == 0) 
+  {
+    client[i].game_ready = 0;  /* Player quitting game but not disconnecting */
+  }
+
+  else if(strncmp(buffer, "exit",strlen("exit")) == 0) /* Terminate this connection */
+  {
+    game_msg_exit(i);
+  }
+
+  else if(strncmp(buffer, "quit",strlen("quit")) == 0) /* Quit the program */
+  {
+    game_msg_quit(i);
+    return(1);
+  }
+  else
+  {
+    printf("command %s not recognized\n", buffer);
+  }
+  return(0);
+}
+
+
+
+int msg_set_name(int i, char* buf)
+{
+  char* p;
+
+  if(buf == NULL)
+    return 0;
+
+  p = strchr(buf, '\t');
+  if(p)
+  { 
+    p++;
+    strncpy(client[i].name, p, NAME_SIZE);
+    return 1;
+  }
+  else
+    return 0;
+}
+
+
+
+void game_msg_correct_answer(int i, char* inbuf)
+{
+  char outbuf[NET_BUF_LEN];
+  char* p = NULL;
+  int id = -1;
+  float t = -1;
+  int points = 0;
+
+  if(!inbuf)
+    return;
+
+  //parse inbuf to get question id:
+  p = strchr(inbuf, '\t');
+  if(!p)
+    return; 
+  p++;
+  id = atoi(p);
+  //Now get time player took to answer:
+  p = strchr(p, '\t');
+  if(!p)
+    t = -1;
+  else
+  {
+    p++;
+    t = atof(p);
+  }
+
+  //Tell mathcards so lists get updated:
+  points = MC_AnsweredCorrectly(id, t);
+  if(!points)
+    return;
+  //If we get to here, the id was successfully parsed out of inbuf
+  //and the corresponding question was found.
+  client[i].score += points;
+
+  //Announcement for server and all clients:
+  snprintf(outbuf, NET_BUF_LEN, 
+          "question id %d was answered in %f seconds for %d points by %s",
+          id, t, points, client[i].name);             
+  broadcast_msg(outbuf);
+
+  DEBUGMSG(debug_lan, "game_msg_correct_answer(): %s\n", outbuf);
+
+  //Tell all players to remove that question:
+  remove_question(id);
+  //send the next question to everyone:
+  game_msg_next_question();
+  //and update the game counters:
+  send_counter_updates();
+  //and the scores:
+  send_score_updates();
+}
+
+
+void game_msg_wrong_answer(int i, char* inbuf)
+{
+  char outbuf[NET_BUF_LEN];
+  char* p;
+  int id;
+
+  if(!inbuf)
+    return;
+
+  //parse inbuf to get question id:
+  p = strchr(inbuf, '\t');
+  if(!p)
+    return; 
+  p++;
+  id = atoi(p);
+
+  //Tell mathcards so lists get updated:
+  if(!MC_NotAnsweredCorrectly(id))
+    return;
+  //If we get to here, the id was successfully parsed out of inbuf
+  //and the corresponding question was found.
+
+  //Announcement for server and all clients:
+  snprintf(outbuf, NET_BUF_LEN, 
+          "question id %d was missed by %s\n",
+          id, client[i].name);             
+  broadcast_msg(outbuf);
+  //Tell all players to remove that question:
+  remove_question(id);
+  //send the next question to everyone:
+  game_msg_next_question();
+  //and update the game counters:
+  send_counter_updates();
+}
+
+
+
+void game_msg_next_question(void)
+{
+  MC_FlashCard flash;
+
+  /* Get next question from MathCards: */
+  if (!MC_NextQuestion(&flash))
+  { 
+    /* no more questions available */
+    printf("MC_NextQuestion() returned NULL - no questions available\n");
+    return;
+  }
+
+  DEBUGMSG(debug_lan, "In game_msg_next_question(), about to send:\n");
+  DEBUGCODE(debug_lan) print_card(flash); 
+
+  /* Send it to all the clients: */ 
+  add_question(&flash);
+}
+
+
+
+
+
+void game_msg_exit(int i)
+{
+  printf("LEFT the GAME : %s",client[i].name);
+  remove_client(i);
+}
+
+
+
+//FIXME don't think we want to allow players to shut down the server
+void game_msg_quit(int i)
+{
+  printf("Server has been shut down by %s\n", client[i].name); 
+  cleanup_server();
+  exit(9);                           // '9' means exit ;)  (just taken an arbitary no:)
+}
+
+
+/* Now this gets called to actually start the game once all the players */
+/* have indicated that they are ready:                                  */
+void start_game(void)
+{
+  char buf[NET_BUF_LEN];
+  int j;
+
+
+  /* NOTE this should no longer be needed - doing the same thing earlier    */
+  /*This loop sees that the game starts only when all the players are ready */
+  /* i.e. if someone is connected but not ready, we return.                 */
+  for(j = 0; j < MAX_CLIENTS; j++)
+  {
+    // Only check sockets that aren't null:
+    if((client[j].game_ready != 1)
+    && (client[j].sock != NULL))
+    {
+      printf("Warning - start_game() entered when someone not ready\n");
+      return;      
+    }
+  }
+
+
+ /***********************Will be modified**************/
+  //Tell everyone we are starting and count who's really in:
+  num_clients = 0;
+  snprintf(buf, NET_BUF_LEN, 
+          "%s\n",
+          "GO_TO_GAME");          
+  for(j = 0; j < MAX_CLIENTS; j++)
+  {
+    if((client[j].game_ready == 1)
+    && (client[j].sock != NULL))
+    {
+      if(SDLNet_TCP_Send(client[j].sock, buf, NET_BUF_LEN) == NET_BUF_LEN)
+        num_clients++;
+      else
+      {
+        printf("in start_game() - failed to send to client %d, removing\n", j);
+        remove_client(j);
+      }
+    }
+  }
+ /*****************************************************/
+
+
+  /* If no players join the game (should not happen) */
+  if(num_clients == 0)
+  {
+    printf("There were no players........=(\n");
+    return;
+  }
+
+  DEBUGMSG(debug_lan, "We have %d players.......\n", num_clients);
+
+  game_in_progress = 1;  //setting the game_in_progress flag to '1'
+  //Start a new math game as far as mathcards is concerned:
+  if (!MC_StartGame())
+  {
+    fprintf(stderr, "\nMC_StartGame() failed!");
+    return;
+  }
+
+  game_in_progress = 1;
+
+  // Zero out scores:
+  for(j = 0; j < MAX_CLIENTS; j++)
+    client[j].score = 0;
+
+  /* Send enough questions to fill the initial comet slots (currently 10) */
+  for(j = 0; j < QUEST_QUEUE_SIZE; j++)
+  {
+    if (!MC_NextQuestion(&flash))
+    { 
+      /* no more questions available */
+      printf("MC_NextQuestion() returned NULL - no questions available\n");
+      return;
+    }
+
+    DEBUGMSG(debug_lan, "In start_game(), about to send:\n");
+    DEBUGCODE(debug_lan) print_card(flash); 
+
+    //Send to all clients with add_question();
+    add_question(&flash);
+  }
+  //Send all the clients the counter totals:
+  send_counter_updates();
+  send_score_updates();
+}
+
+
+
+//More centralized function to update the clients of the number of 
+//questions remaining, whether the mission has been accomplished,
+//and so forth:
+int send_counter_updates(void)
+{
+  int total_questions;
+
+  //If game won, tell everyone:
+  if(MC_MissionAccomplished())
+  {
+    char buf[NET_BUF_LEN];
+    snprintf(buf, NET_BUF_LEN, "%s", "MISSION_ACCOMPLISHED");
+    transmit_all(buf);
+  }
+
+  //Tell everyone how many questions left:
+  total_questions = MC_TotalQuestionsLeft();
+  {
+    char buf[NET_BUF_LEN];
+    snprintf(buf, NET_BUF_LEN, "%s\t%d", "TOTAL_QUESTIONS", total_questions);
+    transmit_all(buf);
+  }
+  return 1;
+}
+
+
+int send_score_updates(void)
+{
+  int i = 0;
+
+  /* Count how many players are active and send number to clients: */
+  {
+    int connected_players = 0;
+    char buf[NET_BUF_LEN];
+    for(i = 0; i < MAX_CLIENTS; i++)
+      if((client[i].game_ready == 1) && (client[i].sock != NULL))
+        connected_players++;
+
+    snprintf(buf, NET_BUF_LEN, "%s\t%d", "CONNECTED_PLAYERS",
+             connected_players);
+    transmit_all(buf);
+  }
+
+  /* Now send out all the names and scores: */
+  for(i = 0; i < MAX_CLIENTS; i++)
+  {
+    if((client[i].game_ready == 1)
+    && (client[i].sock != NULL))
+    {
+      char buf[NET_BUF_LEN];
+      snprintf(buf, NET_BUF_LEN, "%s\t%d\t%s\t%d", "UPDATE_SCORE",
+               i,
+               client[i].name,
+               client[i].score);
+      transmit_all(buf);
+    }
+  }
+
+  return 1;
+}
+
+
+/* Sends a new question to all clients: */
+int add_question(MC_FlashCard* fc)
+{
+  char buf[NET_BUF_LEN];
+
+  if(!fc)
+    return 0;
+
+  snprintf(buf, NET_BUF_LEN,"%s\t%d\t%d\t%d\t%s\t%s\n",
+                "ADD_QUESTION",
+                fc->question_id,
+                fc->difficulty,
+                fc->answer,
+                fc->answer_string,
+                fc->formula_string);
+  transmit_all(buf);
+  return 1;
+}
+
+/* Tells all clients to remove a specific question: */
+int remove_question(int id)
+{
+  char buf[NET_BUF_LEN];
+  snprintf(buf, NET_BUF_LEN, "%s\t%d", "REMOVE_QUESTION", id);
+  transmit_all(buf);
+  return 1;
+}
+
+
+/* Sends a string for the client to display to player: */
+int player_msg(int i, char* msg)
+{
+  char buf[NET_BUF_LEN];
+  if(!msg)
+  {
+    DEBUGMSG(debug_lan, "player_msg() - msg argument is NULL\n");
+    return 0;
+  }
+
+  /* Add header: */
+  snprintf(buf, NET_BUF_LEN, "%s\t%s", "PLAYER_MSG", msg);
+  //NOTE transmit() validates index and socket
+  return transmit(i, buf);
+}
+
+/* Send a player message to all clients: */
+void broadcast_msg(char* msg)
+{
+  int i = 0;
+  if (!msg)
+    return;
+  for(i = 0; i < MAX_CLIENTS; i++)
+    player_msg(i, msg);
+}
+
+/* Send string to client. String should already have its header */ 
+int transmit(int i, char* msg)
+{
+  char buf[NET_BUF_LEN];
+
+  //Validate arguments;
+  if(i < 0 || i > MAX_CLIENTS)
+  {
+    DEBUGMSG(debug_lan,"transmit() - invalid index argument\n");
+    return 0;
+  }
+
+  if(!msg)
+  {
+    DEBUGMSG(debug_lan, "transmit() - msg argument is NULL\n");
+    return 0;
+  }
+  
+  if(!client[i].sock)
+  {
+    return 0;
+  }
+  
+  //NOTE SDLNet's Send() keeps sending until the requested length is
+  //sent, so it really is an error if we send less thatn NET_BUF_LEN
+  snprintf(buf, NET_BUF_LEN, "%s", msg);
+  if(SDLNet_TCP_Send(client[i].sock, buf, NET_BUF_LEN) < NET_BUF_LEN)
+  {
+    printf("The client %s is disconnected\n", client[i].name);
+    remove_client(i);
+    return 0;
+  }
+  //Success:
+  return 1;
+}
+
+
+/* Send the message to all clients: */
+int transmit_all(char* msg)
+{
+  int i = 0;
+  if (!msg)
+    return 0;
+
+  for(i = 0; i < MAX_CLIENTS; i++)
+    transmit(i, msg);
+
+  return 1;
+}
+
+
+
+//Here we read up to max_length bytes from stdin into the buffer.
+//The first '\n' in the buffer, if present, is replaced with a
+//null terminator.
+//returns 0 if no data ready, 1 if at least one byte read.
+//NOTE for this to work we must first set stdin to O_NONBLOCK with:
+//  fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
+
+int read_stdin_nonblock(char* buf, size_t max_length)
+{
+  int bytes_read = 0;
+  char* term = NULL;
+  buf[0] = '\0';
+
+  bytes_read = fread (buf, 1, max_length, stdin);
+  term = strchr(buf, '\n');
+  if (term)
+    *term = '\0';
+     
+  if(bytes_read > 0)
+    bytes_read = 1;
+  else
+    bytes_read = 0;
+      
+  return bytes_read;
+}
+
+
+
+int ServerRunning(void)
+{
+  return server_running;
+}
+
+

Copied: branches/commonification/tuxmath/trunk/src/server.h (from rev 1657, tuxmath/trunk/src/server.h)
===================================================================
--- branches/commonification/tuxmath/trunk/src/server.h	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/server.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,72 @@
+/*
+
+        server.h
+
+        Author: David Bruce, Akash Gangil and the TuxMath team, (C) 2009
+
+        Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
+
+*/
+
+#ifndef SERVER_H
+#define SERVER_H == 1)
+
+#include "SDL_net.h"
+
+
+#define NAME_SIZE 50
+#define DEFAULT_SERVER_NAME "TuxMath LAN Server"
+#define SERVER_NAME_TIMEOUT 30000
+
+typedef struct client_type {
+  int game_ready;   //game_ready = 1 means client has said OK to start
+  char name[NAME_SIZE];
+  int score;
+  TCPsocket sock;
+}client_type;
+
+  
+ 
+/*enum for commands coming from the client side*/
+// enum {
+//   EXIT,
+//   QUIT,
+//   CORRECT_ANSWER,
+//   NOT_ANSWERED_CORRECTLY,
+//   NEXT_QUESTION,
+//   TOTAL_QUESTIONS_LEFT
+// };
+
+
+// /*enum for messages for SendMessage*/
+// enum {
+//   ANSWER_CORRECT,
+//   LIST_SET_UP,
+//   NO_QUESTION_LIST
+// };
+
+
+/* Ways to run the server - all accept command-line style arguments: */
+
+/* 1. Type "tuxmathserver" at command line to run as standalone program. */
+
+/* From within Tuxmath: */
+
+#ifdef HAVE_PTHREAD_H
+/* 2. Using POSIX threads library (RECOMMENDED if pthreads available on your system): */
+int RunServer_pthread(int argc, char* argv[]);
+#endif
+
+/* 3. As a standalone program using system() - same as "tuxmathserver" at console:    */
+int RunServer_prog(int argc, char* argv[]);
+
+/* TODO 4. Using old-school Unix fork() call: */
+int RunServer_fork(int argc, char* argv[]);
+
+/* 2, 3, and 4 all return immediately, with the server running in a separate thread or process.  But if you don't mind waiting... */
+/* 5. Plain "blocking" function call, leaving scheduling issues up to you: */
+int RunServer(int argc, char **argv);
+
+/* Find out if server is already running: */
+int ServerRunning(void);
+#endif

Copied: branches/commonification/tuxmath/trunk/src/servermain.c (from rev 1657, tuxmath/trunk/src/servermain.c)
===================================================================
--- branches/commonification/tuxmath/trunk/src/servermain.c	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/servermain.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,23 @@
+/*
+*  C Implementation: servermain.c
+*
+*       Description: main() function to allow standalone use of server program for 
+*       LAN-based play in Tux,of Math Command.
+*
+*
+* Author: David Bruce and the TuxMath team, (C) 2009
+* Developers list: <tuxmath-devel at lists.sourceforge.net>
+*
+* Copyright: See COPYING file that comes with this distribution.  (Briefly, GNU GPL).
+*
+*/
+
+#include "server.h"
+
+/* This function has to be in its own file that is not linked into tuxmath */
+/* itself because there can only be one main() in a program.  All of the   */
+/* server functionality is contained in server.h and server.c              */
+int main(int argc, char** argv)
+{
+  return RunServer(argc, argv);
+}

Modified: branches/commonification/tuxmath/trunk/src/setup.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/setup.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/setup.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -43,7 +43,6 @@
 #include "mathcards.h"
 #include "setup.h"
 #include "fileops.h"
-#include "fileops_media.h"
 #include "loaders.h"
 #include "game.h"
 #include "menu.h"
@@ -98,6 +97,22 @@
 
 void cleanup_memory(void);
 
+/*
+HACK these two getters are declared in fileops.h and don't seem to be 
+implemented anywhere else, but can only belong here...
+*/
+sprite* GetSprite(int id)
+{
+  if (id >= NUM_SPRITES)
+    return NULL;
+  return sprites[id];
+}
+SDL_Surface* GetImage(int id)
+{
+  if (id >= NUM_IMAGES)
+    return NULL;
+  return images[id];
+}
 
 
 /* --- Set-up function - now in four easier-to-digest courses! --- */
@@ -273,7 +288,8 @@
              strcmp(argv[i], "-c") == 0)
     {
       printf(
-        "\n\"Tux, of Math Command\" version " VERSION ", Copyright (C) 2001 Bill Kendrick\n"
+        "\n\"Tux, of Math Command\" version " VERSION ", Copyright (C) 2001-2009,\n"
+        "Bill Kendrick, David Bruce, Tim Holy, and the Tux4Kids Project.\n"
         "This program is free software; you can redistribute it and/or\n"
         "modify it under the terms of the GNU General Public License\n"
         "as published by the Free Software Foundation.  See COPYING.txt\n"

Copied: branches/commonification/tuxmath/trunk/src/testclient.c (from rev 1657, tuxmath/trunk/src/testclient.c)
===================================================================
--- branches/commonification/tuxmath/trunk/src/testclient.c	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/testclient.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,536 @@
+/*
+*  C Implementation: server.c
+*
+*       Description: Test client program for LAN-based play in Tux,of Math Command.
+*
+*
+* Author: Akash Gangil, David Bruce, and the TuxMath team, (C) 2009
+* Developers list: <tuxmath-devel at lists.sourceforge.net>
+*
+* Copyright: See COPYING file that comes with this distribution.  (Briefly, GNU GPL).
+*
+* NOTE: This file was initially based on example code from The Game Programming Wiki
+* (http://gpwiki.org), in a tutorial covered by the GNU Free Documentation License 1.2.
+* No invariant sections were indicated, and no separate license for the example code
+* was listed. The author was also not listed. AFAICT,this scenario allows incorporation of
+* derivative works into a GPLv2+ project like TuxMath - David Bruce 
+*/
+
+#include "globals.h"
+#include "transtruct.h"
+#include "mathcards.h"
+#include "testclient.h"
+#include "throttle.h"
+#include "network.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h> 
+
+//#include "SDL_net.h"
+
+/* Local (to testclient.c) "globals": */
+
+int quit = 0;
+int game_status = GAME_NOT_STARTED;
+
+MC_FlashCard comets[QUEST_QUEUE_SIZE];    //current questions
+int remaining_quests = 0;
+
+
+/* Local function prototypes: */
+int playgame(void);
+int erase_flashcard(MC_FlashCard* fc);
+MC_FlashCard* find_comet_by_id(int id);
+MC_FlashCard* check_answer(int ans);
+
+int read_stdin_nonblock(char* buf, size_t max_length);
+
+/* Functions to handle messages from server: */
+int game_check_msgs(void);
+int add_quest_recvd(char* buf);
+int remove_quest_recvd(char* buf);
+int player_msg_recvd(char* buf);
+int total_quests_recvd(char* buf);
+int mission_accompl_recvd(char* buf);
+
+/* Display to player: */
+void print_current_quests(void);
+
+/* Main function: ------------------------------------- */
+
+int main(int argc, char **argv)
+{
+  char buffer[NET_BUF_LEN];  // for command-line input
+  int servers_found = 0;
+  int server_number = -1;
+  Uint32 timer = 0;
+
+  //Scan local network to find running server:
+  servers_found = LAN_DetectServers();
+
+  if(servers_found < 1)
+  {
+    printf("No server could be found - exiting.\n");
+    exit(EXIT_FAILURE);
+  }
+  else if(servers_found  == 1)  //One server - connect without player intervention
+  {
+    printf("Single server found - connecting automatically...");
+
+    if(!LAN_AutoSetup(0))  //i.e.first (and only) entry in list
+    {
+      printf("setup_client() failed - exiting.\n");
+      exit(EXIT_FAILURE);
+    }
+
+    printf("connected\n");
+  } 
+
+
+  else  // More than one server - will have to get player selection:
+  {
+    while(server_number < 0 || server_number >= servers_found)
+    {
+      printf("The following TuxMath servers were detected:\n");
+      print_server_list();
+      printf("Enter the SERVER NUMBER you would like to connect to:\n");
+      scanf("%d", &server_number);
+      if(server_number < 0 || server_number >= servers_found)
+        printf("Illegal value - try again.\n");
+    }
+    if(!LAN_AutoSetup(server_number))  //i.e.first (and only) entry in list
+    {
+      printf("setup_client() failed - exiting.\n");
+      exit(EXIT_FAILURE);
+    }
+
+    printf("connected\n");
+  }
+  
+
+  /* Now we are connected - get nickname from player: */
+  {
+    char name[NAME_SIZE];
+    char* p;
+
+    printf("Please enter your name:\n>\n");
+    fgets(buffer, NAME_SIZE, stdin);
+    p = strchr(buffer, '\n');  //get rid of newline character
+    if(p)
+      *p = '\0';
+    strncpy(name, buffer, NAME_SIZE);
+    /* If no nickname received, use default: */
+    if(strlen(name) == 1)
+      strcpy(name, "Anonymous Coward");
+
+    snprintf(buffer, NET_BUF_LEN, "%s", name);
+    LAN_SetName(name);
+  }
+
+  printf("Welcome to the Tux Math Test Client!\n");
+  printf("Type:\n"
+         "'game' to start math game;\n"
+         "'exit' to end client leaving server running;\n"
+         "'quit' to end both client and server\n>\n"); 
+
+  
+  /* Set stdin to be non-blocking: */
+  fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
+
+
+  quit = 0;
+  while(!quit)
+  { 
+    // See if we have any messages from server:
+    game_check_msgs();
+
+    //Get user input from command line and send it to server: 
+    /*now display the options*/
+    if(read_stdin_nonblock(buffer, NET_BUF_LEN))
+    { 
+      //Figure out if we are trying to quit:
+      if( (strncmp(buffer, "exit", 4) == 0)
+        ||(strncmp(buffer, "quit", 4) == 0))
+      
+      {
+        quit = 1;
+      }
+      else if (strncmp(buffer, "game", 4) == 0)
+      {
+        // Begin the actual math game
+        playgame();
+        printf("Math game finished.\n\n");
+        printf("Type:\n"
+               "'game' to start math game;\n"
+               "'exit' to end client leaving server running;\n"
+               "'quit' to end both client and server\n>\n"); 
+      }
+      else
+      {
+        printf("Command not recognized. Type:\n"
+               "'game' to start math game;\n"
+               "'exit' to end client leaving server running;\n"
+               "'quit' to end both client and server\n\n>\n");
+      }
+    }
+    //Limit loop to once per 10 msec so we don't eat all CPU
+    Throttle(10, &timer);
+  }
+ 
+  LAN_Cleanup();
+ 
+  return EXIT_SUCCESS;
+}
+
+
+
+
+
+int game_check_msgs(void)
+{
+  char buf[NET_BUF_LEN];
+  int status = 1;
+  while(1)
+  {
+    buf[0] = '\0';
+    status = LAN_NextMsg(buf);
+    if (status == -1)  //Fatal error
+    {
+      printf("Error - LAN_NextMsg() returned -1\n");
+      return -1;
+    }
+
+    if (status == 0)   //No more messages
+    {
+      break;
+    }
+
+    DEBUGMSG(debug_lan, "Buffer from server is: %s\n", buf);
+
+    /* Now we process the buffer according to the command: */
+    if(strncmp(buf, "SEND_QUESTION", strlen("SEND_QUESTION")) == 0)
+    {
+      if(!add_quest_recvd(buf))
+        printf("SEND_QUESTION received but could not add question\n");
+      else
+        // If we successfully added question, show new questions to user:
+        print_current_quests();
+    }
+    else if(strncmp(buf, "ADD_QUESTION", strlen("ADD_QUESTION")) == 0)
+    {
+      if(!add_quest_recvd(buf))
+        printf("ADD_QUESTION received but could not add question\n");
+      else  
+        print_current_quests();
+    }
+    else if(strncmp(buf, "REMOVE_QUESTION", strlen("REMOVE_QUESTION")) == 0)
+    {
+      if(!remove_quest_recvd(buf)) //remove the question with id in buf
+        printf("REMOVE_QUESTION received but could not remove question\n");
+      else 
+        print_current_quests();
+    }
+    else if(strncmp(buf, "SEND_MESSAGE", strlen("SEND_MESSAGE")) == 0)
+    {
+      printf("%s\n", buf);
+    }
+    else if(strncmp(buf, "PLAYER_MSG", strlen("PLAYER_MSG")) == 0)
+    {
+      player_msg_recvd(buf);
+    }
+    else if(strncmp(buf, "TOTAL_QUESTIONS", strlen("TOTAL_QUESTIONS")) == 0)
+    {
+      //update the "questions remaining" counter
+      total_quests_recvd(buf);
+    }
+    else if(strncmp(buf, "MISSION_ACCOMPLISHED", strlen("MISSION_ACCOMPLISHED")) == 0)
+    {
+      game_status = GAME_OVER_WON; 
+    }
+    else 
+    {
+      printf("game_check_msgs() - unrecognized message: %s\n", buf);
+    }
+  }
+
+  return 1;
+}
+
+
+
+int add_quest_recvd(char* buf)
+{
+  MC_FlashCard* fc = find_comet_by_id(-1);
+
+  if(!fc || !buf)
+  {
+    printf("NULL fc or buf\n");
+    return 0;
+  }
+  /* function call to parse buffer and receive question */
+  if(!Make_Flashcard(buf, fc))
+  {
+    printf("Unable to parse buffer into FlashCard\n");
+    return 0;
+  }
+
+  return 1;
+}
+
+
+
+int remove_quest_recvd(char* buf)
+{
+  int id = 0;
+  char* p = NULL;
+  MC_FlashCard* fc = NULL;
+
+  if(!buf)
+    return 0;
+
+  p = strchr(buf, '\t');
+  if(!p)
+    return 0;
+
+  id = atoi(p);
+  fc = find_comet_by_id(id);
+  if(!fc)
+    return 0;
+
+  erase_flashcard(fc);
+  return 1;
+}
+
+
+
+/* This function prints the 'msg' part of the buffer (i.e. everything */
+/* after the first '\t') to stdout.                                   */
+int player_msg_recvd(char* buf)
+{
+  char* p;
+  if(buf == NULL)
+    return 0;
+  p = strchr(buf, '\t');
+  if(p)
+  { 
+    p++;
+    printf("%s\n", p);
+    return 1;
+  }
+  else
+    return 0;
+}
+
+
+int total_quests_recvd(char* buf)
+{
+  char* p;
+  if(buf == NULL)
+    return 0;
+  p = strchr(buf, '\t');
+  if(p)
+  { 
+    p++;
+    remaining_quests = atoi(p); 
+    return 1;
+  }
+  else
+    return 0;
+}
+
+
+
+
+
+
+int playgame(void)
+{
+  int ans = 0;
+  MC_FlashCard* fc = NULL;
+  char buf[NET_BUF_LEN];
+  Uint32 timer = 0;
+
+  printf("\nStarting Tux, of the Math Command Line ;-)\n");
+  printf("Waiting for other players to be ready...\n\n");
+
+  //Tell server we're ready to start:
+  LAN_StartGame(); 
+  game_status = GAME_IN_PROGRESS;
+
+  /* Start out with our "comets" empty: */
+  {
+    int i;
+    for(i = 0; i < QUEST_QUEUE_SIZE; i ++)
+      erase_flashcard(&comets[i]);
+  }
+
+  //Begin game loop:
+  while (game_status == GAME_IN_PROGRESS)
+  {
+
+    //Check our network messages, bailing out for fatal errors:
+    if (game_check_msgs() == -1)
+      return -1;
+
+
+    //Now we check for any user responses
+
+    //This function returns 1 and updates buf with input from
+    //stdin if input is present.
+    //If no input, it returns 0 without blocking or waiting
+    if(read_stdin_nonblock(buf, NET_BUF_LEN))
+    {
+      //While in game, these just quit the current math game:
+      if ((strncmp(buf, "quit", 4) == 0)
+        ||(strncmp(buf, "exit", 4) == 0)
+        ||(strncmp(buf, "q", 1) == 0))
+      {
+        game_status = GAME_OVER_ESCAPE;
+//        end = 1;   //Exit our loop in playgame()
+        //Tell server we are quitting current game:
+        LAN_LeaveGame();
+      }
+      else
+      {
+        /*NOTE atoi() will return zero for any string that is not
+        a valid int, not just '0' - should not be a big deal for
+        our test program - DSB */
+        ans = atoi(buf);
+        fc = check_answer(ans);
+        if((fc != NULL))
+        {  
+          printf("%s is correct!\nAwait next question...\n>\n", buf);
+          //Tell server we answered it right:
+          //NOTE the '-1' means we aren't tracking times for testclient
+          LAN_AnsweredCorrectly(fc->question_id, -1);
+          erase_flashcard(fc);  
+          print_current_quests();
+        }
+        else  //we got input, but not the correct answer:
+        {
+          int i = rand()%QUEST_QUEUE_SIZE;
+          printf("Sorry, %s is incorrect. Try again!\n", buf); 
+          // Can't tell which question was the 'wrong' one, so we
+          // a non-empty one at random.  Note that this is just for 
+          // purposes of testing LAN_NotAnsweredCorrectly()
+          while(-1 == comets[i].question_id)
+            i = rand()%QUEST_QUEUE_SIZE;
+          LAN_NotAnsweredCorrectly(comets[i].question_id);
+          print_current_quests();
+        }
+      }  //input wasn't any of our keywords
+    } // Input was received 
+
+    Throttle(10, &timer);  //so don't eat all CPU
+  } //End of game loop 
+
+  switch(game_status)
+  {
+    case GAME_OVER_ESCAPE:
+      printf("You quit :(\n");
+      break;
+    case GAME_OVER_WON:
+      printf("You won! :-)\n");
+  }
+
+  DEBUGMSG(debug_lan, "Leaving playgame()\n");
+
+  return 1;
+}
+
+
+
+
+//Here we read up to max_length bytes from stdin into the buffer.
+//The first '\n' in the buffer, if present, is replaced with a
+//null terminator.
+//returns 0 if no data ready, 1 if at least one byte read.
+//NOTE for this to work we must first set stdin to O_NONBLOCK with:
+//  fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
+
+int read_stdin_nonblock(char* buf, size_t max_length)
+{
+  int bytes_read = 0;
+  char* term = NULL;
+  buf[0] = '\0';
+
+  bytes_read = fread (buf, 1, max_length, stdin);
+  term = strchr(buf, '\n');
+  if (term)
+    *term = '\0';
+     
+  if(bytes_read > 0)
+    bytes_read = 1;
+  else
+    bytes_read = 0;
+      
+  return bytes_read;
+}
+
+/* Display the current questions and the number of remaining questions: */
+void print_current_quests(void)
+{
+  int i;
+  printf("\n------------  Current Questions:  -----------\n");
+  for(i = 0; i < QUEST_QUEUE_SIZE; i ++)
+  { 
+    if(comets[i].question_id != -1)
+      printf("Comet %d - question %d:\t%s\n", i, comets[i].question_id, comets[i].formula_string);
+    else
+      printf("Comet %d:\tEmpty\n", i);
+  }
+  printf("-----------------------------------------------\n");
+}
+
+
+int erase_flashcard(MC_FlashCard* fc)
+{
+  if(!fc)
+    return 0;
+  fc->formula_string[0] = '\0';
+  fc->answer_string[0] = '\0';
+  fc->question_id = -1;
+  fc->answer = -9999;
+  fc->difficulty = 0;
+  return 1;
+}
+
+
+/* Return a pointer to an empty comet slot, */
+/* returning NULL if no vacancy found:      */
+
+MC_FlashCard* find_comet_by_id(int id)
+{
+  int i = 0;
+  for(i = 0; i < QUEST_QUEUE_SIZE; i++)
+  {
+    if(comets[i].question_id == id)
+      return &comets[i];
+  }
+  //if we don't find a match:
+  return NULL;
+}
+
+/* Check the "comets" in order to see if the given */
+/* value matches the answer for any of the comets: */
+/* Returns a pointer to the matching comet, or     */
+/* NULL if the answer doesn't match:               */
+
+MC_FlashCard* check_answer(int ans)
+{
+  int i = 0;
+  for(i = 0; i < QUEST_QUEUE_SIZE; i++)
+  {
+    /* Make sure we don't "match" an empty question with a zero answer: */
+    if( (comets[i].question_id != -1)
+     && (comets[i].answer == ans))
+   
+      return &comets[i];
+  }
+  //if we don't find a matching question:
+  return NULL;
+}

Copied: branches/commonification/tuxmath/trunk/src/testclient.h (from rev 1657, tuxmath/trunk/src/testclient.h)
===================================================================
--- branches/commonification/tuxmath/trunk/src/testclient.h	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/testclient.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,35 @@
+/*
+
+        testclient.h
+
+        Description: As of now it conatinsthe enum, which identifies
+        the network commands , as they are added(WORK IN PROGRESS).
+
+        Author: David Bruce ,Akash Gangil and the TuxMath team, (C) 2009
+
+        Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
+
+*/
+
+#ifndef TESTCLIENT_H
+#define TESTCLIENT_H
+
+
+enum {
+  GAME_NOT_STARTED,
+  GAME_IN_PROGRESS,
+  GAME_OVER_WON,
+  GAME_OVER_LOST,
+  GAME_OVER_OTHER,
+  GAME_OVER_ESCAPE,
+  GAME_OVER_WINDOW_CLOSE,
+  GAME_OVER_CHEATER,
+  GAME_OVER_ERROR
+};
+
+
+enum {
+  SEND_QUESTION
+};
+
+#endif

Copied: branches/commonification/tuxmath/trunk/src/throttle.c (from rev 1657, tuxmath/trunk/src/throttle.c)
===================================================================
--- branches/commonification/tuxmath/trunk/src/throttle.c	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/throttle.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,45 @@
+/*
+*  C Implementation: network.c
+*
+*         Description: A simple function that uses SDL_Delay() to keep 
+*                      loops from eating all available CPU.
+
+*
+* Author: David Bruce, and the TuxMath team, (C) 2009
+* Developers list: <tuxmath-devel at lists.sourceforge.net>
+*
+* Copyright: See COPYING file that comes with this distribution.  (Briefly, GNU GPL).
+*/
+
+
+#include "SDL.h"
+
+/* NOTE now store the time elsewhere to make function thread-safe                          */
+
+void Throttle(int loop_msec, Uint32* last_t)
+{
+  Uint32 now_t, wait_t;
+
+  if(!last_t)
+    return;
+
+  //Target loop time must be between 0 and 1000 msec:
+  if(loop_msec < 0)
+    loop_msec = 0;
+  if(loop_msec > 1000)
+    loop_msec = 1000;
+
+  //See if we need to wait:
+  now_t = SDL_GetTicks();
+  if (now_t < (*last_t + loop_msec))
+  {
+    wait_t = (*last_t + loop_msec) - now_t;
+    //Avoid problem if we somehow wrap past uint32 size (at 49.7 days!)
+    if(wait_t < 0)
+      wait_t = 0;
+    if(wait_t > loop_msec)
+      wait_t = loop_msec;
+    SDL_Delay(wait_t);
+  }
+  *last_t = SDL_GetTicks();
+}

Copied: branches/commonification/tuxmath/trunk/src/throttle.h (from rev 1657, tuxmath/trunk/src/throttle.h)
===================================================================
--- branches/commonification/tuxmath/trunk/src/throttle.h	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/throttle.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,24 @@
+/*
+
+        throttle.h
+
+        Description: A simple function that uses SDL_Delay() to keep loops from eating all available
+                     CPU
+        Author: David Bruce and the TuxMath team, (C) 2009
+
+        Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
+
+*/
+
+#ifndef THROTTLE_H
+#define THROTTLE_H
+
+#include "SDL.h"
+
+// This simple function uses SDL_Delay() to wait to return until 'loop_msec'
+// milliseconds after it returned the last time. Per SDL docs, the granularity
+// is likely no better than 10 msec
+// NOTE Uint32* last_t arg added to make function thread-safe
+void Throttle(int loop_msec, Uint32* last_t);
+
+#endif

Modified: branches/commonification/tuxmath/trunk/src/titlescreen.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/titlescreen.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/titlescreen.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -33,11 +33,11 @@
 #include "mathcards.h"
 #include "campaign.h"
 #include "fileops.h"
-#include "fileops_media.h"
 #include "setup.h"
 #include "loaders.h"
 #include "SDL_extras.h"
 #include "menu.h"
+#include "throttle.h"
 
 //NOTE tuxmath.h takes care of this:
 //#ifdef HAVE_LIBT4KCOMMON
@@ -141,6 +141,7 @@
   /* This syntax makes my brain start to explode! */
   { return GetScreen()->flags & SDL_FULLSCREEN ? fs_bkg : win_bkg; }
 
+/* FIXME don't we have to scale these? */
 void set_current_bkg(SDL_Surface* new_bkg)
 {
   if(GetScreen()->flags & SDL_FULLSCREEN)
@@ -263,7 +264,7 @@
   /* NOTE: do we need this ? */
   DEBUGCODE(debug_titlescreen)
     SDL_WM_GrabInput(SDL_GRAB_OFF); /* in case of a freeze, this traps the cursor */
-  else
+  else  // NOTE- the accompanying "if" is inside the DEBUGCODE macro
     SDL_WM_GrabInput(SDL_GRAB_ON);  /* User input goes to TuxMath, not window manager */
   SDL_ShowCursor(1);
 
@@ -566,7 +567,8 @@
       break;
 
     case RUN_INFO:
-      ShowMessage(_("TuxMath is free and open-source!"),
+      ShowMessage(DEFAULT_MENU_FONT_SIZE,
+                  _("TuxMath is free and open-source!"),
                   _("You can help make it better by reporting problems,"),
                   _("suggesting improvements, or adding code."),
                   _("Discuss the future at tuxmath-devel at lists.sourceforge.net"));
@@ -689,7 +691,7 @@
   s2 = _("to create customized game!");
   s3 = _("Press a key or click your mouse to start game.");
   s4 = _("See README.txt for more information");
-  ShowMessage(s1, s2, s3, s4);
+  ShowMessage(DEFAULT_MENU_FONT_SIZE, s1, s2, s3, s4);
 
   if (read_user_config_file()) {
     AudioMusicUnload();
@@ -933,34 +935,36 @@
   s3 = _("Discuss the future of TuxMath at");
   s4 = N_("tuxmath-devel at lists.sourceforge.net");
 
-  ShowMessage(s1, s2, s3, s4);
+  ShowMessage(DEFAULT_MENU_FONT_SIZE, s1, s2, s3, s4);
 }
 
 
 
 
 
-/* FIXME add some background shading to improve legibility */
-void ShowMessage(const char* str1, const char* str2, const char* str3, const char* str4)
+void ShowMessage(int font_size, const char* str1, const char* str2,
+                 const char* str3, const char* str4)
 {
   SDL_Surface *s1, *s2, *s3, *s4;
   SDL_Rect loc;
   int finished = 0;
-  Uint32 frame = 0;
-  Uint32 start = 0;
+  Uint32 timer = 0;
 
+  /* To adjust font size: */
+  float scale = screen->w / 640;
+
   s1 = s2 = s3 = s4 = NULL;
 
   DEBUGMSG(debug_titlescreen, "ShowMessage() - creating text\n" );
 
   if (str1)
-    s1 = BlackOutline(str1, DEFAULT_MENU_FONT_SIZE, &white);
+    s1 = BlackOutline(str1, font_size * scale, &white);
   if (str2)
-    s2 = BlackOutline(str2, DEFAULT_MENU_FONT_SIZE, &white);
+    s2 = BlackOutline(str2, font_size * scale, &white);
   if (str3)
-    s3 = BlackOutline(str3, DEFAULT_MENU_FONT_SIZE, &white);
+    s3 = BlackOutline(str3, font_size * scale, &white);
   if (str4)
-    s4 = BlackOutline(str4, DEFAULT_MENU_FONT_SIZE, &white);
+    s4 = BlackOutline(str4, font_size * scale, &white);
 
   DEBUGMSG(debug_titlescreen, "ShowMessage() - drawing screen\n" );
 
@@ -969,27 +973,35 @@
   if (stop_button)
     SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
 
+  /* Draw shaded background for better legibility: */ 
+  loc.x = screen->w * 0.25;
+  loc.y = screen->h * 0.1;
+  loc.w = screen->w * 0.5;
+  loc.h = screen->h * 0.8;
+  DrawButton(&loc, 50, SEL_RGBA);
+
+
   /* Draw lines of text (do after drawing Tux so text is in front): */
   if (s1)
   {
-    loc.x = (screen->w / 2) - (s1->w/2); loc.y = 10;
+    loc.x = (screen->w / 2) - (s1->w/2); loc.y = screen->h * 0.2;
     SDL_BlitSurface( s1, NULL, screen, &loc);
   }
   if (s2)
   {
-    loc.x = (screen->w / 2) - (s2->w/2); loc.y = 60;
+    loc.x = (screen->w / 2) - (s2->w/2); loc.y = screen->h * 0.35;
     SDL_BlitSurface( s2, NULL, screen, &loc);
   }
   if (s3)
   {
     //loc.x = 320 - (s3->w/2); loc.y = 300;
-    loc.x = (screen->w / 2) - (s3->w/2); loc.y = 110;
+    loc.x = (screen->w / 2) - (s3->w/2); loc.y = screen->h * 0.5;
     SDL_BlitSurface( s3, NULL, screen, &loc);
   }
   if (s4)
   {
     //loc.x = 320 - (s4->w/2); loc.y = 340;
-    loc.x = (screen->w / 2) - (s4->w/2); loc.y = 200;
+    loc.x = (screen->w / 2) - (s4->w/2); loc.y = screen->h * 0.65;
     SDL_BlitSurface( s4, NULL, screen, &loc);
   }
 
@@ -998,8 +1010,6 @@
 
   while (!finished)
   {
-    start = SDL_GetTicks();
-
     while (SDL_PollEvent(&event))
     {
       switch (event.type)
@@ -1030,11 +1040,7 @@
     HandleTitleScreenAnimations();
 
     /* Wait so we keep frame rate constant: */
-    while ((SDL_GetTicks() - start) < 33)
-    {
-      SDL_Delay(20);
-    }
-    frame++;
+    Throttle(20, &timer);
   }  // End of while (!finished) loop
 
   SDL_FreeSurface(s1);

Modified: branches/commonification/tuxmath/trunk/src/titlescreen.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/titlescreen.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/titlescreen.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -94,9 +94,11 @@
 void          DrawTitleScreen(void);
 int           HandleTitleScreenEvents(SDL_Event* evt);
 void          HandleTitleScreenAnimations();
-void          ShowMessage(const char* str1, const char* str2, const char* str3, const char* str4);
+void          ShowMessage(int font_size, const char* str1, const char* str2, const char* str3, const char* str4);
 SDL_Surface*  current_bkg(); //appropriate background for current video mode
 
+/* expecting these to be temporary BML */
+#define playsound(ID) PlaySound(sounds[ID])
 
 /* in audio.c  (from tuxtype): */
 void          PlaySound(Mix_Chunk* sound);

Copied: branches/commonification/tuxmath/trunk/src/transtruct.h (from rev 1657, tuxmath/trunk/src/transtruct.h)
===================================================================
--- branches/commonification/tuxmath/trunk/src/transtruct.h	                        (rev 0)
+++ branches/commonification/tuxmath/trunk/src/transtruct.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -0,0 +1,39 @@
+/*
+
+        transtruct.h
+
+        Description: contains headers for the data structures
+        that would be transferred between the server and the client
+        during the multiplayer LAN game.
+
+        Author: David Bruce ,Akash Gangil and the TuxMath team, (C) 2009
+
+        Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
+
+*/
+#ifndef TRANSTRUCT_H
+#define TRANSTRUCT_H
+
+#define NET_BUF_LEN 512
+#define DEFAULT_PORT 4779
+#define NAME_SIZE 50
+#define MAX_SERVERS 50
+#define MAX_CLIENTS 16
+
+#define MC_USE_NEWARC
+#define MC_FORMULA_LEN 40
+#define MC_ANSWER_LEN 5
+
+#define QUEST_QUEUE_SIZE 10
+
+
+typedef struct _MC_FlashCard {
+  char formula_string[MC_FORMULA_LEN];
+  char answer_string[MC_ANSWER_LEN];
+  int question_id;
+  int answer;
+  int difficulty;
+} MC_FlashCard;
+
+
+#endif

Modified: branches/commonification/tuxmath/trunk/src/tuxmath.c
===================================================================
--- branches/commonification/tuxmath/trunk/src/tuxmath.c	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/tuxmath.c	2009-11-24 23:54:32 UTC (rev 1674)
@@ -19,25 +19,22 @@
   2006-2007
 */
 
-
-#include <stdio.h>
-#include <stdlib.h>
 /* (tuxmath.h brings in "gettext.h" and <locale.h> */
 #include "tuxmath.h"
 #include "setup.h"
 #include "titlescreen.h"
+#include "linewrap.h"
 
+#include <stdio.h>
+#include <stdlib.h>
+
 #ifdef WIN32
 #define TUXLOCALE "./locale"
 #else
 #define TUXLOCALE LOCALEDIR
 #endif
 
-//#ifdef LINEBREAK
-#include "linewrap.h"
-//#endif
-
-int main(int argc, char * argv[])
+int main(int argc, char* argv[])
 {
   const char *s1, *s2, *s3, *s4;
 
@@ -46,6 +43,8 @@
   s3 = bind_textdomain_codeset(PACKAGE, "UTF-8");
   s4 = textdomain(PACKAGE);
 
+  setup(argc, argv);
+
   DEBUGMSG(debug_setup, "PACKAGE = %s\n", PACKAGE);
   DEBUGMSG(debug_setup, "TUXLOCALE = %s\n", TUXLOCALE);
   DEBUGMSG(debug_setup, "setlocale(LC_ALL, \"\") returned: %s\n", s1);
@@ -55,7 +54,6 @@
   DEBUGMSG(debug_setup, "gettext(\"Help\"): %s\n\n", gettext("Help"));
   DEBUGMSG(debug_setup, "After gettext() call\n");
 
-  setup(argc, argv);
   TitleScreen();  /* Run the game! */
   cleanup();
   return 0;

Modified: branches/commonification/tuxmath/trunk/src/tuxmath.h
===================================================================
--- branches/commonification/tuxmath/trunk/src/tuxmath.h	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/src/tuxmath.h	2009-11-24 23:54:32 UTC (rev 1674)
@@ -22,21 +22,8 @@
 #ifndef TUXMATH_H
 #define TUXMATH_H
 
-#include "config.h"
+#include "globals.h"
 
-#ifdef HAVE_LIBT4KCOMMON
-#include <t4k-common.h>
-#endif
-
-// Translation stuff (now works for Mac and Win too!): 
-#include "gettext.h"
-#include <locale.h>
-#define _(String) gettext (String)
-#define gettext_noop(String) String
-#define N_(String) gettext_noop (String)
-
-#include <wchar.h>
-
 #include "SDL.h"
 #include "SDL_image.h"
 
@@ -44,8 +31,6 @@
 #include "SDL_mixer.h"
 #endif
 
-//#define NOSOUND
-#include "globals.h"
 
 #ifndef HAVE_LIBT4KCOMMON
 #define MAX_SPRITE_FRAMES   15

Modified: branches/commonification/tuxmath/trunk/tuxmath.desktop
===================================================================
--- branches/commonification/tuxmath/trunk/tuxmath.desktop	2009-11-24 16:25:12 UTC (rev 1673)
+++ branches/commonification/tuxmath/trunk/tuxmath.desktop	2009-11-24 23:54:32 UTC (rev 1674)
@@ -1,5 +1,5 @@
 [Desktop Entry]
-Name=Tux Math
+Name=Tux Math 
 GenericName=Educational math game
 GenericName[de]=Mathe Spiel
 GenericName[ru]=Образовательная игра
@@ -15,4 +15,4 @@
 Terminal=false
 Categories=Education;Math;
 ## X-SuSE-translate=false
-X-Ubuntu-Gettext-Domain=tuxmath
\ No newline at end of file
+X-Ubuntu-Gettext-Domain=tuxmath




More information about the Tux4kids-commits mailing list