[Tux4kids-commits] r589 - in tuxmath/trunk: . data/missions data/missions/arcade data/missions/campaign data/missions/campaign/ace data/missions/campaign/cadet data/missions/campaign/commando data/missions/campaign/ranger data/missions/campaign/scout data/missions/lessons mingw src

cheezmeister-guest at alioth.debian.org cheezmeister-guest at alioth.debian.org
Wed Aug 6 02:55:08 UTC 2008


Author: cheezmeister-guest
Date: 2008-08-06 02:55:05 +0000 (Wed, 06 Aug 2008)
New Revision: 589

Added:
   tuxmath/trunk/data/missions/arcade/commando
   tuxmath/trunk/data/missions/campaign/Makefile.am
   tuxmath/trunk/data/missions/campaign/ace/Makefile.am
   tuxmath/trunk/data/missions/campaign/cadet/Makefile.am
   tuxmath/trunk/data/missions/campaign/commando/Makefile.am
   tuxmath/trunk/data/missions/campaign/ranger/Makefile.am
   tuxmath/trunk/data/missions/campaign/scout/Makefile.am
Modified:
   tuxmath/trunk/configure
   tuxmath/trunk/configure.ac
   tuxmath/trunk/data/missions/Makefile.am
   tuxmath/trunk/data/missions/arcade/Makefile.am
   tuxmath/trunk/data/missions/arcade/ace
   tuxmath/trunk/data/missions/arcade/ranger
   tuxmath/trunk/data/missions/arcade/scout
   tuxmath/trunk/data/missions/arcade/space_cadet
   tuxmath/trunk/data/missions/lessons/Makefile.am
   tuxmath/trunk/data/missions/lessons/lesson00
   tuxmath/trunk/data/missions/lessons/lesson01
   tuxmath/trunk/data/missions/lessons/lesson02
   tuxmath/trunk/data/missions/lessons/lesson03
   tuxmath/trunk/data/missions/lessons/lesson04
   tuxmath/trunk/data/missions/lessons/lesson05
   tuxmath/trunk/data/missions/lessons/lesson06
   tuxmath/trunk/data/missions/lessons/lesson07
   tuxmath/trunk/data/missions/lessons/lesson08
   tuxmath/trunk/data/missions/lessons/lesson08.1
   tuxmath/trunk/data/missions/lessons/lesson09
   tuxmath/trunk/data/missions/lessons/lesson10
   tuxmath/trunk/data/missions/lessons/lesson11
   tuxmath/trunk/data/missions/lessons/lesson12
   tuxmath/trunk/data/missions/lessons/lesson13
   tuxmath/trunk/data/missions/lessons/lesson14
   tuxmath/trunk/data/missions/lessons/lesson15
   tuxmath/trunk/data/missions/lessons/lesson16
   tuxmath/trunk/data/missions/lessons/lesson17
   tuxmath/trunk/data/missions/lessons/lesson18
   tuxmath/trunk/data/missions/lessons/lesson19
   tuxmath/trunk/data/missions/lessons/lesson20
   tuxmath/trunk/data/missions/lessons/lesson21
   tuxmath/trunk/data/missions/lessons/lesson22
   tuxmath/trunk/data/missions/lessons/lesson23
   tuxmath/trunk/data/missions/lessons/lesson24
   tuxmath/trunk/data/missions/lessons/lesson25
   tuxmath/trunk/data/missions/lessons/lesson26
   tuxmath/trunk/data/missions/lessons/lesson27
   tuxmath/trunk/data/missions/lessons/lesson28
   tuxmath/trunk/data/missions/lessons/lesson29
   tuxmath/trunk/data/missions/lessons/lesson30
   tuxmath/trunk/data/missions/lessons/lesson31
   tuxmath/trunk/data/missions/lessons/lesson32
   tuxmath/trunk/data/missions/lessons/lesson33
   tuxmath/trunk/data/missions/lessons/lesson34
   tuxmath/trunk/data/missions/lessons/lesson35
   tuxmath/trunk/data/missions/lessons/lesson36
   tuxmath/trunk/data/missions/lessons/lesson37
   tuxmath/trunk/data/missions/lessons/lesson38
   tuxmath/trunk/data/missions/lessons/lesson39
   tuxmath/trunk/data/missions/lessons/lesson40
   tuxmath/trunk/data/missions/lessons/lesson41
   tuxmath/trunk/data/missions/lessons/lesson42
   tuxmath/trunk/data/missions/lessons/lesson43
   tuxmath/trunk/data/missions/lessons/lesson44
   tuxmath/trunk/data/missions/lessons/lesson45
   tuxmath/trunk/data/missions/lessons/lesson46
   tuxmath/trunk/data/missions/lessons/lesson47
   tuxmath/trunk/data/missions/lessons/lesson48
   tuxmath/trunk/data/missions/lessons/lesson49
   tuxmath/trunk/data/missions/lessons/lesson50
   tuxmath/trunk/data/missions/lessons/lesson51
   tuxmath/trunk/data/missions/lessons/lesson52
   tuxmath/trunk/data/missions/lessons/lesson53
   tuxmath/trunk/data/missions/lessons/lesson54
   tuxmath/trunk/mingw/SDL_win32_main.c
   tuxmath/trunk/src/ConvertUTF.c
   tuxmath/trunk/src/ConvertUTF.h
   tuxmath/trunk/src/Makefile.in
   tuxmath/trunk/src/SDL_extras.c
   tuxmath/trunk/src/audio.c
   tuxmath/trunk/src/campaign.c
   tuxmath/trunk/src/credits.c
   tuxmath/trunk/src/fileops.c
   tuxmath/trunk/src/fileops.h
   tuxmath/trunk/src/game.c
   tuxmath/trunk/src/gettext.h
   tuxmath/trunk/src/highscore.c
   tuxmath/trunk/src/loaders.c
   tuxmath/trunk/src/mathcards.c
   tuxmath/trunk/src/mathcards.h
   tuxmath/trunk/src/options.c
   tuxmath/trunk/src/pixels.c
   tuxmath/trunk/src/scandir.c
   tuxmath/trunk/src/setup.c
   tuxmath/trunk/src/titlescreen.c
   tuxmath/trunk/src/titlescreen.h
   tuxmath/trunk/src/tuxmath.h
   tuxmath/trunk/src/tuxmathadmin.c
   tuxmath/trunk/src/tuxmathrc.rc
Log:
Merged mathcards branch back into trunk! As best I can tell, this 
iteration is stable.


Modified: tuxmath/trunk/configure
===================================================================
--- tuxmath/trunk/configure	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/configure	2008-08-06 02:55:05 UTC (rev 589)
@@ -17132,7 +17132,7 @@
 # Create Makefiles
 # ---------------------------------------------------------------
 
-ac_config_files="$ac_config_files Makefile data/Makefile data/fonts/Makefile data/images/Makefile data/images/backgrounds/Makefile data/images/cities/Makefile data/images/comets/Makefile data/images/icons/Makefile data/images/igloos/Makefile data/images/penguins/Makefile data/images/sprites/Makefile data/images/status/Makefile data/images/title/Makefile data/images/tux/Makefile data/missions/Makefile data/missions/arcade/Makefile data/missions/lessons/Makefile data/sounds/Makefile doc/Makefile nsis/tuxmath.nsi nsis/tuxmath_with_conf.nsi src/Makefile intl/Makefile po/Makefile.in"
+ac_config_files="$ac_config_files Makefile data/Makefile data/fonts/Makefile data/images/Makefile data/images/backgrounds/Makefile data/images/cities/Makefile data/images/comets/Makefile data/images/icons/Makefile data/images/igloos/Makefile data/images/penguins/Makefile data/images/sprites/Makefile data/images/status/Makefile data/images/title/Makefile data/images/tux/Makefile data/missions/Makefile data/missions/arcade/Makefile data/missions/campaign/Makefile data/missions/campaign/ace/Makefile data/missions/campaign/cadet/Makefile data/missions/campaign/commando/Makefile data/missions/campaign/ranger/Makefile data/missions/campaign/scout/Makefile data/missions/lessons/Makefile data/sounds/Makefile doc/Makefile nsis/tuxmath.nsi nsis/tuxmath_with_conf.nsi src/Makefile intl/Makefile po/Makefile.in"
 
 
 cat >confcache <<\_ACEOF
@@ -17759,6 +17759,12 @@
     "data/images/tux/Makefile") CONFIG_FILES="$CONFIG_FILES data/images/tux/Makefile" ;;
     "data/missions/Makefile") CONFIG_FILES="$CONFIG_FILES data/missions/Makefile" ;;
     "data/missions/arcade/Makefile") CONFIG_FILES="$CONFIG_FILES data/missions/arcade/Makefile" ;;
+    "data/missions/campaign/Makefile") CONFIG_FILES="$CONFIG_FILES data/missions/campaign/Makefile" ;;
+    "data/missions/campaign/ace/Makefile") CONFIG_FILES="$CONFIG_FILES data/missions/campaign/ace/Makefile" ;;
+    "data/missions/campaign/cadet/Makefile") CONFIG_FILES="$CONFIG_FILES data/missions/campaign/cadet/Makefile" ;;
+    "data/missions/campaign/commando/Makefile") CONFIG_FILES="$CONFIG_FILES data/missions/campaign/commando/Makefile" ;;
+    "data/missions/campaign/ranger/Makefile") CONFIG_FILES="$CONFIG_FILES data/missions/campaign/ranger/Makefile" ;;
+    "data/missions/campaign/scout/Makefile") CONFIG_FILES="$CONFIG_FILES data/missions/campaign/scout/Makefile" ;;
     "data/missions/lessons/Makefile") CONFIG_FILES="$CONFIG_FILES data/missions/lessons/Makefile" ;;
     "data/sounds/Makefile") CONFIG_FILES="$CONFIG_FILES data/sounds/Makefile" ;;
     "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;

Modified: tuxmath/trunk/configure.ac
===================================================================
--- tuxmath/trunk/configure.ac	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/configure.ac	2008-08-06 02:55:05 UTC (rev 589)
@@ -219,6 +219,12 @@
 data/images/tux/Makefile
 data/missions/Makefile
 data/missions/arcade/Makefile
+data/missions/campaign/Makefile
+data/missions/campaign/ace/Makefile
+data/missions/campaign/cadet/Makefile
+data/missions/campaign/commando/Makefile
+data/missions/campaign/ranger/Makefile
+data/missions/campaign/scout/Makefile
 data/missions/lessons/Makefile
 data/sounds/Makefile
 doc/Makefile

Modified: tuxmath/trunk/data/missions/Makefile.am
===================================================================
--- tuxmath/trunk/data/missions/Makefile.am	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/Makefile.am	2008-08-06 02:55:05 UTC (rev 589)
@@ -1,7 +1,7 @@
 ## Makefile.am for tuxmath - data/missions:
 ## Process with Automake to create Makefile.in
 
-SUBDIRS = arcade lessons
+SUBDIRS = arcade campaign lessons
 
 missionsdir = $(pkgdatadir)/missions
 

Modified: tuxmath/trunk/data/missions/arcade/Makefile.am
===================================================================
--- tuxmath/trunk/data/missions/arcade/Makefile.am	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/arcade/Makefile.am	2008-08-06 02:55:05 UTC (rev 589)
@@ -4,6 +4,7 @@
 arcadedir = $(pkgdatadir)/missions/arcade
 
 dist_arcade_DATA = ace \
+  commando \
   ranger \
   scout \
   space_cadet

Modified: tuxmath/trunk/data/missions/arcade/ace
===================================================================
--- tuxmath/trunk/data/missions/arcade/ace	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/arcade/ace	2008-08-06 02:55:05 UTC (rev 589)
@@ -8,6 +8,8 @@
 multiplication_allowed = 1
 division_allowed = 1
 allow_negatives = 1
+max_formula_nums = 2
+min_formula_nums = 2
 min_augend = -20
 max_augend = 20
 min_addend = -20

Copied: tuxmath/trunk/data/missions/arcade/commando (from rev 584, tuxmath/branches/mathcards_newarch/data/missions/arcade/commando)
===================================================================
--- tuxmath/trunk/data/missions/arcade/commando	                        (rev 0)
+++ tuxmath/trunk/data/missions/arcade/commando	2008-08-06 02:55:05 UTC (rev 589)
@@ -0,0 +1,61 @@
+# arcade commando lesson file
+
+play_through_list = 0
+allow_speedup = 1
+use_feedback = 0
+addition_allowed = 1
+subtraction_allowed = 1
+multiplication_allowed = 1
+division_allowed = 1
+allow_negatives = 1
+min_formula_nums = 3
+max_formula_nums = 4
+min_augend = -20
+max_augend = 20
+min_addend = -20
+max_addend = 20
+min_minuend = -20
+max_minuend = 20
+min_subtrahend = 0
+max_subtrahend = 20
+min_multiplier = -20
+max_multiplier = 20
+min_multiplicand = -20
+max_multiplicand = 20
+min_divisor = -20
+max_divisor = 20
+min_quotient = -20
+max_quotient = 20
+use_bkgd = 1
+demo_mode = 0
+save_summary = 1
+question_copies = 1
+repeat_wrongs = 1
+copies_repeated_wrongs = 1
+format_add_answer_last = 1
+format_add_answer_first = 1
+format_add_answer_middle = 1
+format_sub_answer_last = 1
+format_sub_answer_first = 1
+format_sub_answer_middle = 1
+format_mult_answer_last = 1
+format_mult_answer_first = 1
+format_mult_answer_middle = 1
+format_div_answer_last = 1
+format_div_answer_first = 1
+format_div_answer_middle = 1
+randomize = 1
+max_answer = 400
+starting_comets = 2
+extra_comets_per_wave = 2
+max_comets = 10
+speed = 0.25
+max_speed = 10.00
+speedup_factor = 1.125
+slow_after_wrong = 0
+max_questions = 25000
+bonus_comet_interval = 20
+fraction_to_keep = 1
+allow_pause = 0
+bonus_speed_ratio = 2.0
+

Modified: tuxmath/trunk/data/missions/arcade/ranger
===================================================================
--- tuxmath/trunk/data/missions/arcade/ranger	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/arcade/ranger	2008-08-06 02:55:05 UTC (rev 589)
@@ -8,6 +8,8 @@
 multiplication_allowed = 1
 division_allowed = 1
 allow_negatives = 0
+max_formula_nums = 2
+min_formula_nums = 2
 min_augend = 0
 max_augend = 20
 min_addend = 0

Modified: tuxmath/trunk/data/missions/arcade/scout
===================================================================
--- tuxmath/trunk/data/missions/arcade/scout	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/arcade/scout	2008-08-06 02:55:05 UTC (rev 589)
@@ -8,6 +8,8 @@
 multiplication_allowed = 0
 division_allowed = 0
 allow_negatives = 0
+max_formula_nums = 2
+min_formula_nums = 2
 min_augend = 0
 max_augend = 10
 min_addend = 0

Modified: tuxmath/trunk/data/missions/arcade/space_cadet
===================================================================
--- tuxmath/trunk/data/missions/arcade/space_cadet	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/arcade/space_cadet	2008-08-06 02:55:05 UTC (rev 589)
@@ -8,6 +8,8 @@
 multiplication_allowed = 0
 division_allowed = 0
 allow_negatives = 0
+max_formula_nums = 2
+min_formula_nums = 2
 min_augend = 0
 max_augend = 10
 min_addend = 0

Copied: tuxmath/trunk/data/missions/campaign/Makefile.am (from rev 588, tuxmath/branches/mathcards_newarch/data/missions/campaign/Makefile.am)
===================================================================
--- tuxmath/trunk/data/missions/campaign/Makefile.am	                        (rev 0)
+++ tuxmath/trunk/data/missions/campaign/Makefile.am	2008-08-06 02:55:05 UTC (rev 589)
@@ -0,0 +1,8 @@
+## Makefile.am for tuxmath - data/missions/campaign:
+## Process with Automake to create Makefile.in
+
+SUBDIRS = ace cadet commando ranger scout
+
+campaigndir = $(pkgdatadir)/missions/campaign
+
+dist_campaign_DATA = campaign

Copied: tuxmath/trunk/data/missions/campaign/ace/Makefile.am (from rev 588, tuxmath/branches/mathcards_newarch/data/missions/campaign/ace/Makefile.am)
===================================================================
--- tuxmath/trunk/data/missions/campaign/ace/Makefile.am	                        (rev 0)
+++ tuxmath/trunk/data/missions/campaign/ace/Makefile.am	2008-08-06 02:55:05 UTC (rev 589)
@@ -0,0 +1,10 @@
+## Makefile.am for tuxmath - data/missions/campaign/ace:
+## Process with Automake to create Makefile.in
+
+campaignacedir = $(pkgdatadir)/missions/campaign/ace
+
+dist_campaignace_DATA = ace \
+  bonus \
+  round1 \
+  round2 \
+  round3

Copied: tuxmath/trunk/data/missions/campaign/cadet/Makefile.am (from rev 588, tuxmath/branches/mathcards_newarch/data/missions/campaign/cadet/Makefile.am)
===================================================================
--- tuxmath/trunk/data/missions/campaign/cadet/Makefile.am	                        (rev 0)
+++ tuxmath/trunk/data/missions/campaign/cadet/Makefile.am	2008-08-06 02:55:05 UTC (rev 589)
@@ -0,0 +1,10 @@
+## Makefile.am for tuxmath - data/missions/campaign/ace:
+## Process with Automake to create Makefile.in
+
+campaigncadetdir = $(pkgdatadir)/missions/campaign/cadet
+
+dist_campaigncadet_DATA = cadet \
+  bonus \
+  round1 \
+  round2 \
+  round3

Copied: tuxmath/trunk/data/missions/campaign/commando/Makefile.am (from rev 588, tuxmath/branches/mathcards_newarch/data/missions/campaign/commando/Makefile.am)
===================================================================
--- tuxmath/trunk/data/missions/campaign/commando/Makefile.am	                        (rev 0)
+++ tuxmath/trunk/data/missions/campaign/commando/Makefile.am	2008-08-06 02:55:05 UTC (rev 589)
@@ -0,0 +1,9 @@
+## Makefile.am for tuxmath - data/missions/campaign/commando:
+## Process with Automake to create Makefile.in
+
+campaigncommandodir = $(pkgdatadir)/missions/campaign/commando
+
+dist_campaigncommando_DATA = commando \
+  round1 \
+  round2 \
+  round3

Copied: tuxmath/trunk/data/missions/campaign/ranger/Makefile.am (from rev 588, tuxmath/branches/mathcards_newarch/data/missions/campaign/ranger/Makefile.am)
===================================================================
--- tuxmath/trunk/data/missions/campaign/ranger/Makefile.am	                        (rev 0)
+++ tuxmath/trunk/data/missions/campaign/ranger/Makefile.am	2008-08-06 02:55:05 UTC (rev 589)
@@ -0,0 +1,10 @@
+## Makefile.am for tuxmath - data/missions/campaign/ranger:
+## Process with Automake to create Makefile.in
+
+campaignrangerdir = $(pkgdatadir)/missions/campaign/ranger
+
+dist_campaignranger_DATA = ranger \
+  bonus \
+  round1 \
+  round2 \
+  round3

Copied: tuxmath/trunk/data/missions/campaign/scout/Makefile.am (from rev 588, tuxmath/branches/mathcards_newarch/data/missions/campaign/scout/Makefile.am)
===================================================================
--- tuxmath/trunk/data/missions/campaign/scout/Makefile.am	                        (rev 0)
+++ tuxmath/trunk/data/missions/campaign/scout/Makefile.am	2008-08-06 02:55:05 UTC (rev 589)
@@ -0,0 +1,10 @@
+## Makefile.am for tuxmath - data/missions/campaign/scout:
+## Process with Automake to create Makefile.in
+
+campaignscoutdir = $(pkgdatadir)/missions/campaign/scout
+
+dist_campaignscout_DATA = scout \
+  bonus \
+  round1 \
+  round2 \
+  round3

Modified: tuxmath/trunk/data/missions/lessons/Makefile.am
===================================================================
--- tuxmath/trunk/data/missions/lessons/Makefile.am	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/Makefile.am	2008-08-06 02:55:05 UTC (rev 589)
@@ -1,9 +1,6 @@
 ## Makefile.am for tuxmath - data/missions/lessons:
 ## Process with Automake to create Makefile.in
 
-
-
-
 lessonsdir = $(pkgdatadir)/missions/lessons
 
 dist_lessons_DATA = lesson00 \

Modified: tuxmath/trunk/data/missions/lessons/lesson00
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson00	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson00	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 400
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson01
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson01	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson01	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 400
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson02
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson02	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson02	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 400
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson03
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson03	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson03	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 10
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson04
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson04	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson04	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 15
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson05
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson05	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson05	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 20
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson06
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson06	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson06	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson07
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson07	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson07	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson08
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson08	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson08	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson08.1
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson08.1	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson08.1	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson09
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson09	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson09	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson10
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson10	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson10	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson11
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson11	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson11	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson12
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson12	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson12	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson13
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson13	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson13	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson14
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson14	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson14	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson15
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson15	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson15	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson16
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson16	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson16	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson17
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson17	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson17	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson18
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson18	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson18	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson19
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson19	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson19	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson20
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson20	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson20	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson21
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson21	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson21	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson22
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson22	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson22	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson23
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson23	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson23	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson24
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson24	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson24	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson25
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson25	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson25	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson26
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson26	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson26	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson27
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson27	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson27	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson28
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson28	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson28	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson29
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson29	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson29	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson30
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson30	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson30	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson31
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson31	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson31	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson32
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson32	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson32	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson33
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson33	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson33	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson34
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson34	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson34	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson35
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson35	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson35	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson36
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson36	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson36	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson37
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson37	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson37	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson38
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson38	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson38	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson39
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson39	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson39	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson40
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson40	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson40	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson41
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson41	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson41	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson42
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson42	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson42	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson43
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson43	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson43	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson44
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson44	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson44	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson45
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson45	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson45	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 400
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson46
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson46	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson46	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson47
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson47	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson47	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson48
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson48	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson48	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson49
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson49	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson49	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson50
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson50	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson50	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson51
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson51	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson51	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson52
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson52	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson52	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson53
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson53	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson53	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10

Modified: tuxmath/trunk/data/missions/lessons/lesson54
===================================================================
--- tuxmath/trunk/data/missions/lessons/lesson54	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/data/missions/lessons/lesson54	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,6 +45,8 @@
 max_answer = 999
 max_questions = 5000
 randomize = 1
+comprehensive = 1
+avg_list_length = 42
 starting_comets = 2
 extra_comets_per_wave = 2
 max_comets = 10


Property changes on: tuxmath/trunk/mingw/SDL_win32_main.c
___________________________________________________________________
Name: svn:executable
   + *

Modified: tuxmath/trunk/src/ConvertUTF.c
===================================================================
--- tuxmath/trunk/src/ConvertUTF.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/ConvertUTF.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -26,10 +26,10 @@
     Author: Mark E. Davis, 1994.
     Rev History: Rick McGowan, fixes & updates May 2001.
     Sept 2001: fixed const & error conditions per
-	mods suggested by S. Parent & A. Lillich.
+        mods suggested by S. Parent & A. Lillich.
     June 2002: Tim Dodd added detection and handling of incomplete
-	source sequences, enhanced error detection, added casts
-	to eliminate compiler warnings.
+        source sequences, enhanced error detection, added casts
+        to eliminate compiler warnings.
     July 2003: slight mods to back out aggressive FFFE detection.
     Jan 2004: updated switches in from-UTF8 conversions.
     Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
@@ -53,52 +53,52 @@
 #define UNI_SUR_HIGH_END    (UTF32)0xDBFF
 #define UNI_SUR_LOW_START   (UTF32)0xDC00
 #define UNI_SUR_LOW_END     (UTF32)0xDFFF
-#define false	   0
-#define true	    1
+#define false           0
+#define true            1
 
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF32toUTF16 (
-	const UTF32** sourceStart, const UTF32* sourceEnd, 
-	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+        const UTF32** sourceStart, const UTF32* sourceEnd, 
+        UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF32* source = *sourceStart;
     UTF16* target = *targetStart;
     while (source < sourceEnd) {
-	UTF32 ch;
-	if (target >= targetEnd) {
-	    result = targetExhausted; break;
-	}
-	ch = *source++;
-	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
-	    /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		if (flags == strictConversion) {
-		    --source; /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		} else {
-		    *target++ = UNI_REPLACEMENT_CHAR;
-		}
-	    } else {
-		*target++ = (UTF16)ch; /* normal case */
-	    }
-	} else if (ch > UNI_MAX_LEGAL_UTF32) {
-	    if (flags == strictConversion) {
-		result = sourceIllegal;
-	    } else {
-		*target++ = UNI_REPLACEMENT_CHAR;
-	    }
-	} else {
-	    /* target is a character in range 0xFFFF - 0x10FFFF. */
-	    if (target + 1 >= targetEnd) {
-		--source; /* Back up source pointer! */
-		result = targetExhausted; break;
-	    }
-	    ch -= halfBase;
-	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
-	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
-	}
+        UTF32 ch;
+        if (target >= targetEnd) {
+            result = targetExhausted; break;
+        }
+        ch = *source++;
+        if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+            /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                if (flags == strictConversion) {
+                    --source; /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                } else {
+                    *target++ = UNI_REPLACEMENT_CHAR;
+                }
+            } else {
+                *target++ = (UTF16)ch; /* normal case */
+            }
+        } else if (ch > UNI_MAX_LEGAL_UTF32) {
+            if (flags == strictConversion) {
+                result = sourceIllegal;
+            } else {
+                *target++ = UNI_REPLACEMENT_CHAR;
+            }
+        } else {
+            /* target is a character in range 0xFFFF - 0x10FFFF. */
+            if (target + 1 >= targetEnd) {
+                --source; /* Back up source pointer! */
+                result = targetExhausted; break;
+            }
+            ch -= halfBase;
+            *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+            *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+        }
     }
     *sourceStart = source;
     *targetStart = target;
@@ -108,48 +108,48 @@
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF16toUTF32 (
-	const UTF16** sourceStart, const UTF16* sourceEnd, 
-	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+        const UTF16** sourceStart, const UTF16* sourceEnd, 
+        UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF16* source = *sourceStart;
     UTF32* target = *targetStart;
     UTF32 ch, ch2;
     while (source < sourceEnd) {
-	const UTF16* oldSource = source; /*  In case we have to back up because of target overflow. */
-	ch = *source++;
-	/* If we have a surrogate pair, convert to UTF32 first. */
-	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
-	    /* If the 16 bits following the high surrogate are in the source buffer... */
-	    if (source < sourceEnd) {
-		ch2 = *source;
-		/* If it's a low surrogate, convert to UTF32. */
-		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
-		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
-			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
-		    ++source;
-		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
-		    --source; /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		}
-	    } else { /* We don't have the 16 bits following the high surrogate. */
-		--source; /* return to the high surrogate */
-		result = sourceExhausted;
-		break;
-	    }
-	} else if (flags == strictConversion) {
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
-		--source; /* return to the illegal value itself */
-		result = sourceIllegal;
-		break;
-	    }
-	}
-	if (target >= targetEnd) {
-	    source = oldSource; /* Back up source pointer! */
-	    result = targetExhausted; break;
-	}
-	*target++ = ch;
+        const UTF16* oldSource = source; /*  In case we have to back up because of target overflow. */
+        ch = *source++;
+        /* If we have a surrogate pair, convert to UTF32 first. */
+        if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+            /* If the 16 bits following the high surrogate are in the source buffer... */
+            if (source < sourceEnd) {
+                ch2 = *source;
+                /* If it's a low surrogate, convert to UTF32. */
+                if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+                    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+                        + (ch2 - UNI_SUR_LOW_START) + halfBase;
+                    ++source;
+                } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+                    --source; /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                }
+            } else { /* We don't have the 16 bits following the high surrogate. */
+                --source; /* return to the high surrogate */
+                result = sourceExhausted;
+                break;
+            }
+        } else if (flags == strictConversion) {
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+                --source; /* return to the illegal value itself */
+                result = sourceIllegal;
+                break;
+            }
+        }
+        if (target >= targetEnd) {
+            source = oldSource; /* Back up source pointer! */
+            result = targetExhausted; break;
+        }
+        *target++ = ch;
     }
     *sourceStart = source;
     *targetStart = target;
@@ -188,7 +188,7 @@
  * in a UTF-8 sequence.
  */
 static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 
-		     0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+                     0x03C82080UL, 0xFA082080UL, 0x82082080UL };
 
 /*
  * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
@@ -212,67 +212,67 @@
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF16toUTF8 (
-	const UTF16** sourceStart, const UTF16* sourceEnd, 
-	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+        const UTF16** sourceStart, const UTF16* sourceEnd, 
+        UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF16* source = *sourceStart;
     UTF8* target = *targetStart;
     while (source < sourceEnd) {
-	UTF32 ch;
-	unsigned short bytesToWrite = 0;
-	const UTF32 byteMask = 0xBF;
-	const UTF32 byteMark = 0x80; 
-	const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
-	ch = *source++;
-	/* If we have a surrogate pair, convert to UTF32 first. */
-	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
-	    /* If the 16 bits following the high surrogate are in the source buffer... */
-	    if (source < sourceEnd) {
-		UTF32 ch2 = *source;
-		/* If it's a low surrogate, convert to UTF32. */
-		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
-		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
-			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
-		    ++source;
-		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
-		    --source; /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		}
-	    } else { /* We don't have the 16 bits following the high surrogate. */
-		--source; /* return to the high surrogate */
-		result = sourceExhausted;
-		break;
-	    }
-	} else if (flags == strictConversion) {
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
-		--source; /* return to the illegal value itself */
-		result = sourceIllegal;
-		break;
-	    }
-	}
-	/* Figure out how many bytes the result will require */
-	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
-	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
-	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
-	} else if (ch < (UTF32)0x110000) {  bytesToWrite = 4;
-	} else {			    bytesToWrite = 3;
-					    ch = UNI_REPLACEMENT_CHAR;
-	}
+        UTF32 ch;
+        unsigned short bytesToWrite = 0;
+        const UTF32 byteMask = 0xBF;
+        const UTF32 byteMark = 0x80; 
+        const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+        ch = *source++;
+        /* If we have a surrogate pair, convert to UTF32 first. */
+        if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+            /* If the 16 bits following the high surrogate are in the source buffer... */
+            if (source < sourceEnd) {
+                UTF32 ch2 = *source;
+                /* If it's a low surrogate, convert to UTF32. */
+                if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+                    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+                        + (ch2 - UNI_SUR_LOW_START) + halfBase;
+                    ++source;
+                } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+                    --source; /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                }
+            } else { /* We don't have the 16 bits following the high surrogate. */
+                --source; /* return to the high surrogate */
+                result = sourceExhausted;
+                break;
+            }
+        } else if (flags == strictConversion) {
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+                --source; /* return to the illegal value itself */
+                result = sourceIllegal;
+                break;
+            }
+        }
+        /* Figure out how many bytes the result will require */
+        if (ch < (UTF32)0x80) {             bytesToWrite = 1;
+        } else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
+        } else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
+        } else if (ch < (UTF32)0x110000) {  bytesToWrite = 4;
+        } else {                            bytesToWrite = 3;
+                                            ch = UNI_REPLACEMENT_CHAR;
+        }
 
-	target += bytesToWrite;
-	if (target > targetEnd) {
-	    source = oldSource; /* Back up source pointer! */
-	    target -= bytesToWrite; result = targetExhausted; break;
-	}
-	switch (bytesToWrite) { /* note: everything falls through. */
-	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 1: *--target =  (UTF8)(ch | firstByteMark[bytesToWrite]);
-	}
-	target += bytesToWrite;
+        target += bytesToWrite;
+        if (target > targetEnd) {
+            source = oldSource; /* Back up source pointer! */
+            target -= bytesToWrite; result = targetExhausted; break;
+        }
+        switch (bytesToWrite) { /* note: everything falls through. */
+            case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 1: *--target =  (UTF8)(ch | firstByteMark[bytesToWrite]);
+        }
+        target += bytesToWrite;
     }
     *sourceStart = source;
     *targetStart = target;
@@ -297,19 +297,19 @@
     const UTF8 *srcptr = source+length;
     switch (length) {
     default: return false;
-	/* Everything else falls through when "true"... */
+        /* Everything else falls through when "true"... */
     case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
     case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
     case 2: if ((a = (*--srcptr)) > 0xBF) return false;
 
-	switch (*source) {
-	    /* no fall-through in this inner switch */
-	    case 0xE0: if (a < 0xA0) return false; break;
-	    case 0xED: if (a > 0x9F) return false; break;
-	    case 0xF0: if (a < 0x90) return false; break;
-	    case 0xF4: if (a > 0x8F) return false; break;
-	    default:   if (a < 0x80) return false;
-	}
+        switch (*source) {
+            /* no fall-through in this inner switch */
+            case 0xE0: if (a < 0xA0) return false; break;
+            case 0xED: if (a > 0x9F) return false; break;
+            case 0xF0: if (a < 0x90) return false; break;
+            case 0xF4: if (a > 0x8F) return false; break;
+            default:   if (a < 0x80) return false;
+        }
 
     case 1: if (*source >= 0x80 && *source < 0xC2) return false;
     }
@@ -326,7 +326,7 @@
 Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
     int length = trailingBytesForUTF8[*source]+1;
     if (source+length > sourceEnd) {
-	return false;
+        return false;
     }
     return isLegalUTF8(source, length);
 }
@@ -334,70 +334,70 @@
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF8toUTF16 (
-	const UTF8** sourceStart, const UTF8* sourceEnd, 
-	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+        const UTF8** sourceStart, const UTF8* sourceEnd, 
+        UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF8* source = *sourceStart;
     UTF16* target = *targetStart;
     while (source < sourceEnd) {
-	UTF32 ch = 0;
-	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
-	if (source + extraBytesToRead >= sourceEnd) {
-	    result = sourceExhausted; break;
-	}
-	/* Do this check whether lenient or strict */
-	if (! isLegalUTF8(source, extraBytesToRead+1)) {
-	    result = sourceIllegal;
-	    break;
-	}
-	/*
-	 * The cases all fall through. See "Note A" below.
-	 */
-	switch (extraBytesToRead) {
-	    case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
-	    case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
-	    case 3: ch += *source++; ch <<= 6;
-	    case 2: ch += *source++; ch <<= 6;
-	    case 1: ch += *source++; ch <<= 6;
-	    case 0: ch += *source++;
-	}
-	ch -= offsetsFromUTF8[extraBytesToRead];
+        UTF32 ch = 0;
+        unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+        if (source + extraBytesToRead >= sourceEnd) {
+            result = sourceExhausted; break;
+        }
+        /* Do this check whether lenient or strict */
+        if (! isLegalUTF8(source, extraBytesToRead+1)) {
+            result = sourceIllegal;
+            break;
+        }
+        /*
+         * The cases all fall through. See "Note A" below.
+         */
+        switch (extraBytesToRead) {
+            case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+            case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+            case 3: ch += *source++; ch <<= 6;
+            case 2: ch += *source++; ch <<= 6;
+            case 1: ch += *source++; ch <<= 6;
+            case 0: ch += *source++;
+        }
+        ch -= offsetsFromUTF8[extraBytesToRead];
 
-	if (target >= targetEnd) {
-	    source -= (extraBytesToRead+1); /* Back up source pointer! */
-	    result = targetExhausted; break;
-	}
-	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		if (flags == strictConversion) {
-		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		} else {
-		    *target++ = UNI_REPLACEMENT_CHAR;
-		}
-	    } else {
-		*target++ = (UTF16)ch; /* normal case */
-	    }
-	} else if (ch > UNI_MAX_UTF16) {
-	    if (flags == strictConversion) {
-		result = sourceIllegal;
-		source -= (extraBytesToRead+1); /* return to the start */
-		break; /* Bail out; shouldn't continue */
-	    } else {
-		*target++ = UNI_REPLACEMENT_CHAR;
-	    }
-	} else {
-	    /* target is a character in range 0xFFFF - 0x10FFFF. */
-	    if (target + 1 >= targetEnd) {
-		source -= (extraBytesToRead+1); /* Back up source pointer! */
-		result = targetExhausted; break;
-	    }
-	    ch -= halfBase;
-	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
-	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
-	}
+        if (target >= targetEnd) {
+            source -= (extraBytesToRead+1); /* Back up source pointer! */
+            result = targetExhausted; break;
+        }
+        if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                if (flags == strictConversion) {
+                    source -= (extraBytesToRead+1); /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                } else {
+                    *target++ = UNI_REPLACEMENT_CHAR;
+                }
+            } else {
+                *target++ = (UTF16)ch; /* normal case */
+            }
+        } else if (ch > UNI_MAX_UTF16) {
+            if (flags == strictConversion) {
+                result = sourceIllegal;
+                source -= (extraBytesToRead+1); /* return to the start */
+                break; /* Bail out; shouldn't continue */
+            } else {
+                *target++ = UNI_REPLACEMENT_CHAR;
+            }
+        } else {
+            /* target is a character in range 0xFFFF - 0x10FFFF. */
+            if (target + 1 >= targetEnd) {
+                source -= (extraBytesToRead+1); /* Back up source pointer! */
+                result = targetExhausted; break;
+            }
+            ch -= halfBase;
+            *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+            *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+        }
     }
     *sourceStart = source;
     *targetStart = target;
@@ -407,50 +407,50 @@
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF32toUTF8 (
-	const UTF32** sourceStart, const UTF32* sourceEnd, 
-	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+        const UTF32** sourceStart, const UTF32* sourceEnd, 
+        UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF32* source = *sourceStart;
     UTF8* target = *targetStart;
     while (source < sourceEnd) {
-	UTF32 ch;
-	unsigned short bytesToWrite = 0;
-	const UTF32 byteMask = 0xBF;
-	const UTF32 byteMark = 0x80; 
-	ch = *source++;
-	if (flags == strictConversion ) {
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		--source; /* return to the illegal value itself */
-		result = sourceIllegal;
-		break;
-	    }
-	}
-	/*
-	 * Figure out how many bytes the result will require. Turn any
-	 * illegally large UTF32 things (> Plane 17) into replacement chars.
-	 */
-	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
-	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
-	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
-	} else if (ch <= UNI_MAX_LEGAL_UTF32) {  bytesToWrite = 4;
-	} else {			    bytesToWrite = 3;
-					    ch = UNI_REPLACEMENT_CHAR;
-					    result = sourceIllegal;
-	}
-	
-	target += bytesToWrite;
-	if (target > targetEnd) {
-	    --source; /* Back up source pointer! */
-	    target -= bytesToWrite; result = targetExhausted; break;
-	}
-	switch (bytesToWrite) { /* note: everything falls through. */
-	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
-	}
-	target += bytesToWrite;
+        UTF32 ch;
+        unsigned short bytesToWrite = 0;
+        const UTF32 byteMask = 0xBF;
+        const UTF32 byteMark = 0x80; 
+        ch = *source++;
+        if (flags == strictConversion ) {
+            /* UTF-16 surrogate values are illegal in UTF-32 */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                --source; /* return to the illegal value itself */
+                result = sourceIllegal;
+                break;
+            }
+        }
+        /*
+         * Figure out how many bytes the result will require. Turn any
+         * illegally large UTF32 things (> Plane 17) into replacement chars.
+         */
+        if (ch < (UTF32)0x80) {             bytesToWrite = 1;
+        } else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
+        } else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
+        } else if (ch <= UNI_MAX_LEGAL_UTF32) {  bytesToWrite = 4;
+        } else {                            bytesToWrite = 3;
+                                            ch = UNI_REPLACEMENT_CHAR;
+                                            result = sourceIllegal;
+        }
+        
+        target += bytesToWrite;
+        if (target > targetEnd) {
+            --source; /* Back up source pointer! */
+            target -= bytesToWrite; result = targetExhausted; break;
+        }
+        switch (bytesToWrite) { /* note: everything falls through. */
+            case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+            case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
+        }
+        target += bytesToWrite;
     }
     *sourceStart = source;
     *targetStart = target;
@@ -460,59 +460,59 @@
 /* --------------------------------------------------------------------- */
 
 ConversionResult ConvertUTF8toUTF32 (
-	const UTF8** sourceStart, const UTF8* sourceEnd, 
-	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+        const UTF8** sourceStart, const UTF8* sourceEnd, 
+        UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
     ConversionResult result = conversionOK;
     const UTF8* source = *sourceStart;
     UTF32* target = *targetStart;
     while (source < sourceEnd) {
-	UTF32 ch = 0;
-	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
-	if (source + extraBytesToRead >= sourceEnd) {
-	    result = sourceExhausted; break;
-	}
-	/* Do this check whether lenient or strict */
-	if (! isLegalUTF8(source, extraBytesToRead+1)) {
-	    result = sourceIllegal;
-	    break;
-	}
-	/*
-	 * The cases all fall through. See "Note A" below.
-	 */
-	switch (extraBytesToRead) {
-	    case 5: ch += *source++; ch <<= 6;
-	    case 4: ch += *source++; ch <<= 6;
-	    case 3: ch += *source++; ch <<= 6;
-	    case 2: ch += *source++; ch <<= 6;
-	    case 1: ch += *source++; ch <<= 6;
-	    case 0: ch += *source++;
-	}
-	ch -= offsetsFromUTF8[extraBytesToRead];
+        UTF32 ch = 0;
+        unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+        if (source + extraBytesToRead >= sourceEnd) {
+            result = sourceExhausted; break;
+        }
+        /* Do this check whether lenient or strict */
+        if (! isLegalUTF8(source, extraBytesToRead+1)) {
+            result = sourceIllegal;
+            break;
+        }
+        /*
+         * The cases all fall through. See "Note A" below.
+         */
+        switch (extraBytesToRead) {
+            case 5: ch += *source++; ch <<= 6;
+            case 4: ch += *source++; ch <<= 6;
+            case 3: ch += *source++; ch <<= 6;
+            case 2: ch += *source++; ch <<= 6;
+            case 1: ch += *source++; ch <<= 6;
+            case 0: ch += *source++;
+        }
+        ch -= offsetsFromUTF8[extraBytesToRead];
 
-	if (target >= targetEnd) {
-	    source -= (extraBytesToRead+1); /* Back up the source pointer! */
-	    result = targetExhausted; break;
-	}
-	if (ch <= UNI_MAX_LEGAL_UTF32) {
-	    /*
-	     * UTF-16 surrogate values are illegal in UTF-32, and anything
-	     * over Plane 17 (> 0x10FFFF) is illegal.
-	     */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		if (flags == strictConversion) {
-		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		} else {
-		    *target++ = UNI_REPLACEMENT_CHAR;
-		}
-	    } else {
-		*target++ = ch;
-	    }
-	} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
-	    result = sourceIllegal;
-	    *target++ = UNI_REPLACEMENT_CHAR;
-	}
+        if (target >= targetEnd) {
+            source -= (extraBytesToRead+1); /* Back up the source pointer! */
+            result = targetExhausted; break;
+        }
+        if (ch <= UNI_MAX_LEGAL_UTF32) {
+            /*
+             * UTF-16 surrogate values are illegal in UTF-32, and anything
+             * over Plane 17 (> 0x10FFFF) is illegal.
+             */
+            if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+                if (flags == strictConversion) {
+                    source -= (extraBytesToRead+1); /* return to the illegal value itself */
+                    result = sourceIllegal;
+                    break;
+                } else {
+                    *target++ = UNI_REPLACEMENT_CHAR;
+                }
+            } else {
+                *target++ = ch;
+            }
+        } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+            result = sourceIllegal;
+            *target++ = UNI_REPLACEMENT_CHAR;
+        }
     }
     *sourceStart = source;
     *targetStart = target;
@@ -525,14 +525,14 @@
     The fall-through switches in UTF-8 reading code save a
     temp variable, some decrements & conditionals.  The switches
     are equivalent to the following loop:
-	{
-	    int tmpBytesToRead = extraBytesToRead+1;
-	    do {
-		ch += *source++;
-		--tmpBytesToRead;
-		if (tmpBytesToRead) ch <<= 6;
-	    } while (tmpBytesToRead > 0);
-	}
+        {
+            int tmpBytesToRead = extraBytesToRead+1;
+            do {
+                ch += *source++;
+                --tmpBytesToRead;
+                if (tmpBytesToRead) ch <<= 6;
+            } while (tmpBytesToRead > 0);
+        }
     In UTF-8 writing code, the switches on "bytesToWrite" are
     similarly unrolled loops.
 

Modified: tuxmath/trunk/src/ConvertUTF.h
===================================================================
--- tuxmath/trunk/src/ConvertUTF.h	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/ConvertUTF.h	2008-08-06 02:55:05 UTC (rev 589)
@@ -45,12 +45,12 @@
     the respective buffers.
 
     Input parameters:
-	sourceStart - pointer to a pointer to the source buffer.
-		The contents of this are modified on return so that
-		it points at the next thing to be converted.
-	targetStart - similarly, pointer to pointer to the target buffer.
-	sourceEnd, targetEnd - respectively pointers to the ends of the
-		two buffers, for overflow checking only.
+        sourceStart - pointer to a pointer to the source buffer.
+                The contents of this are modified on return so that
+                it points at the next thing to be converted.
+        targetStart - similarly, pointer to pointer to the target buffer.
+        sourceEnd, targetEnd - respectively pointers to the ends of the
+                two buffers, for overflow checking only.
 
     These conversion functions take a ConversionFlags argument. When this
     flag is set to strict, both irregular sequences and isolated surrogates
@@ -67,15 +67,15 @@
     they constitute an error.
 
     Output parameters:
-	The value "sourceIllegal" is returned from some routines if the input
-	sequence is malformed.  When "sourceIllegal" is returned, the source
-	value will point to the illegal value that caused the problem. E.g.,
-	in UTF-8 when a sequence is malformed, it points to the start of the
-	malformed sequence.  
+        The value "sourceIllegal" is returned from some routines if the input
+        sequence is malformed.  When "sourceIllegal" is returned, the source
+        value will point to the illegal value that caused the problem. E.g.,
+        in UTF-8 when a sequence is malformed, it points to the start of the
+        malformed sequence.  
 
     Author: Mark E. Davis, 1994.
     Rev History: Rick McGowan, fixes & updates May 2001.
-		 Fixes & updates, Sept 2001.
+                 Fixes & updates, Sept 2001.
 
 ------------------------------------------------------------------------ */
 
@@ -87,10 +87,10 @@
     bit mask & shift operations.
 ------------------------------------------------------------------------ */
 
-typedef unsigned long	UTF32;	/* at least 32 bits */
-typedef unsigned short	UTF16;	/* at least 16 bits */
-typedef unsigned char	UTF8;	/* typically 8 bits */
-typedef unsigned char	Boolean; /* 0 or 1 */
+typedef unsigned long        UTF32;        /* at least 32 bits */
+typedef unsigned short        UTF16;        /* at least 16 bits */
+typedef unsigned char        UTF8;        /* typically 8 bits */
+typedef unsigned char        Boolean; /* 0 or 1 */
 
 /* Some fundamental constants */
 #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
@@ -100,15 +100,15 @@
 #define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
 
 typedef enum {
-	conversionOK, 		/* conversion successful */
-	sourceExhausted,	/* partial character in source, but hit end */
-	targetExhausted,	/* insuff. room in target for conversion */
-	sourceIllegal		/* source sequence is illegal/malformed */
+        conversionOK,                 /* conversion successful */
+        sourceExhausted,        /* partial character in source, but hit end */
+        targetExhausted,        /* insuff. room in target for conversion */
+        sourceIllegal                /* source sequence is illegal/malformed */
 } ConversionResult;
 
 typedef enum {
-	strictConversion = 0,
-	lenientConversion
+        strictConversion = 0,
+        lenientConversion
 } ConversionFlags;
 
 /* This is for C++ and does no harm in C */
@@ -117,28 +117,28 @@
 #endif
 
 ConversionResult ConvertUTF8toUTF16 (
-		const UTF8** sourceStart, const UTF8* sourceEnd, 
-		UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+                const UTF8** sourceStart, const UTF8* sourceEnd, 
+                UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
 
 ConversionResult ConvertUTF16toUTF8 (
-		const UTF16** sourceStart, const UTF16* sourceEnd, 
-		UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-		
+                const UTF16** sourceStart, const UTF16* sourceEnd, 
+                UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+                
 ConversionResult ConvertUTF8toUTF32 (
-		const UTF8** sourceStart, const UTF8* sourceEnd, 
-		UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+                const UTF8** sourceStart, const UTF8* sourceEnd, 
+                UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
 
 ConversionResult ConvertUTF32toUTF8 (
-		const UTF32** sourceStart, const UTF32* sourceEnd, 
-		UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-		
+                const UTF32** sourceStart, const UTF32* sourceEnd, 
+                UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+                
 ConversionResult ConvertUTF16toUTF32 (
-		const UTF16** sourceStart, const UTF16* sourceEnd, 
-		UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+                const UTF16** sourceStart, const UTF16* sourceEnd, 
+                UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
 
 ConversionResult ConvertUTF32toUTF16 (
-		const UTF32** sourceStart, const UTF32* sourceEnd, 
-		UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+                const UTF32** sourceStart, const UTF32* sourceEnd, 
+                UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
 
 Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
 

Modified: tuxmath/trunk/src/Makefile.in
===================================================================
--- tuxmath/trunk/src/Makefile.in	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/Makefile.in	2008-08-06 02:55:05 UTC (rev 589)
@@ -69,9 +69,9 @@
 am__objects_1 = tuxmath.$(OBJEXT) setup.$(OBJEXT) \
 	titlescreen.$(OBJEXT) game.$(OBJEXT) options.$(OBJEXT) \
 	credits.$(OBJEXT) highscore.$(OBJEXT) loaders.$(OBJEXT) \
-	audio.$(OBJEXT) mathcards.$(OBJEXT) fileops.$(OBJEXT) \
-	ConvertUTF.$(OBJEXT) SDL_extras.$(OBJEXT) lessons.$(OBJEXT) \
-	scandir.$(OBJEXT) pixels.$(OBJEXT)
+	audio.$(OBJEXT) mathcards.$(OBJEXT) campaign.$(OBJEXT) \
+	fileops.$(OBJEXT) ConvertUTF.$(OBJEXT) SDL_extras.$(OBJEXT) \
+	lessons.$(OBJEXT) scandir.$(OBJEXT) pixels.$(OBJEXT)
 am_TuxMath_OBJECTS = $(am__objects_1)
 TuxMath_OBJECTS = $(am_TuxMath_OBJECTS)
 TuxMath_LDADD = $(LDADD)
@@ -79,9 +79,9 @@
 am_tuxmath_OBJECTS = tuxmath.$(OBJEXT) setup.$(OBJEXT) \
 	titlescreen.$(OBJEXT) game.$(OBJEXT) options.$(OBJEXT) \
 	credits.$(OBJEXT) highscore.$(OBJEXT) loaders.$(OBJEXT) \
-	audio.$(OBJEXT) mathcards.$(OBJEXT) fileops.$(OBJEXT) \
-	ConvertUTF.$(OBJEXT) SDL_extras.$(OBJEXT) lessons.$(OBJEXT) \
-	scandir.$(OBJEXT) pixels.$(OBJEXT)
+	audio.$(OBJEXT) mathcards.$(OBJEXT) campaign.$(OBJEXT) \
+	fileops.$(OBJEXT) ConvertUTF.$(OBJEXT) SDL_extras.$(OBJEXT) \
+	lessons.$(OBJEXT) scandir.$(OBJEXT) pixels.$(OBJEXT)
 tuxmath_OBJECTS = $(am_tuxmath_OBJECTS)
 tuxmath_LDADD = $(LDADD)
 tuxmath_DEPENDENCIES =
@@ -274,6 +274,7 @@
 	loaders.c	\
 	audio.c 	\
 	mathcards.c	\
+	campaign.c	\
 	fileops.c	\
 	ConvertUTF.c	\
 	SDL_extras.c	\
@@ -291,6 +292,7 @@
 		options.h	\
 		setup.h		\
 		titlescreen.h	\
+		campaign.h	\
 		tuxmath.h	\
 		ConvertUTF.h	\
 		SDL_extras.h	\
@@ -378,6 +380,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ConvertUTF.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/SDL_extras.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/audio.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/campaign.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/credits.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/fileops.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/game.Po at am__quote@

Modified: tuxmath/trunk/src/SDL_extras.c
===================================================================
--- tuxmath/trunk/src/SDL_extras.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/SDL_extras.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -152,92 +152,92 @@
      note: you can have it flip both
 **********************/
 SDL_Surface* Flip( SDL_Surface *in, int x, int y ) {
-	SDL_Surface *out, *tmp;
-	SDL_Rect from_rect, to_rect;
-	Uint32	flags;
-	Uint32  colorkey=0;
+        SDL_Surface *out, *tmp;
+        SDL_Rect from_rect, to_rect;
+        Uint32        flags;
+        Uint32  colorkey=0;
 
-	/* --- grab the settings for the incoming pixmap --- */
+        /* --- grab the settings for the incoming pixmap --- */
 
-	SDL_LockSurface(in);
-	flags = in->flags;
+        SDL_LockSurface(in);
+        flags = in->flags;
 
-	/* --- change in's flags so ignore colorkey & alpha --- */
+        /* --- change in's flags so ignore colorkey & alpha --- */
 
-	if (flags & SDL_SRCCOLORKEY) {
-		in->flags &= ~SDL_SRCCOLORKEY;
-		colorkey = in->format->colorkey;
-	}
-	if (flags & SDL_SRCALPHA) {
-		in->flags &= ~SDL_SRCALPHA;
-	}
+        if (flags & SDL_SRCCOLORKEY) {
+                in->flags &= ~SDL_SRCCOLORKEY;
+                colorkey = in->format->colorkey;
+        }
+        if (flags & SDL_SRCALPHA) {
+                in->flags &= ~SDL_SRCALPHA;
+        }
 
-	SDL_UnlockSurface(in);
+        SDL_UnlockSurface(in);
 
-	/* --- create our new surface --- */
+        /* --- create our new surface --- */
 
-	out = SDL_CreateRGBSurface(
-		SDL_SWSURFACE,
-		in->w, in->h, 32, rmask, gmask, bmask, amask);
+        out = SDL_CreateRGBSurface(
+                SDL_SWSURFACE,
+                in->w, in->h, 32, rmask, gmask, bmask, amask);
 
-	/* --- flip horizontally if requested --- */
+        /* --- flip horizontally if requested --- */
 
-	if (x) {
-		from_rect.h = to_rect.h = in->h;
-		from_rect.w = to_rect.w = 1;
-		from_rect.y = to_rect.y = 0;
-		from_rect.x = 0;
-		to_rect.x = in->w - 1;
+        if (x) {
+                from_rect.h = to_rect.h = in->h;
+                from_rect.w = to_rect.w = 1;
+                from_rect.y = to_rect.y = 0;
+                from_rect.x = 0;
+                to_rect.x = in->w - 1;
 
-		do {
-			SDL_BlitSurface(in, &from_rect, out, &to_rect);
-			from_rect.x++;
-			to_rect.x--;
-		} while (to_rect.x >= 0);
-	}
+                do {
+                        SDL_BlitSurface(in, &from_rect, out, &to_rect);
+                        from_rect.x++;
+                        to_rect.x--;
+                } while (to_rect.x >= 0);
+        }
 
-	/* --- flip vertically if requested --- */
+        /* --- flip vertically if requested --- */
 
-	if (y) {
-		from_rect.h = to_rect.h = 1;
-		from_rect.w = to_rect.w = in->w;
-		from_rect.x = to_rect.x = 0;
-		from_rect.y = 0;
-		to_rect.y = in->h - 1;
+        if (y) {
+                from_rect.h = to_rect.h = 1;
+                from_rect.w = to_rect.w = in->w;
+                from_rect.x = to_rect.x = 0;
+                from_rect.y = 0;
+                to_rect.y = in->h - 1;
 
-		do {
-			SDL_BlitSurface(in, &from_rect, out, &to_rect);
-			from_rect.y++;
-			to_rect.y--;
-		} while (to_rect.y >= 0);
-	}
+                do {
+                        SDL_BlitSurface(in, &from_rect, out, &to_rect);
+                        from_rect.y++;
+                        to_rect.y--;
+                } while (to_rect.y >= 0);
+        }
 
-	/* --- restore colorkey & alpha on in and setup out the same --- */
+        /* --- restore colorkey & alpha on in and setup out the same --- */
 
-	SDL_LockSurface(in);
+        SDL_LockSurface(in);
 
-	if (flags & SDL_SRCCOLORKEY) {
-		in->flags |= SDL_SRCCOLORKEY;
-		in->format->colorkey = colorkey;
-		tmp = SDL_DisplayFormat(out);
-		SDL_FreeSurface(out);
-		out = tmp;
-		out->flags |= SDL_SRCCOLORKEY;
-		out->format->colorkey = colorkey;
-	} else if (flags & SDL_SRCALPHA) {
-		in->flags |= SDL_SRCALPHA;
-		tmp = SDL_DisplayFormatAlpha(out);
-		SDL_FreeSurface(out);
-		out = tmp;
-	} else {
-		tmp = SDL_DisplayFormat(out);
-		SDL_FreeSurface(out);
-		out = tmp;
-	}
+        if (flags & SDL_SRCCOLORKEY) {
+                in->flags |= SDL_SRCCOLORKEY;
+                in->format->colorkey = colorkey;
+                tmp = SDL_DisplayFormat(out);
+                SDL_FreeSurface(out);
+                out = tmp;
+                out->flags |= SDL_SRCCOLORKEY;
+                out->format->colorkey = colorkey;
+        } else if (flags & SDL_SRCALPHA) {
+                in->flags |= SDL_SRCALPHA;
+                tmp = SDL_DisplayFormatAlpha(out);
+                SDL_FreeSurface(out);
+                out = tmp;
+        } else {
+                tmp = SDL_DisplayFormat(out);
+                SDL_FreeSurface(out);
+                out = tmp;
+        }
 
-	SDL_UnlockSurface(in);
+        SDL_UnlockSurface(in);
 
-	return out;
+        return out;
 }
 
 /* Blend two surfaces together. The third argument is between 0.0 and
@@ -274,7 +274,7 @@
     // Check that both images have the same width dimension
     if (S1->w != S2->w) {
       printf("S1->w %d, S2->w %d;  S1->h %d, S2->h %d\n",
-	     S1->w,S2->w,S1->h,S2->h);
+             S1->w,S2->w,S1->h,S2->h);
       printf("Both images must have the same width dimensions\n");
       return S1;
     }
@@ -434,9 +434,9 @@
 
 
 int inRect( SDL_Rect r, int x, int y) {
-	if ((x < r.x) || (y < r.y) || (x > r.x + r.w) || (y > r.y + r.h))
-		return 0;
-	return 1;
+        if ((x < r.x) || (y < r.y) || (x > r.x + r.w) || (y > r.y + r.h))
+                return 0;
+        return 1;
 }
 
 /* Darkens the screen by a factor of 2^bits */
@@ -530,7 +530,7 @@
   /* current colorspace:                                   */
   void (*putpixel) (SDL_Surface*, int, int, Uint32);
   Uint32(*getpixel) (SDL_Surface*, int, int);
- 
+
   float xscale, yscale;
   int x, y;
   int floor_x, ceil_x,
@@ -548,8 +548,8 @@
 
   /* Create surface for zoom: */
 
-  s = SDL_CreateRGBSurface(src->flags,	/* SDL_SWSURFACE, */
-			   new_w, new_h, src->format->BitsPerPixel,
+  s = SDL_CreateRGBSurface(src->flags,        /* SDL_SWSURFACE, */
+                           new_w, new_h, src->format->BitsPerPixel,
                            src->format->Rmask,
                            src->format->Gmask,
                            src->format->Bmask,
@@ -558,8 +558,8 @@
   if (s == NULL)
   {
     fprintf(stderr, "\nError: Can't build zoom surface\n"
-	    "The Simple DirectMedia Layer error that occurred was:\n"
-	    "%s\n\n", SDL_GetError());
+            "The Simple DirectMedia Layer error that occurred was:\n"
+            "%s\n\n", SDL_GetError());
     return NULL;
 //    cleanup();
 //    exit(1);
@@ -647,310 +647,6 @@
   return s;
 }
 
-//FIXME: everything below is slightly modified code from pixels.c and would do
-//       better to be included as such.
 
-#if 0 //selectively omit from here to the end of file until pixels.c is in
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/*
-  pixels.c
-
-  For Tux Paint
-  Pixel read/write functions
-
-  Copyright (c) 2002-2006 by Bill Kendrick and others
-  bill at newbreedsoftware.com
-  http://www.newbreedsoftware.com/tuxpaint/
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-  (See COPYING.txt)
-
-  June 14, 2002 - February 17, 2006
-  $Id: pixels.c,v 1.3 2006/08/27 21:00:55 wkendrick Exp $
-*/
-
-#include "pixels.h"
-#include "compiler.h"
-//#include "debug.h"
-
-/* Draw a single pixel into the surface: */
-void putpixel8(SDL_Surface * surface, int x, int y, Uint32 pixel)
-{
-  Uint8 *p;
-
-//  printf("putpixel8() called\n");
-
-  /* Assuming the X/Y values are within the bounds of this surface... */
-  if (
-      (((unsigned) x < (unsigned) surface->w)
-       && ((unsigned) y < (unsigned) surface->h)))
-  {
-    // Set a pointer to the exact location in memory of the pixel
-    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
-		   (y * surface->pitch) +	/* Go down Y lines */
-		   x);		/* Go in X pixels */
-
-
-    /* Set the (correctly-sized) piece of data in the surface's RAM
-     *          to the pixel value sent in: */
-
-    *p = pixel;
-  }
-}
-
-/* Draw a single pixel into the surface: */
-void putpixel16(SDL_Surface * surface, int x, int y, Uint32 pixel)
-{
-  Uint8 *p;
-
-//  printf("putpixel16() called\n");
-
-  /* Assuming the X/Y values are within the bounds of this surface... */
-  if (
-      (((unsigned) x < (unsigned) surface->w)
-       && ((unsigned) y < (unsigned) surface->h)))
-  {
-    // Set a pointer to the exact location in memory of the pixel
-    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
-		   (y * surface->pitch) +	/* Go down Y lines */
-		   (x * 2));	/* Go in X pixels */
-
-
-    /* Set the (correctly-sized) piece of data in the surface's RAM
-     *          to the pixel value sent in: */
-
-    *(Uint16 *) p = pixel;
-  }
-}
-
-/* Draw a single pixel into the surface: */
-void putpixel24(SDL_Surface * surface, int x, int y, Uint32 pixel)
-{
-  Uint8 *p;
-
-//  printf("putpixel24() called\n");
-
-  /* Assuming the X/Y values are within the bounds of this surface... */
-  if (
-      (((unsigned) x < (unsigned) surface->w)
-       && ((unsigned) y < (unsigned) surface->h)))
-  {
-    // Set a pointer to the exact location in memory of the pixel
-    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
-		   (y * surface->pitch) +	/* Go down Y lines */
-		   (x * 3));	/* Go in X pixels */
-
-
-    /* Set the (correctly-sized) piece of data in the surface's RAM
-     *          to the pixel value sent in: */
-
-    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;
-    }
-
-  }
-}
-
-/* Draw a single pixel into the surface: */
-void putpixel32(SDL_Surface * surface, int x, int y, Uint32 pixel)
-{
-  Uint8 *p;
-
-//  printf("putpixel32() called\n");
-
-  /* Assuming the X/Y values are within the bounds of this surface... */
-  if (
-      (((unsigned) x < (unsigned) surface->w)
-       && ((unsigned) y < (unsigned) surface->h)))
-  {
-    // Set a pointer to the exact location in memory of the pixel
-    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
-		   (y * surface->pitch) +	/* Go down Y lines */
-		   (x * 4));	/* Go in X pixels */
-
-
-    /* Set the (correctly-sized) piece of data in the surface's RAM
-     *          to the pixel value sent in: */
-
-    *(Uint32 *) p = pixel;	// 32-bit display
-  }
-}
-
-/* Get a pixel: */
-Uint32 getpixel8(SDL_Surface * surface, int x, int y)
-{
-  Uint8 *p;
-
-//  printf("getpixel8() called\n");
-
-  /* get the X/Y values within the bounds of this surface */
-  if ((unsigned) x < (unsigned) surface->w)
-    x = (x < 0) ? 0 : surface->w - 1;
-  if ((unsigned) y < (unsigned) surface->h)
-    y = (y < 0) ? 0 : surface->h - 1;
-
-  /* Set a pointer to the exact location in memory of the pixel
-     in question: */
-
-  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
-		 (y * surface->pitch) +	/* Go down Y lines */
-		 x);		/* Go in X pixels */
-
-
-  /* Return the correctly-sized piece of data containing the
-   * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
-   * RGB value) */
-
-  return (*p);
-}
-
-/* Get a pixel: */
-Uint32 getpixel16(SDL_Surface * surface, int x, int y)
-{
-  Uint8 *p;
-
-//  printf("getpixel16() called\n");
-
-  /* get the X/Y values within the bounds of this surface */
-  if ((unsigned) x < (unsigned) surface->w)
-    x = (x < 0) ? 0 : surface->w - 1;
-  if ((unsigned) y < (unsigned) surface->h)
-    y = (y < 0) ? 0 : surface->h - 1;
-
-  /* Set a pointer to the exact location in memory of the pixel
-     in question: */
-
-  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
-		 (y * surface->pitch) +	/* Go down Y lines */
-		 (x * 2));	/* Go in X pixels */
-
-
-  /* Return the correctly-sized piece of data containing the
-   * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
-   * RGB value) */
-
-  return (*(Uint16 *) p);
-}
-
-/* Get a pixel: */
-Uint32 getpixel24(SDL_Surface * surface, int x, int y)
-{
-  Uint8 *p;
-  Uint32 pixel;
-
-//  printf("getpixel24() called\n");
-
-  /* get the X/Y values within the bounds of this surface */
-  if ((unsigned) x < (unsigned) surface->w)
-    x = (x < 0) ? 0 : surface->w - 1;
-  if ((unsigned) y < (unsigned) surface->h)
-    y = (y < 0) ? 0 : surface->h - 1;
-
-  /* Set a pointer to the exact location in memory of the pixel
-     in question: */
-
-  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
-		 (y * surface->pitch) +	/* Go down Y lines */
-		 (x * 3));	/* Go in X pixels */
-
-
-  /* Return the correctly-sized piece of data containing the
-   * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
-   * RGB value) */
-
-  /* Depending on the byte-order, it could be stored RGB or BGR! */
-
-  if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
-    pixel = p[0] << 16 | p[1] << 8 | p[2];
-  else
-    pixel = p[0] | p[1] << 8 | p[2] << 16;
-
-  return pixel;
-}
-
-/* Get a pixel: */
-Uint32 getpixel32(SDL_Surface * surface, int x, int y)
-{
-  Uint8 *p;
-
-//  printf("getpixel32() called\n");
-
-  /* get the X/Y values within the bounds of this surface */
-  if ((unsigned) x < (unsigned) surface->w)
-    x = (x < 0) ? 0 : surface->w - 1;
-  if ((unsigned) y < (unsigned) surface->h)
-    y = (y < 0) ? 0 : surface->h - 1;
-
-  /* Set a pointer to the exact location in memory of the pixel
-     in question: */
-
-  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
-		 (y * surface->pitch) +	/* Go down Y lines */
-		 (x * 4));	/* Go in X pixels */
-
-
-  /* Return the correctly-sized piece of data containing the
-   * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
-   * RGB value) */
-
-  return *(Uint32 *) p;		// 32-bit display
-}
-
-/* Function pointer arrays to allow correct function */
-/* to be used according to colorspace:               */
-void (*putpixels[]) (SDL_Surface *, int, int, Uint32) =
-{
-  putpixel8,
-  putpixel8,
-  putpixel16,
-  putpixel24,
-  putpixel32
-};
-
-Uint32(*getpixels[])(SDL_Surface *, int, int) =
-{
-  getpixel8,
-  getpixel8,
-  getpixel16,
-  getpixel24,
-  getpixel32
-};
-
-#endif

Modified: tuxmath/trunk/src/audio.c
===================================================================
--- tuxmath/trunk/src/audio.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/audio.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -25,7 +25,7 @@
 
 #include "titlescreen.h"
 
-Mix_Music      *music;
+Mix_Music *music;
 
 void playsound(int snd)
 {
@@ -59,12 +59,12 @@
  * loaded using the audioMusicLoad function
  */
 void audioMusicUnload( void ) {
-	if (!Opts_UsingSound()) return;
+  if (!Opts_UsingSound()) return;
 
-	if ( defaultMusic )
-		Mix_FreeMusic( defaultMusic );
+  if ( defaultMusic )
+    Mix_FreeMusic( defaultMusic );
 
-	defaultMusic=NULL;
+  defaultMusic=NULL;
 }
 
 /* audioMusicPlay attempts to play the passed music data. 
@@ -73,8 +73,8 @@
  * Note: loops == -1 means forever
  */
 void audioMusicPlay( Mix_Music *musicData, int loops ) { 
-	if (!Opts_UsingSound()) return;
+  if (!Opts_UsingSound()) return;
 
-	audioMusicUnload();	
-	Mix_PlayMusic( musicData, loops );
+  audioMusicUnload();        
+  Mix_PlayMusic( musicData, loops );
 }

Modified: tuxmath/trunk/src/campaign.c
===================================================================
--- tuxmath/trunk/src/campaign.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/campaign.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -10,6 +10,8 @@
 void briefPlayer(int stage); //show text introducing the given stage
 void readStageSettings(int stage);
 void readRoundSettings(int stage, int round);
+void showGameOver();
+void showGameWon();
 
 char* stagenames[NUM_STAGES] = {"cadet", "scout", "ranger", "ace", "commando"};
 
@@ -18,7 +20,7 @@
   int i, j;
   int gameresult = 0, endcampaign = 0;
   char roundmessage[10];
-  
+  char* endtext[2] = {"Congratulations! You win!", NULL};
   printf("Entering start_campaign()\n");
   
   
@@ -45,7 +47,7 @@
         ;
       else if (gameresult == GAME_OVER_LOST)
       {
-        //TODO game over sequence
+        showGameOver();
         endcampaign = 1;
       }
       else if (gameresult == GAME_OVER_ERROR)
@@ -63,12 +65,19 @@
         return;
       
     }
+    //if we've beaten the last stage, there is no bonus, skip to win sequence
+    if (i == NUM_STAGES - 1)
+    {
+      showGameWon();
+      break;
+    }
     //bonus round
     readStageSettings(i);
     readRoundSettings(i, -1);
     game_set_start_message("Bonus", "", "", "");
     game();
-  }
+  }
+  scroll_text(endtext, screen->clip_rect, 3);
 }
 
 void briefPlayer(int stage)
@@ -120,3 +129,15 @@
     snprintf(fn,PATH_MAX, "campaign/%s/round%d", stagenames[stage], round);
   read_named_config_file(fn);
 }
+
+void showGameOver()
+{
+	char* text[2] = {"Sorry, try again!", NULL};
+	scroll_text(text, screen->clip_rect, 3);
+}
+
+void showGameWon()
+{
+	char* text[2] = {"Mission accomplished. The galaxy is safe!", NULL};
+	scroll_text(text, screen->clip_rect, 3);
+}

Modified: tuxmath/trunk/src/credits.c
===================================================================
--- tuxmath/trunk/src/credits.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/credits.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -478,7 +478,8 @@
   while (!done);
   return quit;
 }
-#if 0
+#if 0 //really cool effect, but not translatable. I'll leave it in in case we 
+      //decide to use it e.g. only for English
 void draw_text(char * str, int offset)
 {
   int i, c, x, y, cur_x, start, hilite;

Modified: tuxmath/trunk/src/fileops.c
===================================================================
--- tuxmath/trunk/src/fileops.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/fileops.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -161,8 +161,8 @@
 */
 static HRESULT ReadRegistry(const char *key, const char *option, char *value, int size)
 {
-  LONG	res;
-  HKEY	hKey = NULL;
+  LONG        res;
+  HKEY        hKey = NULL;
 
   res = RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_READ, &hKey);
   if (res != ERROR_SUCCESS)
@@ -1189,12 +1189,11 @@
     /* terminate string here: */
     *value_end = 0;
 
-    #ifdef TUXMATH_DEBUG
-    printf("parameter = '%s'\t, length = %zu\n", parameter, strlen(parameter));
-    printf("value = '%s'\t, length = %zu\t, atoi() = %d\t, atof() = %.2f\n", value, strlen(value), atoi(value), atof(value));
-    #endif
+    tmdprintf("parameter = '%s'\t, length = %zu\n", parameter, strlen(parameter));
+    tmdprintf("value = '%s'\t, length = %zu\t, atoi() = %d\t, atof() = %.2f\n", value, strlen(value), atoi(value), atof(value));
+    
     /* Now ready to handle each name/value pair! */
-
+    
     /* Set general game_options struct (see tuxmath.h): */ 
     if(0 == strcasecmp(parameter, "per_user_config"))
     {
@@ -1212,14 +1211,14 @@
       /* Only let administrator change this setting */
       if (file_type == GLOBAL_CONFIG_FILE && user_data_dir == NULL)
       {
-	/* Check to see whether the specified homedir exists */
-	dir = opendir(value);
-	if (dir == NULL)
-	  fprintf(stderr,"homedir: %s is not a directory, or it could not be read\n", value);
-	else {
-	  set_user_data_dir(value);  /* copy the homedir setting */
-	  closedir(dir);
-	}
+        /* Check to see whether the specified homedir exists */
+        dir = opendir(value);
+        if (dir == NULL)
+          fprintf(stderr,"homedir: %s is not a directory, or it could not be read\n", value);
+        else {
+          set_user_data_dir(value);  /* copy the homedir setting */
+          closedir(dir);
+        }
       }
     }
 
@@ -1380,324 +1379,28 @@
       Opts_SetMaxComets(atoi(value));
     }
 
-
-    /* Begin setting of math question options (see mathcards.h):   */ 
-
-    /* General math options */
-
-    else if(0 == strcasecmp(parameter, "allow_negatives"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetAllowNegatives(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "max_answer"))
-    {
-      MC_SetMaxAnswer(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_questions"))
-    {
-      MC_SetMaxQuestions(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "play_through_list"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetPlayThroughList(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "repeat_wrongs"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1) 
-        MC_SetRepeatWrongs(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "copies_repeated_wrongs"))
-    {
-      MC_SetCopiesRepeatedWrongs(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "question_copies"))
-    {
-        MC_SetQuestionCopies(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "randomize"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetRandomize(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "fraction_to_keep"))
-    {
-        MC_SetFractionToKeep(atof(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "format_answer_last"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatAnswerLast(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_answer_first"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatAnswerFirst(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_answer_middle"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatAnswerMiddle(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_add_answer_last"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatAddAnswerLast(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_add_answer_first"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatAddAnswerFirst(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_add_answer_middle"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatAddAnswerMiddle(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_sub_answer_last"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatSubAnswerLast(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_sub_answer_first"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatSubAnswerFirst(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_sub_answer_middle"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatSubAnswerMiddle(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_mult_answer_last"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatMultAnswerLast(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_mult_answer_first"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatMultAnswerFirst(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_mult_answer_middle"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatMultAnswerMiddle(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_div_answer_last"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatDivAnswerLast(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_div_answer_first"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatDivAnswerFirst(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "format_div_answer_middle"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetFormatDivAnswerMiddle(v);
-    }
-
-
-    /* Set the allowed math operations: */
-
-
-    else if(0 == strcasecmp(parameter, "addition_allowed"))
-    {
-      MC_SetAddAllowed(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "subtraction_allowed"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetSubAllowed(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "multiplication_allowed"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetMultAllowed(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "division_allowed"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetDivAllowed(v);
-    }
-
-    else if(0 == strcasecmp(parameter, "typing_practice_allowed"))
-    {
-      int v = str_to_bool(value);
-      if (v != -1)
-        MC_SetTypingAllowed(v);
-    }
-
-    /* Set min and max for addition: */
-
-
-    else if(0 == strcasecmp(parameter, "min_augend"))
-    {
-      MC_SetAddMinAugend(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_augend"))
-    {
-      MC_SetAddMaxAugend(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "min_addend"))
-    {
-      MC_SetAddMinAddend(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_addend"))
-    {
-      MC_SetAddMaxAddend(atoi(value));
-    }
-
-
-    /* Set min and max for subtraction: */
-
-
-    else if(0 == strcasecmp(parameter, "min_minuend"))
-    {
-      MC_SetSubMinMinuend(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_minuend"))
-    {
-      MC_SetSubMaxMinuend(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "min_subtrahend"))
-    {
-      MC_SetSubMinSubtrahend(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_subtrahend"))
-    {
-      MC_SetSubMaxSubtrahend(atoi(value));
-    }
-
-
-    /* Set min and max for multiplication: */
-
-
-    else if(0 == strcasecmp(parameter, "min_multiplier"))
-    {
-      MC_SetMultMinMultiplier(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_multiplier"))
-    {
-      MC_SetMultMaxMultiplier(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "min_multiplicand"))
-    {
-      MC_SetMultMinMultiplicand(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_multiplicand"))
-    {
-      MC_SetMultMaxMultiplicand(atoi(value));
-    }
-
-
-    /* Set min and max for division: */
-
-
-    else if(0 == strcasecmp(parameter, "min_divisor"))
-    {
-      MC_SetDivMinDivisor(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "min_quotient"))
-    {
-      MC_SetDivMinQuotient(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_divisor"))
-    {
-      MC_SetDivMaxDivisor(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_quotient"))
-    {
-      MC_SetDivMaxQuotient(atoi(value));
-    }
-
-
-    /* Set min and max for typing practice: */
-
-
-    else if(0 == strcasecmp(parameter, "min_typing_num"))
-    {
-      MC_SetTypeMin(atoi(value));
-    }
-
-    else if(0 == strcasecmp(parameter, "max_typing_num"))
-    {
-      MC_SetTypeMax(atoi(value));
-    }
-
     else
     {   
-      #ifdef TUXMATH_DEBUG
-      printf("parameter not recognized: %s\n", parameter);
-      #endif    
+      MC_SetOp(parameter, atoi(value) ); //automatically handles bad parameters
     }
     free(parameter);
   }
-
+  //handle min > max by disallowing operation
+  if (MC_GetOpt(MIN_AUGEND) > MC_GetOpt(MAX_AUGEND) || 
+      MC_GetOpt(MIN_ADDEND) > MC_GetOpt(MAX_ADDEND) )
+      MC_SetOpt(ADDITION_ALLOWED, 0);
+  if (MC_GetOpt(MIN_MINUEND) > MC_GetOpt(MAX_MINUEND) || 
+      MC_GetOpt(MIN_SUBTRAHEND) > MC_GetOpt(MAX_SUBTRAHEND) )
+      MC_SetOpt(SUBTRACTION_ALLOWED, 0);
+  if (MC_GetOpt(MIN_MULTIPLICAND) > MC_GetOpt(MAX_MULTIPLICAND) || 
+      MC_GetOpt(MIN_MULTIPLIER) > MC_GetOpt(MAX_MULTIPLIER) )
+      MC_SetOpt(MULTIPLICATION_ALLOWED, 0);
+  if (MC_GetOpt(MIN_DIVISOR) > MC_GetOpt(MAX_DIVISOR) || 
+      MC_GetOpt(MIN_QUOTIENT) > MC_GetOpt(MAX_QUOTIENT) )
+      MC_SetOpt(DIVISION_ALLOWED, 0);
+  if (MC_GetOpt(MIN_TYPING_NUM) > MC_GetOpt(MAX_TYPING_NUM) )
+      MC_SetOpt(TYPING_PRACTICE_ALLOWED, 0);
+      
   #ifdef TUXMATH_DEBUG
   printf("\nAfter file read in:\n");
   write_config_file(stdout, 0);
@@ -1747,475 +1450,271 @@
 /* human-readable file.                                        */
 int write_config_file(FILE *fp, int verbose)
 {
-  #ifdef TUXMATH_DEBUG
-  printf("\nEntering write_config_file()\n");
-  #endif
+  int i, vcommentsprimed = 0;
+  static char* vcomments[NOPTS]; //comments when writing out verbose
+  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"
+    "#              Tuxmath Configuration File                  #\n"
+    "#                                                          #\n"
+    "# The behavior of Tuxmath can be controlled to a great     #\n"
+    "# extent by editing this file with any and saving it in    #\n"
+    "# the default options location ($HOME/.tuxmath/options).   #\n"
+    "# The file consists of 'NAME = VALUE' pairs, one pair per  #\n"
+    "# line. Each option is one of the following types:         #\n"
+    "#                                                          #\n"
+    "#     boolean: 1 (synonyms 'true', 'T', 'yes', 'Y', 'on')  #\n"
+    "#              or                                          #\n"
+    "#              0 (synonyms 'false, 'F', 'no', 'N', 'off')  #\n"
+    "#     integer  (i.e. non-fractional numbers)               #\n"
+    "#     float    (i.e decimal fractions)                     #\n"
+    "#                                                          #\n"
+    "# Lines beginning with '#' or ';' are ignored as comments. #\n"
+    "# The synonyms for boolean '0' and '1' are accepted as     #\n"
+    "# input, but always written as '0' or '1' when Tuxmath     #\n"
+    "# writes a config file to disk.                            #\n"
+    "# The file is organized with the more important options    #\n"
+    "# first.                                                   #\n"
+    "############################################################\n"
+    "\n"
+    "############################################################\n"
+    "#                                                          #\n"
+    "#                       Game Mode                          #\n"
+    "#                                                          #\n"
+    "# Parameter: play_through_list (Boolean)                   #\n"
+    "# Default: 1                                               #\n"
+    "#                                                          #\n"
+    "# Tuxmath generates a list of math questions based on      #\n"
+    "# parameters set below.  By default, (play_through_list =  #\n"
+    "# 1) the questions are asked in a random order.            #\n"
+    "# Correctly answered questions are removed from the list.  #\n"
+    "# If the player fails to correctly answer a question       #\n"
+    "# before it hits a city, the question will be reinserted   #\n"
+    "# into the list in a random location.                      #\n"
+    "# The player wins if all questions are answered correctly  #\n"
+    "# before the cities are destroyed.                         #\n"
+    "#                                                          #\n"
+    "# Alternatively, Tuxmath can be played in 'Arcade Mode'    #\n"
+    "# by setting play_through_list = 0 (i.e. 'false'). If this #\n"
+    "# is done, all questions will be randomly reinserted into  #\n"
+    "# the list whether or not they are answered correctly, and #\n"
+    "# the game continues as long as there is a surviving city. #\n"
+    "############################################################\n"
+    "\n";                                                           
+    
+    vcomments[ADDITION_ALLOWED] = 
+    "\n############################################################\n"
+    "#                                                          #\n"
+    "#               Selecting Math Operations                  #\n"
+    "#                                                          #\n"
+    "# Parameter: addition_allowed (boolean)                    #\n"
+    "# Default: 1                                               #\n"
+    "# Parameter: subtraction_allowed (boolean)                 #\n"
+    "# Default: 1                                               #\n"
+    "# Parameter: multiplication_allowed (boolean)              #\n"
+    "# Default: 1                                               #\n"
+    "# Parameter: division_allowed (boolean)                    #\n"
+    "# Default: 1                                               #\n"
+    "#                                                          #\n"
+    "# These options enable questions for each of the four math #\n"
+    "# operations.  All are 1 (yes) by default.                 #\n"
+    "############################################################\n\n";
+    vcomments[TYPING_PRACTICE_ALLOWED] =
+    "\n############################################################\n"
+    "#                                                          #\n"
+    "#                    Typing Practice                       #\n"
+    "#                                                          #\n"
+    "# Parameter: typing_practice_allowed (boolean)             #\n"
+    "# Default: 0                                               #\n"
+    "#                                                          #\n"
+    "# This option simply displays numbers for the youngest     #\n"
+    "# players to type in to learn the keyboard.                #\n"
+    "############################################################\n\n";
+    vcomments[ALLOW_NEGATIVES] =
+    "\n############################################################\n"
+    "#                                                          #\n"
+    "#                 Negative Number Support                  #\n"
+    "#                                                          #\n"
+    "# Parameter: allow_negatives (boolean)                     #\n"
+    "# Default: 0                                               #\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. If it is changed    #\n"
+    "# from 1 (yes) to 0 (no), any negative operand limits will #\n"
+    "# be reset to 0.                                           #\n"
+    "############################################################\n\n";
+    vcomments[MIN_AUGEND] = 
+    "\n############################################################\n"
+    "#                                                          #\n"
+    "#      Minimum and Maximum Values for Operand Ranges       #\n"
+    "#                                                          #\n"
+    "# Parameters: (multiple - all integer type)                #\n"
+    "#                                                          #\n"
+    "# Operand limits can be set to any integer up to the       #\n"
+    "# value of 'max_answer'. Tuxmath will generate questions   #\n"
+    "# for every value in the specified range. The maximum must #\n"
+    "# be greater than or equal to the corresponding minimum    #\n"
+    "# for any questions to be generated for that operation.    #\n"
+    "# Defaults are 0 for minima and 12 for maxima.             #\n"
+    "#                                                          #\n"
+    "# Note: 'allow_negatives' must be set to 1 for negative    #\n"
+    "# values to be accepted (see 'Advanced Options').          #\n"
+    "############################################################\n"
+    "\n# Addition operands:\n"
+    "# augend + addend = sum\n\n";
+    vcomments[MIN_MINUEND] = 
+    "\n# Subtraction operands:\n"
+    "# minuend - subtrahend = difference\n\n";
+    vcomments[MIN_MULTIPLIER] = 
+    "\n# Multiplication operands:\n"
+    "# multiplier * multiplicand = product\n\n";
+    vcomments[MIN_DIVISOR] = 
+    "\n# Division operands:\n"
+    "# dividend / divisor = quotiend\n\n";
+    vcomments[MIN_TYPING_NUM] =
+    "\n# Typing practice:\n";
+    vcomments[QUESTION_COPIES] = 
+    "\n\n\n############################################################\n"
+    "#                                                          #\n"
+    "#                   Advanced Options                       #\n"
+    "#                                                          #\n"
+    "# The remaining settings further customize Tuxmath's       #\n"
+    "# behavior.  Most users will probably not change them.     #\n"
+    "############################################################\n\n";
+    
+    "\n############################################################\n"
+    "#                                                          #\n"
+    "#           Advanced Math Question List Options            #\n"
+    "#                                                          #\n"
+    "# Parameter: question_copies (integer)                     #\n"
+    "# Default: 1                                               #\n"
+    "# Parameter: repeat_wrongs (boolean)                       #\n"
+    "# Default: 1                                               #\n"
+    "# Parameter: copies_repeated_wrongs (integer)              #\n"
+    "# Default: 1                                               #\n"
+    "# Parameter: fraction_to_keep (float)                      #\n"
+    "# Default: 1                                               #\n"
+    "#                                                          #\n"
+    "# These settings offer further control over the question   #\n"
+    "# list and are generally only useful if 'play_through_list'#\n"
+    "# is enabled (as it is by default).                        #\n"
+    "#                                                          #\n"
+    "# 'question_copies' is the number of times each question   #\n"
+    "# is put into the initial list. It can be 1 to 10.         #\n"
+    "#                                                          #\n"
+    "# 'repeat_wrongs' determines whether questions the player  #\n"
+    "# failed to answer correctly will be asked again.          #\n"
+    "#                                                          #\n"
+    "# 'copies_repeated_wrongs' gives the number of times a     #\n"
+    "# missed question will reappear. This can be set anywhere  #\n"
+    "# from 1 to 10.                                            #\n"
+    "#                                                          #\n"
+    "# 'fraction_to_keep' allows a list to be generated that    #\n"
+    "# consists of a randomly-selected subset of the questions  #\n"
+    "# fitting the criteria.  The parameter is a float that     #\n"
+    "# must be greater than 0 and less than or equal to 1. For  #\n"
+    "# example, a value of 0.1 means 10%% of the questions      #\n"
+    "# meeting the criteria will go into the list.              #\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"
+    "#                                                          #\n"
+    "#                 Math Question Formats                    #\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. All parameters are type 'boolean'.      #\n"
+    "############################################################\n\n";
+    vcomments[MAX_ANSWER] = 
+    "\n############################################################\n"
+    "#                                                          #\n"
+    "# Parameter: max_answer (integer)                          #\n"
+    "# Default: 999                                             #\n"
+    "#                                                          #\n"
+    "# 'max_answer' is the largest absolute value allowed in    #\n"
+    "# any value in a question (not only the answer). Default   #\n"
+    "# is 999, which is as high as it can be set. It can be set #\n"
+    "# lower to fine-tune the list for certain 'lessons'.       #\n"
+    "############################################################\n\n";
+    vcomments[MAX_QUESTIONS] = 
+    "\n############################################################\n"
+    "#                                                          #\n"
+    "# Parameter: max_questions (integer)                       #\n"
+    "# Default: 5000                                            #\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"
+    "#                                                          #\n"
+    "# Parameter: randomize (boolean)                           #\n"
+    "# Default: 1                                               #\n"
+    "#                                                          #\n"
+    "# If 'randomize' selected, the list will be shuffled       #\n"
+    "# at the start of the game. Otherwise, the questions       #\n"
+    "# appear in the order the program generates them.          #\n"
+    "############################################################\n\n";
+    
+  }
+  
+  tmdprintf("\nEntering write_config_file()\n");
 
   /* get out if file pointer null */
   if(!fp)
   {
     fprintf (stderr, "write_config_file() - file pointer invalid/n");
-
-    #ifdef TUXMATH_DEBUG
-    printf("Leaving write_config_file()\n");
-    #endif
-
+    tmdprintf("Leaving write_config_file()\n");
     return 0;
   }
-
-  if (verbose)
+  
+  for (i = 0; i < NOPTS; ++i) //for each option
   {
-    fprintf(fp, 
-          "############################################################\n"
-          "#                                                          #\n"
-          "#              Tuxmath Configuration File                  #\n"
-          "#                                                          #\n"
-          "# The behavior of Tuxmath can be controlled to a great     #\n"
-          "# extent by editing this file with any and saving it in    #\n"
-          "# the default options location ($HOME/.tuxmath/options).   #\n"
-          "# The file consists of 'NAME = VALUE' pairs, one pair per  #\n"
-          "# line. Each option is one of the following types:         #\n"
-          "#                                                          #\n"
-          "#     boolean: 1 (synonyms 'true', 'T', 'yes', 'Y', 'on')  #\n"
-          "#              or                                          #\n"
-          "#              0 (synonyms 'false, 'F', 'no', 'N', 'off')  #\n"
-          "#     integer  (i.e. non-fractional numbers)               #\n"
-          "#     float    (i.e decimal fractions)                     #\n"
-          "#                                                          #\n"
-          "# Lines beginning with '#' or ';' are ignored as comments. #\n"
-          "# The synonyms for boolean '0' and '1' are accepted as     #\n"
-          "# input, but always written as '0' or '1' when Tuxmath     #\n"
-          "# writes a config file to disk.                            #\n"
-          "# The file is organized with the more important options    #\n"
-          "# first.                                                   #\n"
-          "############################################################\n"
-          "\n"
-    );
+    if (verbose && vcomments[i]) //comment goes before
+      fprintf(fp, vcomments[i]);
+    fprintf(fp, "%s = %d\n", MC_OPTION_TEXT[i], MC_GetOpt(i) );
   }
-
+  
   if (verbose)
   {
-    fprintf(fp, 
-          "############################################################\n"
-          "#                                                          #\n"
-          "#                       Game Mode                          #\n"
-          "#                                                          #\n"
-          "# Parameter: play_through_list (Boolean)                   #\n"
-          "# Default: 1                                               #\n"
-          "#                                                          #\n"
-          "# Tuxmath generates a list of math questions based on      #\n"
-          "# parameters set below.  By default, (play_through_list =  #\n"
-          "# 1) the questions are asked in a random order.            #\n"
-          "# Correctly answered questions are removed from the list.  #\n"
-          "# If the player fails to correctly answer a question       #\n"
-          "# before it hits a city, the question will be reinserted   #\n"
-          "# into the list in a random location.                      #\n"
-          "# The player wins if all questions are answered correctly  #\n"
-          "# before the cities are destroyed.                         #\n"
-          "#                                                          #\n"
-          "# Alternatively, Tuxmath can be played in 'Arcade Mode'    #\n"
-          "# by setting play_through_list = 0 (i.e. 'false'). If this #\n"
-          "# is done, all questions will be randomly reinserted into  #\n"
-          "# the list whether or not they are answered correctly, and #\n"
-          "# the game continues as long as there is a surviving city. #\n"
-          "############################################################\n"
-          "\n"
-    );
+    //allow_speedup comment
   }
-  fprintf (fp, "play_through_list = %d\n", MC_PlayThroughList());
-
-
+  fprintf(fp, "allow_speedup = %d\n", Opts_AllowSpeedup() );
+  
   if (verbose)
   {
-    fprintf (fp, "\n############################################################\n" 
-                 "#                                                          #\n"
-                 "#                 Speed and Number of Comets               #\n"
-                 "#                                                          #\n"
-                 "# Parameter: allow_speedup (boolean)                       #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: use_feedback  (boolean)                       #\n"
-                 "# Default: 0                                               #\n"
-                 "#                                                          #\n"
-                 "# By default, the comets become faster and more numerous   #\n"
-                 "# with each succeeding. The increase can be prevented      #\n"
-                 "# by setting 'allow_speedup' to 0.                         #\n"
-                 "#                                                          #\n"
-                 "# If 'allow_speedup' is enabled, it is also possible to    #\n"
-                 "# dynamically adjust the speed to the player's performance #\n"
-                 "# by setting 'use_feedback' to 1.  This feature attempts   #\n"
-                 "# to speed the game up if it is too easy for the player,   #\n"
-                 "# and to slow it down if the player is having trouble.     #\n"
-                 "#                                                          #\n"
-                 "# Many additional parameters under 'Advanced Options' can  #\n"
-                 "# be used to fine-tune these behaviors.                    #\n"
-                 "############################################################\n\n");
-  }
-
-  fprintf(fp, "allow_speedup = %d\n", Opts_AllowSpeedup());
-  fprintf(fp, "use_feedback = %d\n", Opts_UseFeedback());
-
-
+    //use_sound comment
+  } 
+  fprintf(fp, "use_sound = %d\n", Opts_UseSound() );
+  
   if (verbose)
   {
-    fprintf (fp, "\n############################################################\n"
-                 "#                                                          #\n"
-                 "#               Selecting Math Operations                  #\n"
-                 "#                                                          #\n"
-                 "# Parameter: addition_allowed (boolean)                    #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: subtraction_allowed (boolean)                 #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: multiplication_allowed (boolean)              #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: division_allowed (boolean)                    #\n"
-                 "# Default: 1                                               #\n"
-                 "#                                                          #\n"
-                 "# These options enable questions for each of the four math #\n"
-                 "# operations.  All are 1 (yes) by default.                 #\n"
-                 "############################################################\n\n");
-  }
-
-  fprintf(fp, "addition_allowed = %d\n", MC_AddAllowed());
-  fprintf(fp, "subtraction_allowed = %d\n", MC_SubAllowed());
-  fprintf(fp, "multiplication_allowed = %d\n", MC_MultAllowed());
-  fprintf(fp, "division_allowed = %d\n", MC_DivAllowed());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n############################################################\n"
-                 "#                                                          #\n"
-                 "#                    Typing Practice                       #\n"
-                 "#                                                          #\n"
-                 "# Parameter: typing_practice_allowed (boolean)             #\n"
-                 "# Default: 0                                               #\n"
-                 "#                                                          #\n"
-                 "# This option simply displays numbers for the youngest     #\n"
-                 "# players to type in to learn the keyboard.                #\n"
-                 "############################################################\n\n");
-  }
-
-  fprintf(fp, "typing_practice_allowed = %d\n", MC_TypingAllowed());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n############################################################\n"
-                 "#                                                          #\n"
-                 "#                 Negative Number Support                  #\n"
-                 "#                                                          #\n"
-                 "# Parameter: allow_negatives (boolean)                     #\n"
-                 "# Default: 0                                               #\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. If it is changed    #\n"
-                 "# from 1 (yes) to 0 (no), any negative operand limits will #\n"
-                 "# be reset to 0.                                           #\n"
-                 "############################################################\n\n");
-  }
-
-  fprintf (fp, "allow_negatives = %d\n", MC_AllowNegatives());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n############################################################\n"
-                 "#                                                          #\n"
-                 "#      Minimum and Maximum Values for Operand Ranges       #\n"
-                 "#                                                          #\n"
-                 "# Parameters: (multiple - all integer type)                #\n"
-                 "#                                                          #\n"
-                 "# Operand limits can be set to any integer up to the       #\n"
-                 "# value of 'max_answer'. Tuxmath will generate questions   #\n"
-                 "# for every value in the specified range. The maximum must #\n"
-                 "# be greater than or equal to the corresponding minimum    #\n"
-                 "# for any questions to be generated for that operation.    #\n"
-                 "# Defaults are 0 for minima and 12 for maxima.             #\n"
-                 "#                                                          #\n"
-                 "# Note: 'allow_negatives' must be set to 1 for negative    #\n"
-                 "# values to be accepted (see 'Advanced Options').          #\n"
-                 "############################################################\n");
-  }
-
-  if (verbose)
-  {
-    fprintf(fp, "\n# Addition operands:\n"
-              "# augend + addend = sum\n\n");
-  }
-  fprintf(fp, "min_augend = %d\n", MC_AddMinAugend());
-  fprintf(fp, "max_augend = %d\n", MC_AddMaxAugend());
-  fprintf(fp, "min_addend = %d\n", MC_AddMinAddend());
-  fprintf(fp, "max_addend = %d\n", MC_AddMaxAddend());
-
-  if (verbose)
-  {
-    fprintf(fp, "\n# Subtraction operands:"
-              "\n# minuend - subtrahend = difference\n\n");
-  }
-  fprintf(fp, "min_minuend = %d\n", MC_SubMinMinuend());
-  fprintf(fp, "max_minuend = %d\n", MC_SubMaxMinuend());
-  fprintf(fp, "min_subtrahend = %d\n", MC_SubMinSubtrahend());
-  fprintf(fp, "max_subtrahend = %d\n", MC_SubMaxSubtrahend());
-
-  if (verbose)
-  {
-    fprintf(fp, "\n# Multiplication operands:"
-              "\n# multiplier * multiplicand = product\n\n");
-  }
-  fprintf(fp, "min_multiplier = %d\n", MC_MultMinMultiplier());
-  fprintf(fp, "max_multiplier = %d\n", MC_MultMaxMultiplier());
-  fprintf(fp, "min_multiplicand = %d\n", MC_MultMinMultiplicand());
-  fprintf(fp, "max_multiplicand = %d\n", MC_MultMaxMultiplicand());
-
-  if (verbose)
-  {
-    fprintf(fp, "\n# Division operands:"
-              "\n# dividend/divisor = quotient\n\n");
-  }
-  fprintf(fp, "min_divisor = %d\n",MC_DivMinDivisor());
-  fprintf(fp, "max_divisor = %d\n", MC_DivMaxDivisor());
-  fprintf(fp, "min_quotient = %d\n", MC_DivMinQuotient());
-  fprintf(fp, "max_quotient = %d\n", MC_DivMaxQuotient());
-
-  if (verbose)
-  {
-    fprintf(fp, "\n# Typing practice:\n\n");
-  }
-  fprintf(fp, "min_typing_num = %d\n",MC_TypeMin());
-  fprintf(fp, "max_typing_num = %d\n", MC_TypeMax());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n\n############################################################\n" 
-                 "#                                                          #\n"
-                 "#                 General Game Options                     #\n"
-                 "#                                                          #\n"
-                 "# Parameter: use_sound (boolean)                           #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: menu_sound (boolean)                          #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: menu_music (boolean)                          #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: fullscreen (boolean)                          #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: demo_mode (boolean)                           #\n"
-                 "# Default: 0                                               #\n"
-                 "# Parameter: use_keypad (boolean)                          #\n"
-                 "# Default: 0                                               #\n"
-                 "# Parameter: allow_pause (boolean)                         #\n"
-                 "# Default: 0                                               #\n"
-                 "# Parameter: use_igloos (boolean)                          #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: save_game_summary (boolean)                   #\n"
-                 "# Default: 1                                               #\n"
-                 "#                                                          #\n"
-                 "# These parameters control various aspects of Tuxmath's    #\n"
-                 "# not directly related to the math question to be asked.   #\n"
-                 "############################################################\n");
-
-  }
-  if (verbose)
-  {
-    fprintf (fp, "\n# Use game sounds and background music if possible:\n");
-  }
-  fprintf(fp, "use_sound = %d\n", Opts_UseSound());
-  fprintf(fp, "menu_sound = %d\n", Opts_MenuSound());
-  fprintf(fp, "menu_music = %d\n", Opts_MenuMusic());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n# Use fullscreen at 640x480 resolution instead of\n"
-                 "# 640x480 window. Change to 0 if SDL has trouble with\n"
-                 "# fullscreen on your system:\n");
-  }
-  fprintf(fp, "fullscreen = %d\n", Opts_Fullscreen());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n# Display jpg images for background:\n");
-  }
-  fprintf(fp, "use_bkgd = %d\n", Opts_UseBkgd());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n# Run Tuxmath as demo (i.e. without user input):\n");
-  }
-  fprintf(fp, "demo_mode = %d\n", Opts_DemoMode());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n# Display onscreen numeric keypad - allows mouse-only\n"
-               "# gameplay or use with touchscreens:\n");
-  }
-  fprintf(fp, "use_keypad = %d\n", Opts_UseKeypad());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n# Allow 'Pause' feature - should disable this\n"
-               "# when competing for high scores!\n");
-  }
-  fprintf(fp, "allow_pause = %d\n", Opts_AllowPause());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n# Use newer graphics where Tux defends igloo-\n"
-               "# dwelling penguins (for those who find the older\n"
-               "# images of exploding cities to be distasteful)\n");
-  }
-  fprintf(fp, "use_igloos = %d\n", Opts_UseIgloos());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n# By default, Tuxmath saves summaries of the last\n"
-               "# ten games in the user's .tuxmath directory. Set\n"
-               "# this parameter to '0' to turn off.\n");
-  }
-  fprintf(fp, "save_summary = %d\n", Opts_SaveSummary());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n\n\n############################################################\n" 
-                 "#                                                          #\n"
-                 "#                   Advanced Options                       #\n"
-                 "#                                                          #\n"
-                 "# The remaining settings further customize Tuxmath's       #\n"
-                 "# behavior.  Most users will probably not change them.     #\n"
-                 "############################################################\n\n");
-  }
-
-  if (verbose)
-  {
-    fprintf (fp, "\n############################################################\n"
-                 "#                                                          #\n"
-                 "#           Advanced Math Question List Options            #\n"
-                 "#                                                          #\n"
-                 "# Parameter: question_copies (integer)                     #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: repeat_wrongs (boolean)                       #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: copies_repeated_wrongs (integer)              #\n"
-                 "# Default: 1                                               #\n"
-                 "# Parameter: fraction_to_keep (float)                      #\n"
-                 "# Default: 1                                               #\n"
-                 "#                                                          #\n"
-                 "# These settings offer further control over the question   #\n"
-                 "# list and are generally only useful if 'play_through_list'#\n"
-                 "# is enabled (as it is by default).                        #\n"
-                 "#                                                          #\n"
-                 "# 'question_copies' is the number of times each question   #\n"
-                 "# is put into the initial list. It can be 1 to 10.         #\n"
-                 "#                                                          #\n"
-                 "# 'repeat_wrongs' determines whether questions the player  #\n"
-                 "# failed to answer correctly will be asked again.          #\n"
-                 "#                                                          #\n"
-                 "# 'copies_repeated_wrongs' gives the number of times a     #\n"
-                 "# missed question will reappear. This can be set anywhere  #\n"
-                 "# from 1 to 10.                                            #\n"
-                 "#                                                          #\n"
-                 "# 'fraction_to_keep' allows a list to be generated that    #\n"
-                 "# consists of a randomly-selected subset of the questions  #\n"
-                 "# fitting the criteria.  The parameter is a float that     #\n"
-                 "# must be greater than 0 and less than or equal to 1. For  #\n"
-                 "# example, a value of 0.1 means 10%% of the questions       #\n"
-                 "# meeting the criteria will go into the list.              #\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");
-  }
-
-  fprintf (fp, "question_copies = %d\n", MC_QuestionCopies());
-  fprintf (fp, "repeat_wrongs = %d\n", MC_RepeatWrongs());
-  fprintf (fp, "copies_repeated_wrongs = %d\n", MC_CopiesRepeatedWrongs());
-  fprintf (fp, "fraction_to_keep = %.2f\n", MC_FractionToKeep());
-
-
-  if (verbose)
-  {
-    fprintf (fp, "\n############################################################\n"
-                 "#                                                          #\n"
-                 "#                 Math Question Formats                    #\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. All parameters are type 'boolean'.      #\n"
-                 "############################################################\n\n");
-  }
-
-  fprintf (fp, "format_add_answer_last = %d\n", MC_FormatAddAnswerLast());
-  fprintf (fp, "format_add_answer_first = %d\n", MC_FormatAddAnswerFirst());
-  fprintf (fp, "format_add_answer_middle = %d\n", MC_FormatAddAnswerMiddle());
-  fprintf (fp, "format_sub_answer_last = %d\n", MC_FormatSubAnswerLast());
-  fprintf (fp, "format_sub_answer_first = %d\n", MC_FormatSubAnswerFirst());
-  fprintf (fp, "format_sub_answer_middle = %d\n", MC_FormatSubAnswerMiddle());
-  fprintf (fp, "format_mult_answer_last = %d\n", MC_FormatMultAnswerLast());
-  fprintf (fp, "format_mult_answer_first = %d\n", MC_FormatMultAnswerFirst());
-  fprintf (fp, "format_mult_answer_middle = %d\n", MC_FormatMultAnswerMiddle());
-  fprintf (fp, "format_div_answer_last = %d\n", MC_FormatDivAnswerLast());
-  fprintf (fp, "format_div_answer_first = %d\n", MC_FormatDivAnswerFirst());
-  fprintf (fp, "format_div_answer_middle = %d\n", MC_FormatDivAnswerMiddle());
-
-
-  if (verbose)
-  {
-    fprintf (fp, "\n############################################################\n"
-                 "#                                                          #\n"
-                 "# Parameter: max_answer (integer)                          #\n"
-                 "# Default: 999                                             #\n"
-                 "#                                                          #\n"
-                 "# 'max_answer' is the largest absolute value allowed in    #\n"
-                 "# any value in a question (not only the answer). Default   #\n"
-                 "# is 999, which is as high as it can be set. It can be set #\n"
-                 "# lower to fine-tune the list for certain 'lessons'.       #\n"
-                 "############################################################\n\n");
-  }
-  fprintf (fp, "max_answer = %d\n", MC_MaxAnswer());
-
-  if (verbose)
-  {
-    fprintf (fp, "\n############################################################\n"
-                 "#                                                          #\n"
-                 "# Parameter: max_questions (integer)                       #\n"
-                 "# Default: 5000                                            #\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");
-  }
-  fprintf (fp, "max_questions = %d\n", MC_MaxQuestions());  
-
-  if (verbose)
-  {
-    fprintf (fp, "\n############################################################\n"
-                 "#                                                          #\n"
-                 "# Parameter: randomize (boolean)                           #\n"
-                 "# Default: 1                                               #\n"
-                 "#                                                          #\n"
-                 "# If 'randomize' selected, the list will be shuffled       #\n"
-                 "# at the start of the game. Otherwise, the questions       #\n"
-                 "# appear in the order the program generates them.          #\n"
-                 "############################################################\n\n");
-  }
-  fprintf (fp, "randomize = %d\n", MC_Randomize());
-
-
-  if (verbose)
-  {
     fprintf (fp, "\n############################################################\n" 
                  "#                                                          #\n"
                  "#                Advanced Comet Speed Options              #\n"
@@ -2607,7 +2106,7 @@
     fp = fopen(filepath1, "a"); /* "a" means append to end of file */
     if (fp) {
       if (write_column_names) {
-	fprintf(fp,"\"User\",\"Mission\",\"Date\",\"Completed?\",\"Number answered\",\"Percent correct\",\"Time per question\"\n");
+        fprintf(fp,"\"User\",\"Mission\",\"Date\",\"Completed?\",\"Number answered\",\"Percent correct\",\"Time per question\"\n");
       }
       mission_name = strdup(last_config_file_name);
       fprintf(fp,"\"%s\",\"%s\",%d/%d/%d,%d,%d,%d,%g\n", get_user_name(), get_file_name(mission_name), datetime.tm_year+1900, datetime.tm_mon+1, datetime.tm_mday, MC_MissionAccomplished(), total_answered, ((MC_NumAnsweredCorrectly() * 100)/ total_answered), median_time);
@@ -3076,7 +2575,7 @@
       if (sounds[i] == NULL)
       {
         fprintf(stderr,
-	        "\nError: I couldn't load a sound file:\n"
+                "\nError: I couldn't load a sound file:\n"
                 "%s\n"
                 "The Simple DirectMedia error that occured was:\n"
                 "%s\n\n", sound_filenames[i], SDL_GetError());
@@ -3102,7 +2601,7 @@
       if (musics[i] == NULL)
       {
         fprintf(stderr,
-	        "\nError: I couldn't load a music file:\n"
+                "\nError: I couldn't load a music file:\n"
                 "%s\n"
                 "The Simple DirectMedia error that occured was:\n"
                 "%s\n\n", music_filenames[i], SDL_GetError());
@@ -3111,12 +2610,12 @@
       
       if (i == NUM_MUSICS - 1)
       {
-	dest.x = 0;
-	dest.y = (screen->h) - 10;
-	dest.w = ((screen->w) * (i + 1 + NUM_IMAGES + NUM_SOUNDS)) / total_files;
-	dest.h = 10;
-	
-	SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 255, 0));
+        dest.x = 0;
+        dest.y = (screen->h) - 10;
+        dest.w = ((screen->w) * (i + 1 + NUM_IMAGES + NUM_SOUNDS)) / total_files;
+        dest.h = 10;
+        
+        SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 255, 0));
         SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
       }
     }

Modified: tuxmath/trunk/src/fileops.h
===================================================================
--- tuxmath/trunk/src/fileops.h	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/fileops.h	2008-08-06 02:55:05 UTC (rev 589)
@@ -1,11 +1,11 @@
 /*
 C Interface: fileops.h
 
-Description: File operations - together, fileops.h and fileops.c contain 
-all code involving disk operations. The older header files images.h and 
+Description: File operations - together, fileops.h and fileops.c contain
+all code involving disk operations. The older header files images.h and
 sounds.h have been incorporated here. The intention is to make it easier to
-port tuxmath to other operating systems, as code to read and write as 
-well as paths and file locations may be more OS-dependent. 
+port tuxmath to other operating systems, as code to read and write as
+well as paths and file locations may be more OS-dependent.
 
 
 Author: David Bruce <dbruce at tampabay.rr.com>, (C) 2006
@@ -13,8 +13,8 @@
 Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL)
 */
 
-#ifndef CONFIG_H
-#define CONFIG_H
+#ifndef FILEOPS_H
+#define FILEOPS_H
 
 #include "tuxmath.h"
 
@@ -235,7 +235,8 @@
 int write_user_config_file(void);
 int read_high_scores(void);
 int append_high_scores(int tableid,int score,char *player_name);
-void set_high_score_path(void);
+void set_high_score_path(void);
+void set_user_data_dir(const char* dirname);
 int write_goldstars(void);
 
 /* These functions are used by titlescreen() to assist with the login */

Modified: tuxmath/trunk/src/game.c
===================================================================
--- tuxmath/trunk/src/game.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/game.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -42,8 +42,8 @@
 #define FPS 15                     /* 15 frames per second */
 #define MS_PER_FRAME (1000 / FPS)
 
-#define CITY_EXPL_START 3 * 5  /* Must be mult. of 5 (number of expl frames) */
-#define ANIM_FRAME_START 4 * 2 /* Must be mult. of 2 (number of tux frames) */
+#define CITY_EXPL_START (3 * 5)  /* Must be mult. of 5 (number of expl frames) */
+#define ANIM_FRAME_START (4 * 2) /* Must be mult. of 2 (number of tux frames) */
 #define GAMEOVER_COUNTER_START 40
 #define LEVEL_START_WAIT_START 20
 #define LASER_START 5
@@ -61,12 +61,6 @@
 const int SND_IGLOO_SIZZLE = SND_SIZZLE;
 const int IMG_CITY_NONE = 0;
 
-char operchars[4] = {
-   "+-*/"
-};
-
-
-
 typedef struct comet_type {
   int alive;
   int expl;
@@ -118,7 +112,7 @@
 static float comet_feedback_height;
 static float danger_level;
 
-static int digits[3];
+static int digits[MC_MAX_DIGITS];
 
 static comet_type* comets = NULL;
 static city_type* cities = NULL;
@@ -133,8 +127,9 @@
 SDL_Surface* current_bkgd()
   { return screen->flags & SDL_FULLSCREEN ? scaled_bkgd : bkgd; }
 
-static game_message s1, s2, s3, s4, s5;
-static int start_message_chosen = 0;
+static game_message s1, s2, s3, s4, s5;
+static int start_message_chosen = 0;
+
 
 typedef struct {
   int x_is_blinking;
@@ -167,7 +162,7 @@
 static int check_exit_conditions(void);
 
 static void draw_numbers(const char* str, int x, int y);
-static void game_set_message(game_message *,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_write_message(const game_message* msg);
 static void game_write_messages(void);
@@ -187,7 +182,7 @@
 static void game_key_event(SDLKey key);
 static void free_on_exit(void);
 
-static void help_add_comet(int a,int oper,int b,int c);
+static void help_add_comet(const char* formula_str, const char* ans_str);
 static int help_renderframe_exit(void);
 
 static void game_recalc_positions(void);
@@ -277,7 +272,7 @@
     {
       if (!Mix_PlayingMusic())
       {
-	    Mix_PlayMusic(musics[MUS_GAME + (rand() % 3)], 0);
+            Mix_PlayMusic(musics[MUS_GAME + (rand() % 3)], 0);
       }
     }
 #endif
@@ -291,7 +286,7 @@
       //  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;
+        now_time = MS_PER_FRAME;
       SDL_Delay(now_time);
     }
   }
@@ -380,7 +375,7 @@
         now_time = SDL_GetTicks();
 
         if (now_time < last_time + MS_PER_FRAME)
-	  SDL_Delay(last_time + MS_PER_FRAME - now_time);
+          SDL_Delay(last_time + MS_PER_FRAME - now_time);
       }
       while (looping);
       break;
@@ -424,7 +419,7 @@
         now_time = SDL_GetTicks();
 
         if (now_time < last_time + MS_PER_FRAME)
-	  SDL_Delay(last_time + MS_PER_FRAME - now_time);
+          SDL_Delay(last_time + MS_PER_FRAME - now_time);
       }
       while (looping);
 
@@ -464,29 +459,31 @@
   else
   {
     /* return to title() screen: */
-    
     return game_status;
   }
 }
-/* 
-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.
+
+/* 
+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.
 */
-void game_set_start_message(const char* m1, const char* m2, 
-                            const char* m3, const char* m4)
-{
-  game_set_message(&s1, m1, screen->w / 2 - 40, RES_Y * 0 / 4);
-  game_set_message(&s2, m2, screen->w / 2 - 40, RES_Y * 1 / 4);
-  game_set_message(&s3, m3, screen->w / 2 - 40, RES_Y * 2 / 4);
-  game_set_message(&s4, m4, screen->w / 2 - 40, RES_Y * 3 / 4);
-  start_message_chosen = 1;
-}
+void game_set_start_message(const char* m1, const char* m2, 
+                            const char* m3, const char* m4)
+{
+  game_set_message(&s1, m1, screen->w / 2 - 40, RES_Y * 0 / 4);
+  game_set_message(&s2, m2, screen->w / 2 - 40, RES_Y * 1 / 4);
+  game_set_message(&s3, m3, screen->w / 2 - 40, RES_Y * 2 / 4);
+  game_set_message(&s4, m4, screen->w / 2 - 40, RES_Y * 3 / 4);
+  start_message_chosen = 1;
+}
 
 int game_initialize(void)
 {
   int i,img;
+  
+  tmdprintf("Entering game_initialize()\n");
+
   /* Clear window: */
-
   SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
   SDL_Flip(screen);
 
@@ -495,6 +492,18 @@
   SDL_quit_received = 0;
   escape_received = 0;
 
+  /* Start MathCards backend: */
+  /* 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())
+  {
+    tmdprintf("\nMC_StartGame() failed!");
+    fprintf(stderr, "\nMC_StartGame() failed!");
+    return 0;
+  }
+
   /* Allocate memory */
   comets = NULL;  // set in case allocation fails partway through
   cities = NULL;
@@ -505,6 +514,21 @@
     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;
+        }
+      }
+  }
+  
   cities = (city_type *) malloc(NUM_CITIES * sizeof(city_type));
   if (cities == NULL) {
     printf("Allocation of cities failed");
@@ -521,20 +545,7 @@
     return 0;
   }
 
-  /* Start MathCards backend: */
-  /* 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())
-  {
-#ifdef TUXMATH_DEBUG
-    printf("\nMC_StartGame() failed!");
-#endif
-    fprintf(stderr, "\nMC_StartGame() failed!");
-    return 0;
-  }
-
+  
   /* Write pre-game info to game summary file: */
   if (Opts_SaveSummary())
   {
@@ -606,9 +617,7 @@
 
   if (Opts_BonusCometInterval()) {
     bonus_comet_counter = Opts_BonusCometInterval() + 1;
-#ifdef TUXMATH_DEBUG
-    printf("\nInitializing with bonus_comet_counter = %d\n",bonus_comet_counter);
-#endif
+    tmdprintf("\nInitializing with bonus_comet_counter = %d\n",bonus_comet_counter);
   }
   extra_life_earned = 0;
   cloud.status = EXTRA_LIFE_OFF;
@@ -631,15 +640,15 @@
   tux_anim = -1;
   tux_anim_frame = 0;
 
-  // Initialize the messages
-  if (!start_message_chosen)
-  {
-    game_clear_message(&s1);
-    game_clear_message(&s2);
-    game_clear_message(&s3);
-    game_clear_message(&s4);
+  // Initialize the messages
+  game_clear_message(&s5);
+  if (!start_message_chosen)
+  {
+    game_clear_message(&s1);
+    game_clear_message(&s2);
+    game_clear_message(&s3);
+    game_clear_message(&s4);
   }
-  game_clear_message(&s5);
 
   help_controls.x_is_blinking = 0;
   help_controls.extra_life_is_blinking = 0;
@@ -730,7 +739,7 @@
 
   // Bring in a comet
   speed = 2;
-  help_add_comet(2,MC_OPER_ADD,1,3);
+  help_add_comet("2 + 1 = ?", "3");
   help_controls.laser_enabled = 1;
   level_start_wait = 0;
 
@@ -773,7 +782,7 @@
     return;
   game_clear_message(&s5);
 
-  help_add_comet(3,MC_OPER_MULT,3,9);
+  help_add_comet("3 * 3 = ?", "9");
   comets[0].y = 2*(screen->h)/3;   // start it low down
   while (!(comets[0].expl) && !(quit_help = help_renderframe_exit()));  // wait 3 secs
   if (quit_help)
@@ -798,7 +807,7 @@
     return;
   game_clear_message(&s3);
 
-  help_add_comet(56,MC_OPER_DIV,8,7);
+  help_add_comet("56 / 8 = ?", "7");
   comets[0].y = 2*(screen->h)/3;   // start it low down
   while (comets[0].alive && !(quit_help = help_renderframe_exit()));
   if (quit_help)
@@ -811,7 +820,7 @@
   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);
-  help_add_comet(2,MC_OPER_ADD,2,4);
+  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()));
@@ -883,32 +892,27 @@
   return (game_status != GAME_IN_PROGRESS);
 }
 
-void help_add_comet(int a,int oper,int b,int c)
+/* explicitly create a comet with a hardcoded problem */
+void help_add_comet(const char* formula_str, const char* ans_str)
 {
-  char probstr[MC_FORMULA_LEN];
-  char ansstr[MC_ANSWER_LEN];
+//  char probstr[MC_FORMULA_LEN];
+//  char ansstr[MC_ANSWER_LEN];
 
   comets[0].alive = 1;
   comets[0].expl = 0;
-  comets[0].answer = c;
+  comets[0].answer = atoi(ans_str);
   num_comets_alive = 1;
   comets[0].city = 0;
   comets[0].x = cities[0].x;
   comets[0].y = 0;
   comets[0].zapped = 0;
   comets[0].bonus = 0;
-  comets[0].flashcard.num1 = a;
-  comets[0].flashcard.num2 = b;
-  comets[0].flashcard.num3 = c;
-  comets[0].flashcard.operation = oper;
-  comets[0].flashcard.format = MC_FORMAT_ANS_LAST;
-  snprintf(probstr,MC_FORMULA_LEN,"%d %c %d = ?",a,operchars[oper],b);
-  strncpy(comets[0].flashcard.formula_string,probstr,MC_FORMULA_LEN);
-  snprintf(ansstr,MC_ANSWER_LEN,"%d",c);
-  strncpy(comets[0].flashcard.answer_string,ansstr,MC_ANSWER_LEN);
+
+  strncpy(comets[0].flashcard.formula_string,formula_str,MC_MaxFormulaSize() );
+  strncpy(comets[0].flashcard.answer_string,ans_str,MC_MaxAnswerSize() );
 }
 
-void game_set_message(game_message *msg,char *txt,int x,int y)
+void game_set_message(game_message *msg,const char *txt,int x,int y)
 {
   msg->x = x;
   msg->y = y;
@@ -935,9 +939,7 @@
     else
       rect.x = msg->x;              // left justified
     rect.y = msg->y;
-    
     SDL_SetAlpha(surf, SDL_SRCALPHA, msg->alpha);
-    
     SDL_BlitSurface(surf, NULL, screen, &rect);
     SDL_FreeSurface(surf);
     //SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
@@ -996,8 +998,8 @@
     picked_comet = (rand() % MAX_COMETS);
 
     if (!(comets[picked_comet].alive &&
-	  comets[picked_comet].expl < COMET_EXPL_END)
-	|| comets[picked_comet].y < 80)
+          comets[picked_comet].expl < COMET_EXPL_END)
+        || comets[picked_comet].y < 80)
     {
       picked_comet = -1;
     }
@@ -1006,7 +1008,7 @@
       /* 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_answer--;  // sometimes get it wrong on purpose
 
       #ifdef TUXMATH_DEBUG
       printf("Demo mode, comet %d attacked with answer %d\n",picked_comet,demo_answer);
@@ -1069,7 +1071,8 @@
 
 void game_handle_answer(void)
 {
-  int i, num, lowest, lowest_y;
+  int i, j, lowest, lowest_y;
+  char ans[MC_MAX_DIGITS+2]; //extra space for negative, and for final '\0'
   Uint32 ctime;
 
   if (!doing_answer)
@@ -1078,15 +1081,40 @@
   }
 
   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.
+  for (i = 0; i < MC_MAX_DIGITS - 1 && !digits[i]; ++i); //skip leading 0s
+  for (j = neg_answer_picked ? 1 : 0; i < MC_MAX_DIGITS; ++i, ++j)
+    ans[j] = digits[i] + '0';
+  ans[j] = '\0';
+  
+/*
   if (neg_answer_picked)
   {
-    num = -num;
+    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? */
@@ -1095,9 +1123,11 @@
 
   for (i = 0; i < MAX_COMETS; i++)
   {
+    mcdprintf("Comparing '%s' with '%s'\n", comets[i].flashcard.answer_string, ans);
     if (comets[i].alive &&
         comets[i].expl < COMET_EXPL_END &&
-        comets[i].answer == num &&
+        //comets[i].answer == num &&
+        0 == strncmp(comets[i].flashcard.answer_string, ans, MC_MAX_DIGITS+1) &&
         comets[i].y > lowest_y)
     {
       lowest = i;
@@ -1158,9 +1188,10 @@
 
     /* [ add = 25, sub = 50, mul = 75, div = 100 ] */
     /* [ the higher the better ] */
-    add_score(((25 * (comets[lowest].flashcard.operation + 1)) *
-              (screen->h - comets[lowest].y + 1)) /
-	       screen->h);
+    /* FIXME looks like it might score a bit differently based on screen mode? */
+    add_score(25 * comets[lowest].flashcard.difficulty *
+              (screen->h - comets[lowest].y + 1) /
+               screen->h);
   }
   else
   {
@@ -1180,9 +1211,8 @@
   }
 
   /* Clear digits: */
-  digits[0] = 0;
-  digits[1] = 0;
-  digits[2] = 0;
+  for (i = 0; i < MC_MAX_DIGITS; ++i)
+    digits[i] = 0;
   neg_answer_picked = 0;
 }
 
@@ -1197,7 +1227,7 @@
   s3.alpha -= SDL_ALPHA_OPAQUE / LEVEL_START_WAIT_START;
   s4.alpha -= SDL_ALPHA_OPAQUE / LEVEL_START_WAIT_START;
   tmdprintf("alpha = %d\n", s1.alpha);
-  
+
   level_start_wait--;
   if (level_start_wait > LEVEL_START_WAIT_START / 4)
     tux_img = IMG_TUX_RELAX1;
@@ -1278,8 +1308,8 @@
       /* Make bonus comet move faster at chosen ratio: */
       if (comets[i].bonus)
       {
-	comets[i].y += speed * Opts_BonusSpeedRatio() *
-	               city_expl_height / (RES_Y - images[IMG_CITY_BLUE]->h);
+        comets[i].y += speed * Opts_BonusSpeedRatio() *
+                       city_expl_height / (RES_Y - images[IMG_CITY_BLUE]->h);
       }
       else /* Regular comet: */
       {
@@ -1289,61 +1319,61 @@
 
       /* Does it threaten a city? */
       if (comets[i].y > 3 * screen->h / 4)
-	cities[this_city].threatened = 1;
+        cities[this_city].threatened = 1;
 
       /* Did it hit a city? */
       if (comets[i].y >= city_expl_height &&
-	  comets[i].expl < COMET_EXPL_END)
+          comets[i].expl < COMET_EXPL_END)
       {
         /* Tell MathCards about it - question not answered correctly: */
         MC_NotAnsweredCorrectly(&(comets[i].flashcard));
 
-	/* Store the time the question was present on screen (do this */
-	/* in a way that avoids storing it if the time wrapped around */
-	ctime = SDL_GetTicks();
-	if (ctime > comets[i].time_started) {
-	  MC_AddTimeToList((float)(ctime - comets[i].time_started)/1000);
-	}
+        /* Store the time the question was present on screen (do this */
+        /* in a way that avoids storing it if the time wrapped around */
+        ctime = SDL_GetTicks();
+        if (ctime > comets[i].time_started) {
+          MC_AddTimeToList((float)(ctime - comets[i].time_started)/1000);
+        }
 
         /* Record data for speed feedback */
-	/* Do this only for cities that are alive; dead cities */
+        /* Do this only for cities that are alive; dead cities */
         /* might not get much protection from the player */
-	if (Opts_UseFeedback() && cities[this_city].hits_left) {
-	  comet_feedback_number++;
+        if (Opts_UseFeedback() && cities[this_city].hits_left) {
+          comet_feedback_number++;
           comet_feedback_height += 1.0 + Opts_CityExplHandicap();
 
 #ifdef FEEDBACK_DEBUG
- 	  printf("Added comet feedback with height %g\n",
+           printf("Added comet feedback with height %g\n",
                   1.0 + Opts_CityExplHandicap());
 #endif
- 	}
+         }
 
         /* Disable shields/destroy city/create steam cloud: */
         if (cities[this_city].hits_left)
-	{
-	  cities[this_city].status = CITY_EXPLODING;
-	  if (Opts_UseIgloos()) {
-	    playsound(SND_IGLOO_SIZZLE);
-	    cities[this_city].counter = IGLOO_SWITCH_START;
-	    steam[this_city].status = STEAM_ON;
-	    steam[this_city].counter = STEAM_START;
-	  }
-	  else {
-	    if (cities[comets[i].city].hits_left == 2) {
-	      playsound(SND_SHIELDSDOWN);
-	      cities[this_city].counter = 1;  /* Will act immediately */
-	    }
-	    else {
-	      playsound(SND_EXPLOSION);
-	      cities[this_city].counter = CITY_EXPL_START;
-	    }
-	  }
-	  cities[this_city].hits_left--;
-	}
+        {
+          cities[this_city].status = CITY_EXPLODING;
+          if (Opts_UseIgloos()) {
+            playsound(SND_IGLOO_SIZZLE);
+            cities[this_city].counter = IGLOO_SWITCH_START;
+            steam[this_city].status = STEAM_ON;
+            steam[this_city].counter = STEAM_START;
+          }
+          else {
+            if (cities[comets[i].city].hits_left == 2) {
+              playsound(SND_SHIELDSDOWN);
+              cities[this_city].counter = 1;  /* Will act immediately */
+            }
+            else {
+              playsound(SND_EXPLOSION);
+              cities[this_city].counter = CITY_EXPL_START;
+            }
+          }
+          cities[this_city].hits_left--;
+        }
 
-	/* If this was a bonus comet, restart the counter */
-	if (comets[i].bonus)
-	  bonus_comet_counter = Opts_BonusCometInterval()+1;
+        /* If this was a bonus comet, restart the counter */
+        if (comets[i].bonus)
+          bonus_comet_counter = Opts_BonusCometInterval()+1;
 
        /* If slow_after_wrong selected, set flag to go back to starting speed and */
         /* number of attacking comets: */
@@ -1364,22 +1394,22 @@
       if (comets[i].expl >= COMET_EXPL_END)
       {
         comets[i].expl--;
-	if (comets[i].expl < COMET_EXPL_END) {
-	  comets[i].alive = 0;
-	  if (bonus_comet_counter > 1 && comets[i].zapped) {
-	    bonus_comet_counter--;
+        if (comets[i].expl < COMET_EXPL_END) {
+          comets[i].alive = 0;
+          if (bonus_comet_counter > 1 && comets[i].zapped) {
+            bonus_comet_counter--;
 #ifdef TUXMATH_DEBUG
-	    printf("\nbonus_comet_counter is now %d\n",bonus_comet_counter);
+            printf("\nbonus_comet_counter is now %d\n",bonus_comet_counter);
 #endif
-	  }
-	  if (comets[i].bonus && comets[i].zapped) {
-	    playsound(SND_EXTRA_LIFE);
-	    extra_life_earned = 1;
+          }
+          if (comets[i].bonus && comets[i].zapped) {
+            playsound(SND_EXTRA_LIFE);
+            extra_life_earned = 1;
 #ifdef TUXMATH_DEBUG
-	    printf("\nExtra life earned!");
+            printf("\nExtra life earned!");
 #endif
-	  }
-	}
+          }
+        }
       }
     }
   }
@@ -1403,9 +1433,9 @@
     {
       if (num_comets_alive == 0)
       {
-	if (!check_extra_life()) {
-	  /* Time for the next wave! */
-	  wave++;
+        if (!check_extra_life()) {
+          /* Time for the next wave! */
+          wave++;
           reset_level();
         }
       }
@@ -1435,61 +1465,61 @@
     {
       cities[i].counter--;
       if (cities[i].counter == 0) {
-	if (cities[i].hits_left)
-	  cities[i].status = CITY_PRESENT;
-	else {
-	  if (Opts_UseIgloos()) {
-	    cities[i].status = CITY_EVAPORATING;
-	    cities[i].counter = EVAPORATING_COUNTER_START;
-	    cities[i].img = IMG_IGLOO_MELTED1;
-	  } else {
-	    cities[i].status = CITY_GONE;
-	    cities[i].img = IMG_CITY_NONE;
-	  }
-	}
+        if (cities[i].hits_left)
+          cities[i].status = CITY_PRESENT;
+        else {
+          if (Opts_UseIgloos()) {
+            cities[i].status = CITY_EVAPORATING;
+            cities[i].counter = EVAPORATING_COUNTER_START;
+            cities[i].img = IMG_IGLOO_MELTED1;
+          } else {
+            cities[i].status = CITY_GONE;
+            cities[i].img = IMG_CITY_NONE;
+          }
+        }
       }
     }
     /* Choose the correct city/igloo image */
     if (Opts_UseIgloos()) {
       if (cities[i].status == CITY_EVAPORATING) {
-	/* Handle the evaporation animation */
-	cities[i].layer = 0;  /* these have to be drawn below the penguin */
-	cities[i].counter--;
-	if (cities[i].counter == 0) {
-	  cities[i].img--;
-	  if (cities[i].img < IMG_IGLOO_MELTED3) {
-	    cities[i].img = IMG_CITY_NONE;
-	    cities[i].status = CITY_GONE;
-	  }
-	  else
-	    cities[i].counter = EVAPORATING_COUNTER_START;
-	}
-      }	else {
-	if (cities[i].status != CITY_GONE) {
-	  cities[i].layer = 1;  /* these have to be drawn above the penguin */
-	  cities[i].img = IMG_IGLOO_MELTED1 + cities[i].hits_left;
-	  /* If we're in the middle of an "explosion," don't switch to the
-	     new igloo. Note the steam may have a different counter than
-	     the igloo on this matter; the switch is designed to occur
-	     halfway through the steam cloud. */
-	  if (cities[i].status == CITY_EXPLODING)
-	    cities[i].img++;
-	}
+        /* Handle the evaporation animation */
+        cities[i].layer = 0;  /* these have to be drawn below the penguin */
+        cities[i].counter--;
+        if (cities[i].counter == 0) {
+          cities[i].img--;
+          if (cities[i].img < IMG_IGLOO_MELTED3) {
+            cities[i].img = IMG_CITY_NONE;
+            cities[i].status = CITY_GONE;
+          }
+          else
+            cities[i].counter = EVAPORATING_COUNTER_START;
+        }
+      }        else {
+        if (cities[i].status != CITY_GONE) {
+          cities[i].layer = 1;  /* these have to be drawn above the penguin */
+          cities[i].img = IMG_IGLOO_MELTED1 + cities[i].hits_left;
+          /* If we're in the middle of an "explosion," don't switch to the
+             new igloo. Note the steam may have a different counter than
+             the igloo on this matter; the switch is designed to occur
+             halfway through the steam cloud. */
+          if (cities[i].status == CITY_EXPLODING)
+            cities[i].img++;
+        }
       }
     }
     else {
       /* We're using the original "city" graphics */
       cities[i].layer = 0;   /* No layering needed */
       if (cities[i].hits_left)
-	cities[i].img = IMG_CITY_BLUE;
+        cities[i].img = IMG_CITY_BLUE;
       else if (cities[i].status == CITY_EXPLODING)
-	cities[i].img = (IMG_CITY_BLUE_EXPL5 - (cities[i].counter / (CITY_EXPL_START / 5)));
+        cities[i].img = (IMG_CITY_BLUE_EXPL5 - (cities[i].counter / (CITY_EXPL_START / 5)));
       else
-	cities[i].img = IMG_CITY_BLUE_DEAD;
+        cities[i].img = IMG_CITY_BLUE_DEAD;
 
       /* Change image to appropriate color: */
       cities[i].img = cities[i].img + ((wave % MAX_CITY_COLORS) *
-		   (IMG_CITY_GREEN - IMG_CITY_BLUE));
+                   (IMG_CITY_GREEN - IMG_CITY_BLUE));
 
     }
   }
@@ -1512,26 +1542,26 @@
       penguins[i].status = PENGUIN_DUCKING;
     else if (!cities[i].threatened && penguins[i].status == PENGUIN_DUCKING) {
       if (cities[i].hits_left == 2)
-	penguins[i].status = PENGUIN_HAPPY;
+        penguins[i].status = PENGUIN_HAPPY;
       else
-	penguins[i].status = PENGUIN_GRUMPY;
+        penguins[i].status = PENGUIN_GRUMPY;
     }
     switch (penguins[i].status) {
     case PENGUIN_HAPPY:
       penguins[i].img = IMG_PENGUIN_FLAPDOWN;
       if (rand() % FLAPPING_INTERVAL == 0) {
-	penguins[i].status = PENGUIN_FLAPPING;
-	penguins[i].counter = FLAPPING_START;
+        penguins[i].status = PENGUIN_FLAPPING;
+        penguins[i].counter = FLAPPING_START;
       }
       break;
     case PENGUIN_FLAPPING:
       if (penguins[i].counter % 4 >= 2)
-	penguins[i].img = IMG_PENGUIN_FLAPUP;
+        penguins[i].img = IMG_PENGUIN_FLAPUP;
       else
-	penguins[i].img = IMG_PENGUIN_FLAPDOWN;
+        penguins[i].img = IMG_PENGUIN_FLAPDOWN;
       penguins[i].counter--;
       if (penguins[i].counter == 0)
-	penguins[i].status = PENGUIN_HAPPY;
+        penguins[i].status = PENGUIN_HAPPY;
       break;
     case PENGUIN_DUCKING:
       penguins[i].img = IMG_PENGUIN_INCOMING;
@@ -1539,59 +1569,59 @@
     case PENGUIN_GRUMPY:
       penguins[i].img = IMG_PENGUIN_GRUMPY;
       if (rand() % FLAPPING_INTERVAL == 0) {
-	penguins[i].status = PENGUIN_WORRIED;
-	penguins[i].counter = FLAPPING_START;
+        penguins[i].status = PENGUIN_WORRIED;
+        penguins[i].counter = FLAPPING_START;
       }
       break;
     case PENGUIN_WORRIED:
       penguins[i].img = IMG_PENGUIN_WORRIED;
       penguins[i].counter--;
       if (penguins[i].counter == 0)
-	penguins[i].status = PENGUIN_GRUMPY;
+        penguins[i].status = PENGUIN_GRUMPY;
       break;
     case PENGUIN_STANDING_UP:
       penguins[i].img = IMG_PENGUIN_STANDING_UP;
       penguins[i].counter--;
       if (penguins[i].counter == 0)
-	penguins[i].status = PENGUIN_WALKING_OFF;
+        penguins[i].status = PENGUIN_WALKING_OFF;
       break;
     case PENGUIN_SITTING_DOWN:
       penguins[i].img = IMG_PENGUIN_SITTING_DOWN;
       penguins[i].counter--;
       if (penguins[i].counter == 0) {
-	penguins[i].status = PENGUIN_FLAPPING;
-	penguins[i].counter = FLAPPING_START;
+        penguins[i].status = PENGUIN_FLAPPING;
+        penguins[i].counter = FLAPPING_START;
       }
       break;
     case PENGUIN_WALKING_ON:
       walk_counter = (penguins[i].counter % 8)/2;
       if (walk_counter == 3)
-	walk_counter = 1;
+        walk_counter = 1;
       penguins[i].img = IMG_PENGUIN_WALK_ON1 + walk_counter;
       penguins[i].counter++;
       direction = 2*(i < NUM_CITIES/2)-1;  /* +1 for walk right, -1 for left */
       penguins[i].x += direction*PENGUIN_WALK_SPEED;
       if (direction*penguins[i].x >= direction*cities[i].x) {
-	penguins[i].status = PENGUIN_SITTING_DOWN;
-	penguins[i].counter = STANDING_COUNTER_START;
-	penguins[i].x = cities[i].x;
+        penguins[i].status = PENGUIN_SITTING_DOWN;
+        penguins[i].counter = STANDING_COUNTER_START;
+        penguins[i].x = cities[i].x;
       }
       penguins[i].layer = 3;  /* Stand in front of steam */
       break;
     case PENGUIN_WALKING_OFF:
       walk_counter = (penguins[i].counter % 8)/2;
       if (walk_counter == 3)
-	walk_counter = 1;
+        walk_counter = 1;
       penguins[i].img = IMG_PENGUIN_WALK_OFF1 + walk_counter;
       penguins[i].counter++;
       direction = 1-2*(i < NUM_CITIES/2);
       penguins[i].x += direction*PENGUIN_WALK_SPEED;
       if (direction < 0) {
-	if (penguins[i].x + images[IMG_PENGUIN_WALK_OFF1]->w/2 < 0)
-	  penguins[i].status = PENGUIN_OFFSCREEN;
+        if (penguins[i].x + images[IMG_PENGUIN_WALK_OFF1]->w/2 < 0)
+          penguins[i].status = PENGUIN_OFFSCREEN;
       } else {
-	if (penguins[i].x - images[IMG_PENGUIN_WALK_OFF1]->w/2 > screen->w)
-	  penguins[i].status = PENGUIN_OFFSCREEN;
+        if (penguins[i].x - images[IMG_PENGUIN_WALK_OFF1]->w/2 > screen->w)
+          penguins[i].status = PENGUIN_OFFSCREEN;
       }
       penguins[i].layer = 3;
       break;
@@ -1612,16 +1642,16 @@
     if (steam[i].counter) {
       steam[i].counter--;
       if (!steam[i].counter) {
-	steam[i].status = STEAM_OFF;
-	if (cloud.status != EXTRA_LIFE_ON || cloud.city != i) {
-	  /* The penguin was ducking, now we can stop */
+        steam[i].status = STEAM_OFF;
+        if (cloud.status != EXTRA_LIFE_ON || cloud.city != i) {
+          /* The penguin was ducking, now we can stop */
           if (cities[i].hits_left)
             penguins[i].status = PENGUIN_GRUMPY;
           else {
             penguins[i].status = PENGUIN_STANDING_UP;
-	    penguins[i].counter = STANDING_COUNTER_START;
-	  }
-	}
+            penguins[i].counter = STANDING_COUNTER_START;
+          }
+        }
       }
     }
     if (steam[i].status == STEAM_OFF)
@@ -1650,8 +1680,8 @@
     fewest_index = -1;
     for (i = 0; i < NUM_CITIES; i++) {
       if (cities[i].hits_left < fewest_hits_left) {
-	fewest_hits_left = cities[i].hits_left;
-	fewest_index = i;
+        fewest_hits_left = cities[i].hits_left;
+        fewest_index = i;
       }
     }
     if (fewest_hits_left == 2)
@@ -1708,28 +1738,28 @@
       // Cloud is "parked," handle the snowfall and igloo rebuilding
       cities[cloud.city].status = CITY_REBUILDING;
       igloo_top = screen->h - igloo_vertical_offset
-	- images[IMG_IGLOO_INTACT]->h;
+        - images[IMG_IGLOO_INTACT]->h;
       for (i = 0, num_below_igloo = 0; i < NUM_SNOWFLAKES; i++) {
-	cloud.snowflake_y[i] += SNOWFLAKE_SPEED;
-	if (cloud.snowflake_y[i] > igloo_top)
-	  num_below_igloo++;
+        cloud.snowflake_y[i] += SNOWFLAKE_SPEED;
+        if (cloud.snowflake_y[i] > igloo_top)
+          num_below_igloo++;
       }
       if (cloud.snowflake_y[NUM_SNOWFLAKES-1] > igloo_top) {
-	cities[cloud.city].hits_left = 2;
-	cities[cloud.city].img = IMG_IGLOO_INTACT; // completely rebuilt
+        cities[cloud.city].hits_left = 2;
+        cities[cloud.city].img = IMG_IGLOO_INTACT; // completely rebuilt
       } else if (cities[cloud.city].hits_left == 0) {
-	// We're going to draw one of the blended igloos
-	// FIXME: It's a hack to encode a blended igloo with a negative number!
-	penguins[cloud.city].layer = 0;
-	cities[cloud.city].layer = 1;
-	if (num_below_igloo < 3)
-	  num_below_igloo = 0;   // Don't show progress until a few have fallen
-	cities[cloud.city].img = -((float) (num_below_igloo)/NUM_SNOWFLAKES) * NUM_BLENDED_IGLOOS;
+        // We're going to draw one of the blended igloos
+        // FIXME: It's a hack to encode a blended igloo with a negative number!
+        penguins[cloud.city].layer = 0;
+        cities[cloud.city].layer = 1;
+        if (num_below_igloo < 3)
+          num_below_igloo = 0;   // Don't show progress until a few have fallen
+        cities[cloud.city].img = -((float) (num_below_igloo)/NUM_SNOWFLAKES) * NUM_BLENDED_IGLOOS;
       }
       if (cloud.snowflake_y[NUM_SNOWFLAKES-1] > screen->h - igloo_vertical_offset) {
-	/* exit rebuilding when last snowflake at igloo bottom */
-	cloud.status = EXTRA_LIFE_OFF;
-	cities[cloud.city].status = CITY_PRESENT;
+        /* exit rebuilding when last snowflake at igloo bottom */
+        cloud.status = EXTRA_LIFE_OFF;
+        cities[cloud.city].status = CITY_PRESENT;
       }
     }
   }
@@ -1756,9 +1786,9 @@
   if (laser.alive)
   {
     draw_line(laser.x1, laser.y1, laser.x2, laser.y2,
-		  255 / ((LASER_START + 1) - laser.alive),
-		  192 / ((LASER_START + 1) - laser.alive),
-		  64);
+                  255 / ((LASER_START + 1) - laser.alive),
+                  192 / ((LASER_START + 1) - laser.alive),
+                  64);
   }
 
   /* Draw numeric keypad: */
@@ -1766,7 +1796,7 @@
   {
     /* pick image to draw: */
     int keypad_image;
-    if (MC_AllowNegatives())
+    if (MC_GetOpt(ALLOW_NEGATIVES) )
     {
       /* draw regular keypad */
       keypad_image = IMG_KEYPAD;
@@ -1846,7 +1876,7 @@
 void game_draw_comets(void)
 {
 
-  int i,j, img, max_layer,offset;
+  int i, img;
   SDL_Rect dest;
   char* comet_str;
 
@@ -1860,7 +1890,7 @@
         /* Decide which image to display: */
         img = IMG_COMET1 + ((frame + i) % 3);
         /* Display the formula (flashing, in the bottom half
-		   of the screen) */
+                   of the screen) */
         if (comets[i].y < screen->h / 2 || frame % 8 < 6)
         {
           comet_str = comets[i].flashcard.formula_string;
@@ -1900,7 +1930,7 @@
         /* Decide which image to display: */
         img = IMG_COMET1 + ((frame + i) % 3);
         /* Display the formula (flashing, in the bottom half
-		   of the screen) */
+                   of the screen) */
         if (comets[i].y < screen->h / 2 || frame % 8 < 6)
         {
           comet_str = comets[i].flashcard.formula_string;
@@ -1949,84 +1979,84 @@
     max_layer = 0;
     do {
       for (i = 0; i < NUM_CITIES; i++) {
-	if (cities[i].status != CITY_GONE && cities[i].layer > max_layer)
-	  max_layer = cities[i].layer;
-	if (penguins[i].status != PENGUIN_OFFSCREEN && penguins[i].layer > max_layer)
-	  max_layer = penguins[i].layer;
-	if (steam[i].status == STEAM_ON && steam[i].layer > max_layer)
-	  max_layer = steam[i].layer;
-	if (cities[i].layer == current_layer &&
-	    cities[i].img != IMG_CITY_NONE) {
-	  // Handle the blended igloo images, which are encoded
-	  // (FIXME) with a negative image number
-	  if (cities[i].img <= 0)
-	    this_image = blended_igloos[-cities[i].img];
-	  else
-	    this_image = images[cities[i].img];
-	  //this_image = blended_igloos[frame % NUM_BLENDED_IGLOOS];
-	  dest.x = cities[i].x - (this_image->w / 2);
-	  dest.y = (screen->h) - (this_image->h) - igloo_vertical_offset;
-	  if (cities[i].img == IMG_IGLOO_MELTED3 ||
-	      cities[i].img == IMG_IGLOO_MELTED2)
-	    dest.y -= (images[IMG_IGLOO_MELTED1]->h - this_image->h)/2;
-	  dest.w = (this_image->w);
-	  dest.h = (this_image->h);
-	  SDL_BlitSurface(this_image, NULL, screen, &dest);
-	}
-	if (penguins[i].layer == current_layer &&
-	    penguins[i].status != PENGUIN_OFFSCREEN) {
-	  this_image = images[penguins[i].img];
-	  if (penguins[i].status == PENGUIN_WALKING_OFF ||
-	      penguins[i].status == PENGUIN_WALKING_ON) {
-	    /* With walking penguins, we have to use flipped images
-	       when it's walking left. The other issue is that the
-	       images are of different widths, so aligning on the
-	       center produces weird forward-backward walking. The
-	       reliable way is the align them all on the tip of the
-	       beak (the right border of the unflipped image) */
-	    dest.x = penguins[i].x - (this_image->w / 2);
-	    dest.y = (screen->h) - (this_image->h);
-	    if ((i<NUM_CITIES/2 && penguins[i].status==PENGUIN_WALKING_OFF) ||
-		(i>=NUM_CITIES/2 && penguins[i].status==PENGUIN_WALKING_ON)) {
-	      /* walking left */
-	      this_image = flipped_images[flipped_img_lookup[penguins[i].img]];
-	      dest.x = penguins[i].x - images[IMG_PENGUIN_WALK_OFF2]->w/2;
-	    } else
-	      dest.x = penguins[i].x - this_image->w
-		+ images[IMG_PENGUIN_WALK_OFF2]->w/2;   /* walking right */
-	  }
-	  else {
-	    dest.x = penguins[i].x - (this_image->w / 2);
-	    dest.y = (screen->h) - (5*(this_image->h))/4 - igloo_vertical_offset;
-	  }
-	  dest.w = (this_image->w);
-	  dest.h = (this_image->h);
-	  SDL_BlitSurface(this_image, NULL, screen, &dest);
-	}
-	if (steam[i].layer == current_layer &&
-	    steam[i].status == STEAM_ON) {
-	  this_image = images[steam[i].img];
-	  dest.x = cities[i].x - (this_image->w / 2);
-	  dest.y = (screen->h) - this_image->h - ((4 * images[IMG_IGLOO_INTACT]->h) / 7);
-	  dest.w = (this_image->w);
-	  dest.h = (this_image->h);
-	  SDL_BlitSurface(this_image, NULL, screen, &dest);
-	}
+        if (cities[i].status != CITY_GONE && cities[i].layer > max_layer)
+          max_layer = cities[i].layer;
+        if (penguins[i].status != PENGUIN_OFFSCREEN && penguins[i].layer > max_layer)
+          max_layer = penguins[i].layer;
+        if (steam[i].status == STEAM_ON && steam[i].layer > max_layer)
+          max_layer = steam[i].layer;
+        if (cities[i].layer == current_layer &&
+            cities[i].img != IMG_CITY_NONE) {
+          // Handle the blended igloo images, which are encoded
+          // (FIXME) with a negative image number
+          if (cities[i].img <= 0)
+            this_image = blended_igloos[-cities[i].img];
+          else
+            this_image = images[cities[i].img];
+          //this_image = blended_igloos[frame % NUM_BLENDED_IGLOOS];
+          dest.x = cities[i].x - (this_image->w / 2);
+          dest.y = (screen->h) - (this_image->h) - igloo_vertical_offset;
+          if (cities[i].img == IMG_IGLOO_MELTED3 ||
+              cities[i].img == IMG_IGLOO_MELTED2)
+            dest.y -= (images[IMG_IGLOO_MELTED1]->h - this_image->h)/2;
+          dest.w = (this_image->w);
+          dest.h = (this_image->h);
+          SDL_BlitSurface(this_image, NULL, screen, &dest);
+        }
+        if (penguins[i].layer == current_layer &&
+            penguins[i].status != PENGUIN_OFFSCREEN) {
+          this_image = images[penguins[i].img];
+          if (penguins[i].status == PENGUIN_WALKING_OFF ||
+              penguins[i].status == PENGUIN_WALKING_ON) {
+            /* With walking penguins, we have to use flipped images
+               when it's walking left. The other issue is that the
+               images are of different widths, so aligning on the
+               center produces weird forward-backward walking. The
+               reliable way is the align them all on the tip of the
+               beak (the right border of the unflipped image) */
+            dest.x = penguins[i].x - (this_image->w / 2);
+            dest.y = (screen->h) - (this_image->h);
+            if ((i<NUM_CITIES/2 && penguins[i].status==PENGUIN_WALKING_OFF) ||
+                (i>=NUM_CITIES/2 && penguins[i].status==PENGUIN_WALKING_ON)) {
+              /* walking left */
+              this_image = flipped_images[flipped_img_lookup[penguins[i].img]];
+              dest.x = penguins[i].x - images[IMG_PENGUIN_WALK_OFF2]->w/2;
+            } else
+              dest.x = penguins[i].x - this_image->w
+                + images[IMG_PENGUIN_WALK_OFF2]->w/2;   /* walking right */
+          }
+          else {
+            dest.x = penguins[i].x - (this_image->w / 2);
+            dest.y = (screen->h) - (5*(this_image->h))/4 - igloo_vertical_offset;
+          }
+          dest.w = (this_image->w);
+          dest.h = (this_image->h);
+          SDL_BlitSurface(this_image, NULL, screen, &dest);
+        }
+        if (steam[i].layer == current_layer &&
+            steam[i].status == STEAM_ON) {
+          this_image = images[steam[i].img];
+          dest.x = cities[i].x - (this_image->w / 2);
+          dest.y = (screen->h) - this_image->h - ((4 * images[IMG_IGLOO_INTACT]->h) / 7);
+          dest.w = (this_image->w);
+          dest.h = (this_image->h);
+          SDL_BlitSurface(this_image, NULL, screen, &dest);
+        }
       }
       current_layer++;
     } while (current_layer <= max_layer);
     if (cloud.status == EXTRA_LIFE_ON) {
       /* Render cloud & snowflakes */
       for (i = 0; i < NUM_SNOWFLAKES; i++) {
-	if (cloud.snowflake_y[i] > cloud.y &&
-	    cloud.snowflake_y[i] < screen->h - igloo_vertical_offset) {
-	  this_image = images[IMG_SNOW1+cloud.snowflake_size[i]];
-	  dest.x = cloud.snowflake_x[i] - this_image->w/2 + cloud.x;
-	  dest.y = cloud.snowflake_y[i] - this_image->h/2;
-	  dest.w = this_image->w;
-	  dest.h = this_image->h;
-	  SDL_BlitSurface(this_image, NULL, screen, &dest);
-	}
+        if (cloud.snowflake_y[i] > cloud.y &&
+            cloud.snowflake_y[i] < screen->h - igloo_vertical_offset) {
+          this_image = images[IMG_SNOW1+cloud.snowflake_size[i]];
+          dest.x = cloud.snowflake_x[i] - this_image->w/2 + cloud.x;
+          dest.y = cloud.snowflake_y[i] - this_image->h/2;
+          dest.w = this_image->w;
+          dest.h = this_image->h;
+          SDL_BlitSurface(this_image, NULL, screen, &dest);
+        }
       }
       this_image = images[IMG_CLOUD];
       dest.x = cloud.x - this_image->w/2;
@@ -2049,19 +2079,19 @@
 
       /* Draw sheilds: */
       if (cities[i].hits_left > 1) {
-	for (j = (frame % 3); j < images[IMG_SHIELDS]->h; j = j + 3) {
-	  src.x = 0;
-	  src.y = j;
-	  src.w = images[IMG_SHIELDS]->w;
-	  src.h = 1;
+        for (j = (frame % 3); j < images[IMG_SHIELDS]->h; j = j + 3) {
+          src.x = 0;
+          src.y = j;
+          src.w = images[IMG_SHIELDS]->w;
+          src.h = 1;
 
-	  dest.x = cities[i].x - (images[IMG_SHIELDS]->w / 2);
-	  dest.y = (screen->h) - (images[IMG_SHIELDS]->h) + j;
-	  dest.w = src.w;
-	  dest.h = src.h;
+          dest.x = cities[i].x - (images[IMG_SHIELDS]->w / 2);
+          dest.y = (screen->h) - (images[IMG_SHIELDS]->h) + j;
+          dest.w = src.w;
+          dest.h = src.h;
 
-	  SDL_BlitSurface(images[IMG_SHIELDS], &src, screen, &dest);
-	}
+          SDL_BlitSurface(images[IMG_SHIELDS], &src, screen, &dest);
+        }
       }
     }
   }
@@ -2087,7 +2117,7 @@
 
   /* If we are playing through a defined list of questions */
   /* without "recycling", display number of remaining questions: */
-  if (MC_PlayThroughList())
+  if (MC_GetOpt(PLAY_THROUGH_LIST) )
   {
     draw_question_counter();
   }
@@ -2105,7 +2135,7 @@
     dest.y = images[IMG_EXTRA_LIFE]->h/4;
     dest.h = images[IMG_EXTRA_LIFE]->h/2;
     dest.w = ((Opts_BonusCometInterval() + 1 - bonus_comet_counter)
-	      * images[IMG_EXTRA_LIFE]->w) / Opts_BonusCometInterval();
+              * images[IMG_EXTRA_LIFE]->w) / Opts_BonusCometInterval();
     SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 255, 0));
   }
 
@@ -2127,7 +2157,7 @@
 
   /* Draw "score" label: */
   dest.x = (screen->w - ((images[IMG_NUMBERS]->w / 10) * 7) -
-	        images[IMG_SCORE]->w -
+                images[IMG_SCORE]->w -
                 images[IMG_STOP]->w - 5);
   dest.y = 0;
   dest.w = images[IMG_SCORE]->w;
@@ -2281,23 +2311,16 @@
   }
   num_comets_alive = 0;
 
-  /* Clear LED digits: */
+  /* Clear LED F: */
 
-  digits[0] = 0;
-  digits[1] = 0;
-  digits[2] = 0;
+  for (i = 0; i < MC_MAX_DIGITS; ++i)
+    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);
-//  do
-//  {
-//    /* Don't pick the same one as last time... */
-//    i = rand() % NUM_BKGDS;
-//  }
-//  while (i == last_bkgd);
 
   last_bkgd = i;
 
@@ -2322,10 +2345,10 @@
     if (bkgd == NULL || scaled_bkgd == NULL)
     {
       fprintf(stderr,
-	      "\nWarning: Could not load background image:\n"
-	      "%s\n"
-	      "The Simple DirectMedia error that ocurred was: %s\n",
-	      fname, SDL_GetError());
+              "\nWarning: Could not load background image:\n"
+              "%s\n"
+              "The Simple DirectMedia error that ocurred was: %s\n",
+              fname, SDL_GetError());
       Opts_SetUseBkgd(0);
     }
   }
@@ -2362,70 +2385,70 @@
 
       if (use_feedback)
       {
-	#ifdef FEEDBACK_DEBUG
-	printf("Evaluating feedback...\n  old danger level = %g,",danger_level);
+        #ifdef FEEDBACK_DEBUG
+        printf("Evaluating feedback...\n  old danger level = %g,",danger_level);
         #endif
 
         /* Update our danger level, i.e., the target height */
-	danger_level = 1 - (1-danger_level) /
-	                   Opts_DangerLevelSpeedup();
-	if (danger_level > Opts_DangerLevelMax())
-	  danger_level = Opts_DangerLevelMax();
+        danger_level = 1 - (1-danger_level) /
+                           Opts_DangerLevelSpeedup();
+        if (danger_level > Opts_DangerLevelMax())
+          danger_level = Opts_DangerLevelMax();
 
-	#ifdef FEEDBACK_DEBUG
-	printf(" new danger level = %g.\n",danger_level);
-	#endif
+        #ifdef FEEDBACK_DEBUG
+        printf(" new danger level = %g.\n",danger_level);
+        #endif
 
-	/* Check to see whether we have any feedback data. If not, skip it. */
-	if (comet_feedback_number == 0)
+        /* Check to see whether we have any feedback data. If not, skip it. */
+        if (comet_feedback_number == 0)
         {
-	  use_feedback = 0;  /* No comets above living cities, skip feedback */
+          use_feedback = 0;  /* No comets above living cities, skip feedback */
 
-	  #ifdef FEEDBACK_DEBUG
-	  printf("No feedback data available, aborting.\n\n");
-	  #endif
-	}
-	else
+          #ifdef FEEDBACK_DEBUG
+          printf("No feedback data available, aborting.\n\n");
+          #endif
+        }
+        else
         {
-	  /* Compute the average height of comet destruction. */
-	  comet_avg_height = comet_feedback_height/comet_feedback_number;
+          /* Compute the average height of comet destruction. */
+          comet_avg_height = comet_feedback_height/comet_feedback_number;
 
-	  /* Determine how this average height compares with target. */
-	  height_differential = comet_avg_height - danger_level;
+          /* Determine how this average height compares with target. */
+          height_differential = comet_avg_height - danger_level;
 
-	  /* Set the speed so that we move halfway towards the target */
-	  /* height. That makes the changes a bit more conservative. */
+          /* Set the speed so that we move halfway towards the target */
+          /* height. That makes the changes a bit more conservative. */
 
-	  #ifdef FEEDBACK_DEBUG
-	  printf("  comet average height = %g, height differential = %g.\n",
+          #ifdef FEEDBACK_DEBUG
+          printf("  comet average height = %g, height differential = %g.\n",
                  comet_avg_height, height_differential);
-	  printf("  old speed = %g,",speed);
-	  #endif
+          printf("  old speed = %g,",speed);
+          #endif
 
-	  speed *= (1 - height_differential/danger_level/2);
+          speed *= (1 - height_differential/danger_level/2);
 
-	  /* Enforce bounds on speed */
-	  if (speed < MINIMUM_SPEED)
-	    speed = MINIMUM_SPEED;
-	  if (speed > Opts_MaxSpeed())
-	    speed = Opts_MaxSpeed();
+          /* Enforce bounds on speed */
+          if (speed < MINIMUM_SPEED)
+            speed = MINIMUM_SPEED;
+          if (speed > Opts_MaxSpeed())
+            speed = Opts_MaxSpeed();
 
-	  #ifdef FEEDBACK_DEBUG
-	  printf(" new speed = %g.\n",speed);
-	  printf("Feedback evaluation complete.\n\n");
-	  #endif
-	}
+          #ifdef FEEDBACK_DEBUG
+          printf(" new speed = %g.\n",speed);
+          printf("Feedback evaluation complete.\n\n");
+          #endif
+        }
       }
 
       if (!use_feedback)
       {
         /* This is not an "else" because we might skip feedback */
-	/* when comet_feedback_number == 0 */
-	speed = speed * Opts_SpeedupFactor();
-	if (speed > Opts_MaxSpeed())
-	{
-	  speed = Opts_MaxSpeed();
-	}
+        /* when comet_feedback_number == 0 */
+        speed = speed * Opts_SpeedupFactor();
+        if (speed > Opts_MaxSpeed())
+        {
+          speed = Opts_MaxSpeed();
+        }
       }
     }
   }
@@ -2484,32 +2507,33 @@
 
   /* If we make it to here, create a new comet!                  */
 
-  /* 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;
-    }
-  }
+  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;
+//    }
+//  }
+  
 
-
   comets[found].alive = 1;
   num_comets_alive++;
 
@@ -2610,9 +2634,9 @@
       for (j = 0; j < 4; j++)
       {
         if (str[i] == operchars[j])
- 	{
-	  c = 10 + j;
-	}
+        {
+          c = 10 + j;
+        }
       }
     }
 
@@ -2630,7 +2654,7 @@
       dest.h = src.h;
 
       SDL_BlitSurface(images[IMG_NUMS], &src,
-			  screen, &dest);
+                          screen, &dest);
       /* Move the 'cursor' one character width: */
       cur_x = cur_x + char_width;
     }
@@ -2664,31 +2688,31 @@
       /* Determine which character to display: */
 
       if (str[i] >= '0' && str[i] <= '9')
-	c = str[i] - '0';
+        c = str[i] - '0';
 
 
       /* 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;
+        {
+          src.x = c * (images[IMG_NUMBERS]->w / 10);
+          src.y = 0;
+          src.w = (images[IMG_NUMBERS]->w / 10);
+          src.h = images[IMG_NUMBERS]->h;
 
-	  dest.x = cur_x;
-	  dest.y = y;
-	  dest.w = src.w;
-	  dest.h = src.h;
+          dest.x = cur_x;
+          dest.y = y;
+          dest.w = src.w;
+          dest.h = src.h;
 
-	  SDL_BlitSurface(images[IMG_NUMBERS], &src,
-			  screen, &dest);
+          SDL_BlitSurface(images[IMG_NUMBERS], &src,
+                          screen, &dest);
 
 
           /* Move the 'cursor' one character width: */
 
-	  cur_x = cur_x + (images[IMG_NUMBERS]->w / 10);
-	}
+          cur_x = cur_x + (images[IMG_NUMBERS]->w / 10);
+        }
     }
 }
 
@@ -2734,11 +2758,11 @@
     while (SDL_PollEvent(&event))
     {
       if (event.type == SDL_KEYDOWN)
-	pause_done = 1;
+        pause_done = 1;
       else if (event.type == SDL_QUIT)
       {
         SDL_quit_received = 1;
- 	pause_quit = 1;
+         pause_quit = 1;
       }
     }
 
@@ -2940,17 +2964,17 @@
 
   /* begin drawing so as to center display depending on whether minus */
   /* sign needed (4 digit slots) or not (3 digit slots) DSB */
-  if (MC_AllowNegatives())
+  if (MC_GetOpt(ALLOW_NEGATIVES) )
     dest.x = ((screen->w - ((images[IMG_LEDNUMS]->w) / 10) * 4) / 2);
   else
     dest.x = ((screen->w - ((images[IMG_LEDNUMS]->w) / 10) * 3) / 2);
 
-  for (i = -1; i < 3; i++)  /* -1 is special case to allow minus sign */
+  for (i = -1; i < MC_MAX_DIGITS; i++) /* -1 is special case to allow minus sign */
                               /* with minimal modification of existing code DSB */
   {
     if (-1 == i)
     {
-      if (MC_AllowNegatives())
+      if (MC_GetOpt(ALLOW_NEGATIVES))
       {
         if (neg_answer_picked)
           src.x =  (images[IMG_LED_NEG_SIGN]->w) / 2;
@@ -3021,7 +3045,7 @@
   /* make sure keypad image is valid and has non-zero dimensions: */
   /* FIXME maybe this checking should be done once at the start */
   /* of game() rather than with every mouse click */
-  if (MC_AllowNegatives())
+  if (MC_GetOpt(ALLOW_NEGATIVES))
   {
     if (!images[IMG_KEYPAD])
       return;
@@ -3167,7 +3191,7 @@
 /* on-screen keypad */
 void game_key_event(SDLKey key)
 {
-
+  int i;
   key_pressed = 1;   // Signal back in cases where waiting on any key
 
   if (key == SDLK_ESCAPE)
@@ -3244,29 +3268,37 @@
   if (key >= SDLK_0 && key <= SDLK_9)
   {
     /* [0]-[9]: Add a new digit: */
-    digits[0] = digits[1];
-    digits[1] = digits[2];
-    digits[2] = key - SDLK_0;
+    for (i = 0; i < MC_MAX_DIGITS-1; ++i)
+      digits[i] = digits[i+1];
+    digits[MC_MAX_DIGITS-1] = key - SDLK_0;
+    
+//    digits[0] = digits[1];
+//    digits[1] = digits[2];
+//    digits[2] = key - SDLK_0;
     tux_pressing = 1;
   }
   else if (key >= SDLK_KP0 && key <= SDLK_KP9)
   {
     /* Keypad [0]-[9]: Add a new digit: */
-    digits[0] = digits[1];
-    digits[1] = digits[2];
-    digits[2] = key - SDLK_KP0;
+    for (i = 0; i < MC_MAX_DIGITS-1; ++i)
+      digits[i] = digits[i+1];
+    digits[MC_MAX_DIGITS-1] = key - SDLK_KP0;
+    
+//    digits[0] = digits[1];
+//    digits[1] = digits[2];
+//    digits[2] = key - SDLK_KP0;
     tux_pressing = 1;
   }
   /* support for negative answer input DSB */
   else if ((key == SDLK_MINUS || key == SDLK_KP_MINUS)
-        && MC_AllowNegatives())  /* do nothing unless neg answers allowed */
+        && MC_GetOpt(ALLOW_NEGATIVES) )  /* do nothing unless neg answers allowed */
   {
     /* allow player to make answer negative: */
     neg_answer_picked = 1;
     tux_pressing = 1;
   }
   else if ((key == SDLK_PLUS || key == SDLK_KP_PLUS)
-         && MC_AllowNegatives())  /* do nothing unless neg answers allowed */
+         && MC_GetOpt(ALLOW_NEGATIVES) )  /* do nothing unless neg answers allowed */
   {
     /* allow player to make answer positive: */
     neg_answer_picked = 0;
@@ -3274,17 +3306,16 @@
   }
   else if (key == SDLK_BACKSPACE ||
            key == SDLK_CLEAR ||
-	   key == SDLK_DELETE)
+           key == SDLK_DELETE)
   {
     /* [BKSP]: Clear digits! */
-    digits[0] = 0;
-    digits[1] = 0;
-    digits[2] = 0;
+    for (i = 0; i < MC_MAX_DIGITS; ++i)
+      digits[i] = 0;
     tux_pressing = 1;
   }
   else if (key == SDLK_RETURN ||
            key == SDLK_KP_ENTER ||
-	   key == SDLK_SPACE)
+           key == SDLK_SPACE)
   {
     /* [ENTER]: Accept digits! */
     doing_answer = 1;
@@ -3296,6 +3327,7 @@
 void add_score(int inc)
 {
   score += inc;
+  tmdprintf("Score is now: %d\n", score);
 }
 
 
@@ -3311,8 +3343,9 @@
     comets[i].x = 0;
     comets[i].y = 0;
     comets[i].answer = 0;
-    strncpy(comets[i].flashcard.formula_string, " ", MC_FORMULA_LEN);
-    strncpy(comets[i].flashcard.answer_string, " ", MC_ANSWER_LEN);
+//    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;
   }
 }
@@ -3342,6 +3375,9 @@
 
 void free_on_exit(void)
 {
+  int i;
+  for (i = 0; i < MAX_MAX_COMETS; ++i)
+    MC_FreeFlashcard(&(comets[i].flashcard));
   free(comets);
   free(cities);
   free(penguins);

Modified: tuxmath/trunk/src/gettext.h
===================================================================
--- tuxmath/trunk/src/gettext.h	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/gettext.h	2008-08-06 02:55:05 UTC (rev 589)
@@ -127,8 +127,8 @@
 #endif
 static const char *
 pgettext_aux (const char *domain,
-	      const char *msg_ctxt_id, const char *msgid,
-	      int category)
+              const char *msg_ctxt_id, const char *msgid,
+              int category)
 {
   const char *translation = dcgettext (domain, msg_ctxt_id, category);
   if (translation == msg_ctxt_id)
@@ -146,9 +146,9 @@
 #endif
 static const char *
 npgettext_aux (const char *domain,
-	       const char *msg_ctxt_id, const char *msgid,
-	       const char *msgid_plural, unsigned long int n,
-	       int category)
+               const char *msg_ctxt_id, const char *msgid,
+               const char *msgid_plural, unsigned long int n,
+               int category)
 {
   const char *translation =
     dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
@@ -185,8 +185,8 @@
 #endif
 static const char *
 dcpgettext_expr (const char *domain,
-		 const char *msgctxt, const char *msgid,
-		 int category)
+                 const char *msgctxt, const char *msgid,
+                 int category)
 {
   size_t msgctxt_len = strlen (msgctxt) + 1;
   size_t msgid_len = strlen (msgid) + 1;
@@ -208,10 +208,10 @@
       translation = dcgettext (domain, msg_ctxt_id, category);
 #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
       if (msg_ctxt_id != buf)
-	free (msg_ctxt_id);
+        free (msg_ctxt_id);
 #endif
       if (translation != msg_ctxt_id)
-	return translation;
+        return translation;
     }
   return msgid;
 }
@@ -230,9 +230,9 @@
 #endif
 static const char *
 dcnpgettext_expr (const char *domain,
-		  const char *msgctxt, const char *msgid,
-		  const char *msgid_plural, unsigned long int n,
-		  int category)
+                  const char *msgctxt, const char *msgid,
+                  const char *msgid_plural, unsigned long int n,
+                  int category)
 {
   size_t msgctxt_len = strlen (msgctxt) + 1;
   size_t msgid_len = strlen (msgid) + 1;
@@ -254,10 +254,10 @@
       translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
 #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
       if (msg_ctxt_id != buf)
-	free (msg_ctxt_id);
+        free (msg_ctxt_id);
 #endif
       if (!(translation == msg_ctxt_id || translation == msgid_plural))
-	return translation;
+        return translation;
     }
   return (n == 1 ? msgid : msgid_plural);
 }

Modified: tuxmath/trunk/src/highscore.c
===================================================================
--- tuxmath/trunk/src/highscore.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/highscore.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -140,7 +140,7 @@
           /* "Right" button - go to next page: */
           if (inRect( rightRect, event.button.x, event.button.y ))
           {
-            if (diff_level < ACE_HIGH_SCORE)
+            if (diff_level < NUM_HIGH_SCORE_LEVELS - 1)
             {
               diff_level++;
               if (Opts_MenuSound())
@@ -187,7 +187,7 @@
           SDL_BlitSurface(images[IMG_LEFT], NULL, screen, &leftRect);
       }
       /* Draw regular or grayed-out right arrow: */
-      if (diff_level == ACE_HIGH_SCORE)
+      if (diff_level == NUM_HIGH_SCORE_LEVELS - 1)
       {
         if (images[IMG_RIGHT_GRAY])
           SDL_BlitSurface(images[IMG_RIGHT_GRAY], NULL, screen, &rightRect);
@@ -242,6 +242,9 @@
               break;
             case ACE_HIGH_SCORE:
               srfc = BlackOutline(_("Ace"), title_font, &white);
+              break;
+            case COMMANDO_HIGH_SCORE:
+              srfc = BlackOutline(_("Commando"), title_font, &white);
               break;
             default:
               srfc = BlackOutline(_("Space Cadet"), title_font, &white);
@@ -311,7 +314,7 @@
       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 TUX3: tux_frame = 4; break;                        
       case TUX4: tux_frame = 3; break;
       case TUX5: tux_frame = 2; break;
       default: tux_frame = 0;
@@ -568,7 +571,7 @@
       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 TUX3: tux_frame = 4; break;                        
       case TUX4: tux_frame = 3; break;
       case TUX5: tux_frame = 2; break;
       default: tux_frame = 0;
@@ -624,7 +627,7 @@
 
   /* Make sure diff_level is valid: */
   if (diff_level < 0
-   || diff_level > ACE_HIGH_SCORE)
+   || diff_level >= NUM_HIGH_SCORE_LEVELS)
   {
     fprintf(stderr, "In insert_score(), diff_level invalid!\n");
     return 0;
@@ -703,6 +706,11 @@
       {
         fprintf(fp, "\nAce:\n");
         break;
+      }
+      case COMMANDO_HIGH_SCORE:
+      {
+        fprintf(fp, "\nCommando:\n");
+        break;
       }
     }
 
@@ -777,9 +785,9 @@
 {
   /* Make sure diff_level is valid: */
   if (diff_level < 0
-   || diff_level > ACE_HIGH_SCORE)
+   || diff_level >= NUM_HIGH_SCORE_LEVELS)
   {
-    fprintf(stderr, "In HS_Score(), diff_level invalid!\n");
+    fprintf(stderr, "In HS_Score(), diff_level = %d, invalid!\n", diff_level);
     return -1;
   }
 
@@ -800,7 +808,7 @@
 {
   /* Make sure diff_level is valid: */
   if (diff_level < 0
-   || diff_level > ACE_HIGH_SCORE)
+   || diff_level >= NUM_HIGH_SCORE_LEVELS)
   {
     fprintf(stderr, "In HS_Score(), diff_level invalid!\n");
     return NULL;

Modified: tuxmath/trunk/src/loaders.c
===================================================================
--- tuxmath/trunk/src/loaders.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/loaders.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -32,13 +32,13 @@
 /* FIXME Doesn't seem to work consistently on all versions of Windows */
 /* check to see if file exists, if so return true */
 // int checkFile( const char *file ) {
-// 	static struct stat fileStats;
+//         static struct stat fileStats;
 // 
-// 	fileStats.st_mode = 0;
+//         fileStats.st_mode = 0;
 // 
-// 	stat( file, &fileStats );
-// 		
-// 	return (S_IFREG & fileStats.st_mode);
+//         stat( file, &fileStats );
+//                 
+//         return (S_IFREG & fileStats.st_mode);
 // }
 
 
@@ -88,7 +88,7 @@
 
 
 int max( int n1, int n2 ) {
-	return (n1 > n2 ? n1 : n2);
+  return (n1 > n2 ? n1 : n2);
 }
 
 
@@ -132,7 +132,7 @@
 
 /* FIXME checkFile() not working right in Win32 - skipping. */
 /***********************
-	LoadImage : Load an image and set transparent if requested
+        LoadImage : Load an image and set transparent if requested
 ************************/
 SDL_Surface* LoadImage( char *datafile, int mode )
 {
@@ -211,7 +211,7 @@
 }
 
 /***********************
-	LoadBkgd() : a wrapper for LoadImage() that scales the
+        LoadBkgd() : a wrapper for LoadImage() that scales the
         image to the size of the screen using zoom(), taken
         from TuxPaint
 ************************/
@@ -284,54 +284,62 @@
 
 
 sprite* FlipSprite( sprite *in, int X, int Y ) {
-	sprite *out;
+  sprite *out;
 
-	out = malloc(sizeof(sprite));
-	if (in->default_img != NULL)
-		out->default_img = Flip( in->default_img, X, Y );
-	else
-		out->default_img = NULL;
-	for ( out->num_frames=0; out->num_frames<in->num_frames; out->num_frames++ )
-		out->frame[out->num_frames] = Flip( in->frame[out->num_frames], X, Y );
-	out->cur = 0;
-	return out;
+  out = malloc(sizeof(sprite));
+  if (in->default_img != NULL)
+          out->default_img = Flip( in->default_img, X, Y );
+  else
+          out->default_img = NULL;
+  for ( out->num_frames=0; out->num_frames<in->num_frames; out->num_frames++ )
+          out->frame[out->num_frames] = Flip( in->frame[out->num_frames], X, Y );
+  out->cur = 0;
+  return out;
 }
 
 
 sprite* LoadSprite( char* name, int MODE ) {
-	sprite *new_sprite;
-	char fn[PATH_MAX];
-	int x;
+  sprite *new_sprite;
+  char fn[PATH_MAX];
+  int x;
 
-	/* JA --- HACK check out what has changed with new code */
+  /* JA --- HACK check out what has changed with new code */
 
-	new_sprite = malloc(sizeof(sprite));
+  new_sprite = malloc(sizeof(sprite));
 
-	sprintf(fn, "%sd.png", name);  // The 'd' means the default image
-	new_sprite->default_img = LoadImage( fn, MODE|IMG_NOT_REQUIRED );
-	for (x = 0; x < MAX_SPRITE_FRAMES; x++) {
-		sprintf(fn, "%s%d.png", name, x);
-		new_sprite->frame[x] = LoadImage( fn, MODE|IMG_NOT_REQUIRED );
-		if ( new_sprite->frame[x] == NULL ) {
-			new_sprite->cur = 0;
-			new_sprite->num_frames = x;
-			break;
-		}
-	}
+  sprintf(fn, "%sd.png", name);  // The 'd' means the default image
+  new_sprite->default_img = LoadImage( fn, MODE|IMG_NOT_REQUIRED );
+  for (x = 0; x < MAX_SPRITE_FRAMES; x++) {
+          sprintf(fn, "%s%d.png", name, x);
+          new_sprite->frame[x] = LoadImage( fn, MODE|IMG_NOT_REQUIRED );
+          if ( new_sprite->frame[x] == NULL ) {
+                  new_sprite->cur = 0;
+                  new_sprite->num_frames = x;
+                  break;
+          }
+  }
 
 
-	
-	return new_sprite;
+  
+  return new_sprite;
 }
 
 
 
 void FreeSprite( sprite *gfx ) {
-	int x;
-	for (x = 0; x < gfx->num_frames; x++)
-		SDL_FreeSurface( gfx->frame[x] );
-	SDL_FreeSurface( gfx->default_img );
-	free(gfx);
+  int x;
+  if (!gfx)
+    return;
+  printf("Freeing image");
+  tmdprintf(" at %p", gfx);
+  for (x = 0; x < gfx->num_frames; x++)
+  {
+    printf(".");
+    SDL_FreeSurface( gfx->frame[x] );
+  }              
+  SDL_FreeSurface( gfx->default_img );
+  printf("done\n");
+  free(gfx);
 }
 
 void next_frame(sprite* s)
@@ -341,7 +349,7 @@
 }
 
 /***************************
-	LoadSound : Load a sound/music patch from a file.
+        LoadSound : Load a sound/music patch from a file.
 ****************************/
 Mix_Chunk* LoadSound( char *datafile )
 { 
@@ -359,8 +367,8 @@
 }
 
 /************************
-	LoadMusic : Load
-	music from a datafile
+        LoadMusic : Load
+        music from a datafile
 *************************/
 Mix_Music *LoadMusic(char *datafile )
 { 

Modified: tuxmath/trunk/src/mathcards.c
===================================================================
--- tuxmath/trunk/src/mathcards.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/mathcards.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -1,3078 +1,2077 @@
-/*
-*  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).
-*
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include "mathcards.h"
-
-/* "Globals" for mathcards.c: */
-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;
-
-/* 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;
-
-/* "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(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 randomly_keep(void);
-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_node(FILE* fp, MC_MathQuestion* ptr);
-
-/* these functions are dead code unless compiling with debug turned on: */
-#ifdef MC_DEBUG 
-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);
-#endif
-
-/*  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)
-{
-  #ifdef MC_DEBUG
-  printf("\nEntering MC_Initialize()");
-  #endif
-
-  /* check flag to see if we did this already */
-  if (initialized)
-  {
-
-    #ifdef MC_DEBUG
-    printf("\nAlready initialized");  
-    MC_PrintMathOptions(stdout, 0); 
-    printf("\nLeaving MC_Initialize()\n");
-    #endif
-
-    return 1;
-  }
-  math_opts = malloc(sizeof(MC_Options));
-  /* bail out if no struct */
-  if (!math_opts)
-  {
-
-    #ifdef MC_DEBUG
-    printf("\nError: math_opts null or invalid");
-    printf("\nLeaving MC_Initialize()\n");
-    #endif
-
-    fprintf(stderr, "\nUnable to initialize math_options");
+/*
+*  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).
+*
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <time.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: */
+#ifdef MC_DEBUG
+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);
+#endif
+
+/* 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);
+static MC_MathQuestion* add_all_valid(MC_ProblemType pt, MC_MathQuestion* list, MC_MathQuestion* end_of_list);
+static MC_MathQuestion* find_node(const 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)
+  {
+
+    #ifdef MC_DEBUG
+    printf("\nAlready initialized");
+    MC_PrintMathOptions(stdout, 0);
+    printf("\nLeaving MC_Initialize()\n");
+    #endif
+
+    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;
+
+  #ifdef MC_DEBUG
+  MC_PrintMathOptions(stdout, 0);
+  printf("\nLeaving MC_Initialize()\n");
+  #endif
+
+  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;
+
+  #ifdef MC_DEBUG
+  print_counters();
+  #endif
+
+  /* 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;
+
+    #ifdef MC_DEBUG
+    print_counters();
+    print_list(stdout, question_list);
+    printf("\nLeaving MC_StartGameUsingWrongs()\n");
+    #endif
+
+    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++;
+
+  #ifdef MC_DEBUG
+  printf("\nnext question is:");
+  print_card(*fc);
+  print_counters();
+  printf("\n\nLeaving MC_NextQuestion()\n");
+  #endif
+
+  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;
+  }
+
+  #ifdef MC_DEBUG
+  printf("\nQuestion was:");
+  print_card(*fc);
+  #endif
+
+  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--;
+  }
+
+  #ifdef MC_DEBUG
+  print_counters();
+  printf("\nLeaving MC_AnsweredCorrectly()\n");
+  #endif
+
+  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;
+  }
+
+  #ifdef MC_DEBUG
+  printf("\nQuestion was:");
+  print_card(*fc);
+  #endif
+
+  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--;
+  }
+
+  #ifdef MC_DEBUG
+  print_counters();
+  printf("\nLeaving MC_NotAnswered_Correctly()\n");
+  #endif
+
+  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) {
+      #ifdef MC_DEBUG
+      printf("\nError: allocation for time_per_question_list failed\n");
+      #endif
+      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, 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;
+}
+
+/* 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;
+}
+
+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(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;
+  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");
+}
+
+#ifdef MC_DEBUG
+void print_card(MC_FlashCard card)
+{
+  printf("\nprint_card():");
+  printf("formula_string = %s, answer_string = %s\n",
+         card.formula_string, card.answer_string);
+}
+
+/* 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;
+}
+#endif
+
+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;
-  } 
-
-  /* set general math options */
-  math_opts->play_through_list = DEFAULT_PLAY_THROUGH_LIST;
-  math_opts->repeat_wrongs = DEFAULT_REPEAT_WRONGS;
-  math_opts->copies_repeated_wrongs = DEFAULT_COPIES_REPEATED_WRONGS;
-  math_opts->allow_negatives = DEFAULT_ALLOW_NEGATIVES;
-  math_opts->max_answer = DEFAULT_MAX_ANSWER;
-  math_opts->max_questions = DEFAULT_MAX_QUESTIONS;
-  math_opts->question_copies = DEFAULT_QUESTION_COPIES;
-  math_opts->randomize = DEFAULT_RANDOMIZE;
-  math_opts->fraction_to_keep = DEFAULT_FRACTION_TO_KEEP;
-  /* set question formats:  */
-  math_opts->format_add_answer_last = DEFAULT_FORMAT_ADD_ANSWER_LAST; 
-  math_opts->format_add_answer_first = DEFAULT_FORMAT_ADD_ANSWER_FIRST;
-  math_opts->format_add_answer_middle = DEFAULT_FORMAT_ADD_ANSWER_MIDDLE;
-  math_opts->format_sub_answer_last = DEFAULT_FORMAT_SUB_ANSWER_LAST;
-  math_opts->format_sub_answer_first = DEFAULT_FORMAT_SUB_ANSWER_FIRST;
-  math_opts->format_sub_answer_middle = DEFAULT_FORMAT_SUB_ANSWER_MIDDLE;
-  math_opts->format_mult_answer_last = DEFAULT_FORMAT_MULT_ANSWER_LAST;
-  math_opts->format_mult_answer_first = DEFAULT_FORMAT_MULT_ANSWER_FIRST;
-  math_opts->format_mult_answer_middle = DEFAULT_FORMAT_MULT_ANSWER_MIDDLE;
-  math_opts->format_div_answer_last = DEFAULT_FORMAT_DIV_ANSWER_LAST;
-  math_opts->format_div_answer_first = DEFAULT_FORMAT_DIV_ANSWER_FIRST;
-  math_opts->format_div_answer_middle = DEFAULT_FORMAT_DIV_ANSWER_MIDDLE;
-
-  /* set addition options: */
-  math_opts->addition_allowed = DEFAULT_ADDITION_ALLOWED;
-  math_opts->min_augend = DEFAULT_MIN_AUGEND;
-  math_opts->max_augend = DEFAULT_MAX_AUGEND;
-  math_opts->min_addend = DEFAULT_MIN_ADDEND;
-  math_opts->max_addend = DEFAULT_MAX_ADDEND;
-  /* set subtraction options: */
-  math_opts->subtraction_allowed = DEFAULT_SUBTRACTION_ALLOWED;
-  math_opts->min_minuend = DEFAULT_MIN_MINUEND;
-  math_opts->max_minuend = DEFAULT_MAX_MINUEND;
-  math_opts->min_subtrahend = DEFAULT_MIN_SUBTRAHEND;
-  math_opts->max_subtrahend = DEFAULT_MAX_SUBTRAHEND;
-  /* set multiplication options: */
-  math_opts->multiplication_allowed = DEFAULT_MULTIPLICATION_ALLOWED;
-  math_opts->min_multiplier = DEFAULT_MIN_MULTIPLIER;
-  math_opts->max_multiplier = DEFAULT_MAX_MULTIPLIER;
-  math_opts->min_multiplicand = DEFAULT_MIN_MULTIPLICAND;
-  math_opts->max_multiplicand = DEFAULT_MAX_MULTIPLICAND;
-  /* set division options: */
-  math_opts->division_allowed = DEFAULT_DIVISION_ALLOWED;
-  math_opts->min_divisor = DEFAULT_MIN_DIVISOR;
-  math_opts->max_divisor = DEFAULT_MAX_DIVISOR;
-  math_opts->min_quotient = DEFAULT_MIN_QUOTIENT;
-  math_opts->max_quotient = DEFAULT_MAX_QUOTIENT;
-  /* set typing practice options: */
-  math_opts->typing_practice_allowed = DEFAULT_TYPING_PRACTICE_ALLOWED;
-  math_opts->min_typing_num = DEFAULT_MIN_TYPING_NUM;
-  math_opts->max_typing_num = DEFAULT_MAX_TYPING_NUM;
-
-  /* if no negatives to be used, reset any negatives to 0 */
-  if (!math_opts->allow_negatives)
-  {
-    clear_negatives();
-  }
-
-  initialized = 1;
-
-  #ifdef MC_DEBUG
-  MC_PrintMathOptions(stdout, 0); 
-  printf("\nLeaving MC_Initialize()\n");
-  #endif 
-
-  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)
-{
-  #ifdef MC_DEBUG
-  printf("\nEntering MC_StartGame()");
-  #endif
-
-  /* if math_opts not set up yet, initialize it: */
-  if (!initialized)
-  {
-
-    #ifdef MC_DEBUG
-    printf("\nNot initialized - calling MC_Initialize()");
-    #endif  
-
-    MC_Initialize();
-  }
-
-  if (!math_opts)  
-  {
-    #ifdef MC_DEBUG
-    printf("\nCould not initialize - bailing out");
-    printf("\nLeavinging MC_StartGame()\n");
-    #endif
-
-    return 0;
-  }
-  /* we know math_opts exists if we make it to here */
   
-  /* 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;
+  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;
+  }
 
-  /* 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;
-  }
-
-  /* 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;
-
-  #ifdef MC_DEBUG
-  print_counters();
-  #endif
-
-  /* make sure list now exists and has non-zero length: */
-  if (question_list && quest_list_length)
-  {
-    #ifdef MC_DEBUG
-    printf("\nGame set up successfully");
-    printf("\nLeaving MC_StartGame()\n");
-    #endif
-
-    return 1;
-  }
-  else
-  {
-    #ifdef MC_DEBUG
-    printf("\nGame NOT set up successfully - no valid list");
-    printf("\nLeaving MC_StartGame()\n");
-    #endif
-
-    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)
-{
-  #ifdef MC_DEBUG
-  printf("\nEntering MC_StartGameUsingWrongs()");
-  #endif
-
-  /* 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))
-  {
-    #ifdef MC_DEBUG
-    printf("\nNon-zero length wrong_quests list found, will");
-    printf("\nuse for new game list:");
-    #endif
-
-    /* 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;
-
-    #ifdef MC_DEBUG
-    print_counters();
-    print_list(stdout, question_list);
-    printf("\nLeaving MC_StartGameUsingWrongs()\n");
-    #endif
-
-    return 1;
-  }
-  else /* if no wrong_quests list, go to MC_StartGame()   */
-       /* to set up list based on math_opts               */
-  {
-    #ifdef MC_DEBUG
-    printf("\nNo wrong questions to review - generate list from math_opts\n");
-    printf("\nLeaving MC_StartGameUsingWrongs()\n");
-    #endif
-
-    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)
-{
-  #ifdef MC_DEBUG
-  printf("\nEntering MC_NextQuestion()");
-  #endif
-
-  /* (so we can free the node after removed from list:) */
-  MC_MathQuestion* ptr;
-  ptr = question_list;
-
-  if (!fc )
-  {
-    fprintf(stderr, "\nInvalid MC_FlashCard* argument!\n");
-
-    #ifdef MC_DEBUG
-    printf("\nInvalid MC_FlashCard* argument!");
-    printf("\nLeaving MC_NextQuestion()\n");
-    #endif
-
-    return 0;
-  }
-
-  if (!question_list ||
-/*      !next_question || */
-      !list_length(question_list) )
-  {
-    #ifdef MC_DEBUG
-    printf("\nquestion_list invalid or empty");
-    printf("\nLeaving MC_NextQuestion()\n");
-    #endif
-
-    return 0;
-  }
-  /* FIXME: could clean this up a bit with a copy_card() function */
-  fc->num1 = question_list->card.num1;
-  fc->num2 = question_list->card.num2;
-  fc->num3 = question_list->card.num3;
-  fc->operation = question_list->card.operation;
-  fc->format = question_list->card.format;
-  strncpy(fc->formula_string, question_list->card.formula_string, MC_FORMULA_LEN);  
-  strncpy(fc->answer_string, question_list->card.answer_string, MC_ANSWER_LEN);  
-
-  /* take first question node out of list and free it:   */
-  question_list = remove_node(question_list, question_list);
-  free(ptr);
-  quest_list_length--;
-  questions_pending++;
-
-  #ifdef MC_DEBUG
-  printf("\nnext question is:");
-  print_card(*fc);
-  print_counters();
-  printf("\nLeaving MC_NextQuestion()\n");
-  #endif
-
-  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)
-{
-  #ifdef MC_DEBUG
-  printf("\nEntering MC_AnsweredCorrectly()");
-  #endif
-
-  if (!fc)
-  {
-    fprintf(stderr, "\nMC_AnsweredCorrectly() passed invalid pointer as argument!\n");
-
-    #ifdef MC_DEBUG
-    printf("\nInvalid MC_FlashCard* argument!");
-    printf("\nLeaving MC_AnsweredCorrectly()\n");
-    #endif
-
-    return 0;
-  }
-
-  #ifdef MC_DEBUG
-  printf("\nQuestion was:");
-  print_card(*fc);
-  #endif
+  ret->card = MC_AllocateFlashcard();
+  ret->next = ret->previous = NULL;
   
-  answered_correctly++;
-  questions_pending--;
-
-  if (!math_opts->play_through_list)
-  /* reinsert question into question list at random location */
-  {
-    #ifdef MC_DEBUG
-    printf("\nReinserting question into list");
-    #endif
-
-    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
-  {
-    #ifdef MC_DEBUG
-    printf("\nNot reinserting question into list");
-    #endif
-    /* not recycling questions so fewer questions remain:      */
-    unanswered--;
-  }
-
-  #ifdef MC_DEBUG
-  print_counters();
-  printf("\nLeaving MC_AnsweredCorrectly()\n");
-  #endif
-
-  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)
+  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);
+    #ifdef MC_DEBUG
+    print_card(ret);
+    #endif
+  }
+  //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)
 {
-  #ifdef MC_DEBUG
-  printf("\nEntering MC_NotAnsweredCorrectly()");
-  #endif
-
-  if (!fc)
-  {
-    fprintf(stderr, "\nMC_NotAnsweredCorrectly() passed invalid pointer as argument!\n");
-
-    #ifdef MC_DEBUG
-    printf("\nInvalid MC_FlashCard* argument!");
-    printf("\nLeaving MC_NotAnsweredCorrectly()\n");
-    #endif
-
-    return 0;
-  }
-
-  #ifdef MC_DEBUG
-  printf("\nQuestion was:");
-  print_card(*fc);
-  #endif
-
-  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 */
-  {
-    #ifdef MC_DEBUG
-    printf("\nAdding to wrong_quests list");
-    #endif
-
-    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->repeat_wrongs)
-  {
-    int i;
-
-    #ifdef MC_DEBUG
-    printf("\nAdding %d copies to question_list:", math_opts->copies_repeated_wrongs);
-    #endif
- 
-    /* can put in more than one copy (to drive the point home!) */
-    for (i = 0; i < math_opts->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++;
+  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;
     }
-    /* unanswered stays the same if a single copy recycled or */
-    /* increases by 1 for each "extra" copy reinserted:       */
-    unanswered += (math_opts->copies_repeated_wrongs - 1);
-  }
-  else
-  {
-    #ifdef MC_DEBUG
-    printf("\nNot repeating wrong answers\n");
-    #endif
-
-    /* not repeating questions so list gets shorter:      */
-    unanswered--;
-  }
-
-  #ifdef MC_DEBUG
-  print_counters();
-  printf("\nLeaving MC_NotAnswered_Correctly()\n");
-  #endif
-
-  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->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) {
-      #ifdef MC_DEBUG
-      printf("\nError: allocation for time_per_question_list failed\n");
-      #endif
-      return 0;
+    */
+    if (op > MC_OPER_DIV || op < MC_OPER_ADD)
+    {
+      mcdprintf("Invalid operator: value %d\n", op);
+      return DEFAULT_CARD;
     }
-    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;
-}
-
-
-/* Simple Get()- and Set()-style functions for math options settings: */
-
-
-/* Set general math options: */
-void MC_SetMaxAnswer(int max)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetMaxAnswer(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_answer = sane_value(max);
-}
-
-
-void MC_SetMaxQuestions(int max)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetMaxQuestions(): math_opts not valid!\n");
-    return;
-  }
-  if (max < 0)
-  {
-    fprintf(stderr, "\nMC_SetMaxQuestions(): max_questions cannot be negative!\n");
-    return;
-  }
-  math_opts->max_questions = max;
-}
-
-void MC_SetAllowNegatives(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetAllowNegatives(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->allow_negatives = int_to_bool(opt);
-  if (!opt)
-  {
-    clear_negatives();
-  }
-}
-
-
-void MC_SetPlayThroughList(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetPlayThroughList(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->play_through_list = int_to_bool(opt);
-}
-
-
-void MC_SetRepeatWrongs(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetRepeatWrongs(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->repeat_wrongs = int_to_bool(opt);
-}
-
-
-void MC_SetCopiesRepeatedWrongs(int copies)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetCopiesRepeatedWrongs(): math_opts not valid!\n");
-    return;
-  }
-  /* number of copies must be between 1 and 10: */
-  if (copies < 1)
-    copies = 1;
-  if (copies > 10)
-    copies = 10;
-  math_opts->copies_repeated_wrongs = copies;
-}
-
-
-
-/*NOTE - list can contain more than one format */
-void MC_SetFormatAnswerLast(int opt)       /* Enable questions like:  a + b = ?    */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatAnswerLast(): math_opts not valid!\n");
-    return;
-  }
-
-  MC_SetFormatAddAnswerLast(opt);
-  MC_SetFormatSubAnswerLast(opt);
-  MC_SetFormatMultAnswerLast(opt);
-  MC_SetFormatDivAnswerLast(opt);
-} 
-
-
-void MC_SetFormatAnswerFirst(int opt)      /* Enable questions like:  ? + b = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatAnswerFirst(): math_opts not valid!\n");
-    return;
-  }
-
-  MC_SetFormatAddAnswerFirst(opt);
-  MC_SetFormatSubAnswerFirst(opt);
-  MC_SetFormatMultAnswerFirst(opt);
-  MC_SetFormatDivAnswerFirst(opt);
-}
-
- 
-void MC_SetFormatAnswerMiddle(int opt)     /* Enable questions like:  a + ? = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatAnswerMiddle(): math_opts not valid!\n");
-    return;
-  }
-
-  MC_SetFormatAddAnswerMiddle(opt);
-  MC_SetFormatSubAnswerMiddle(opt);
-  MC_SetFormatMultAnswerMiddle(opt);
-  MC_SetFormatDivAnswerMiddle(opt);
-} 
-
-
-
-/* Addition-specific question formats: */
-void MC_SetFormatAddAnswerLast(int opt)       /* Enable questions like:  a + b = ?    */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatAddAnswerLast(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_add_answer_last = int_to_bool(opt);
-} 
-
-
-void MC_SetFormatAddAnswerFirst(int opt)      /* Enable questions like:  ? + b = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatAddAnswerFirst(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_add_answer_first = int_to_bool(opt);
-}
-
- 
-void MC_SetFormatAddAnswerMiddle(int opt)     /* Enable questions like:  a + ? = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatAddAnswerMiddle(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_add_answer_middle = int_to_bool(opt);
-} 
-
-
-
-/* Subtraction-specific question formats: */
-void MC_SetFormatSubAnswerLast(int opt)       /* Enable questions like:  a - b = ?    */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatSubAnswerLast(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_sub_answer_last = int_to_bool(opt);
-} 
-
-
-void MC_SetFormatSubAnswerFirst(int opt)      /* Enable questions like:  ? - b = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatSubAnswerFirst(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_sub_answer_first = int_to_bool(opt);
-}
-
- 
-void MC_SetFormatSubAnswerMiddle(int opt)     /* Enable questions like:  a - ? = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatSubAnswerMiddle(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_sub_answer_middle = int_to_bool(opt);
-} 
-
-
-
-/* Multiplication-specific question formats: */
-void MC_SetFormatMultAnswerLast(int opt)       /* Enable questions like:  a * b = ?    */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatMultAnswerLast(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_mult_answer_last = int_to_bool(opt);
-} 
-
-
-void MC_SetFormatMultAnswerFirst(int opt)      /* Enable questions like:  ? * b = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatMultAnswerFirst(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_mult_answer_first = int_to_bool(opt);
-}
-
- 
-void MC_SetFormatMultAnswerMiddle(int opt)     /* Enable questions like:  a * ? = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatMultAnswerMiddle(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_mult_answer_middle = int_to_bool(opt);
-} 
-
-
-/* Division-specific question formats: */
-void MC_SetFormatDivAnswerLast(int opt)       /* Enable questions like:  a / b = ?    */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatDivAnswerLast(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_div_answer_last = int_to_bool(opt);
-} 
-
-
-void MC_SetFormatDivAnswerFirst(int opt)      /* Enable questions like:  ? / b = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatDivAnswerFirst(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_div_answer_first = int_to_bool(opt);
-}
-
- 
-void MC_SetFormatDivAnswerMiddle(int opt)     /* Enable questions like:  a / ? = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetFormatDivAnswerMiddle(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->format_div_answer_middle = int_to_bool(opt);
-} 
-
-
-
-void MC_SetQuestionCopies(int copies)      /* how many times each question is put in list */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetQuestionCopies(): math_opts not valid!\n");
-    return;
-  }
-  /* number of copies must be between 1 and 10: */
-  if (copies < 1)
-    copies = 1;
-  if (copies > 10)
-    copies = 10;
-  math_opts->question_copies = copies;
-}
-
-
-void MC_SetRandomize(int opt)   
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetRandomize(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->randomize = int_to_bool(opt);
-} 
-
-void MC_SetFractionToKeep(float fract)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetRandomize(): math_opts not valid!\n");
-    return;
-  }
-  /* must be between 0 and 1: */
-  if (fract < 0)
-    fract = 0;
-  if (fract > 1)
-    fract = 1;
-  math_opts->fraction_to_keep = fract;
-}
-
-
-/* Set math operations to be used in game: */
-void MC_SetAddAllowed(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetAddAllowed(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->addition_allowed = int_to_bool(opt);
-}
-
-
-void MC_SetSubAllowed(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetSubAllowed(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->subtraction_allowed = int_to_bool(opt);
-}
-
-
-void MC_SetMultAllowed(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetMultAllowed(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->multiplication_allowed = int_to_bool(opt);
-}
-
-
-void MC_SetDivAllowed(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetDivAllowed(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->division_allowed = int_to_bool(opt);
-}
-
-
-void MC_SetTypingAllowed(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetTypingAllowed(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->typing_practice_allowed = int_to_bool(opt);
-}
-
-
-
-/* Set min and max for addition: */
-void MC_SetAddMin(int opt)
-{
-  MC_SetAddMinAugend(opt);
-  MC_SetAddMinAddend(opt);
-}
-
-
-void MC_SetAddMinAugend(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetAddMinAugend(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->min_augend = sane_value(opt);
-}
-
-
-void MC_SetAddMinAddend(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetAddMinAddend(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->min_addend = sane_value(opt);
-}
-
-
-void MC_SetAddMax(int opt)
-{
-  MC_SetAddMaxAugend(opt);
-  MC_SetAddMaxAddend(opt);
-}
-
-
-void MC_SetAddMaxAugend(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetAddMaxAugend(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_augend = sane_value(opt);
-}
-
-
-void MC_SetAddMaxAddend(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetAddMaxAddend(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_addend = sane_value(opt);
-}
-
-
-
-
-/* Set min and max for subtraction: */
-void MC_SetSubMin(int opt)
-{
-  MC_SetSubMinMinuend(opt);
-  MC_SetSubMinSubtrahend(opt);
-}
-
-
-void MC_SetSubMinMinuend(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_MC_SetSubMinMinuend(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->min_minuend = sane_value(opt);
-}
-
-
-void MC_SetSubMinSubtrahend(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetSubMinSubtrahend(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->min_subtrahend = sane_value(opt);
-}
-
-
-void MC_SetSubMax(int opt)
-{
-  MC_SetSubMaxMinuend(opt);
-  MC_SetSubMaxSubtrahend(opt);
-}
-
-
-void MC_SetSubMaxMinuend(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetSubMaxMinuend(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_minuend = sane_value(opt);
-}
-
-
-void MC_SetSubMaxSubtrahend(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetSubMaxSubtrahend(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_subtrahend = sane_value(opt);
-}
-
-
-
-
-/* Set min and max for multiplication: */
-void MC_SetMultMin(int opt)
-{
-  MC_SetMultMinMultiplier(opt);
-  MC_SetMultMinMultiplicand(opt);
-}
-
-
-void MC_SetMultMinMultiplier(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetMultMinMultiplier(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->min_multiplier = sane_value(opt);
-}
-
-
-void MC_SetMultMinMultiplicand(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetMultMinMultiplicand(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->min_multiplicand = sane_value(opt);
-}
-
-
-void MC_SetMultMax(int opt)
-{
-  MC_SetMultMaxMultiplier(opt);
-  MC_SetMultMaxMultiplicand(opt);
-}
-
-
-void MC_SetMultMaxMultiplier(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetMultMaxMultiplier(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_multiplier = sane_value(opt);
-}
-
-
-void MC_SetMultMaxMultiplicand(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetMultMaxMultiplicand(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_multiplicand = sane_value(opt);
-}
-
-
-
-
-/* Set min and max for division: */
-void MC_SetDivMin(int opt)
-{
-  MC_SetDivMinDivisor(opt);
-  MC_SetDivMinQuotient(opt);
-}
-
-
-void MC_SetDivMinDivisor(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetDivMinDivisor(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->min_divisor = sane_value(opt);
-}
-
-
-void MC_SetDivMinQuotient(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetDivMinQuotient(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->min_quotient = sane_value(opt);
-}
-
-
-void MC_SetDivMax(int opt)
-{
-  MC_SetDivMaxDivisor(opt);
-  MC_SetDivMaxQuotient(opt);
-}
-
-
-void MC_SetDivMaxDivisor(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetDivMaxDivisor(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_divisor = sane_value(opt);
-}
-
-
-void MC_SetDivMaxQuotient(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetDivMaxQuotient(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_quotient = sane_value(opt);
-}
-
-
-/* Set min and max for division: */
-void MC_SetTypeMin(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetTypeMin(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->min_typing_num = sane_value(opt);
-}
-
-
-void MC_SetTypeMax(int opt)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SetTypeMax(): math_opts not valid!\n");
-    return;
-  }
-  math_opts->max_typing_num = sane_value(opt);
-}
-
-
-/*"Get" type methods to query option parameters */
-
-/* Query general math options: */
-int MC_MaxAnswer(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_MaxAnswer(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_answer;
-}
-
-
-int MC_MaxQuestions(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_MaxQuestions(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_questions;
-}
-
-
-int MC_AllowNegatives(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_AllowNegatives(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->allow_negatives;
-}
-
-
-int MC_PlayThroughList(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_PlayThroughList(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->play_through_list;
-}
-
-
-int MC_RepeatWrongs(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_RepeatWrongs(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->repeat_wrongs;
-}
-
-
-int MC_CopiesRepeatedWrongs(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_CopiesRepeatedWrongs(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->copies_repeated_wrongs;
-}
-
-
-float MC_FractionToKeep(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FractionToKeep(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->fraction_to_keep;
-}
-
-
-
-int MC_FormatAddAnswerLast(void)      /* a + b = ?                                               */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatAddAnswerLast(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_add_answer_last;
-} 
-
-
-int MC_FormatAddAnswerFirst(void)     /* ? + b = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatAddAnswerFirst(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_add_answer_first;
-} 
-
-
-int MC_FormatAddAnswerMiddle(void)    /* a + ? = c                                               */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatAddAnswerMiddle(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_add_answer_middle;
-} 
-
-
-int MC_FormatSubAnswerLast(void)      /* a - b = ?                                               */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatSubAnswerLast(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_sub_answer_last;
-} 
-
-
-int MC_FormatSubAnswerFirst(void)     /* ? - b = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatSubAnswerFirst(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_sub_answer_first;
-} 
-
-
-int MC_FormatSubAnswerMiddle(void)    /* a - ? = c                                               */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatSubAnswerMiddle(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_sub_answer_middle;
-} 
-
-int MC_FormatMultAnswerLast(void)      /* a * b = ?                                               */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatMultAnswerLast(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_mult_answer_last;
-} 
-
-
-int MC_FormatMultAnswerFirst(void)     /* ? * b = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatMultAnswerFirst(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_mult_answer_first;
-} 
-
-
-int MC_FormatMultAnswerMiddle(void)    /* a * ? = c                                               */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatMultAnswerMiddle(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_mult_answer_middle;
-} 
-
-
-int MC_FormatDivAnswerLast(void)      /* a / b = ?                                               */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatDivAnswerLast(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_div_answer_last;
-} 
-
-
-int MC_FormatDivAnswerFirst(void)     /* ? / b = c   */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatDivAnswerFirst(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_div_answer_first;
-} 
-
-
-int MC_FormatDivAnswerMiddle(void)    /* a / ? = c                                               */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_FormatAnswerMiddle(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->format_add_answer_middle;
-} 
-
-
-
-int MC_QuestionCopies(void)         /* how many times each question is put in list */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_QuestionCopies(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->question_copies;
-} 
-
-
-int MC_Randomize(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_Randomize(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->randomize;
-} 
-
-
-
-/* Query the allowed math operations: */
-int MC_AddAllowed(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_AddAllowed(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->addition_allowed;
-}
-
-
-int MC_SubAllowed(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SubAllowed(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->subtraction_allowed;
-}
-
-
-int MC_MultAllowed(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_MultAllowed(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->multiplication_allowed;
-}
-
-
-int MC_DivAllowed(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_DivAllowed(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->division_allowed;
-}
-
-
-int MC_TypingAllowed(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_TypeAllowed(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->typing_practice_allowed;
-}
-
-
-/* Query min and max for addition: */
-int MC_AddMinAugend(void)               /* the "augend" is the first addend i.e. "a" in "a + b = c" */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_AddMinAugend(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->min_augend;
-}
-
-
-int MC_AddMinAddend(void)               /* options for the other addend */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_AddMinAddend(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->min_addend;
-}
-
-
-int MC_AddMaxAugend(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_AddMaxAugend(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_augend;
-}
-
-
-int MC_AddMaxAddend(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_AddMaxAddend(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_addend;
-}
-
-
-
-/* Query min and max for subtraction: */
-int MC_SubMinMinuend(void)              /* minuend - subtrahend = difference */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SubMinMinuend(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->min_minuend;
-}
-
-
-int MC_SubMinSubtrahend(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SubMinSubtrahend(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->min_subtrahend;
-}
-
-
-
-int MC_SubMaxMinuend(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SubMaxMinuend(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_minuend;
-}
-
-
-
-int MC_SubMaxSubtrahend(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_SubMaxSubtrahend(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_subtrahend;
-}
-
-
-
-/* Query min and max for multiplication: */
-int MC_MultMinMultiplier(void)          /* multiplier * multiplicand = product */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_MultMinMultiplier(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->min_multiplier;
-}
-
-
-int MC_MultMinMultiplicand(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_MultMinMultiplicand(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->min_multiplicand;
-}
-
-
-
-int MC_MultMaxMultiplier(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_MultMaxMultiplier(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_multiplier;
-}
-
-
-
-int MC_MultMaxMultiplicand(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_MultMaxMultiplicand(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_multiplicand;
-}
-
-
-
-/* Query min and max for division: */
-int MC_DivMinDivisor(void)             /* dividend/divisor = quotient */
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_DivMinDivisor(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->min_divisor;
-}
-
-
-int MC_DivMinQuotient(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_DivMinQuotient(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->min_quotient;
-}
-
-
-int MC_DivMaxDivisor(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_DivMaxDivisor(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_divisor;
-}
-
-
-int MC_DivMaxQuotient(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_DivMaxQuotient(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_quotient;
-}
-
-
-/* Query min and max for typing practice: */
-int MC_TypeMin(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_TypeMin(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->min_typing_num;
-}
-
-
-int MC_TypeMax(void)
-{
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMC_TypeMax(): math_opts not valid!\n");
-    return MC_MATH_OPTS_INVALID;
-  }
-  return math_opts->max_typing_num;
-}
-
-
-/* prints struct to file */
-void MC_PrintMathOptions(FILE* fp, int verbose)
-{
-  #ifdef MC_DEBUG
-  printf("\nEntering MC_PrintMathOptions()\n");
-  #endif
-
-  /* bail out if no struct */
-  if (!math_opts)
-  {
-    fprintf(stderr, "\nMath Options struct does not exist!\n");
-    return;
-  }
-
-  if (verbose)
-  {
-    fprintf (fp, "\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");
-  }  
-  fprintf (fp, "play_through_list = %d\n", math_opts->play_through_list);
-  fprintf (fp, "question_copies = %d\n", math_opts->question_copies);
-  fprintf (fp, "repeat_wrongs = %d\n", math_opts->repeat_wrongs);
-  fprintf (fp, "copies_repeated_wrongs = %d\n", math_opts->copies_repeated_wrongs);
-
-  if (verbose)
-  {
-    fprintf (fp, "\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");
-  }  
-  fprintf (fp, "format_add_answer_last = %d\n", math_opts->format_add_answer_last);
-  fprintf (fp, "format_add_answer_first = %d\n", math_opts->format_add_answer_first);
-  fprintf (fp, "format_add_answer_middle = %d\n", math_opts->format_add_answer_middle);
-  fprintf (fp, "format_sub_answer_last = %d\n", math_opts->format_sub_answer_last);
-  fprintf (fp, "format_sub_answer_first = %d\n", math_opts->format_sub_answer_first);
-  fprintf (fp, "format_sub_answer_middle = %d\n", math_opts->format_sub_answer_middle);
-  fprintf (fp, "format_mult_answer_last = %d\n", math_opts->format_mult_answer_last);
-  fprintf (fp, "format_mult_answer_first = %d\n", math_opts->format_mult_answer_first);
-  fprintf (fp, "format_mult_answer_middle = %d\n", math_opts->format_mult_answer_middle);
-  fprintf (fp, "format_div_answer_last = %d\n", math_opts->format_div_answer_last);
-  fprintf (fp, "format_div_answer_first = %d\n", math_opts->format_div_answer_first);
-  fprintf (fp, "format_div_answer_middle = %d\n", math_opts->format_div_answer_middle);
-
-  if (verbose)
-  {
-    fprintf (fp, "\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");
-  }  
-  fprintf (fp, "allow_negatives = %d\n", math_opts->allow_negatives);
-
-  if (verbose)
-  {
-    fprintf (fp, "\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");
-  }  
-  fprintf (fp, "max_answer = %d\n", math_opts->max_answer);
-
-  if (verbose)
-  {
-    fprintf (fp, "\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");
-  }  
-  fprintf (fp, "max_questions = %d\n", math_opts->max_questions);  
-
-  if (verbose)
-  {
-    fprintf (fp, "\n############################################################\n"
-                 "# If 'randomize' selected, the list will be shuffled       #\n"
-                 "# at the start of the game.  Default is 1 (yes).           #\n"
-                 "############################################################\n\n");
-  }
-  fprintf (fp, "randomize = %d\n", math_opts->randomize);
-
-  if (verbose)
-  {
-    fprintf (fp, "\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");
-  }
-  fprintf(fp, "addition_allowed = %d\n", math_opts->addition_allowed);
-  fprintf(fp, "subtraction_allowed = %d\n", math_opts->subtraction_allowed);
-  fprintf(fp, "multiplication_allowed = %d\n", math_opts->multiplication_allowed);
-  fprintf(fp, "division_allowed = %d\n", math_opts->division_allowed);
-
-
-  if (verbose)
-  {
-    fprintf (fp, "\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");
-  }
-  fprintf(fp, "\n# Addition operands: augend + addend = sum\n");
-  fprintf(fp, "min_augend = %d\n", math_opts->min_augend);
-  fprintf(fp, "max_augend = %d\n", math_opts->max_augend);
-  fprintf(fp, "min_addend = %d\n", math_opts->min_addend);
-  fprintf(fp, "max_addend = %d\n", math_opts->max_addend);
-
-  fprintf(fp, "\n# Subtraction operands: minuend - subtrahend = difference\n");
-  fprintf(fp, "min_minuend = %d\n", math_opts->min_minuend);
-  fprintf(fp, "max_minuend = %d\n", math_opts->max_minuend);
-  fprintf(fp, "min_subtrahend = %d\n", math_opts->min_subtrahend);
-  fprintf(fp, "max_subtrahend = %d\n", math_opts->max_subtrahend);
-
-  fprintf(fp, "\n# Multiplication operands: multiplier * multiplicand = product\n");
-  fprintf(fp, "min_multiplier = %d\n", math_opts->min_multiplier);
-  fprintf(fp, "max_multiplier = %d\n", math_opts->max_multiplier);
-  fprintf(fp, "min_multiplicand = %d\n", math_opts->min_multiplicand);
-  fprintf(fp, "max_multiplicand = %d\n", math_opts->max_multiplicand);
-
-  fprintf(fp, "\n# Division operands: dividend/divisor = quotient\n");
-  fprintf(fp, "min_divisor = %d\n",math_opts->min_divisor);
-  fprintf(fp, "max_divisor = %d\n", math_opts->max_divisor);
-  fprintf(fp, "min_quotient = %d\n", math_opts->min_quotient);
-  fprintf(fp, "max_quotient = %d\n", math_opts->max_quotient);
-
-  fprintf(fp, "\n# Typing practice:\n");
-  fprintf(fp, "min_typing_num = %d\n",math_opts->min_typing_num);
-  fprintf(fp, "max_typing_num = %d\n",math_opts->max_typing_num);
-
-  #ifdef MC_DEBUG
-  printf("\nLeaving MC_PrintMathOptions()\n");
-  #endif
-}
-
-
-
-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)
-{
-  if (math_opts->min_augend < 0)
-    math_opts->min_augend = 0;
-  if (math_opts->max_augend < 0)
-    math_opts->max_augend = 0;
-  if (math_opts->min_addend < 0)
-    math_opts->min_addend = 0;
-  if (math_opts->max_addend < 0)
-    math_opts->max_addend = 0;
-
-  if (math_opts->min_minuend < 0)
-    math_opts->min_minuend = 0;
-  if (math_opts->max_minuend < 0)
-    math_opts->max_minuend = 0;
-  if (math_opts->min_subtrahend < 0)
-    math_opts->min_subtrahend = 0;
-  if (math_opts->max_subtrahend < 0)
-    math_opts->max_subtrahend = 0;
-
-  if (math_opts->min_multiplier < 0)
-    math_opts->min_multiplier = 0;
-  if (math_opts->max_multiplier < 0)
-    math_opts->max_multiplier = 0;
-  if (math_opts->min_multiplicand < 0)
-    math_opts->min_multiplicand = 0;
-  if (math_opts->max_multiplicand < 0)
-    math_opts->max_multiplicand = 0;
-
-  if (math_opts->min_divisor < 0)
-    math_opts->min_divisor = 0;
-  if (math_opts->max_divisor < 0)
-    math_opts->max_divisor = 0;
-  if (math_opts->min_quotient < 0)
-    math_opts->min_quotient = 0;
-  if (math_opts->max_quotient < 0)
-    math_opts->max_quotient = 0;
-
-  if (math_opts->min_typing_num < 0)
-    math_opts->min_typing_num = 0;
-  if (math_opts->max_typing_num < 0)
-    math_opts->max_typing_num = 0;
-}
-
-/* using parameters from the mission struct, create linked list of "flashcards" */
-/* FIXME should figure out how to proceed correctly if we run out of memory */
-/* FIXME very redundant code - figure out way to iterate through different */
-/* math operations and question formats                                    */
-MC_MathQuestion* generate_list(void)
-{
-  MC_MathQuestion* top_of_list = NULL;
-  MC_MathQuestion* end_of_list = NULL;
-  MC_MathQuestion* tmp_ptr = NULL;
-
-  int i, j, k;
-  int length = 0;
-
-  #ifdef MC_DEBUG
-  printf("\nEntering generate_list()");
-  MC_PrintMathOptions(stdout, 0);
-  #endif
- 
-  /* add nodes for each math operation allowed */
-
-  #ifdef MC_DEBUG
-  printf("\ngenerating addition questions\n");
-  #endif
-
-  if (math_opts->addition_allowed)
-  {
-    #ifdef MC_DEBUG
-    printf("\nAddition problems");
-    #endif
-    for (i = math_opts->min_augend; i <= math_opts->max_augend; i++)
+    //choose two numbers in the proper range and get their result
+    
+    else
     {
-      for (j = math_opts->min_addend; j <= math_opts->max_addend; j++)
-      {
-        /* check if max_answer exceeded or if question */
-        /* contains undesired negative values:         */
-        if (validate_question(i, j, i + j))
-        {  
-          /* put in the desired number of copies: */
-          for (k = 0; k < math_opts->question_copies; k++)
-          {
-            /* put in questions in each selected format: */
+      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]; 
 
-            /* questions like num1 + num2 = ? */
-            if (math_opts->format_add_answer_last)
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-              {
-                tmp_ptr = create_node(i, j, MC_OPER_ADD, i + j, MC_FORMAT_ANS_LAST);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-
-            /* questions like num1 + ? = num3 */
-            if (math_opts->format_add_answer_middle)
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-              {
-                tmp_ptr = create_node(i, j, MC_OPER_ADD, i + j, MC_FORMAT_ANS_MIDDLE);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-
-            /* questions like ? + num2 = num3 */
-            if (math_opts->format_add_answer_first)
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-
-              {
-                tmp_ptr = create_node(i, j, MC_OPER_ADD, i + j, MC_FORMAT_ANS_FIRST);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-          }
-        }
-      }
-    }
-  }
-
-  #ifdef MC_DEBUG
-  printf("generating subtraction questions\n");
-  #endif
-
-  if (math_opts->subtraction_allowed)
-  {
-    #ifdef MC_DEBUG
-    printf("\nSubtraction problems");
-    #endif
-    for (i = math_opts->min_minuend; i <= math_opts->max_minuend; i++)
-    {
-      for (j = math_opts->min_subtrahend; j <= math_opts->max_subtrahend; j++)
+      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)  
       {
-        /* check if max_answer exceeded or if question */
-        /* contains undesired negative values:         */
-        if (validate_question(i, j, i - j))
-        {  
-          /* put in the desired number of copies: */
-          for (k = 0; k < math_opts->question_copies; k++)
-          {
-            /* put in questions in each selected format: */
-
-            /* questions like num1 - num2 = ? */
-            if (math_opts->format_sub_answer_last)
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-
-              {
-                tmp_ptr = create_node(i, j, MC_OPER_SUB, i - j, MC_FORMAT_ANS_LAST);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-
-            /* questions like num1 - ? = num3 */
-            if (math_opts->format_sub_answer_middle)
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-
-              {
-                tmp_ptr = create_node(i, j, MC_OPER_SUB, i - j, MC_FORMAT_ANS_MIDDLE);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-
-            /* questions like ? - num2 = num3 */
-            if (math_opts->format_sub_answer_first)
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-              {
-                tmp_ptr = create_node(i, j, MC_OPER_SUB, i - j, MC_FORMAT_ANS_FIRST);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-          }
-        }
+        if (r2 == 0)
+          r2 = 1;
+        ret.difficulty = r1;
+        r1 *= r2;
+        ans = ret.difficulty;
       }
-    }
-  }
+    }
 
-  #ifdef MC_DEBUG
-  printf("generating multiplication questions\n");
-  #endif
 
-  if (math_opts->multiplication_allowed)
-  {
-    #ifdef MC_DEBUG
-    printf("\nMultiplication problems");
-    #endif
-    for (i = math_opts->min_multiplier; i <= math_opts->max_multiplier; i++)
-    {
-      for (j = math_opts->min_multiplicand; j <= math_opts->max_multiplicand; j++)
-      {
-        /* check if max_answer exceeded or if question */
-        /* contains undesired negative values:         */
-        if (validate_question(i, j, i * j))
-        {  
-          /* put in the desired number of copies: */
-          for (k = 0; k < math_opts->question_copies; k++)
-          {
-            /* put in questions in each selected format: */
+    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;
 
-            /* questions like num1 x num2 = ? */
-            if (math_opts->format_mult_answer_last)
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-              {
-                tmp_ptr = create_node(i, j, MC_OPER_MULT, i * j, MC_FORMAT_ANS_LAST);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-
-            /* questions like num1 x ? = num3 */
-            /* (no questions like 0 x ? = 0) because answer indeterminate */
-            if ((math_opts->format_mult_answer_middle)
-             && (i != 0)) 
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-              {
-                tmp_ptr = create_node(i, j, MC_OPER_MULT, i * j, MC_FORMAT_ANS_MIDDLE);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-
-            /* questions like ? x num2 = num3 */
-            /* (no questions like ? X 0 = 0) because answer indeterminate */
-            if ((math_opts->format_mult_answer_first)
-             && (j != 0))
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-              {
-                tmp_ptr = create_node(i, j, MC_OPER_MULT, i * j, MC_FORMAT_ANS_FIRST);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-          }
-        }
-      }
-    }
-  }
-
-  #ifdef MC_DEBUG
-  printf("generating division questions\n");
-  #endif
-
-  if (math_opts->division_allowed)
+  }
+  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)
   {
-    #ifdef MC_DEBUG
-    printf("\nDivision problems");
-    #endif
-    for (i = math_opts->min_quotient; i <= math_opts->max_quotient; i++)
-    {
-      for (j = math_opts->min_divisor; j <= math_opts->max_divisor; j++)
-      {
-        /* check if max_answer exceeded or if question */
-        /* contains undesired negative values:         */
-        if (j                                     /* must avoid division by zero: */      
-            &&
-            validate_question(i * j, j, i))       /* division problems are generated as multiplication */
-        {  
-          /* put in the desired number of copies: */
-          for (k = 0; k < math_opts->question_copies; k++)
-          {
-            /* put in questions in each selected format: */
-
-            /* questions like num1 / num2 = ? */
-            if (math_opts->format_div_answer_last)
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-              {
-                tmp_ptr = create_node(i * j, j, MC_OPER_DIV, i, MC_FORMAT_ANS_LAST);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-
-            /* questions like num1 / ? = num3 */
-            if ((math_opts->format_div_answer_middle)
-               && (i))      /* This avoids creating indeterminate questions: 0/? = 0 */
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-              {
-                tmp_ptr = create_node(i * j, j, MC_OPER_DIV, i, MC_FORMAT_ANS_MIDDLE);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-
-            /* questions like ? / num2  = num3 */
-            if (math_opts->format_div_answer_first)
-            {
-              /* make sure max_questions not exceeded, */
-              /* also check if question being randomly kept or discarded: */
-              if ((length < math_opts->max_questions)
-                 && randomly_keep())
-              {
-                tmp_ptr = create_node(i * j, j, MC_OPER_DIV, i, MC_FORMAT_ANS_FIRST);
-                top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-                end_of_list = tmp_ptr;
-                length++; 
-              } 
-            }
-          }
-        }
-      }
-    }
+    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 );     
   }
-
-  #ifdef MC_DEBUG
-  printf("generating typing practice questions\n");
-  #endif
-
-  if (math_opts->typing_practice_allowed)
-  {
-    #ifdef MC_DEBUG
-    printf("\nTyping problems");
-    #endif
-    for (i = math_opts->min_typing_num; i <= math_opts->max_typing_num; i++)
-    {
-      /* check if max_answer exceeded or if question */
-      /* contains undesired negative values:         */
-      if (validate_question(i, i, i))
-      {  
-        /* put in the desired number of copies: */
-        for (k = 0; k < math_opts->question_copies; k++)
-        {
-          /* make sure max_questions not exceeded, */
-          /* also check if question being randomly kept or discarded: */
-          if ((length < math_opts->max_questions)
-               && randomly_keep())
-          {
-            tmp_ptr = create_node(i, i, MC_OPER_TYPING_PRACTICE, i, MC_FORMAT_ANS_LAST);
-            top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
-            end_of_list = tmp_ptr;
-            length++; 
-          } 
-        }
-      }
-    }
-  }
-  #ifdef MC_DEBUG
-  length = list_length(top_of_list); 
-  printf("\nlength before randomization:\t%d", length); 
-  #endif
-
-  /*  now shuffle list if desired: */
-  if (math_opts->randomize)
-  {
-    if(!randomize_list(&top_of_list))
-    { 
-      fprintf(stderr, "Error during list randomization!\n");
-      return NULL;
-    }
-  }
-
-  #ifdef MC_DEBUG
-  length = list_length(top_of_list); 
-  printf("\nlength after randomization:\t%d", length); 
-  printf("\nLeaving generate_list()\n");
-  #endif
-
-  return top_of_list;
-}
-
-
-/* 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->max_answer)
-   || abs_value(n2) > abs_value(math_opts->max_answer)
-   || abs_value(n3) > abs_value(math_opts->max_answer))
-  {
-    return 0;
-  }
-  /* make sure none of values are negative if negatives not allowed: */
-  if (!math_opts->allow_negatives)
-  {
-    if (n1 < 0 || n2 < 0 || n3 < 0)
-    {
-      return 0;
-    }
-  }
-  return 1;  
-}
-
-/* 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.num1 = n1;
-  ptr->card.num2 = n2;  
-  ptr->card.num3 = ans;
-  ptr->card.operation = op;
-  ptr->card.format = f;
-  ptr->next = NULL;
-  ptr->previous = NULL;
-
-
-  /* creating formula_string  and answer_string is a little more work: */
-  {
-    char oper_char;
-    /* find out correct operation character */
-    switch (op)
-    {
-      case MC_OPER_ADD:
+  return ret;
+}
+
+MC_MathQuestion* generate_list(void)
+{
+  int i;
+  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;
+
+  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
+  {
+    for (i = MC_PT_TYPING; i < MC_NUM_PTYPES; ++i)
+    {
+      if (!MC_GetOpt(i + TYPING_PRACTICE_ALLOWED) )
+        continue;
+
+      list = add_all_valid(i, list, end_of_list);
+
+    }
+
+    if (MC_GetOpt(RANDOMIZE) )
       {
-        oper_char = '+';
-        break;
-      }
-      case MC_OPER_SUB:
+        mcdprintf("Randomizing list\n");
+        randomize_list(&list);
+      }
+
+    if (length)
+    {
+      cl = list_length(list);
+      if (length > cl) //if not enough questions, pad out with randoms
       {
-        oper_char = '-';
-        break;
-      }
-      case MC_OPER_MULT:
+        mcdprintf("Padding out list from %d to %d questions\n", cl, length);
+        for (i = cl; i < length; ++i)
+        {
+          tnode = malloc(sizeof(MC_MathQuestion) );
+          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
       {
-        oper_char = '*';
-        break;
+        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;
       }
-      case MC_OPER_DIV:
-      {
-        oper_char = '/';
-        break; 
-      }
-      case MC_OPER_TYPING_PRACTICE:
-      {
-        snprintf(ptr->card.formula_string, MC_FORMULA_LEN, "%d",ptr->card.num1);
-        snprintf(ptr->card.answer_string, MC_ANSWER_LEN, "%d",ptr->card.num1);
-        return ptr;  /* Don't need to look at formats for this case. */
-      }
-      default:
-      {
-        fprintf(stderr, "\nIn create_node(): invalid math operation\n");
-        free(ptr);
-        ptr = 0;
-
-        return 0;
-      }
-    }
-
-    switch (f) /* f is format argument */
-    {
-      case MC_FORMAT_ANS_LAST:  /* e.g. num1 + num2 = ? */
-      {
-        snprintf(ptr->card.formula_string, MC_FORMULA_LEN,"%d %c %d = ?",
-                 ptr->card.num1,
-                 oper_char,
-                 ptr->card.num2);
-        snprintf(ptr->card.answer_string, MC_ANSWER_LEN, "%d",ptr->card.num3);
-       break;
-      }
-      case MC_FORMAT_ANS_MIDDLE:  /* e.g. num1 + ? = num3 */
-      {
-        snprintf(ptr->card.formula_string, MC_FORMULA_LEN,"%d %c ? = %d",
-                 ptr->card.num1,
-	         oper_char,
-	         ptr->card.num3);
-        snprintf(ptr->card.answer_string, MC_ANSWER_LEN, "%d",ptr->card.num2);
-        break;
-      }
-      case MC_FORMAT_ANS_FIRST:  /* e.g. ? + num2 = num3 */
-      {
-        snprintf(ptr->card.formula_string, MC_FORMULA_LEN,"? %c %d = %d",
-                 oper_char,
-                 ptr->card.num2,
-                 ptr->card.num3);
-        snprintf(ptr->card.answer_string, MC_ANSWER_LEN, "%d",ptr->card.num1);
-        break;
-      }
-      default:  /* should not get to here if MathCards behaves correctly */
-      {
-        fprintf(stderr, "\ncreate_node() - invalid question format\n");
-        free(ptr);
-        ptr = 0;
-
- 
-        return 0;
-      }
-    }
-  }
-
-  /* ptr should now point to a properly constructed node: */
-  return ptr;
-}
-
-
-#ifdef MC_DEBUG
-/* 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)
-{
-  return create_node(other->card.num1,
-                     other->card.num2,
-                     other->card.operation,
-                     other->card.num3,
-                     other->card.format);
-}
-#endif
-
-MC_MathQuestion* create_node_from_card(MC_FlashCard* flashcard)
-{
-  return create_node(flashcard->num1,
-                     flashcard->num2,
-                     flashcard->operation,
-                     flashcard->num3,
-                     flashcard->format);
-}
-
-#ifdef MC_DEBUG
-/* FIXME take care of strings */
-
-MC_FlashCard* create_card_from_node(MC_MathQuestion* node)
-{
-  MC_FlashCard* fc;
-  if (!node)
-    return 0;
-  fc = malloc(sizeof(MC_FlashCard));
-  fc->num1 = node->card.num1;
-  fc->num2 = node->card.num2;
-  fc->num3 = node->card.num3;
-  fc->operation = node->card.operation;
-  fc->format = node->card.format;
-  return fc;
-}
-#endif
-
-
-/* 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)
+    }
+  }
+
+  else
+  {
+
+
+    for (i = 0; i < length; ++i)
+    {
+      tnode = malloc(sizeof(MC_MathQuestion) );
+      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;
+  }
+  printf("Sorry, don't recognize option '%s'\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 option index: %d\n", index);
+    return;
+  }
+  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 i;
+  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
+  //FIXME ensure div meets minimum divisor if possible (it might not be)
+  return div;
+}
+
+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);
+
+  if (!MC_GetOpt(pt + TYPING_PRACTICE_ALLOWED) )
+    return list;
+
+  if (pt == MC_PT_TYPING)
   {
-    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.num1 = original->card.num1;
-  copy->card.num2 = original->card.num2;
-  copy->card.num3 = original->card.num3;
-  copy->card.operation = original->card.operation;
-  copy->card.format = original->card.format;
-  strncpy(copy->card.formula_string,
-          original->card.formula_string,
-          MC_FORMULA_LEN);
-  strncpy(copy->card.answer_string,
-          original->card.answer_string,
-          MC_ANSWER_LEN);
-  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 (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)
+    mcdprintf("Adding typing...\n");
+    for (i = MC_GetOpt(MIN_TYPING_NUM); i < MC_GetOpt(MAX_TYPING_NUM); ++i)
     {
-      print_node(fp, ptr);
-      ptr = ptr->next;
-    }
+      mcdprintf("(%d)\n", i);
+      tnode = allocate_node();
+      snprintf(tnode->card.formula_string, max_formula_size, "%d", i);
+      snprintf(tnode->card.answer_string, max_formula_size, "%d", i);
+      list = insert_node(list, end_of_list, tnode);
+      end_of_list = tnode;
+    }
+  }
+  else if (MC_PT_ARITHMETIC)
+  {
+    mcdprintf("Adding arithmetic...\n");
+    for (k = MC_OPER_ADD; k < MC_NUM_OPERS; ++k)
+    {
+      if (!MC_GetOpt(k + ADDITION_ALLOWED) )
+        continue;
+      mcdprintf("\n*%d*\n", k);
+      for (i = MC_GetOpt(MIN_AUGEND + 4 * k); i < MC_GetOpt(MAX_AUGEND + 4 * k); ++i)
+      {
+        mcdprintf("\n%d:\n", i);
+        for (j = MC_GetOpt(MIN_ADDEND + 4 * k); j < MC_GetOpt(MAX_ADDEND + 4 * k); ++j)
+        {
+          //mcdprintf("%d,", j);
+          if (k == MC_OPER_ADD)
+            ans = i + j;
+          else if (k == MC_OPER_SUB)
+          {
+            ans = i - j;
+            if (ans < 0 && !MC_GetOpt(ALLOW_NEGATIVES) )
+              continue;
+          }
+          else if (k == MC_OPER_MULT)
+            ans = i * j;
+          else if (k == MC_OPER_DIV)
+          {
+            mcdprintf("%d %d %d\n", ans, i, j);
+            tmp = i;
+            i *= j;
+            ans = j;
+            j = tmp;
+            mcdprintf("%d %d %d\n", ans, i, j);
+          }
+
+          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
+          if (MC_GetOpt(FORMAT_ANSWER_LAST) && MC_GetOpt(FORMAT_ADD_ANSWER_LAST + k * 3) )
+          {
+            tnode = allocate_node();
+            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);
+            list = insert_node(list, end_of_list, tnode);
+            end_of_list = tnode;
+          }
+          if (MC_GetOpt(FORMAT_ANSWER_FIRST) && MC_GetOpt(FORMAT_ADD_ANSWER_FIRST + k * 3) )
+          {
+            tnode = allocate_node();
+            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);
+            list = insert_node(list, end_of_list, tnode);
+            end_of_list = tnode;
+          }
+          if (MC_GetOpt(FORMAT_ANSWER_MIDDLE) && MC_GetOpt(FORMAT_ADD_ANSWER_MIDDLE + k * 3) )
+          {
+            tnode = allocate_node();
+            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);
+            list = insert_node(list, end_of_list, tnode);
+            end_of_list = tnode;
+          }
+          //reset j to keep loop from exploding
+          if (k == MC_OPER_DIV)
+            mcdprintf("resetting to %d %d\n", j = ans, i = tmp);
+        }
+      }
+    }
+  }
+  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();
+        snprintf(tnode->card.formula_string, max_formula_size, "%d ? %d", i,j);
+        list = insert_node(list, end_of_list, tnode);
+        end_of_list = tnode;
+      }
+    }
   }
-}
+  mcdprintf("Exiting add_all_valid()\n");
+  return list;
+}
 
-void print_vect_list(FILE* fp, MC_MathQuestion** vect, int length)
+MC_MathQuestion* find_node(const MC_MathQuestion* list, int num)
 {
-  if (!vect)
-  {
-    fprintf(fp, "\nprint_vect_list(): list empty or pointer invalid\n");
-    return;
-  }
-
-  {
-    int i = 0;
-    for(i = 0; i < length; i++) 
-      print_node(fp, vect[i]);
-  }
-  fprintf(stderr, "Leaving print_vect_list()\n");
-}
-
-/* Don't need this much now that formula_string part of card struct:  */
-void print_node(FILE* fp, MC_MathQuestion* ptr)
-{
-  if (!ptr || !fp)
-  {
-    return;
-  }
-
-  fprintf(fp, "%s\n", ptr->card.formula_string);
-  /*fprintf(fp, "randomizer = %d\n", ptr->randomizer);*/
-}  
-
-
-#ifdef MC_DEBUG
-void print_card(MC_FlashCard card)
-{
-  printf("\nprint_card():");
-  printf("\n%d,  %d \tOper %d \tAnswer %d \t Format %d\n",
-           card.num1,
-           card.num2,
-           card.operation,
-           card.num3,
-           card.format);
-}
-#endif
-
-
-#ifdef MC_DEBUG
-/* 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);
-}
-#endif
-
-int list_length(MC_MathQuestion* list)
-{
-  int length = 0;
-  while (list)
-  {
-    length++;
+  while (--num > 0 && list)
     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)
+void reformat_arithmetic(MC_FlashCard* card, MC_Format f)
 {
-  if (!first || !other)
-    return 0;
-  if (first->card.num1 == other->card.num1
-   && first->card.num2 == other->card.num2
-   && first->card.operation == other->card.operation
-   && first->card.format == other->card.format)
-    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;
+  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
   
-  if (i < 0 
-   && math_opts
-   && !math_opts->allow_negatives)
   {
-    i = 0;
-  }
+    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);
 
-  return i;
+    //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, nans);
+    card->answer = atoi(card->answer_string);
+  }
 }
-
-int abs_value(int i)
-{
-  if (i > 0)
-    return i;
-  else
-    return -i;
-}
-
-
-/* Returns true at probability set by math_opts->fraction_to_keep */
-int randomly_keep(void)
-{
-  int random;
-
-  if (!math_opts)
-    return 0;
-
-  /* Skip random number generation if keeping all (default) */
-  if (1 == math_opts->fraction_to_keep)
-    return 1;
-
-  random = rand() % 1000;
-
-  if (random < (math_opts->fraction_to_keep * 1000))
-    return 1;
-  else
-    return 0;
-}
-
-/* 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;
-}

Modified: tuxmath/trunk/src/mathcards.h
===================================================================
--- tuxmath/trunk/src/mathcards.h	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/mathcards.h	2008-08-06 02:55:05 UTC (rev 589)
@@ -1,166 +1,154 @@
 /*
 
-	mathcards.h
-	
-	Description: contains headers for a flashcard-type math game. 
+        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)
 
+        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
-#define MC_FORMULA_LEN 16
-#define MC_ANSWER_LEN 5
+#define MC_DEBUG
+#ifdef MC_DEBUG
+#define mcdprintf(...) printf(__VA_ARGS__)
+#else
+#define mcdprintf(...) 0
+#endif
 
+#define MC_USE_NEWARC
 
+typedef enum _MC_ProblemType {
+  MC_PT_TYPING,
+  MC_PT_ARITHMETIC,
+  MC_PT_COMPARISON,
+  MC_NUM_PTYPES
+} MC_ProblemType;
 
-/* type of math operation used in a given question */
-enum {
+/* 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_OPER_TYPING_PRACTICE,
   MC_NUM_OPERS
-};
+} MC_Operation;
 
 /* math question formats: */
-enum {
+typedef enum _MC_Format {
   MC_FORMAT_ANS_LAST,     /* a + b = ? */
   MC_FORMAT_ANS_FIRST,    /* ? + b = c */
-  MC_FORMAT_ANS_MIDDLE    /* a + ? = c */
-};
+  MC_FORMAT_ANS_MIDDLE,    /* a + ? = c */
+  MC_NUM_FORMATS
+} MC_Format;
 
-/* This struct contains all options that determine what */
-/* math questions are asked during a game */
-typedef struct MC_Options {
-  /* general math options */
-  int play_through_list;
-  int repeat_wrongs;
-  int copies_repeated_wrongs;
-  int allow_negatives;
-  int max_answer;
-  int max_questions;
-  int question_copies;         /* how many times each question is put in list */
-  int randomize;               /* whether to shuffle cards */
-  float fraction_to_keep;      /* Can use to have list contain a random subset */
-                               /* of the questions meeting selection criteria. */
 
-  /*  math question formats:   NOTE - list can contain more than one format*/
-  /* operation-specific question formats:  */
-  int format_add_answer_last;      /* a + b = ?    */ 
-  int format_add_answer_first;     /* ? + b = c    */
-  int format_add_answer_middle;    /* a + ? = c    */
-  int format_sub_answer_last;      /* a - b = ?    */ 
-  int format_sub_answer_first;     /* ? - b = c    */
-  int format_sub_answer_middle;    /* a - ? = c    */
-  int format_mult_answer_last;     /* a * b = ?    */ 
-  int format_mult_answer_first;    /* ? * b = c    */
-  int format_mult_answer_middle;   /* a * ? = c    */
-  int format_div_answer_last;      /* a / b = ?    */ 
-  int format_div_answer_first;     /* ? / b = c    */
-  int format_div_answer_middle;    /* a / ? = c    */
+/*
+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          ,
 
-  /* addition options */
-  int addition_allowed;
-  int min_augend;              /* the "augend" is the first addend i.e. "a" in "a + b = c" */
-  int max_augend;
-  int min_addend;              /* options for the other addend */
-  int max_addend;
-  /* subtraction options */
-  int subtraction_allowed;
-  int min_minuend;             /* minuend - subtrahend = difference */
-  int max_minuend;
-  int min_subtrahend;
-  int max_subtrahend;
-  /* multiplication options */
-  int multiplication_allowed;
-  int min_multiplier;          /* multiplier * multiplicand = product */
-  int max_multiplier;
-  int min_multiplicand;
-  int max_multiplicand;
-  /* division options */
-  int division_allowed;
-  int min_divisor;             /* dividend/divisor = quotient */
-  int max_divisor;
-  int min_quotient;
-  int max_quotient;
-  /* typing practice options */
-  int typing_practice_allowed;
-  int min_typing_num;
-  int max_typing_num;
+  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    */
 
-} MC_Options;
+  ADDITION_ALLOWED          ,
+  SUBTRACTION_ALLOWED       ,
+  MULTIPLICATION_ALLOWED    ,
+  DIVISION_ALLOWED          ,
+  TYPING_PRACTICE_ALLOWED   ,
+  ARITHMETIC_ALLOWED        ,
+  COMPARISON_ALLOWED        ,
 
-/* default values for math_options */
-#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    */
+  MIN_AUGEND                , /* augend + addend = sum */
+  MAX_AUGEND                ,
+  MIN_ADDEND                ,
+  MAX_ADDEND                ,
 
-#define DEFAULT_PLAY_THROUGH_LIST 1       /* play until all questions in list answered */                                                                               /* correctly */
-#define DEFAULT_REPEAT_WRONGS   1         /* reuse incorrectly answered questions or not */
-#define DEFAULT_COPIES_REPEATED_WRONGS 1  /* how many copies of an incorrectly answered */                                                                              /* question to re-insert*/
-#define DEFAULT_ALLOW_NEGATIVES 0
-#define DEFAULT_MAX_ANSWER 999
-#define DEFAULT_MAX_QUESTIONS 5000
-#define DEFAULT_QUESTION_COPIES 1         /* how many times each question is put in list */
-#define DEFAULT_RANDOMIZE 1               /* whether to shuffle cards */
-#define DEFAULT_FRACTION_TO_KEEP 1
+  MIN_MINUEND               , /* minuend - subtrahend = difference */
+  MAX_MINUEND               ,
+  MIN_SUBTRAHEND            ,
+  MAX_SUBTRAHEND            ,
 
-#define DEFAULT_FORMAT_ANSWER_LAST 1      /* question format is: a + b = ? */
-#define DEFAULT_FORMAT_ANSWER_FIRST 0     /* question format is: ? + b = c */
-#define DEFAULT_FORMAT_ANSWER_MIDDLE 0    /* question format is: a + ? = c */
-#define DEFAULT_FORMAT_ADD_ANSWER_LAST 1    /* addition-specific default formats: */
-#define DEFAULT_FORMAT_ADD_ANSWER_FIRST 0     
-#define DEFAULT_FORMAT_ADD_ANSWER_MIDDLE 0 
-#define DEFAULT_FORMAT_SUB_ANSWER_LAST 1    /* subtraction-specific default formats: */
-#define DEFAULT_FORMAT_SUB_ANSWER_FIRST 0     
-#define DEFAULT_FORMAT_SUB_ANSWER_MIDDLE 0 
-#define DEFAULT_FORMAT_MULT_ANSWER_LAST 1    /* multiplication-specific default formats: */
-#define DEFAULT_FORMAT_MULT_ANSWER_FIRST 0     
-#define DEFAULT_FORMAT_MULT_ANSWER_MIDDLE 0 
-#define DEFAULT_FORMAT_DIV_ANSWER_LAST 1     /* division-specific default formats: */
-#define DEFAULT_FORMAT_DIV_ANSWER_FIRST 0     
-#define DEFAULT_FORMAT_DIV_ANSWER_MIDDLE 0 
+  MIN_MULTIPLIER            , /* multiplier * multiplicand = product */
+  MAX_MULTIPLIER            ,
+  MIN_MULTIPLICAND          ,
+  MAX_MULTIPLICAND          ,
 
-#define DEFAULT_ADDITION_ALLOWED 1
-#define DEFAULT_SUBTRACTION_ALLOWED 1
-#define DEFAULT_MULTIPLICATION_ALLOWED 1
-#define DEFAULT_DIVISION_ALLOWED 1
-#define DEFAULT_TYPING_PRACTICE_ALLOWED 0
+  MIN_DIVISOR               , /* dividend/divisor = quotient */
+  MAX_DIVISOR               , /* note - generate_list() will prevent */
+  MIN_QUOTIENT              , /* questions with division by zero.    */
+  MAX_QUOTIENT              ,
 
-#define DEFAULT_MIN_AUGEND 0              /* augend + addend = sum */
-#define DEFAULT_MAX_AUGEND 12
-#define DEFAULT_MIN_ADDEND 0
-#define DEFAULT_MAX_ADDEND 12
+  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           ,
 
-#define DEFAULT_MIN_MINUEND 0             /* minuend - subtrahend = difference */
-#define DEFAULT_MAX_MINUEND 12
-#define DEFAULT_MIN_SUBTRAHEND 0
-#define DEFAULT_MAX_SUBTRAHEND 12
+  RANDOMIZE                 , /* whether to shuffle cards */
+
+  COMPREHENSIVE             , /* whether to generate all questions 'in order' */
+  AVG_LIST_LENGTH           ,
+  VARY_LIST_LENGTH          ,
 
-#define DEFAULT_MIN_MULTIPLIER 0          /* multiplier * multiplicand = product */
-#define DEFAULT_MAX_MULTIPLIER 12
-#define DEFAULT_MIN_MULTIPLICAND 0
-#define DEFAULT_MAX_MULTIPLICAND 12
+  NOPTS
+};
 
-#define DEFAULT_MIN_DIVISOR 0              /* dividend/divisor = quotient */
-#define DEFAULT_MAX_DIVISOR 12             /* note - generate_list() will prevent */
-#define DEFAULT_MIN_QUOTIENT 0             /* questions with division by zero.    */
-#define DEFAULT_MAX_QUOTIENT 12
+extern const char* const MC_OPTION_TEXT[];
+extern const int MC_DEFAULTS[];
+extern const char operchars[MC_NUM_OPERS];
 
-#define DEFAULT_MIN_TYPING_NUM 0           /* range for "typing tutor" mode, for kids */
-#define DEFAULT_MAX_TYPING_NUM 12          /* just learning to use keyboard.          */
+/* 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];
+  //float fraction_to_keep; //being a float, we can't keep this in the same array
+} MC_Options;             //it'll stay a special case, unless more float options
+
+#ifndef MC_USE_NEWARC
 /* struct for individual "flashcard" */
 typedef struct MC_FlashCard {
   int num1;
@@ -171,6 +159,15 @@
   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 {
@@ -180,16 +177,16 @@
   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, */  
+/*  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.                              */
@@ -274,144 +271,23 @@
 int MC_NumNotAnsweredCorrectly(void);
 float MC_MedianTimePerQuestion(void);
 
-/* Simple "Set/Get" type functions for option parameters: */
-
-/* Simple functions to set option parameters: */
-
-/* Set general math options:   */
-void MC_SetPlayThroughList(int opt);
-void MC_SetRepeatWrongs(int opt);
-void MC_SetQuestionCopies(int copies);         /* how many times each question is put in list */
-void MC_SetCopiesRepeatedWrongs(int copies);
-void MC_SetMaxAnswer(int max);
-void MC_SetMaxQuestions(int max); 
-void MC_SetAllowNegatives(int opt);
-void MC_SetRandomize(int opt);           
-void MC_SetFractionToKeep(float fract);
-
-/* Set question formats for all operations:     */
-/* NOTE - list can contain more than one format */
-/* Use these to set format the same for all four operations: */
-void MC_SetFormatAnswerLast(int opt);      /* a + b = ?, a - b = ?, a * b = ?, a / b = ?  */ 
-void MC_SetFormatAnswerFirst(int opt);     /* ? + b = c, etc   */
-void MC_SetFormatAnswerMiddle(int opt);    /* a + ? = c, etc   */
-/* Uset these to set operation-specific question formats:                  */
-void MC_SetFormatAddAnswerLast(int opt);      /* a + b = ? */
-void MC_SetFormatAddAnswerFirst(int opt);     /* ? + b = c */
-void MC_SetFormatAddAnswerMiddle(int opt);    /* a + ? = c */
-void MC_SetFormatSubAnswerLast(int opt);      /* a - b = ? */
-void MC_SetFormatSubAnswerFirst(int opt);     /* ? - b = c */
-void MC_SetFormatSubAnswerMiddle(int opt);    /* a - ? = c */
-void MC_SetFormatMultAnswerLast(int opt);     /* a * b = ? */
-void MC_SetFormatMultAnswerFirst(int opt);    /* ? * b = c */
-void MC_SetFormatMultAnswerMiddle(int opt);   /* a * ? = c */
-void MC_SetFormatDivAnswerLast(int opt);      /* a / b = ? */
-void MC_SetFormatDivAnswerFirst(int opt);     /* ? / b = c */
-void MC_SetFormatDivAnswerMiddle(int opt);    /* a / ? = c */ 
-
-/* Set the allowed math operations: */
-void MC_SetAddAllowed(int opt);
-void MC_SetSubAllowed(int opt);
-void MC_SetMultAllowed(int opt);
-void MC_SetDivAllowed(int opt);
-void MC_SetTypingAllowed(int opt);
-
-/* Set min and max for addition: */
-void MC_SetAddMin(int opt);                    /* augend + addend = sum */
-void MC_SetAddMinAugend(int opt);              /* the "augend" is the first addend i.e. "a" in "a + b = c" */
-void MC_SetAddMinAddend(int opt);              /* options for the other addend */
-void MC_SetAddMax(int opt);
-void MC_SetAddMaxAugend(int opt);
-void MC_SetAddMaxAddend(int opt);
-
-/* Set min and max for subtraction: */
-void MC_SetSubMin(int opt);
-void MC_SetSubMinMinuend(int opt);             /* minuend - subtrahend = difference */
-void MC_SetSubMinSubtrahend(int opt);
-void MC_SetSubMax(int opt);
-void MC_SetSubMaxMinuend(int opt);
-void MC_SetSubMaxSubtrahend(int opt);
-
-/* Set min and max for multiplication: */
-void MC_SetMultMin(int opt);
-void MC_SetMultMinMultiplier(int opt);         /* multiplier * multiplicand = product */
-void MC_SetMultMinMultiplicand(int opt);
-void MC_SetMultMax(int opt);
-void MC_SetMultMaxMultiplier(int opt);
-void MC_SetMultMaxMultiplicand(int opt);
-
-/* Set min and max for division: */
-void MC_SetDivMin(int opt);
-void MC_SetDivMinDivisor(int opt);            /* dividend/divisor = quotient */
-void MC_SetDivMinQuotient(int opt);
-void MC_SetDivMax(int opt);
-void MC_SetDivMaxDivisor(int opt);
-void MC_SetDivMaxQuotient(int opt);
-
-/* Set min and max for typing practice: */
-void MC_SetTypeMin(int opt);
-void MC_SetTypeMax(int opt);
-
-/* "Get" type functions to query option parameters: */
-
-/* Query general math options: */
-int MC_PlayThroughList(void);
-int MC_RepeatWrongs(void);
-int MC_CopiesRepeatedWrongs(void);
-int MC_MaxAnswer(void);
-int MC_MaxQuestions(void);
-int MC_AllowNegatives(void);
-int MC_QuestionCopies(void);         /* how many times each question is put in list */
-int MC_Randomize(void);         
-float MC_FractionToKeep(void);
-
-int MC_FormatAddAnswerLast(void);      /* a + b = ?   */ 
-int MC_FormatAddAnswerFirst(void);     /* ? + b = c   */
-int MC_FormatAddAnswerMiddle(void);    /* a + ? = c   */
-int MC_FormatSubAnswerLast(void);      /* a - b = ?   */ 
-int MC_FormatSubAnswerFirst(void);     /* ? - b = c   */
-int MC_FormatSubAnswerMiddle(void);    /* a - ? = c   */
-int MC_FormatMultAnswerLast(void);      /* a * b = ?   */ 
-int MC_FormatMultAnswerFirst(void);     /* ? * b = c   */
-int MC_FormatMultAnswerMiddle(void);    /* a * ? = c   */
-int MC_FormatDivAnswerLast(void);      /* a / b = ?   */ 
-int MC_FormatDivAnswerFirst(void);     /* ? / b = c   */
-int MC_FormatDivAnswerMiddle(void);    /* a / ? = c   */
-
-
-/* Query the allowed math operations: */
-int MC_AddAllowed(void);
-int MC_SubAllowed(void);
-int MC_MultAllowed(void);
-int MC_DivAllowed(void);
-int MC_TypingAllowed(void);
-
-/* Query min and max for addition: */
-int MC_AddMinAugend(void);              /* the "augend" is the first addend i.e. "a" in "a + b = c" */
-int MC_AddMinAddend(void);              /* options for the other addend */
-int MC_AddMaxAugend(void);
-int MC_AddMaxAddend(void);
-
-/* Query min and max for subtraction: */
-int MC_SubMinMinuend(void);             /* minuend - subtrahend = difference */
-int MC_SubMinSubtrahend(void);
-int MC_SubMaxMinuend(void);
-int MC_SubMaxSubtrahend(void);
-
-/* Query min and max for multiplication: */
-int MC_MultMinMultiplier(void);         /* multiplier * multiplicand = product */
-int MC_MultMinMultiplicand(void);
-int MC_MultMaxMultiplier(void);
-int MC_MultMaxMultiplicand(void);
-
-/* Query min and max for division: */
-int MC_DivMinDivisor(void);            /* dividend/divisor = quotient */
-int MC_DivMinQuotient(void);
-int MC_DivMaxDivisor(void);
-int MC_DivMaxQuotient(void);
-
-/* Query min and max for typing practice: */
-int MC_TypeMin(void);
-int MC_TypeMax(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);
+void MC_SetFractionToKeep(float val);
+float MC_GetFractionToKeep(void);
+int MC_VerifyOptionListSane(void);
+int MC_MaxFormulaSize(void);
+int MC_MaxAnswerSize(void);
+MC_FlashCard MC_AllocateFlashcard();
+void MC_FreeFlashcard(MC_FlashCard* fc);
+void MC_ResetFlashCard(MC_FlashCard* fc);
+int MC_FlashCardGood(const MC_FlashCard* fc); //verifies a flashcard is valid
+void reformat_arithmetic(MC_FlashCard* card, MC_Format f);
 #endif

Modified: tuxmath/trunk/src/options.c
===================================================================
--- tuxmath/trunk/src/options.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/options.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -981,42 +981,42 @@
   fprintf(fp, "use_feedback = %d\n", game_options->use_feedback);
 
 
-   if(verbose)
-   {
-     fprintf (fp, "\n# (Feedback) Set the desired danger level.\n"
-             "# 0 = too safe, comets typically exploded right at the very top\n"
-             "# 1 = too dangerous, comets typically exploded at the moment they hit cities\n"
-             "# Set it somewhere between these extremes. As a guideline, early\n"
-             "# elementary kids might feel comfortable around 0.2-0.3, older kids\n"
-             "# at around 0.4-0.6. Default 0.35.\n");
-   }
-   fprintf(fp, "danger_level = %f\n", game_options->danger_level);
+  if(verbose)
+  {
+    fprintf (fp, "\n# (Feedback) Set the desired danger level.\n"
+            "# 0 = too safe, comets typically exploded right at the very top\n"
+            "# 1 = too dangerous, comets typically exploded at the moment they hit cities\n"
+            "# Set it somewhere between these extremes. As a guideline, early\n"
+            "# elementary kids might feel comfortable around 0.2-0.3, older kids\n"
+            "# at around 0.4-0.6. Default 0.35.\n");
+  }
+  fprintf(fp, "danger_level = %f\n", game_options->danger_level);
 
-   if(verbose)
-   {
-     fprintf (fp, "\n# (Feedback) Set danger level speedup.\n"
-                  "# The margin of safety will decrease by this factor each wave.\n"
-                  "# Default 1.1. Note 1 = no increase in danger level.\n");
-   }
-   fprintf(fp, "danger_level_speedup = %f\n", game_options->danger_level_speedup);
+  if(verbose)
+  {
+    fprintf (fp, "\n# (Feedback) Set danger level speedup.\n"
+                 "# The margin of safety will decrease by this factor each wave.\n"
+                 "# Default 1.1. Note 1 = no increase in danger level.\n");
+  }
+  fprintf(fp, "danger_level_speedup = %f\n", game_options->danger_level_speedup);
 
-   if(verbose)
-   {
-     fprintf (fp, "\n# (Feedback) Set the maximum danger level.\n"
-                  "# Default 0.9.\n");
-   }
-   fprintf(fp, "danger_level_max = %f\n", game_options->danger_level_max);
+  if(verbose)
+  {
+    fprintf (fp, "\n# (Feedback) Set the maximum danger level.\n"
+                 "# Default 0.9.\n");
+  }
+  fprintf(fp, "danger_level_max = %f\n", game_options->danger_level_max);
 
-   if (verbose)
-   { 
-     fprintf (fp, "\n# (Feedback) Set the handicap for hitting cities.\n"
-                  "# When bigger than 0, this causes the game to slow down\n"
-                  "# by an extra amount after a wave in which one or more\n"
-                  "# cities get hit. Note that this is similar to slow_after_wrong,\n"
-                  "# but allows for more gradual changes.\n"
-                  "# Default 0 (no extra handicap).\n");
-   }
-   fprintf(fp, "city_explode_handicap = %f\n", game_options->city_expl_handicap);
+  if (verbose)
+  { 
+    fprintf (fp, "\n# (Feedback) Set the handicap for hitting cities.\n"
+                 "# When bigger than 0, this causes the game to slow down\n"
+                 "# by an extra amount after a wave in which one or more\n"
+                 "# cities get hit. Note that this is similar to slow_after_wrong,\n"
+                 "# but allows for more gradual changes.\n"
+                 "# Default 0 (no extra handicap).\n");
+  }
+  fprintf(fp, "city_explode_handicap = %f\n", game_options->city_expl_handicap);
 
 /*
   fprintf(fp, "num_cities = %d\n", game_options->num_cities);

Modified: tuxmath/trunk/src/pixels.c
===================================================================
--- tuxmath/trunk/src/pixels.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/pixels.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -42,9 +42,9 @@
        && likely((unsigned) y < (unsigned) surface->h)))
   {
     // Set a pointer to the exact location in memory of the pixel
-    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
-		   (y * surface->pitch) +	/* Go down Y lines */
-		   x);		/* Go in X pixels */
+    p = (Uint8 *) (((Uint8 *) surface->pixels) +        /* Start: beginning of RAM */
+                   (y * surface->pitch) +        /* Go down Y lines */
+                   x);                /* Go in X pixels */
 
 
     /* Set the (correctly-sized) piece of data in the surface's RAM
@@ -65,9 +65,9 @@
        && likely((unsigned) y < (unsigned) surface->h)))
   {
     // Set a pointer to the exact location in memory of the pixel
-    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
-		   (y * surface->pitch) +	/* Go down Y lines */
-		   (x * 2));	/* Go in X pixels */
+    p = (Uint8 *) (((Uint8 *) surface->pixels) +        /* Start: beginning of RAM */
+                   (y * surface->pitch) +        /* Go down Y lines */
+                   (x * 2));        /* Go in X pixels */
 
 
     /* Set the (correctly-sized) piece of data in the surface's RAM
@@ -88,9 +88,9 @@
        && likely((unsigned) y < (unsigned) surface->h)))
   {
     // Set a pointer to the exact location in memory of the pixel
-    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
-		   (y * surface->pitch) +	/* Go down Y lines */
-		   (x * 3));	/* Go in X pixels */
+    p = (Uint8 *) (((Uint8 *) surface->pixels) +        /* Start: beginning of RAM */
+                   (y * surface->pitch) +        /* Go down Y lines */
+                   (x * 3));        /* Go in X pixels */
 
 
     /* Set the (correctly-sized) piece of data in the surface's RAM
@@ -123,15 +123,15 @@
        && likely((unsigned) y < (unsigned) surface->h)))
   {
     // Set a pointer to the exact location in memory of the pixel
-    p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start: beginning of RAM */
-		   (y * surface->pitch) +	/* Go down Y lines */
-		   (x * 4));	/* Go in X pixels */
+    p = (Uint8 *) (((Uint8 *) surface->pixels) +        /* Start: beginning of RAM */
+                   (y * surface->pitch) +        /* Go down Y lines */
+                   (x * 4));        /* Go in X pixels */
 
 
     /* Set the (correctly-sized) piece of data in the surface's RAM
      *          to the pixel value sent in: */
 
-    *(Uint32 *) p = pixel;	// 32-bit display
+    *(Uint32 *) p = pixel;        // 32-bit display
   }
 }
 
@@ -149,9 +149,9 @@
   /* Set a pointer to the exact location in memory of the pixel
      in question: */
 
-  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
-		 (y * surface->pitch) +	/* Go down Y lines */
-		 x);		/* Go in X pixels */
+  p = (Uint8 *) (((Uint8 *) surface->pixels) +        /* Start at top of RAM */
+                 (y * surface->pitch) +        /* Go down Y lines */
+                 x);                /* Go in X pixels */
 
 
   /* Return the correctly-sized piece of data containing the
@@ -175,9 +175,9 @@
   /* Set a pointer to the exact location in memory of the pixel
      in question: */
 
-  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
-		 (y * surface->pitch) +	/* Go down Y lines */
-		 (x * 2));	/* Go in X pixels */
+  p = (Uint8 *) (((Uint8 *) surface->pixels) +        /* Start at top of RAM */
+                 (y * surface->pitch) +        /* Go down Y lines */
+                 (x * 2));        /* Go in X pixels */
 
 
   /* Return the correctly-sized piece of data containing the
@@ -202,9 +202,9 @@
   /* Set a pointer to the exact location in memory of the pixel
      in question: */
 
-  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
-		 (y * surface->pitch) +	/* Go down Y lines */
-		 (x * 3));	/* Go in X pixels */
+  p = (Uint8 *) (((Uint8 *) surface->pixels) +        /* Start at top of RAM */
+                 (y * surface->pitch) +        /* Go down Y lines */
+                 (x * 3));        /* Go in X pixels */
 
 
   /* Return the correctly-sized piece of data containing the
@@ -235,16 +235,16 @@
   /* Set a pointer to the exact location in memory of the pixel
      in question: */
 
-  p = (Uint8 *) (((Uint8 *) surface->pixels) +	/* Start at top of RAM */
-		 (y * surface->pitch) +	/* Go down Y lines */
-		 (x * 4));	/* Go in X pixels */
+  p = (Uint8 *) (((Uint8 *) surface->pixels) +        /* Start at top of RAM */
+                 (y * surface->pitch) +        /* Go down Y lines */
+                 (x * 4));        /* Go in X pixels */
 
 
   /* Return the correctly-sized piece of data containing the
    * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
    * RGB value) */
 
-  return *(Uint32 *) p;		// 32-bit display
+  return *(Uint32 *) p;                // 32-bit display
 }
 
 void (*putpixels[]) (SDL_Surface *, int, int, Uint32) =

Modified: tuxmath/trunk/src/scandir.c
===================================================================
--- tuxmath/trunk/src/scandir.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/scandir.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -35,8 +35,8 @@
 #undef DIRSIZ
 
 #define DIRSIZ(dp)                                          \
-		((sizeof(struct dirent) - sizeof(dp)->d_name) +     \
-		(((dp)->d_reclen + 1 + 3) &~ 3))
+                ((sizeof(struct dirent) - sizeof(dp)->d_name) +     \
+                (((dp)->d_reclen + 1 + 3) &~ 3))
 
 #if defined(__sun) && defined(__SVR4)
 # define dirfd(d) ((d)->dd_fd)
@@ -51,7 +51,7 @@
  */
 int alphasort(const void *d1, const void *d2)
 {
-	return strcmp((*(struct dirent * const *)d1)->d_name, (*(struct dirent * const *)d2)->d_name);
+  return strcmp((*(struct dirent * const *)d1)->d_name, (*(struct dirent * const *)d2)->d_name);
 }
 
 
@@ -61,78 +61,78 @@
  */
 int scandir(const char *dirname, struct dirent ***namelist, int (*sdfilter)(struct dirent *), int (*dcomp)(const void *, const void *))
 {
-	struct dirent *d, *p, **names;
-	struct stat stb;
-	size_t nitems;
-	size_t arraysz;
-	DIR *dirp;
+  struct dirent *d, *p, **names;
+  struct stat stb;
+  size_t nitems;
+  size_t arraysz;
+  DIR *dirp;
 
-	if ((dirp = opendir(dirname)) == NULL)
-		return(-1);
+  if ((dirp = opendir(dirname)) == NULL)
+    return(-1);
 
-	if (fstat(dirfd(dirp), &stb) < 0)
-		return(-1);
+  if (fstat(dirfd(dirp), &stb) < 0)
+    return(-1);
 
-	/*
-	 * estimate the array size by taking the size of the directory file
-	 * and dividing it by a multiple of the minimum size entry.
-	 */
-	arraysz = (stb.st_size / 24);
+  /*
+   * estimate the array size by taking the size of the directory file
+   * and dividing it by a multiple of the minimum size entry.
+   */
+  arraysz = (stb.st_size / 24);
 
-	names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
-	if (names == NULL)
-		return(-1);
+  names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
+  if (names == NULL)
+    return(-1);
 
-	nitems = 0;
+  nitems = 0;
 
-	while ((d = readdir(dirp)) != NULL)
-	{
+  while ((d = readdir(dirp)) != NULL)
+  {
 
-		if (sdfilter != NULL && !(*sdfilter)(d))
-			continue;       /* just selected names */
+    if (sdfilter != NULL && !(*sdfilter)(d))
+      continue;       /* just selected names */
 
-		/*
-		 * Make a minimum size copy of the data
-		 */
+    /*
+     * Make a minimum size copy of the data
+     */
 
-		p = (struct dirent *)malloc(DIRSIZ(d));
-		if (p == NULL)
-			return(-1);
+    p = (struct dirent *)malloc(DIRSIZ(d));
+    if (p == NULL)
+      return(-1);
 
-		p->d_ino = d->d_ino;
-		p->d_reclen = d->d_reclen;
-		/*p->d_namlen = d->d_namlen;*/
-		memcpy(p->d_name, d->d_name, p->d_reclen + 1);
+    p->d_ino = d->d_ino;
+    p->d_reclen = d->d_reclen;
+    /*p->d_namlen = d->d_namlen;*/
+    memcpy(p->d_name, d->d_name, p->d_reclen + 1);
 
-		/*
-		 * Check to make sure the array has space left and
-		 * realloc the maximum size.
-		 */
+    /*
+     * Check to make sure the array has space left and
+     * realloc the maximum size.
+     */
 
-		if (++nitems >= arraysz)
-		{
+    if (++nitems >= arraysz)
+    {
 
-			if (fstat(dirfd(dirp), &stb) < 0)
-				return(-1);     /* just might have grown */
+      if (fstat(dirfd(dirp), &stb) < 0)
+        return(-1);     /* just might have grown */
 
-			arraysz = stb.st_size / 12;
+      arraysz = stb.st_size / 12;
 
-			names = (struct dirent **)realloc((char *)names, arraysz * sizeof(struct dirent *));
-			if (names == NULL)
-				return(-1);
-		}
+      names = (struct dirent **)realloc((char *)names, arraysz * sizeof(struct dirent *));
+      if (names == NULL)
+        return(-1);
+    }
 
-		names[nitems-1] = p;
-	}
+    names[nitems-1] = p;
+  }
 
-	closedir(dirp);
+  closedir(dirp);
 
-	if (nitems && dcomp != NULL)
-		qsort(names, nitems, sizeof(struct dirent *), dcomp);
+  if (nitems && dcomp != NULL)
+    qsort(names, nitems, sizeof(struct dirent *), dcomp);
 
-	*namelist = names;
+  *namelist = names;
 
-	return nitems;
+  return nitems;
 }
 
 
@@ -140,8 +140,8 @@
 
 
 /*-----------------------------------------------------------------------
- * Here come alphasort and scandir for Windows
- *-----------------------------------------------------------------------*/
+* Here come alphasort and scandir for Windows
+*-----------------------------------------------------------------------*/
 #if defined(WIN32)
 
 #undef DATADIR     // stupid windows.h defines DATADIR, too
@@ -149,111 +149,111 @@
 
 /*-----------------------------------------------------------------------*/
 /**
- * Alphabetic order comparison routine.
- */
+* Alphabetic order comparison routine.
+*/
 int alphasort(const void *d1, const void *d2)
 {
-	return stricmp((*(struct dirent * const *)d1)->d_name, (*(struct dirent * const *)d2)->d_name);
+  return stricmp((*(struct dirent * const *)d1)->d_name, (*(struct dirent * const *)d2)->d_name);
 }
 
 /*-----------------------------------------------------------------------*/
 /**
- * Scan a directory for all its entries
- */
+* Scan a directory for all its entries
+*/
 int scandir(const char *dirname, struct dirent ***namelist, int (*sdfilter)(struct dirent *), int (*dcomp)(const void *, const void *))
 {
-	int len;
-	char *findIn, *d;
-	WIN32_FIND_DATA find;
-	HANDLE h;
-	int nDir = 0, NDir = 0;
-	struct dirent **dir = 0, *selectDir;
-	unsigned long ret;
+  int len;
+  char *findIn, *d;
+  WIN32_FIND_DATA find;
+  HANDLE h;
+  int nDir = 0, NDir = 0;
+  struct dirent **dir = 0, *selectDir;
+  unsigned long ret;
 
-	len    = strlen(dirname);
-	findIn = (char *)malloc(len+5);
-	strcpy(findIn, dirname);
-	printf("scandir : findIn orign=%s\n", findIn);
-	for (d = findIn; *d; d++)
-		if (*d=='/')
-			*d='\\';
-	if ((len==0))
-	{
-		strcpy(findIn, ".\\*");
-	}
-	if ((len==1)&& (d[-1]=='.'))
-	{
-		strcpy(findIn, ".\\*");
-	}
-	if ((len>0) && (d[-1]=='\\'))
-	{
-		*d++ = '*';
-		*d = 0;
-	}
-	if ((len>1) && (d[-1]=='.') && (d[-2]=='\\'))
-	{
-		d[-1] = '*';
-	}
-	if ((len>1) && (d[-2]!='\\') && (d[-1]!='*'))
-	{
-		*d++ = '\\';
-		*d++ = '*';
-		*d = 0;
-	}
+  len    = strlen(dirname);
+  findIn = (char *)malloc(len+5);
+  strcpy(findIn, dirname);
+  printf("scandir : findIn orign=%s\n", findIn);
+  for (d = findIn; *d; d++)
+    if (*d=='/')
+      *d='\\';
+  if ((len==0))
+  {
+    strcpy(findIn, ".\\*");
+  }
+  if ((len==1)&& (d[-1]=='.'))
+  {
+    strcpy(findIn, ".\\*");
+  }
+  if ((len>0) && (d[-1]=='\\'))
+  {
+    *d++ = '*';
+    *d = 0;
+  }
+  if ((len>1) && (d[-1]=='.') && (d[-2]=='\\'))
+  {
+    d[-1] = '*';
+  }
+  if ((len>1) && (d[-2]!='\\') && (d[-1]!='*'))
+  {
+    *d++ = '\\';
+    *d++ = '*';
+    *d = 0;
+  }
 
-	printf("scandir : findIn processed=%s\n", findIn);
-	if ((h=FindFirstFile(findIn, &find))==INVALID_HANDLE_VALUE)
-	{
-		printf("scandir : FindFirstFile error\n");
-		ret = GetLastError();
-		if (ret != ERROR_NO_MORE_FILES)
-		{
-			// TODO: return some error code
-		}
-		*namelist = dir;
-		return nDir;
-	}
-	do
-	{
-		printf("scandir : findFile=%s\n", find.cFileName);
-		selectDir=(struct dirent*)malloc(sizeof(struct dirent)+strlen(find.cFileName));
-		strcpy(selectDir->d_name, find.cFileName);
-		if (!sdfilter || (*sdfilter)(selectDir))
-		{
-			if (nDir==NDir)
-			{
-				struct dirent **tempDir = (struct dirent **)calloc(sizeof(struct dirent*), NDir+33);
-				if (NDir)
-					memcpy(tempDir, dir, sizeof(struct dirent*)*NDir);
-				if (dir)
-					free(dir);
-				dir = tempDir;
-				NDir += 32;
-			}
-			dir[nDir] = selectDir;
-			nDir++;
-			dir[nDir] = 0;
-		}
-		else
-		{
-			free(selectDir);
-		}
-	}
-	while (FindNextFile(h, &find));
-	ret = GetLastError();
-	if (ret != ERROR_NO_MORE_FILES)
-	{
-		// TODO: return some error code
-	}
-	FindClose(h);
+  printf("scandir : findIn processed=%s\n", findIn);
+  if ((h=FindFirstFile(findIn, &find))==INVALID_HANDLE_VALUE)
+  {
+    printf("scandir : FindFirstFile error\n");
+    ret = GetLastError();
+    if (ret != ERROR_NO_MORE_FILES)
+    {
+      // TODO: return some error code
+    }
+    *namelist = dir;
+    return nDir;
+  }
+  do
+  {
+    printf("scandir : findFile=%s\n", find.cFileName);
+    selectDir=(struct dirent*)malloc(sizeof(struct dirent)+strlen(find.cFileName));
+    strcpy(selectDir->d_name, find.cFileName);
+    if (!sdfilter || (*sdfilter)(selectDir))
+    {
+      if (nDir==NDir)
+      {
+        struct dirent **tempDir = (struct dirent **)calloc(sizeof(struct dirent*), NDir+33);
+        if (NDir)
+          memcpy(tempDir, dir, sizeof(struct dirent*)*NDir);
+        if (dir)
+          free(dir);
+        dir = tempDir;
+        NDir += 32;
+      }
+      dir[nDir] = selectDir;
+      nDir++;
+      dir[nDir] = 0;
+    }
+    else
+    {
+      free(selectDir);
+    }
+  }
+  while (FindNextFile(h, &find));
+  ret = GetLastError();
+  if (ret != ERROR_NO_MORE_FILES)
+  {
+    // TODO: return some error code
+  }
+  FindClose(h);
 
-	free (findIn);
+  free (findIn);
 
-	if (dcomp)
-		qsort (dir, nDir, sizeof(*dir),dcomp);
+  if (dcomp)
+    qsort (dir, nDir, sizeof(*dir),dcomp);
 
-	*namelist = dir;
-	return nDir;
+  *namelist = dir;
+  return nDir;
 }
 
 #endif /* WIN32 */

Modified: tuxmath/trunk/src/setup.c
===================================================================
--- tuxmath/trunk/src/setup.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/setup.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -214,7 +214,7 @@
         "If you don't answer a comet's math equation before it hits\n"
         "one of your cities, the city's shields will be destroyed.\n"
         "If that city is hit by another comet, it is destroyed completely.\n"
-	"When you lose all of your cities, the game ends.\n\n");
+        "When you lose all of your cities, the game ends.\n\n");
 
       printf("Note: all settings are now stored in a config file named 'options' in\n"
              "a hidden directory named './tuxmath' within the user's home directory.\n"
@@ -225,12 +225,12 @@
              "to configure the behavior of Tuxmath.\n\n");
 
       printf("Run the game with:\n"
-	"--homedir dirname      - seek for user home director(ies) in the specified\n"
-	"                         location, rather than the user's actual home\n"
-	"                         directory.  You can set up a user directory tree in\n"
-	"                         this location (see README).  This option is\n"
-	"                         especially useful for schools where all students log\n"
-	"                         in with a single user name.\n"
+        "--homedir dirname      - seek for user home director(ies) in the specified\n"
+        "                         location, rather than the user's actual home\n"
+        "                         directory.  You can set up a user directory tree in\n"
+        "                         this location (see README).  This option is\n"
+        "                         especially useful for schools where all students log\n"
+        "                         in with a single user name.\n"
         "--optionfile filename  - read config settings from named file. The locations\n"
         "                         searched for a file with a matching name are the\n"
         "                         current working directory, the absolute path of the\n"
@@ -244,15 +244,15 @@
         "--answersmiddle  - to ask questions in format: num1 + ? = num3\n"
         "                   instead of default format: num1 + num2 = ?\n"
         "--nosound        - to disable sound/music\n"
-	"--nobackground   - to disable background photos (for slower systems)\n"
-	"--fullscreen     - to run in fullscreen, if possible (vs. windowed)\n"
+        "--nobackground   - to disable background photos (for slower systems)\n"
+        "--fullscreen     - to run in fullscreen, if possible (vs. windowed)\n"
         "--windowed       - to run in a window rather than fullscreen\n"
         "--keypad         - to enable the on-sceen numeric keypad\n"
-	"--demo           - to run the program as a cycling demonstration\n"
-	"--speed S        - set initial speed of the game\n"
-	"                   (S may be fractional, default is 1.0)\n"
+        "--demo           - to run the program as a cycling demonstration\n"
+        "--speed S        - set initial speed of the game\n"
+        "                   (S may be fractional, default is 1.0)\n"
         "--allownegatives - to allow answers to be less than zero\n"
-	);
+        );
 
       printf("\n");
 
@@ -260,24 +260,24 @@
       exit(0);
     }
     else if (strcmp(argv[i], "--copyright") == 0 ||
-	     strcmp(argv[i], "-c") == 0)
+             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 Bill Kendrick\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");
+        "\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_on_error();
       exit(0);
     }
     else if (strcmp(argv[i], "--usage") == 0 ||
-	     strcmp(argv[i], "-u") == 0)
+             strcmp(argv[i], "-u") == 0)
     {
       /* Display (happy) usage: */
 
@@ -288,26 +288,26 @@
       // Parse the user choice of a non-default home directory
       if (i >= argc -1)
       {
-	fprintf(stderr, "%s option requires an argument (dirname)\n", argv[i]);
-	usage(1, argv[0]);
+        fprintf(stderr, "%s option requires an argument (dirname)\n", argv[i]);
+        usage(1, argv[0]);
       }
       else // see whether the specified name is a directory
       {
-	if ((dirp = opendir(argv[i+1])) == NULL)
-	  fprintf(stderr,"homedir: %s is not a directory, or it could not be read\n", argv[i+1]);
-	else {
-	  set_user_data_dir(argv[i+1]);  // copy the homedir setting
-	  closedir(dirp);
-	}
-	i++;   // to pass over the next argument, so remaining options parsed
+        if ((dirp = opendir(argv[i+1])) == NULL)
+          fprintf(stderr,"homedir: %s is not a directory, or it could not be read\n", argv[i+1]);
+        else {
+          set_user_data_dir(argv[i+1]);  // copy the homedir setting
+          closedir(dirp);
+        }
+        i++;   // to pass over the next argument, so remaining options parsed
       }
     }
     else if (0 == strcmp(argv[i], "--optionfile"))
     {
       if (i >= argc - 1)
       {
-	fprintf(stderr, "%s option requires an argument (filename)\n", argv[i]);
-	usage(1, argv[0]);
+        fprintf(stderr, "%s option requires an argument (filename)\n", argv[i]);
+        usage(1, argv[0]);
       }
       else /* try to read file named in following arg: */
       {
@@ -319,27 +319,27 @@
       i++; /* so program doesn't barf on next arg (the filename) */
     }
     else if (strcmp(argv[i], "--fullscreen") == 0 ||
-	     strcmp(argv[i], "-f") == 0)
+             strcmp(argv[i], "-f") == 0)
     {
       Opts_SetFullscreen(1);
     }
     else if (strcmp(argv[i], "--windowed") == 0 ||
-	     strcmp(argv[i], "-w") == 0)
+             strcmp(argv[i], "-w") == 0)
     {
       Opts_SetFullscreen(0);
     }
     else if (strcmp(argv[i], "--nosound") == 0 ||
-	     strcmp(argv[i], "-s") == 0 ||
-	     strcmp(argv[i], "--quiet") == 0 ||
-	     strcmp(argv[i], "-q") == 0)
+             strcmp(argv[i], "-s") == 0 ||
+             strcmp(argv[i], "--quiet") == 0 ||
+             strcmp(argv[i], "-q") == 0)
     {
       Opts_SetUseSound(-1);  // prevent options files from overwriting
     }
     else if (strcmp(argv[i], "--version") == 0 ||
-	     strcmp(argv[i], "-v") == 0)
+             strcmp(argv[i], "-v") == 0)
     {
       printf("Tux, of Math Command (\"tuxmath\")\n"
-	     "Version " VERSION "\n");
+             "Version " VERSION "\n");
       cleanup_on_error();
       exit(0);
     }
@@ -349,7 +349,7 @@
       Opts_SetUseBkgd(0);
     }
     else if (strcmp(argv[i], "--demo") == 0 ||
-	     strcmp(argv[i], "-d") == 0)
+             strcmp(argv[i], "-d") == 0)
     {
       Opts_SetDemoMode(1);
     }
@@ -361,32 +361,32 @@
     else if (strcmp(argv[i], "--allownegatives") == 0 ||
              strcmp(argv[i], "-n") == 0)
     {
-      MC_SetAllowNegatives(1);
+      MC_SetOpt(ALLOW_NEGATIVES, 1);
     }
     else if (strcmp(argv[i], "--playthroughlist") == 0 ||
              strcmp(argv[i], "-l") == 0)
     {
-      MC_SetPlayThroughList(1);
+      MC_SetOpt(PLAY_THROUGH_LIST, 1);
     }
     else if (strcmp(argv[i], "--answersfirst") == 0)
     {
-      MC_SetFormatAnswerLast(0);
-      MC_SetFormatAnswerFirst(1);
-      MC_SetFormatAnswerMiddle(0);
+      MC_SetOpt(FORMAT_ANSWER_LAST, 0);
+      MC_SetOpt(FORMAT_ANSWER_FIRST, 1);
+      MC_SetOpt(FORMAT_ANSWER_MIDDLE, 0);
     }
     else if (strcmp(argv[i], "--answersmiddle") == 0)
     {
-      MC_SetFormatAnswerLast(0);
-      MC_SetFormatAnswerFirst(0);
-      MC_SetFormatAnswerMiddle(1);
+      MC_SetOpt(FORMAT_ANSWER_LAST, 0);
+      MC_SetOpt(FORMAT_ANSWER_FIRST, 0);
+      MC_SetOpt(FORMAT_ANSWER_MIDDLE, 1);
     }
     else if (strcmp(argv[i], "--speed") == 0 ||
-	     strcmp(argv[i], "-s") == 0)
+             strcmp(argv[i], "-s") == 0)
     {
       if (i >= argc - 1)
       {
-	fprintf(stderr, "%s option requires an argument\n", argv[i]);
-	usage(1, argv[0]);
+        fprintf(stderr, "%s option requires an argument\n", argv[i]);
+        usage(1, argv[0]);
       }
 
       Opts_SetSpeed(strtod(argv[i + 1], (char **) NULL));
@@ -427,8 +427,8 @@
   {
     fprintf(stderr,
            "\nError: I could not initialize video!\n"
-	   "The Simple DirectMedia error that occured was:\n"
-	   "%s\n\n", SDL_GetError());
+           "The Simple DirectMedia error that occured was:\n"
+           "%s\n\n", SDL_GetError());
     cleanup_on_error();
     exit(1);
   }
@@ -474,11 +474,11 @@
       //if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 2048) < 0)
       if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, AUDIO_S16SYS, 2, 2048) < 0)
       {
-	fprintf(stderr,
-		"\nWarning: I could not set up audio for 44100 Hz "
-		"16-bit stereo.\n"
-		"The Simple DirectMedia error that occured was:\n"
-		"%s\n\n", SDL_GetError());
+        fprintf(stderr,
+                "\nWarning: I could not set up audio for 44100 Hz "
+                "16-bit stereo.\n"
+                "The Simple DirectMedia error that occured was:\n"
+                "%s\n\n", SDL_GetError());
 
       }
     }
@@ -523,8 +523,8 @@
       {
         fprintf(stderr,
               "\nWarning: I could not open the display in fullscreen mode.\n"
-	      "The Simple DirectMedia error that occured was:\n"
-	      "%s\n\n", SDL_GetError());
+              "The Simple DirectMedia error that occured was:\n"
+              "%s\n\n", SDL_GetError());
         Opts_SetFullscreen(0);
       }
     }
@@ -538,8 +538,8 @@
     {
       fprintf(stderr,
             "\nError: I could not open the display.\n"
-	    "The Simple DirectMedia error that occured was:\n"
-	    "%s\n\n", SDL_GetError());
+            "The Simple DirectMedia error that occured was:\n"
+            "%s\n\n", SDL_GetError());
       cleanup_on_error();
       exit(1);
     }

Modified: tuxmath/trunk/src/titlescreen.c
===================================================================
--- tuxmath/trunk/src/titlescreen.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/titlescreen.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -115,14 +115,14 @@
 /* --- locations we need --- */
 
 SDL_Rect dest,
-	 Tuxdest,
-	 Titledest,
+         Tuxdest,
+         Titledest,
          stopRect,
          Backrect,
          Tuxback,
          Titleback,
-	 cursor,
-	 beak;
+         cursor,
+         beak;
 
 /* The background image scaled to windowed 648x480 */
 SDL_Surface* bkg = NULL;
@@ -432,8 +432,12 @@
   int i;
 
   for (i = 0; i < N_SPRITES; i++)
+  {
+    tmdprintf("Freeing image #%d: ", i);
     FreeSprite(sprite_list[i]);
+  }
   free(sprite_list);
+  tmdprintf("Images freed\n");
   sprite_list = NULL;
 }
 
@@ -441,9 +445,11 @@
 
 void TitleScreen_unload_media(void)
 {
+  tmdprintf("Unloading media\n");
   FreeSprite(Tux);
   Tux = NULL;
   TitleScreen_unload_menu();
+  
   SDL_FreeSurface(egg);
   SDL_FreeSurface(bkg);
   SDL_FreeSurface(scaled_bkg);
@@ -661,40 +667,41 @@
   while (choice >= 0) {
     switch (choice) {
       case 0: {
-	// Training academy lessons
-	ret = run_lessons_menu();
-	break;
+        // Training academy lessons
+        ret = run_lessons_menu();
+        break;
       }
       case 1: {
-	// Arcade games
-	ret = run_arcade_menu();
-	break;
+        // Arcade games
+        ret = run_arcade_menu();
+        break;
       }
       case 2: {
-	// Custom game
-	ret = run_custom_menu();
-	break;
+        // Custom game
+        ret = run_custom_menu();
+        break;
       }
       case 3: {
-	// Help
-	Opts_SetHelpMode(1);
-	Opts_SetDemoMode(0);
-	if (Opts_MenuMusic())  //Turn menu music off for game
-	  {audioMusicUnload();}
-	game();
-	RecalcTitlePositions();
-	if (Opts_MenuMusic()) //Turn menu music back on
-	  {audioMusicLoad( "tuxi.ogg", -1 );}
-	Opts_SetHelpMode(0);
-	break;
+        // Help
+        Opts_SetHelpMode(1);
+        Opts_SetDemoMode(0);
+        if (Opts_MenuMusic())  //Turn menu music off for game
+          {audioMusicUnload();}
+        game();
+        RecalcTitlePositions();
+        if (Opts_MenuMusic()) //Turn menu music back on
+          {audioMusicLoad( "tuxi.ogg", -1 );}
+        Opts_SetHelpMode(0);
+        break;
       }
       case 4: {
-	// More options
-	ret = run_options_menu();
+        // More options
+        ret = run_options_menu();
         break;
       }
       case 5: {
-	// Quit
+        // Quit
+        tmdprintf("Exiting main menu\n");
         return 0;
       }
     }
@@ -706,19 +713,24 @@
 
 int run_arcade_menu(void)
 {
-  const unsigned char* menu_text[6] =
+  const unsigned char* menu_text[7] =
     {(const unsigned char*)N_("Space Cadet"),
      (const unsigned char*)N_("Scout"),
      (const unsigned char*)N_("Ranger"),
      (const unsigned char*)N_("Ace"),
+     (const unsigned char*)N_("Commando"),
      (const unsigned char*)N_("Hall Of Fame"),
      (const unsigned char*)N_("Main menu")};
-  const char* arcade_config_files[4] =
-    {"arcade/space_cadet", "arcade/scout", "arcade/ranger", "arcade/ace"};
-  const int arcade_high_score_tables[4] =
-    {CADET_HIGH_SCORE,SCOUT_HIGH_SCORE,RANGER_HIGH_SCORE,ACE_HIGH_SCORE};
-  sprite* sprites[6] =
-    {NULL, NULL, NULL, NULL, NULL, NULL};
+  const char* arcade_config_files[5] =
+    {"arcade/space_cadet", "arcade/scout", "arcade/ranger", "arcade/ace", 
+     "arcade/commando"
+    };
+  const int arcade_high_score_tables[5] =
+    {CADET_HIGH_SCORE,SCOUT_HIGH_SCORE,RANGER_HIGH_SCORE,ACE_HIGH_SCORE,
+     COMMANDO_HIGH_SCORE
+    };
+  sprite* sprites[7] =
+    {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
   menu_options menu_opts;
   int choice,hs_table;
 
@@ -727,54 +739,55 @@
   sprites[1] = sprite_list[SPRITE_SCOUT];
   sprites[2] = sprite_list[SPRITE_RANGER];
   sprites[3] = sprite_list[SPRITE_ACE];
-  sprites[4] = sprite_list[SPRITE_TROPHY];
-  sprites[5] = sprite_list[SPRITE_MAIN];
+  //TODO commando sprite
+  sprites[5] = sprite_list[SPRITE_TROPHY];
+  sprites[6] = sprite_list[SPRITE_MAIN];
 
 //  set_default_menu_options(&menu_opts);
 //  menu_opts.ytop = 100;
 
   //This function takes care of all the drawing and receives
   //user input:
-  choice = choose_menu_item(menu_text,sprites,6,NULL,NULL);
+  choice = choose_menu_item(menu_text,sprites,7,NULL,NULL);
 
   while (choice >= 0) {
-    if (choice < 4) {
+    if (choice < NUM_HIGH_SCORE_LEVELS) {
       // Play arcade game
       if (read_named_config_file(arcade_config_files[choice]))
       {
-	audioMusicUnload();
-	game();
-	RecalcTitlePositions();
-	if (Opts_MenuMusic()) {
-	  audioMusicLoad( "tuxi.ogg", -1 );
-	}
-	/* See if player made high score list!                        */
-	read_high_scores();  /* Update, in case other users have added to it */
-	hs_table = arcade_high_score_tables[choice];
-	if (check_score_place(hs_table, Opts_LastScore()) < HIGH_SCORES_SAVED){
+        audioMusicUnload();
+        game();
+        RecalcTitlePositions();
+        if (Opts_MenuMusic()) {
+          audioMusicLoad( "tuxi.ogg", -1 );
+        }
+        /* See if player made high score list!                        */
+        read_high_scores();  /* Update, in case other users have added to it */
+        hs_table = arcade_high_score_tables[choice];
+        if (check_score_place(hs_table, Opts_LastScore()) < HIGH_SCORES_SAVED){
 
-	  unsigned char player_name[HIGH_SCORE_NAME_LENGTH * 3];
+          unsigned 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(choice,Opts_LastScore(),&player_name[0]);
+          /* 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(choice,Opts_LastScore(),&player_name[0]);
 
 #ifdef TUXMATH_DEBUG
-	  print_high_scores(stderr);
+          print_high_scores(stderr);
 #endif
-	}
+        }
       } else {
-	fprintf(stderr, "\nCould not find %s config file\n",arcade_config_files[choice]);
+        fprintf(stderr, "\nCould not find %s config file\n",arcade_config_files[choice]);
       }
 
-    } else if (choice == 4) {
+    } else if (choice == NUM_HIGH_SCORE_LEVELS) {
       // Display the Hall of Fame
       DisplayHighScores(CADET_HIGH_SCORE);
     }
@@ -864,14 +877,14 @@
       // Demo
       if (read_named_config_file("demo"))
       {
-	audioMusicUnload();
-	game();
-	RecalcTitlePositions();
-	if (Opts_MenuMusic()) {
-	  audioMusicLoad( "tuxi.ogg", -1 );
-	}
+        audioMusicUnload();
+        game();
+        RecalcTitlePositions();
+        if (Opts_MenuMusic()) {
+          audioMusicLoad( "tuxi.ogg", -1 );
+        }
       } else {
-	fprintf(stderr, "\nCould not find demo config file\n");
+        fprintf(stderr, "\nCould not find demo config file\n");
       }
 
       break;
@@ -880,9 +893,9 @@
       // Project Info
       //NotImplemented();
       ShowMessage(_("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"));
+                  _("You can help make it better by reporting problems,"),
+                  _("suggesting improvements, or adding code."),
+                  _("Discuss the future at tuxmath-devel at lists.sourceforge.net"));
       break;
     }
     case 2: {
@@ -1042,21 +1055,21 @@
       // User pressed escape or selected Quit/Back, handle by quitting
       // or going up a level
       if (level == 0) {
-	// We are going to quit without logging in.
-	// Clean up memory (prob. not necessary, but prevents Valgrind errors!)
-	for (i = 0; i < n_login_questions; i++)
-	  free(user_login_questions[i]);
-	free(user_login_questions);
-	for (i = 0; i < n_users; i++)
-	  free(user_names[i]);
-	free(user_names);
-	return -1;
+        // We are going to quit without logging in.
+        // Clean up memory (prob. not necessary, but prevents Valgrind errors!)
+        for (i = 0; i < n_login_questions; i++)
+          free(user_login_questions[i]);
+        free(user_login_questions);
+        for (i = 0; i < n_users; i++)
+          free(user_names[i]);
+        free(user_names);
+        return -1;
       }
       else {
-	// Go back up one level of the directory tree
-	user_data_dirname_up();
-	level--;
-	menu_opts.starting_entry = -1;
+        // Go back up one level of the directory tree
+        user_data_dirname_up();
+        level--;
+        menu_opts.starting_entry = -1;
       }
     }
     else {
@@ -1105,7 +1118,7 @@
 /* (the function returns the index for the selected menu item)  */
 /* -1 indicates that the user pressed escape                    */
 /****************************************************************/
-int choose_menu_item(const unsigned char **menu_text, sprite **menu_sprites, int n_menu_entries, menu_options* custom_mo, void (*set_custom_menu_opts)(menu_options*) )
+int choose_menu_item(const char **menu_text, sprite **menu_sprites, int n_menu_entries, menu_options* custom_mo, void (*set_custom_menu_opts)(menu_options*) )
 {
   // Pixel renderings of menu text choices
   SDL_Surface **menu_item_unselected = NULL;
@@ -1206,7 +1219,7 @@
     buttonheight = 0;
     for (i = 0; i < n_menu_entries; i++)
       if (buttonheight < menu_item_unselected[i]->h)
-	buttonheight = menu_item_unselected[i]->h;
+        buttonheight = menu_item_unselected[i]->h;
     buttonheight += 10;
   } else
     buttonheight = menu_opts.buttonheight;
@@ -1360,7 +1373,7 @@
 
         case SDL_MOUSEMOTION:
         {
-	  loc = -1;  // By default, don't be in any entry
+          loc = -1;  // By default, don't be in any entry
           for (i = 0; (i < n_entries_per_screen) && (loc_screen_start + i < n_menu_entries); i++)
           {
             if (inRect(menu_button_rect[i], event.motion.x, event.motion.y))
@@ -1423,8 +1436,8 @@
               }
 
               loc = loc_screen_start + i;
-	      stop = 1;
-	      break;
+              stop = 1;
+              break;
             }
           }
 
@@ -1434,8 +1447,8 @@
             if (loc_screen_start - n_entries_per_screen >= 0)
             {
               //loc = loc_screen_start - n_entries_per_screen;
-	      loc_screen_start -= n_entries_per_screen;
-	      loc = -1;  // nothing selected
+              loc_screen_start -= n_entries_per_screen;
+              loc = -1;  // nothing selected
               if (Opts_MenuSound())
               {
                 playsound(SND_TOCK);
@@ -1450,8 +1463,8 @@
             if (loc_screen_start + n_entries_per_screen < n_menu_entries)
             {
               //loc = loc_screen_start + n_entries_per_screen;
-	      loc_screen_start += n_entries_per_screen;
-	      loc = -1;  // nothing selected
+              loc_screen_start += n_entries_per_screen;
+              loc = -1;  // nothing selected
               if (Opts_MenuSound())
               {
                 playsound(SND_TOCK);
@@ -1487,7 +1500,7 @@
             {
               if (Opts_MenuSound())
                 playsound(SND_POP);
-	      stop = 1;
+              stop = 1;
               break;
             }
 
@@ -1499,9 +1512,9 @@
               if (Opts_MenuSound())
                 playsound(SND_TOCK);
               if (loc_screen_start - n_entries_per_screen >= 0) {
-		loc_screen_start -= n_entries_per_screen;
-		loc = -1;
-	      }
+                loc_screen_start -= n_entries_per_screen;
+                loc = -1;
+              }
               //  {loc = loc_screen_start - n_entries_per_screen;}
               break;
             }
@@ -1514,9 +1527,9 @@
               if (Opts_MenuSound())
                 playsound(SND_TOCK);
               if (loc_screen_start + n_entries_per_screen < n_menu_entries) {
-		loc_screen_start += n_entries_per_screen;
-		loc = -1;
-	      }
+                loc_screen_start += n_entries_per_screen;
+                loc = -1;
+              }
               //  {loc = (loc_screen_start + n_entries_per_screen);}
               break;
             }
@@ -1528,15 +1541,15 @@
                 playsound(SND_TOCK);
               if (loc > title_offset)
                 {loc--;}
-	      else if (n_menu_entries <= n_entries_per_screen) {
-		loc = n_menu_entries-1;  // wrap around if only 1 screen
-	      }
-	      else if (loc == -1 && loc_screen_start > 0) {
-		loc = loc_screen_start-1;
-		loc_screen_start -= n_entries_per_screen;
-	      }
-	      if (loc != old_loc)
-		warp_mouse = 1;
+              else if (n_menu_entries <= n_entries_per_screen) {
+                loc = n_menu_entries-1;  // wrap around if only 1 screen
+              }
+              else if (loc == -1 && loc_screen_start > 0) {
+                loc = loc_screen_start-1;
+                loc_screen_start -= n_entries_per_screen;
+              }
+              if (loc != old_loc)
+                warp_mouse = 1;
               break;
             }
 
@@ -1548,12 +1561,12 @@
                 playsound(SND_TOCK);
               if (loc >= 0 && loc + 1 < n_menu_entries)
                 {loc++;}
-	      else if (n_menu_entries <= n_entries_per_screen)
-		loc = title_offset;       // wrap around if only 1 screen
-	      else if (loc == -1)
-		loc = loc_screen_start;
-	      if (loc != old_loc)
-		warp_mouse = 1;
+              else if (n_menu_entries <= n_entries_per_screen)
+                loc = title_offset;       // wrap around if only 1 screen
+              else if (loc == -1)
+                loc = loc_screen_start;
+              if (loc != old_loc)
+                warp_mouse = 1;
               break;
            }
 
@@ -1595,11 +1608,11 @@
                 audioMusicLoad("tuxi.ogg", -1);
               }
               break;
-            }
-#ifdef TESTING_CAMPAIGN
-            case SDLK_c:
-            {
-              start_campaign();
+            }
+#ifdef TESTING_CAMPAIGN
+            case SDLK_c:
+            {
+              start_campaign();
               RecalcTitlePositions();
               RecalcMenuPositions(&n_entries_per_screen,
                                   n_menu_entries,
@@ -1613,8 +1626,9 @@
                                   &back_text_rect,
                                   &left_arrow_rect,
                                   &right_arrow_rect);
-              redraw = 1;
+              redraw = 1;
             }
+
 #endif
             default:
             {
@@ -1656,57 +1670,57 @@
       if (images[IMG_STOP])
         SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
       if (Tux->frame[0])
-	SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
+        SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
       /* Redraw the menu entries */
       for (imod = 0; imod < n_entries_per_screen; imod++)
-	menu_button_rect[imod].w = 0;  // so undrawn buttons don't affect width
+        menu_button_rect[imod].w = 0;  // so undrawn buttons don't affect width
       for (i = loc_screen_start, imod = 0; i < loc_screen_start+n_entries_per_screen && i < n_menu_entries; i++, imod++) {
-	menu_text_rect[imod].w = menu_item_unselected[i]->w;
-	if (i >= title_offset) {
-	  menu_button_rect[imod].w = menu_text_rect[imod].w + 30;
-	  if (menu_sprites != NULL)
-	    menu_button_rect[imod].w += 60;
-	}
+        menu_text_rect[imod].w = menu_item_unselected[i]->w;
+        if (i >= title_offset) {
+          menu_button_rect[imod].w = menu_text_rect[imod].w + 30;
+          if (menu_sprites != NULL)
+            menu_button_rect[imod].w += 60;
+        }
       }
 
       if (menu_opts.button_same_width)
-	set_buttons_max_width(menu_button_rect,back_button_rect,n_entries_per_screen);
+        set_buttons_max_width(menu_button_rect,back_button_rect,n_entries_per_screen);
       // Make sure the menu title mouse button didn't get turned on
       if (loc_screen_start == 0 && title_offset)
-	menu_button_rect[0].w = 0;
+        menu_button_rect[0].w = 0;
       for (i = loc_screen_start, imod = 0; i < loc_screen_start+n_entries_per_screen && i < n_menu_entries; i++, imod++) {
-	if (i == loc) {  //Draw text in yellow
-	  DrawButton(&menu_button_rect[imod], 10, SEL_RGBA);
-	  SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu_text_rect[imod]);
-	}
-	else {          //Draw text in white
-	  if (menu_button_rect[imod].w > 0)
-	    DrawButton(&menu_button_rect[imod], 10, REG_RGBA);
-	  SDL_BlitSurface(menu_item_unselected[i], NULL, screen, &menu_text_rect[imod]);
-	}
-	if (menu_sprites != NULL && (i >= title_offset) && menu_sprites[i-title_offset] != NULL)
-	  SDL_BlitSurface(menu_sprites[i-title_offset]->default_img, NULL, screen, &menu_sprite_rect[imod]);
+        if (i == loc) {  //Draw text in yellow
+          DrawButton(&menu_button_rect[imod], 10, SEL_RGBA);
+          SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu_text_rect[imod]);
+        }
+        else {          //Draw text in white
+          if (menu_button_rect[imod].w > 0)
+            DrawButton(&menu_button_rect[imod], 10, REG_RGBA);
+          SDL_BlitSurface(menu_item_unselected[i], NULL, screen, &menu_text_rect[imod]);
+        }
+        if (menu_sprites != NULL && (i >= title_offset) && menu_sprites[i-title_offset] != NULL)
+          SDL_BlitSurface(menu_sprites[i-title_offset]->default_img, NULL, screen, &menu_sprite_rect[imod]);
       }
 
       /* --- draw 'left' and 'right' buttons --- */
       if (n_menu_entries > n_entries_per_screen) {
-	if (loc_screen_start > 0)        // i.e. not on first page
-	{
-	    SDL_BlitSurface(images[IMG_LEFT], NULL, screen, &left_arrow_rect);
-	}
-	else  /* Draw grayed-out left button: */
+        if (loc_screen_start > 0)        // i.e. not on first page
         {
-	  SDL_BlitSurface(images[IMG_LEFT_GRAY], NULL, screen, &left_arrow_rect);
-	}
+            SDL_BlitSurface(images[IMG_LEFT], NULL, screen, &left_arrow_rect);
+        }
+        else  /* Draw grayed-out left button: */
+        {
+          SDL_BlitSurface(images[IMG_LEFT_GRAY], NULL, screen, &left_arrow_rect);
+        }
 
-	if (loc_screen_start + n_entries_per_screen < n_menu_entries)  // not on last page
+        if (loc_screen_start + n_entries_per_screen < n_menu_entries)  // not on last page
         {
-	  SDL_BlitSurface(images[IMG_RIGHT], NULL, screen, &right_arrow_rect);
-	}
-	else  /* Draw grayed-out right button: */
-	{
-	  SDL_BlitSurface(images[IMG_RIGHT_GRAY], NULL, screen, &right_arrow_rect);
-	}
+          SDL_BlitSurface(images[IMG_RIGHT], NULL, screen, &right_arrow_rect);
+        }
+        else  /* Draw grayed-out right button: */
+        {
+          SDL_BlitSurface(images[IMG_RIGHT_GRAY], NULL, screen, &right_arrow_rect);
+        }
       }
       
       SDL_Flip(screen);//SDL_UpdateRect(screen, 0, 0, 0 ,0);
@@ -1714,68 +1728,68 @@
       // This is not a full redraw, but the selected entry did change.
       // By just redrawing the old and new selections, we avoid flickering.
       if (old_loc >= 0) {
-	imod = old_loc-loc_screen_start;
-	use_sprite = (menu_sprites != NULL && old_loc >= title_offset && menu_sprites[old_loc-title_offset] != NULL);
+        imod = old_loc-loc_screen_start;
+        use_sprite = (menu_sprites != NULL && old_loc >= title_offset && menu_sprites[old_loc-title_offset] != NULL);
         temp_rect = menu_button_rect[imod];
         SDL_FillRect(screen, &temp_rect, 0);
-	SDL_BlitSurface(current_bkg(), &back_button_rect[imod], screen, &temp_rect);   // redraw background
-	if (use_sprite) {
-	  // Some of the sprites extend beyond the menu button, so we
-	  // have to make sure we redraw in the sprite rects, too
-	  SDL_BlitSurface(current_bkg(), &back_sprite_rect[imod], screen, &temp_rect);
-	}
-	DrawButton(&menu_button_rect[imod], 10, REG_RGBA);  // draw button
-	//temp_rect = menu_text_rect[imod];
-	SDL_BlitSurface(menu_item_unselected[old_loc], NULL, screen, &menu_text_rect[imod]);  // draw text
-	if (use_sprite) {
-	  temp_rect = menu_sprite_rect[imod];
-	  tmdprintf("Sprite %d at (%d %d)\n",  imod, temp_rect.x, temp_rect.y);
-	  SDL_BlitSurface(menu_sprites[old_loc-title_offset]->default_img, NULL, screen, &temp_rect);
-	  // Also update the sprite rect (in some cases the sprite
-	  // extends beyond the menu button)
-	  SDL_UpdateRect(screen, menu_sprite_rect[imod].x, menu_sprite_rect[imod].y, menu_sprite_rect[imod].w, menu_sprite_rect[imod].h);
-	}
-	SDL_UpdateRect(screen, menu_button_rect[imod].x, menu_button_rect[imod].y, menu_button_rect[imod].w, menu_button_rect[imod].h);
+        SDL_BlitSurface(current_bkg(), &back_button_rect[imod], screen, &temp_rect);   // redraw background
+        if (use_sprite) {
+          // Some of the sprites extend beyond the menu button, so we
+          // have to make sure we redraw in the sprite rects, too
+          SDL_BlitSurface(current_bkg(), &back_sprite_rect[imod], screen, &temp_rect);
+        }
+        DrawButton(&menu_button_rect[imod], 10, REG_RGBA);  // draw button
+        //temp_rect = menu_text_rect[imod];
+        SDL_BlitSurface(menu_item_unselected[old_loc], NULL, screen, &menu_text_rect[imod]);  // draw text
+        if (use_sprite) {
+          temp_rect = menu_sprite_rect[imod];
+          tmdprintf("Sprite %d at (%d %d)\n",  imod, temp_rect.x, temp_rect.y);
+          SDL_BlitSurface(menu_sprites[old_loc-title_offset]->default_img, NULL, screen, &temp_rect);
+          // Also update the sprite rect (in some cases the sprite
+          // extends beyond the menu button)
+          SDL_UpdateRect(screen, menu_sprite_rect[imod].x, menu_sprite_rect[imod].y, menu_sprite_rect[imod].w, menu_sprite_rect[imod].h);
+        }
+        SDL_UpdateRect(screen, menu_button_rect[imod].x, menu_button_rect[imod].y, menu_button_rect[imod].w, menu_button_rect[imod].h);
       }
       if (loc >= 0) {
-	imod = loc-loc_screen_start;
-	use_sprite = (menu_sprites != NULL && loc >= title_offset && menu_sprites[loc] != NULL);
-	temp_rect = menu_button_rect[imod];
-	SDL_BlitSurface(current_bkg, &back_button_rect[imod], screen, &temp_rect);
-	if (use_sprite)
-	{
-	  temp_rect = menu_sprite_rect[imod];
-	  SDL_BlitSurface(current_bkg, &back_sprite_rect[imod], screen, &temp_rect);
-	}
-	DrawButton(&menu_button_rect[imod], 10, SEL_RGBA);
-	SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu_text_rect[imod]);
-	if (use_sprite) {
-	  menu_sprites[loc-title_offset]->cur = 0;  // start at beginning of animation sequence
-	  SDL_BlitSurface(menu_sprites[loc-title_offset]->frame[menu_sprites[loc-title_offset]->cur], NULL, screen, &menu_sprite_rect[imod]);
-	  SDL_UpdateRect(screen, menu_sprite_rect[imod].x, menu_sprite_rect[imod].y, menu_sprite_rect[imod].w, menu_sprite_rect[imod].h);
-	  next_frame(menu_sprites[loc-title_offset]);
-	}
-	SDL_UpdateRect(screen, menu_button_rect[imod].x, menu_button_rect[imod].y, menu_button_rect[imod].w, menu_button_rect[imod].h);
-	tmdprintf("Updating rect: %d %d %d %d\n", menu_button_rect[imod].x, menu_button_rect[imod].y, menu_button_rect[imod].w, menu_button_rect[imod].h);
+        imod = loc-loc_screen_start;
+        use_sprite = (menu_sprites != NULL && loc >= title_offset && menu_sprites[loc] != NULL);
+        temp_rect = menu_button_rect[imod];
+        SDL_BlitSurface(current_bkg(), &(back_button_rect[imod]), screen, &temp_rect);
+        if (use_sprite)
+        {
+          temp_rect = menu_sprite_rect[imod];
+          SDL_BlitSurface(current_bkg(), &(back_sprite_rect[imod]), screen, &temp_rect);
+        }
+        DrawButton(&menu_button_rect[imod], 10, SEL_RGBA);
+        SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu_text_rect[imod]);
+        if (use_sprite) {
+          menu_sprites[loc-title_offset]->cur = 0;  // start at beginning of animation sequence
+          SDL_BlitSurface(menu_sprites[loc-title_offset]->frame[menu_sprites[loc-title_offset]->cur], NULL, screen, &menu_sprite_rect[imod]);
+          SDL_UpdateRect(screen, menu_sprite_rect[imod].x, menu_sprite_rect[imod].y, menu_sprite_rect[imod].w, menu_sprite_rect[imod].h);
+          next_frame(menu_sprites[loc-title_offset]);
+        }
+        SDL_UpdateRect(screen, menu_button_rect[imod].x, menu_button_rect[imod].y, menu_button_rect[imod].w, menu_button_rect[imod].h);
+        tmdprintf("Updating rect: %d %d %d %d\n", menu_button_rect[imod].x, menu_button_rect[imod].y, menu_button_rect[imod].w, menu_button_rect[imod].h);
       }
     } else if (frame_counter % 5 == 0 && loc >= 0) {
       // No user input changed anything, but check to see if we need to
       // animate the sprite
       if (menu_sprites != NULL && loc >= title_offset && menu_sprites[loc-title_offset] != NULL) {
-	imod = loc-loc_screen_start;
-	//SDL_BlitSurface(current_bkg, &menu_button_rect[imod], screen, &menu_button_rect[imod]);
-	temp_rect = menu_sprite_rect[imod];
-	SDL_BlitSurface(current_bkg(), &back_sprite_rect[imod], screen, &temp_rect);
-	DrawButton(&menu_button_rect[imod], 10, SEL_RGBA);
-	//SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu_text_rect[imod]);
-	// Note: even though the whole button was redrawn, we don't
-	// have to redraw the text & background as long as we don't
-	// update that rect. If something else changes and we go to
-	// full-screen updates, then remove the "commenting-out" on
-	// the two lines above
-	SDL_BlitSurface(menu_sprites[loc-title_offset]->frame[menu_sprites[loc-title_offset]->cur], NULL, screen, &menu_sprite_rect[imod]);
-	SDL_UpdateRect(screen, menu_sprite_rect[imod].x, menu_sprite_rect[imod].y, menu_sprite_rect[imod].w, menu_sprite_rect[imod].h);
-	next_frame(menu_sprites[loc-title_offset]);
+        imod = loc-loc_screen_start;
+        //SDL_BlitSurface(current_bkg, &menu_button_rect[imod], screen, &menu_button_rect[imod]);
+        temp_rect = menu_sprite_rect[imod];
+        SDL_BlitSurface(current_bkg(), &back_sprite_rect[imod], screen, &temp_rect);
+        DrawButton(&menu_button_rect[imod], 10, SEL_RGBA);
+        //SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu_text_rect[imod]);
+        // Note: even though the whole button was redrawn, we don't
+        // have to redraw the text & background as long as we don't
+        // update that rect. If something else changes and we go to
+        // full-screen updates, then remove the "commenting-out" on
+        // the two lines above
+        SDL_BlitSurface(menu_sprites[loc-title_offset]->frame[menu_sprites[loc-title_offset]->cur], NULL, screen, &menu_sprite_rect[imod]);
+        SDL_UpdateRect(screen, menu_sprite_rect[imod].x, menu_sprite_rect[imod].y, menu_sprite_rect[imod].w, menu_sprite_rect[imod].h);
+        next_frame(menu_sprites[loc-title_offset]);
       }
     }
 
@@ -1817,7 +1831,8 @@
     }
     
     if (egg_active) { //if we need to, draw the egg cursor
-      SDL_GetMouseState(&cursor.x, &cursor.y);
+      //who knows why GetMouseState() doesn't take Sint16's...
+      SDL_GetMouseState((int*)&cursor.x, (int*)&cursor.y); 
       cursor.x -= egg->w / 2; //center vertically
       SDL_BlitSurface(egg, NULL, screen, &cursor);
       SDL_UpdateRect(screen, cursor.x, cursor.y, cursor.w, cursor.h);
@@ -2071,28 +2086,28 @@
 UpdateScreen : Update the screen and increment the frame num
 ***************************/
 void UpdateScreen(int *frame) {
-	int i;
+  int i;
 
-	/* -- First erase everything we need to -- */
-	for (i = 0; i < numupdates; i++)
-		if (blits[i].type == 'E')
-			SDL_LowerBlit(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
-//	SNOW_erase();
+  /* -- First erase everything we need to -- */
+  for (i = 0; i < numupdates; i++)
+    if (blits[i].type == 'E')
+      SDL_LowerBlit(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
+//        SNOW_erase();
 
-	/* -- then draw -- */
-	for (i = 0; i < numupdates; i++)
-		if (blits[i].type == 'D')
-			SDL_BlitSurface(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
-//	SNOW_draw();
+  /* -- then draw -- */
+  for (i = 0; i < numupdates; i++)
+    if (blits[i].type == 'D')
+      SDL_BlitSurface(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
+//        SNOW_draw();
 
-	/* -- update the screen only where we need to! -- */
-//	if (SNOW_on)
-//		SDL_UpdateRects(screen, SNOW_add( (SDL_Rect*)&dstupdate, numupdates ), SNOW_rects);
-//	else
-		SDL_UpdateRects(screen, numupdates, dstupdate);
+/* -- update the screen only where we need to! -- */
+//        if (SNOW_on)
+//                SDL_UpdateRects(screen, SNOW_add( (SDL_Rect*)&dstupdate, numupdates ), SNOW_rects);
+//        else
+    SDL_UpdateRects(screen, numupdates, dstupdate);
 
-	numupdates = 0;
-	*frame = *frame + 1;
+  numupdates = 0;
+  *frame = *frame + 1;
 }
 
 

Modified: tuxmath/trunk/src/titlescreen.h
===================================================================
--- tuxmath/trunk/src/titlescreen.h	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/titlescreen.h	2008-08-06 02:55:05 UTC (rev 589)
@@ -26,7 +26,7 @@
 #define to_upper(c) (((c) >= 'a' && (c) <= 'z') ? (c) -32 : (c))
 #define COL2RGB( col ) SDL_MapRGB( screen->format, col->r, col->g, col->b )
 
-//#define FNLEN	200
+//#define FNLEN        200
 
 #define MAX_SPRITE_FRAMES 30
 
@@ -44,7 +44,7 @@
 #include "SDL_ttf.h"
 
 #ifndef MACOSX
-#include "config.h"
+//#include "config.h"
 #endif
 
 #include "tuxmath.h"
@@ -53,10 +53,10 @@
 
 
 typedef struct {
-	SDL_Surface *frame[MAX_SPRITE_FRAMES];
-	SDL_Surface *default_img;
-	int num_frames;
-	int cur;
+  SDL_Surface *frame[MAX_SPRITE_FRAMES];
+  SDL_Surface *default_img;
+  int num_frames;
+  int cur;
 } sprite;
 
 // Options that affect how menus are presented
@@ -74,10 +74,10 @@
 
 
 #define menu_font  "AndikaDesRevA.ttf"  /*  "GenAI102.ttf" */
-#define menu_font_size	18
+#define menu_font_size       18
 
 #define ttf_font  "AndikaDesRevA.ttf"  /*   "GenAI102.ttf" */
-#define ttf_font_size	18
+#define ttf_font_size        18
 
 #define MAX_LESSONS 100
 #define MAX_NUM_WORDS   500
@@ -87,15 +87,15 @@
 #define MAX_UPDATES 180
 
 
-#define WAIT_MS				2500
-#define	FRAMES_PER_SEC	                50
-#define FULL_CIRCLE		        140
+#define WAIT_MS                               2500
+#define FRAMES_PER_SEC                        50
+#define FULL_CIRCLE                           140
 
 
 /* Title sequence constants */
-#define PRE_ANIM_FRAMES			10
-#define PRE_FRAME_MULT			3
-#define MENU_SEP			20
+#define PRE_ANIM_FRAMES                       10
+#define PRE_FRAME_MULT                        3
+#define MENU_SEP                              20
 
 /* paths */
 
@@ -115,7 +115,7 @@
 
 SDL_Surface* current_bkg(); //appropriate background for current video mode
 
-#define MUSIC_FADE_OUT_MS	80
+#define MUSIC_FADE_OUT_MS        80
 
 enum {
     WIPE_BLINDS_VERT,
@@ -134,9 +134,9 @@
 #define TITLE_MENU_DEPTH                4
 
 #define OPTIONS_SUBMENU                 4
-#define GAME_OPTIONS_SUBMENU	       	3
-#define ARCADE_SUBMENU	        	2
-#define ROOTMENU		        1
+#define GAME_OPTIONS_SUBMENU                       3
+#define ARCADE_SUBMENU                        2
+#define ROOTMENU                        1
 
 
 /* --- timings for tux blinking --- */
@@ -157,7 +157,11 @@
 /*In titlescreen.c */
 void TitleScreen(void);
 int ChooseMission(void);  //FIXME really should be in fileops.c
-int choose_menu_item(const unsigned char**, sprite**, int, menu_options*, void (*)(menu_options*) );
+int choose_menu_item(const char **menu_text, 
+                     sprite **menu_sprites, 
+                     int n_menu_entries, 
+                     menu_options* custom_mo, 
+                     void (*set_custom_menu_opts)(menu_options*) );
 void set_default_menu_options(menu_options *);
 
 
@@ -167,7 +171,9 @@
 Mix_Chunk   *LoadSound( char* datafile );
 SDL_Surface *LoadImage( char* datafile, int mode );
 SDL_Surface* LoadBkgd(char* datafile);
-int          LoadBothBkgds(char* datafile, SDL_Surface** fs_bkgd, SDL_Surface** win_bkgd);
+int          LoadBothBkgds(char* datafile, 
+                           SDL_Surface** fs_bkgd, 
+                           SDL_Surface** win_bkgd);
 sprite      *LoadSprite( char* name, int MODE );
 sprite      *FlipSprite( sprite* in, int X, int Y );
 void         FreeSprite( sprite* gfx );

Modified: tuxmath/trunk/src/tuxmath.h
===================================================================
--- tuxmath/trunk/src/tuxmath.h	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/tuxmath.h	2008-08-06 02:55:05 UTC (rev 589)
@@ -22,7 +22,9 @@
 #ifndef TUXMATH_H
 #define TUXMATH_H
 
-#include "config.h"
+//To build with CMake, comment out this line so we don't include "config.h"
+//To build with Autotools, uncomment it as we must have "config.h"
+//#include "config.h"
 
 // Translation stuff (now works for Mac and Win too!): 
 #include "gettext.h"
@@ -81,7 +83,7 @@
 #define DEFAULT_STARTING_COMETS 2
 #define DEFAULT_EXTRA_COMETS_PER_WAVE 2
 #define DEFAULT_MAX_COMETS 10
-#define DEFAULT_SAVE_SUMMARY 1	
+#define DEFAULT_SAVE_SUMMARY 1        
 #define DEFAULT_SOUND_HW_AVAILABLE 1
 #define DEFAULT_USE_IGLOOS 1
 #define DEFAULT_USE_FEEDBACK 0
@@ -98,7 +100,7 @@
 
 #define MINIMUM_SPEED 0.8
 #define MAX_MAX_SPEED 20.0
-#define MIN_SPEEDUP_FACTOR 1
+#define MIN_SPEEDUP_FACTOR 1.0
 #define MAX_SPEEDUP_FACTOR 2.0
 #define MAX_BONUS_SPEED_RATIO 3.0
 #define MIN_COMETS 1
@@ -115,15 +117,16 @@
 #define REG_RGBA 16,16,96,96
 #define SEL_RGBA 16,16,128,128
 
-#define RES_X	640
-#define RES_Y	480
-#define PIXEL_BITS 32	
+#define RES_X        640
+#define RES_Y        480
+#define PIXEL_BITS 32        
 
 enum { 
   CADET_HIGH_SCORE,
   SCOUT_HIGH_SCORE,
   RANGER_HIGH_SCORE,
   ACE_HIGH_SCORE,
+  COMMANDO_HIGH_SCORE,
   NUM_HIGH_SCORE_LEVELS
 };
 

Modified: tuxmath/trunk/src/tuxmathadmin.c
===================================================================
--- tuxmath/trunk/src/tuxmathadmin.c	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/tuxmathadmin.c	2008-08-06 02:55:05 UTC (rev 589)
@@ -114,66 +114,66 @@
       exit(EXIT_SUCCESS);
     }
     else if (strcmp(argv[i], "--copyright") == 0 ||
-	     strcmp(argv[i], "-c") == 0)
+             strcmp(argv[i], "-c") == 0)
     {
       printf(
-	"\ntuxmathadmin version " ADMINVERSION ", Copyright (C) 2007 Tim Holy\n"
+        "\ntuxmathadmin version " ADMINVERSION ", Copyright (C) 2007 Tim Holy\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");
+        "\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");
       exit(EXIT_SUCCESS);
     }
     else if (strcmp(argv[i], "--usage") == 0 ||
-	     strcmp(argv[i], "-u") == 0) {
+             strcmp(argv[i], "-u") == 0) {
       usage(0, argv[0]);
       exit(EXIT_SUCCESS);
     }
     else if (strcmp(argv[i], "--path") == 0) {
       if (i+1 > argc) {
-	fprintf(stderr, "%s option requires an argument (a directory name)\n", argv[i]);
-	usage(EXIT_FAILURE, argv[0]);
+        fprintf(stderr, "%s option requires an argument (a directory name)\n", argv[i]);
+        usage(EXIT_FAILURE, argv[0]);
       }
       else {
-	path = argv[i+1];
-	dir = opendir(path);  // determine whether directory exists
-	if (dir == NULL)
-	  error(EXIT_FAILURE,errno,"path:\n  %s",path);
-	closedir(dir);
-	i++; // increment so further processing skips over the argument
+        path = argv[i+1];
+        dir = opendir(path);  // determine whether directory exists
+        if (dir == NULL)
+          error(EXIT_FAILURE,errno,"path:\n  %s",path);
+        closedir(dir);
+        i++; // increment so further processing skips over the argument
       }
     }
     else if (strcmp(argv[i], "--level") == 0) {
       if (i+1 > argc) {
-	fprintf(stderr, "%s option requires an argument (a level number)\n", argv[i]);
-	usage(EXIT_FAILURE, argv[0]);
+        fprintf(stderr, "%s option requires an argument (a level number)\n", argv[i]);
+        usage(EXIT_FAILURE, argv[0]);
       }
       else {
-	success = sscanf(argv[i+1],"%d",&level);
-	if (!success) {
-	  fprintf(stderr,"level: %s is not a number\n",argv[i+1]);
-	  exit(EXIT_FAILURE);
-	}
-	i++; // increment so further processing skips over the argument
+        success = sscanf(argv[i+1],"%d",&level);
+        if (!success) {
+          fprintf(stderr,"level: %s is not a number\n",argv[i+1]);
+          exit(EXIT_FAILURE);
+        }
+        i++; // increment so further processing skips over the argument
       }
     }
     else if (strcmp(argv[i], "--createhomedirs") == 0) {
       is_creatinghomedirs = 1;
       if (i+1 > argc) {
-	fprintf(stderr, "%s option requires an argument (a file name)\n", argv[i]);
-	usage(EXIT_FAILURE, argv[0]);
+        fprintf(stderr, "%s option requires an argument (a file name)\n", argv[i]);
+        usage(EXIT_FAILURE, argv[0]);
       }
       else {
-	file = argv[i+1];
-	fp = fopen(file,"r");   // determine whether the file exists
-	if (fp == NULL)
-	  error(EXIT_FAILURE,errno,"createhomedirs using:\n  %s",file);
-	fclose(fp);  // don't read it yet, do that elsewhere
-	i++; // increment so further processing skips over the argument
+        file = argv[i+1];
+        fp = fopen(file,"r");   // determine whether the file exists
+        if (fp == NULL)
+          error(EXIT_FAILURE,errno,"createhomedirs using:\n  %s",file);
+        fclose(fp);  // don't read it yet, do that elsewhere
+        i++; // increment so further processing skips over the argument
       }
     }
     else if (strcmp(argv[i], "--confighighscores") == 0) {
@@ -277,42 +277,42 @@
 void display_help(void)
 {
   printf("\ntuxmathadmin\n"
-	 "This program facilitates administering tuxmath, and is particularly\n"
-	 "useful for schools and the like that may have many users.\n\n"
-	 "Examples:\n"
-	 "  tuxmathadmin --path /servervolume/tuxmath_users --createhomedirs users.csv\n"
-	 "  tuxmathadmin --createhomedirs users.csv\n"
-	 "    Creates a user directory tree in location /servervolume/tuxmath_users,\n"
-	 "    according to the structure specified in users.csv.  See configure.pdf\n"
-	 "    for details.  The second syntax is applicable if you've defined the\n"
-	 "    homedir path in the global configuration file.\n\n"
-	 "  tuxmathadmin --confighighscores --level 3\n"
-	 "    Sets up sharing of high scores at level 3 of the hierarchy (top is\n"
-	 "    level 1).  If students logging in are presented with a choice of grade,\n"
-	 "    then classroom, and then user, then level 1 is the school, level 2 is the\n"
-	 "    grade, level 3 is the classroom, and level 4 is the individual student.\n"
-	 "    So level 3 would set it up so that all kids in the same classroom would\n"
-	 "    compete for high scores.\n\n"
-	 "  tuxmathadmin --unconfighighscores\n"
-	 "    Removes any existing highscores configuration.\n\n"
-	 "  tuxmathadmin --clearhighscores\n"
-	 "    Clears high scores for all users in the location specified by the homedir\n"
-	 "    setting in the global configuration file.\n\n"
-	 "  tuxmathadmin --path /servervolume/tuxmath_users/2ndgrade --clearhighscores\n"
-	 "    Clears the high scores for all users inside the 2ndgrade hierarchy.\n\n"
-	 "  tuxmathadmin --cleargoldstars\n"
-	 "    Clears the gold stars for all users.\n\n"
-	 "  tuxmathadmin --path /servervolume/tuxmath_users/1st\\ grade/Mrs.\\ Smith --cleargoldstars\n"
-	 "    Clears the gold stars for all users in Mrs. Smith's first grade class.\n\n"
-	 "  tuxmathadmin --consolidatelogs\n"
-	 "    Creates consolidated_log.csv files at one level above the lowest level\n"
-	 "    of the directory hierarchy. These files can be opened with a spreadsheet\n"
-	 "    program. This may be useful for tracking student progress.\n"
-	 "    Note also that each student has a personal log.csv file in his/her own\n"
-	 "    directory.\n\n"
-	 "  tuxmathadmin --clearlogs\n"
-	 "    Deletes all log.csv files in the directory hierarchy.\n\n"
-	 );
+         "This program facilitates administering tuxmath, and is particularly\n"
+         "useful for schools and the like that may have many users.\n\n"
+         "Examples:\n"
+         "  tuxmathadmin --path /servervolume/tuxmath_users --createhomedirs users.csv\n"
+         "  tuxmathadmin --createhomedirs users.csv\n"
+         "    Creates a user directory tree in location /servervolume/tuxmath_users,\n"
+         "    according to the structure specified in users.csv.  See configure.pdf\n"
+         "    for details.  The second syntax is applicable if you've defined the\n"
+         "    homedir path in the global configuration file.\n\n"
+         "  tuxmathadmin --confighighscores --level 3\n"
+         "    Sets up sharing of high scores at level 3 of the hierarchy (top is\n"
+         "    level 1).  If students logging in are presented with a choice of grade,\n"
+         "    then classroom, and then user, then level 1 is the school, level 2 is the\n"
+         "    grade, level 3 is the classroom, and level 4 is the individual student.\n"
+         "    So level 3 would set it up so that all kids in the same classroom would\n"
+         "    compete for high scores.\n\n"
+         "  tuxmathadmin --unconfighighscores\n"
+         "    Removes any existing highscores configuration.\n\n"
+         "  tuxmathadmin --clearhighscores\n"
+         "    Clears high scores for all users in the location specified by the homedir\n"
+         "    setting in the global configuration file.\n\n"
+         "  tuxmathadmin --path /servervolume/tuxmath_users/2ndgrade --clearhighscores\n"
+         "    Clears the high scores for all users inside the 2ndgrade hierarchy.\n\n"
+         "  tuxmathadmin --cleargoldstars\n"
+         "    Clears the gold stars for all users.\n\n"
+         "  tuxmathadmin --path /servervolume/tuxmath_users/1st\\ grade/Mrs.\\ Smith --cleargoldstars\n"
+         "    Clears the gold stars for all users in Mrs. Smith's first grade class.\n\n"
+         "  tuxmathadmin --consolidatelogs\n"
+         "    Creates consolidated_log.csv files at one level above the lowest level\n"
+         "    of the directory hierarchy. These files can be opened with a spreadsheet\n"
+         "    program. This may be useful for tracking student progress.\n"
+         "    Note also that each student has a personal log.csv file in his/her own\n"
+         "    directory.\n\n"
+         "  tuxmathadmin --clearlogs\n"
+         "    Deletes all log.csv files in the directory hierarchy.\n\n"
+         );
 }
 
 // This function does the work of creating the user directory tree,
@@ -359,7 +359,7 @@
     line_cur = line_begin;
     while (!(*line_cur == '\r' || *line_cur == '\n')) {
       if (*line_cur == ',')
-	this_line_total_depth++;
+        this_line_total_depth++;
       line_cur++;
     }
 
@@ -368,23 +368,23 @@
       max_depth = this_line_total_depth;
       current_dirtree = (char **) malloc(max_depth * sizeof(char*));
       if (current_dirtree == NULL) {
-	fprintf(stderr,"Error: couldn't allocate memory for directory tree.\n");
-	exit(EXIT_FAILURE);
+        fprintf(stderr,"Error: couldn't allocate memory for directory tree.\n");
+        exit(EXIT_FAILURE);
       }
       for (i = 0; i < max_depth; i++) {
-	current_dirtree[i] = (char *) malloc(PATH_MAX * sizeof(char));
-	if (current_dirtree[i] == NULL){
-	  fprintf(stderr,"Error: couldn't allocate memory for directory tree.\n");
-	  exit(EXIT_FAILURE);
-	} else
-	  *(current_dirtree[i]) = '\0';  // initialize with blank string
+        current_dirtree[i] = (char *) malloc(PATH_MAX * sizeof(char));
+        if (current_dirtree[i] == NULL){
+          fprintf(stderr,"Error: couldn't allocate memory for directory tree.\n");
+          exit(EXIT_FAILURE);
+        } else
+          *(current_dirtree[i]) = '\0';  // initialize with blank string
       }
     }
     else {
       // Check that this line doesn't change the size of the directory hierarchy
       if (this_line_total_depth != max_depth) {
-	fprintf(stderr,"Error: line\n  '%s'\ncontains a different number of depths to the hierarchy than the previous setting (%d).\n",buf,max_depth);
-	exit(EXIT_FAILURE);
+        fprintf(stderr,"Error: line\n  '%s'\ncontains a different number of depths to the hierarchy than the previous setting (%d).\n",buf,max_depth);
+        exit(EXIT_FAILURE);
       }
     }
     
@@ -403,29 +403,29 @@
       // the string, so don't be bothered that line_cur could get to be
       // one less than line_begin.
       while (line_cur >= line_begin && *line_cur != ',')
-	line_cur--;
+        line_cur--;
       // Determine whether we have a new directory name
       if (line_cur+1 < line_cur_end) {
-	// We do, copy it over including the terminal \0
-	copy_start = line_cur+1;
-	if (*copy_start == '\"')
-	  copy_start++;
-	if (line_cur_end[-1] == '\"') {
-	  line_cur_end--;
-	  *line_cur_end = '\0';
-	}
-	memcpy(current_dirtree[current_depth],copy_start,line_cur_end-copy_start+1);
-	stop_blanking = 1;  // don't clear blank fields in the future
+        // We do, copy it over including the terminal \0
+        copy_start = line_cur+1;
+        if (*copy_start == '\"')
+          copy_start++;
+        if (line_cur_end[-1] == '\"') {
+          line_cur_end--;
+          *line_cur_end = '\0';
+        }
+        memcpy(current_dirtree[current_depth],copy_start,line_cur_end-copy_start+1);
+        stop_blanking = 1;  // don't clear blank fields in the future
       }
       else {
-	// Blank this particular field, because we don't want old
-	// subdirectories hanging around
-	if (!stop_blanking)
-	  *(current_dirtree[current_depth]) = '\0';
+        // Blank this particular field, because we don't want old
+        // subdirectories hanging around
+        if (!stop_blanking)
+          *(current_dirtree[current_depth]) = '\0';
       }
       current_depth--;
       if (line_cur >= line_begin)
-	*line_cur = '\0'; // end the processing at the comma
+        *line_cur = '\0'; // end the processing at the comma
       line_cur_end = line_cur;
     }
 
@@ -441,73 +441,73 @@
       strncpy(fullpath+len,current_dirtree[i],PATH_MAX-len);
       len = strlen(fullpath);
       if (fullpath[len-1] != '/' && len+1 < PATH_MAX) {
-	fullpath[len] = '/';  // append a slash, if need be
-	fullpath[len+1] = '\0';
+        fullpath[len] = '/';  // append a slash, if need be
+        fullpath[len+1] = '\0';
       }
     }
 
     // Create the directory
     if (strlen(fullpath) < PATH_MAX) {
       if (mkdir(fullpath,mask) < 0) {
-	// There was some kind of error, figure out what happened.
-	// Be a little more verbose than the standard library errors.
-	if (errno == EEXIST) {
-	  fprintf(stderr,"Warning: %s already exists, continuing.\n",fullpath);
-	}
-	else if (errno == ENAMETOOLONG) {
-	  fprintf(stderr,"Error: the directory name:\n  %s\nwas too long.\n",fullpath);
-	  exit(EXIT_FAILURE);
-	}
-	else if (errno == ENOENT) {
-	  fprintf(stderr,"Error: One of the upper-level directories in:\n  %s\ndoesn't exist.  Check the syntax of your configuration file.\n",fullpath);
-	  exit(EXIT_FAILURE);
-	}
-	else if (errno == ENOSPC) {
-	  fprintf(stderr,"Error: the device has no room available.\n");
-	  exit(EXIT_FAILURE);
-	}
-	else {
-	  // Fall back on the standard library for the remaining error
-	  // handling
-	  fprintf(stderr,"Error: couldn't make directory %s:\nDo you have write permission for this location?\nDo you need to be root/administrator?\n",fullpath);
-	  error(EXIT_FAILURE,errno,"error");
-	}
+        // There was some kind of error, figure out what happened.
+        // Be a little more verbose than the standard library errors.
+        if (errno == EEXIST) {
+          fprintf(stderr,"Warning: %s already exists, continuing.\n",fullpath);
+        }
+        else if (errno == ENAMETOOLONG) {
+          fprintf(stderr,"Error: the directory name:\n  %s\nwas too long.\n",fullpath);
+          exit(EXIT_FAILURE);
+        }
+        else if (errno == ENOENT) {
+          fprintf(stderr,"Error: One of the upper-level directories in:\n  %s\ndoesn't exist.  Check the syntax of your configuration file.\n",fullpath);
+          exit(EXIT_FAILURE);
+        }
+        else if (errno == ENOSPC) {
+          fprintf(stderr,"Error: the device has no room available.\n");
+          exit(EXIT_FAILURE);
+        }
+        else {
+          // Fall back on the standard library for the remaining error
+          // handling
+          fprintf(stderr,"Error: couldn't make directory %s:\nDo you have write permission for this location?\nDo you need to be root/administrator?\n",fullpath);
+          error(EXIT_FAILURE,errno,"error");
+        }
       }
       else {
-	fsync(fileno(stderr));
-	fprintf(stdout,"Creating %s\n",fullpath);
-	fsync(fileno(stdout));
+        fsync(fileno(stderr));
+        fprintf(stdout,"Creating %s\n",fullpath);
+        fsync(fileno(stdout));
 
-	// Append the name to the user_menu_entries file
-	// First we split off the last item in fullpath
-	line_begin = fullpath;
-	len = strlen(line_begin);
-	line_begin[len-1] = '\0';  // replace terminal '/' with \0
-	line_cur = line_begin + len-1;
-	while (line_cur > line_begin && *line_cur != '/')
-	  line_cur--;
-	if (line_cur > line_begin) { // as long as not making in the root directory...a bad idea anyway!
-	  *line_cur = '\0';  // Split into two strings
-	}
-	else {
-	  line_begin = "/";
-	}
-	line_cur++;   // line_cur now points to beginning of newest directory
-	strncpy(buf,line_begin,PATH_MAX);  // we don't need buf anymore
-	buf[strlen(buf)] = '/';  // append directory separator
-	len = strlen(buf);
-	strncpy(buf+len,USER_MENU_ENTRIES_FILENAME,PATH_MAX-len-strlen(USER_MENU_ENTRIES_FILENAME));
-	// Now do the appending
-	fpue = fopen(buf,"a");
-	if (!fpue) {
-	  fprintf(stderr,"Error: can't open file %s for writing.\n",buf);
-	  exit(EXIT_FAILURE);
-	}
-	len = fprintf(fpue,"%s\n",line_cur);
-	if (len != strlen(line_cur)+1) {
-	  error(EXIT_FAILURE,errno,"Error writing %s to file %s.\n",line_cur,buf);
-	}
-	fclose(fpue);
+        // Append the name to the user_menu_entries file
+        // First we split off the last item in fullpath
+        line_begin = fullpath;
+        len = strlen(line_begin);
+        line_begin[len-1] = '\0';  // replace terminal '/' with \0
+        line_cur = line_begin + len-1;
+        while (line_cur > line_begin && *line_cur != '/')
+          line_cur--;
+        if (line_cur > line_begin) { // as long as not making in the root directory...a bad idea anyway!
+          *line_cur = '\0';  // Split into two strings
+        }
+        else {
+          line_begin = "/";
+        }
+        line_cur++;   // line_cur now points to beginning of newest directory
+        strncpy(buf,line_begin,PATH_MAX);  // we don't need buf anymore
+        buf[strlen(buf)] = '/';  // append directory separator
+        len = strlen(buf);
+        strncpy(buf+len,USER_MENU_ENTRIES_FILENAME,PATH_MAX-len-strlen(USER_MENU_ENTRIES_FILENAME));
+        // Now do the appending
+        fpue = fopen(buf,"a");
+        if (!fpue) {
+          fprintf(stderr,"Error: can't open file %s for writing.\n",buf);
+          exit(EXIT_FAILURE);
+        }
+        len = fprintf(fpue,"%s\n",line_cur);
+        if (len != strlen(line_cur)+1) {
+          error(EXIT_FAILURE,errno,"Error writing %s to file %s.\n",line_cur,buf);
+        }
+        fclose(fpue);
       }
     }
     else {
@@ -538,19 +538,19 @@
 
   n_dirs = directory_crawl(path);
   success = 0;  // This will change to 1 if we find a directory of the
-		// right level
+                // right level
   for (i = 0; i < n_dirs; i++) {
     if (directory_level[i] == level) {
       // Create a blank highscores file in this directory
       strncpy(buf,directory[i],PATH_MAX);
       strncat(buf,HIGHSCORE_FILENAME,PATH_MAX-strlen(buf)-1);
       if (strlen(buf) >= PATH_MAX-1) {
-	fprintf(stderr,"confighighscores: pathname %s truncated, exiting.\n",buf);
-	exit(EXIT_FAILURE);
+        fprintf(stderr,"confighighscores: pathname %s truncated, exiting.\n",buf);
+        exit(EXIT_FAILURE);
       }
       fp = fopen(buf,"w");
       if (!fp)
-	error(EXIT_FAILURE,errno,"confighighscores: file:\n  %s",buf);
+        error(EXIT_FAILURE,errno,"confighighscores: file:\n  %s",buf);
       // That creates a blank file, which is all we have to do
       fclose(fp);
       success = 1;
@@ -597,7 +597,7 @@
       fclose(fp);
       fp = fopen(buf,"w");
       if (!fp)
-	error(EXIT_FAILURE,errno,"clearhighscores: file:\n  %s",buf);
+        error(EXIT_FAILURE,errno,"clearhighscores: file:\n  %s",buf);
       // That creates a blank file, which is all we have to do
       fclose(fp);
     }
@@ -664,30 +664,30 @@
       // Skip over white space, and especially blank lines
       line_begin = eatwhite(buf);
       if (strlen(line_begin) == 0)
-	continue;
+        continue;
       // Create the full path & filename of the user's log.csv file
       strncpy(buf2,directory[i],PATH_MAX);
       strncat(buf2,line_begin,PATH_MAX-strlen(buf2)-1);
       strncat(buf2,"/log.csv",PATH_MAX-strlen(buf2)-1);
       fplogread = fopen(buf2,"r");
       if (fplogread) {
-	// Copy the relevant lines from the user's log.csv file to the
-	// consolidated log file.  Make sure only one copy of the
-	// column names is written.
-	while(fgets(buf3, PATH_MAX, fplogread)) {
-	  line_begin = eatwhite(buf3);
-	  if (strlen(line_begin) == 0)
-	    continue;
-	  if (strncmp(line_begin,"\"User",5) == 0) {
-	    if (!column_names_written) {
-	      fprintf(fplogwrite,"%s\n",line_begin);
-	      column_names_written = 1;
-	    }
-	  } else {
-	    fprintf(fplogwrite,"%s\n",line_begin);
-	  }
-	}
-	fclose(fplogread);
+        // Copy the relevant lines from the user's log.csv file to the
+        // consolidated log file.  Make sure only one copy of the
+        // column names is written.
+        while(fgets(buf3, PATH_MAX, fplogread)) {
+          line_begin = eatwhite(buf3);
+          if (strlen(line_begin) == 0)
+            continue;
+          if (strncmp(line_begin,"\"User",5) == 0) {
+            if (!column_names_written) {
+              fprintf(fplogwrite,"%s\n",line_begin);
+              column_names_written = 1;
+            }
+          } else {
+            fprintf(fplogwrite,"%s\n",line_begin);
+          }
+        }
+        fclose(fplogread);
       }
     }
     fclose(fpusersread);
@@ -725,7 +725,7 @@
       // We found such a file, delete it
       fclose(fp);
       if (remove(buf) < 0)
-	error(EXIT_FAILURE,errno,"%s: file:\n  %s",invoke_name,buf);
+        error(EXIT_FAILURE,errno,"%s: file:\n  %s",invoke_name,buf);
     }
   }
 
@@ -758,22 +758,22 @@
       // Find the "=" sign
       tmpvalue = strchr(param_begin+strlen(varname), '=');
       if (tmpvalue == NULL)
-	continue;
+        continue;
       // Skip over the "=" sign
       tmpvalue++;
       // Skip whitespace
       while (isspace(*tmpvalue))
-	tmpvalue++;
+        tmpvalue++;
       // Eliminate any whitespace at end
       param_begin = tmpvalue;
       tmpvalue = param_begin + strlen(param_begin) - 1;
       while (tmpvalue > param_begin && isspace(*tmpvalue)) {
-	*tmpvalue = '\0';
-	tmpvalue--;
+        *tmpvalue = '\0';
+        tmpvalue--;
       }
       // Abort if empty
       if (strlen(param_begin) == 0)
-	continue;
+        continue;
       // Successful, copy the result
       *value = strdup(param_begin);
       return 1;
@@ -829,45 +829,45 @@
       // Just parse directories of the most recently-added level
       // (we've already done the work for previous levels)
       if (directory_level[i] == current_level) {
-	// Read the user_menu_entries file, if it exists
-	// Note that previous items already have "/" appended, no need
-	// to worry about that here.
-	strncpy(fullpath,directory[i],PATH_MAX);
-	strncat(fullpath,USER_MENU_ENTRIES_FILENAME,PATH_MAX-strlen(fullpath)-1);
-	fp = fopen(fullpath,"r");
-	if (fp != NULL) {
-	  // We found the user_menu_entries file, read it and add directories
-	  while (fgets (buf, PATH_MAX, fp)) {
-	    if (current_length >= MAX_USERS) {
-	      fprintf(stderr,"Error: maximum number of users exceeded.");
-	      exit(EXIT_FAILURE);
-	    }
-	    // Skip over leading & trailing white space, and
-	    // especially blank lines
-	    line_begin = eatwhite(buf);
-	    if (strlen(line_begin) == 0)
-	      continue;
+        // Read the user_menu_entries file, if it exists
+        // Note that previous items already have "/" appended, no need
+        // to worry about that here.
+        strncpy(fullpath,directory[i],PATH_MAX);
+        strncat(fullpath,USER_MENU_ENTRIES_FILENAME,PATH_MAX-strlen(fullpath)-1);
+        fp = fopen(fullpath,"r");
+        if (fp != NULL) {
+          // We found the user_menu_entries file, read it and add directories
+          while (fgets (buf, PATH_MAX, fp)) {
+            if (current_length >= MAX_USERS) {
+              fprintf(stderr,"Error: maximum number of users exceeded.");
+              exit(EXIT_FAILURE);
+            }
+            // Skip over leading & trailing white space, and
+            // especially blank lines
+            line_begin = eatwhite(buf);
+            if (strlen(line_begin) == 0)
+              continue;
 
-	    directory[current_length] = (char *) malloc((strlen(directory[i])+strlen(line_begin)+2)*sizeof(char));
-	    if (directory[current_length] == NULL) {
-	      fprintf(stderr,"Memory allocation error in directory_crawl.\n");
-	      exit(EXIT_FAILURE);
-	    }
-	    // Append each new directory to the list
-	    strcpy(directory[current_length],directory[i]);
-	    strcat(directory[current_length],line_begin);
-	    strcat(directory[current_length],"/");
-	    directory_level[current_length] = current_level+1;
-	    // Check to make sure it's valid
-	    dir = opendir(directory[current_length]);
-	    if (dir == NULL)
-	      error(EXIT_FAILURE,errno,"directory:\n %s",directory[current_length]);
-	    closedir(dir);
-	    current_length++;
-	  }
-	  isdone = 0;  // We know we need to check the subdirectories
-	  fclose(fp);
-	}  // end of: if (fp != NULL)
+            directory[current_length] = (char *) malloc((strlen(directory[i])+strlen(line_begin)+2)*sizeof(char));
+            if (directory[current_length] == NULL) {
+              fprintf(stderr,"Memory allocation error in directory_crawl.\n");
+              exit(EXIT_FAILURE);
+            }
+            // Append each new directory to the list
+            strcpy(directory[current_length],directory[i]);
+            strcat(directory[current_length],line_begin);
+            strcat(directory[current_length],"/");
+            directory_level[current_length] = current_level+1;
+            // Check to make sure it's valid
+            dir = opendir(directory[current_length]);
+            if (dir == NULL)
+              error(EXIT_FAILURE,errno,"directory:\n %s",directory[current_length]);
+            closedir(dir);
+            current_length++;
+          }
+          isdone = 0;  // We know we need to check the subdirectories
+          fclose(fp);
+        }  // end of: if (fp != NULL)
       } // end of: if (directory_level[i] == current_level)
     } // end of: loop over previous directories
     current_level++;  // We're all done parsing this level, move on

Modified: tuxmath/trunk/src/tuxmathrc.rc
===================================================================
--- tuxmath/trunk/src/tuxmathrc.rc	2008-08-05 20:35:28 UTC (rev 588)
+++ tuxmath/trunk/src/tuxmathrc.rc	2008-08-06 02:55:05 UTC (rev 589)
@@ -1,2 +1,2 @@
 #define TUXMATH_ICON                       104
-TUXMATH_ICON			ICON "../data/images/tuxmath.ico"
+TUXMATH_ICON                        ICON "../data/images/tuxmath.ico"




More information about the Tux4kids-commits mailing list