[Tux4kids-commits] r1477 - tuxmath/branches/lan/src

David Bruce dbruce-guest at alioth.debian.org
Thu Sep 3 22:06:06 UTC 2009


Author: dbruce-guest
Date: 2009-09-03 22:06:06 +0000 (Thu, 03 Sep 2009)
New Revision: 1477

Added:
   tuxmath/branches/lan/src/menu.c
   tuxmath/branches/lan/src/menu.h
   tuxmath/branches/lan/src/titlescreen.c.old
Modified:
   tuxmath/branches/lan/src/CMakeLists.txt
   tuxmath/branches/lan/src/Makefile.am
   tuxmath/branches/lan/src/SDL_extras.c
   tuxmath/branches/lan/src/SDL_extras.h
   tuxmath/branches/lan/src/SDL_rotozoom.c
   tuxmath/branches/lan/src/campaign.c
   tuxmath/branches/lan/src/convert_utf.c
   tuxmath/branches/lan/src/credits.c
   tuxmath/branches/lan/src/factoroids.c
   tuxmath/branches/lan/src/fileops.c
   tuxmath/branches/lan/src/fileops.h
   tuxmath/branches/lan/src/fileops_media.c
   tuxmath/branches/lan/src/game.c
   tuxmath/branches/lan/src/game.h
   tuxmath/branches/lan/src/globals.h
   tuxmath/branches/lan/src/highscore.c
   tuxmath/branches/lan/src/lessons.c
   tuxmath/branches/lan/src/loaders.c
   tuxmath/branches/lan/src/loaders.h
   tuxmath/branches/lan/src/mathcards.c
   tuxmath/branches/lan/src/mathcards.h
   tuxmath/branches/lan/src/multiplayer.c
   tuxmath/branches/lan/src/options.c
   tuxmath/branches/lan/src/scandir.c
   tuxmath/branches/lan/src/scandir.h
   tuxmath/branches/lan/src/setup.c
   tuxmath/branches/lan/src/titlescreen.c
   tuxmath/branches/lan/src/titlescreen.h
   tuxmath/branches/lan/src/tuxmath.c
   tuxmath/branches/lan/src/tuxmath.h
Log:
committing merged files to branch
(does not build yet)



Modified: tuxmath/branches/lan/src/CMakeLists.txt
===================================================================
--- tuxmath/branches/lan/src/CMakeLists.txt	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/CMakeLists.txt	2009-09-03 22:06:06 UTC (rev 1477)
@@ -24,6 +24,7 @@
   fileops.c
   fileops_media.c
   game.c
+  menu.c
   highscore.c
   lessons.c
   loaders.c
@@ -97,16 +98,26 @@
   set(_rsvg_cflags "${_rsvg_cflags} ${f}")
 endforeach(f)
 
+set(_cairo_cflags "")
+foreach(f ${CAIRO_CFLAGS})
+  set(_cairo_cflags "${_cairo_cflags} ${f}")
+endforeach(f)
+
 set(_rsvg_ldflags "")
 foreach(f ${RSVG_LDFLAGS})
   set(_rsvg_ldflags "${_rsvg_ldflags} ${f}")
 endforeach(f)
 
+set(_cairo_ldflags "")
+foreach(f ${CAIRO_LDFLAGS})
+  set(_cairo_ldflags "${_cairo_ldflags} ${f}")
+endforeach(f)
+
 set_target_properties (
   tuxmath
   PROPERTIES COMPILE_FLAGS
-  "-DDATA_PREFIX=\\\"${TUXMATH_DATA_PREFIX}\\\" -DVERSION=\\\"${TUXMATH_VERSION}\\\" -DLOCALEDIR=\\\"${LOCALE_DIR}\\\" -DPACKAGE=\\\"tuxmath\\\" ${_rsvg_cflags}"
-  LINK_FLAGS "${_rsvg_ldflags}"
+  "-DDATA_PREFIX=\\\"${TUXMATH_DATA_PREFIX}\\\" -DVERSION=\\\"${TUXMATH_VERSION}\\\" -DLOCALEDIR=\\\"${LOCALE_DIR}\\\" -DPACKAGE=\\\"tuxmath\\\" ${_rsvg_cflags} ${_cairo_cflags}"
+  LINK_FLAGS "${_rsvg_ldflags} ${_cairo_ldflags}"
   )
 
 target_link_libraries (tuxmath

Modified: tuxmath/branches/lan/src/Makefile.am
===================================================================
--- tuxmath/branches/lan/src/Makefile.am	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/Makefile.am	2009-09-03 22:06:06 UTC (rev 1477)
@@ -7,7 +7,7 @@
 DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
 
 AM_CFLAGS=-Wall -g -DDATA_PREFIX=\"${DATA_PREFIX}\" -DDEBUG \
-	-DVERSION=\"@NAME_VERSION@\" -D$(SOUND)SOUND
+	-D$(SOUND)SOUND
 
 AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" \
 	-I../intl -I$(top_srcdir)/intl
@@ -31,6 +31,7 @@
 tuxmath_SOURCES = tuxmath.c \
 	setup.c 	\
 	titlescreen.c	\
+	menu.c		\
 	game.c 		\
 	factoroids.c    \
 	fileops_media.c \
@@ -75,6 +76,7 @@
 	loaders.h	\
         network.h       \
 	titlescreen.h   \
+	menu.h		\
 	options.h	\
 	setup.h		\
 	mathcards.h 	\
@@ -99,7 +101,3 @@
 # How to make an RC file
 tuxmathrc.o: tuxmathrc.rc
 	$(WINDRES) -i $< -o $@
-
-
-
-

Modified: tuxmath/branches/lan/src/SDL_extras.c
===================================================================
--- tuxmath/branches/lan/src/SDL_extras.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/SDL_extras.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -19,29 +19,39 @@
 
 
 
-/* DrawButton() creates and draws a translucent button with */
-/* rounded ends.  All colors and alpha values are supported.*/
+/* DrawButton() creates a translucent button with rounded ends
+   and draws it on the screen.
+   All colors and alpha values are supported.*/
 void DrawButton(SDL_Rect* target_rect,
                 int radius,
                 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
 {
+  SDL_Surface* tmp_surf = CreateButton(target_rect->w, target_rect->h,
+                                       radius, r, g, b, a);
+  SDL_BlitSurface(tmp_surf, NULL, screen, target_rect);
+  SDL_FreeSurface(tmp_surf);
+}
+
+/* CreateButton() creates a translucent button with rounded ends
+   All colors and alpha values are supported.*/
+SDL_Surface* CreateButton(int w, int h, int radius,
+                          Uint8 r, Uint8 g, Uint8 b, Uint8 a)
+{
   /* NOTE - we use a 32-bit temp surface even if we have a 16-bit */
   /* screen - it gets converted during blitting.                  */
   SDL_Surface* tmp_surf = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
-                                          target_rect->w,
-                                          target_rect->h,
+                                          w,
+                                          h,
                                           32,
                                           rmask, gmask, bmask, amask);
+
   Uint32 color = SDL_MapRGBA(tmp_surf->format, r, g, b, a);
   SDL_FillRect(tmp_surf, NULL, color);
   RoundCorners(tmp_surf, radius);
-
-  SDL_BlitSurface(tmp_surf, NULL, screen, target_rect);
-  SDL_FreeSurface(tmp_surf);
+  return tmp_surf;
 }
 
 
-
 void RoundCorners(SDL_Surface* s, Uint16 radius)
 {
   int y = 0;
@@ -246,7 +256,7 @@
    Currently this works only with RGBA images, but this is largely to
    make the (fast) pointer arithmetic work out; it could be easily
    generalized to other image types. */
-SDL_Surface* Blend(SDL_Surface *S1,SDL_Surface *S2,float gamma)
+SDL_Surface* Blend(SDL_Surface *S1, SDL_Surface *S2, float gamma)
 {
   SDL_PixelFormat *fmt1, *fmt2;
   Uint8 r1, r2, g1, g2, b1, b2, a1, a2;
@@ -349,12 +359,40 @@
   return ret;
 }
 
+
+/* free every surface in the array together with the array itself */
+void FreeSurfaceArray(SDL_Surface** surfs, int length)
+{
+  int i;
+
+  if(surfs == NULL)
+    return;
+
+  for(i = 0; i < length; i++)
+    if(surfs[i] != NULL)
+      SDL_FreeSurface(surfs[i]);
+  free(surfs);
+}
+
 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;
 }
 
+void UpdateRect(SDL_Surface* surf, SDL_Rect* rect)
+{
+  SDL_UpdateRect(surf, rect->x, rect->y, rect->w, rect->h);
+}
+
+void SetRect(SDL_Rect* rect, const float* pos)
+{
+  rect->x = pos[0] * screen->w;
+  rect->y = pos[1] * screen->h;
+  rect->w = pos[2] * screen->w;
+  rect->h = pos[3] * screen->h;
+}
+
 /* Darkens the screen by a factor of 2^bits */
 void DarkenScreen(Uint8 bits)
 {
@@ -390,28 +428,49 @@
   }
 }
 
-
-void SwitchScreenMode(void)
+/* change window size (works only in windowed mode) */
+void ChangeWindowSize(int new_res_x, int new_res_y)
 {
-  int window = (screen->flags & SDL_FULLSCREEN);
   SDL_Surface* oldscreen = screen;
 
-  if (!window)
+  if(!(screen->flags & SDL_FULLSCREEN))
   {
-    screen = SDL_SetVideoMode(fs_res_x,
-                              fs_res_y,
+    screen = SDL_SetVideoMode(new_res_x,
+                              new_res_y,
                               PIXEL_BITS,
-                              SDL_SWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN);
-  }
-  else
-  {
-    screen = SDL_SetVideoMode(RES_X,
-                              RES_Y,
-                              PIXEL_BITS,
                               SDL_SWSURFACE|SDL_HWPALETTE);
 
+    if(screen == NULL)
+    {
+      fprintf(stderr,
+              "\nError: I could not change screen mode into %d x %d.\n",
+              new_res_x, new_res_y);
+      screen = oldscreen;
+    }
+    else
+    {
+      DEBUGMSG(debug_sdl, "ChangeWindowSize(): Changed window size to %d x %d\n", screen->w, screen->h);
+      oldscreen = NULL;
+      win_res_x = screen->w;
+      win_res_y = screen->h;
+      SDL_UpdateRect(screen, 0, 0, 0, 0);
+    }
   }
+  else
+    DEBUGMSG(debug_sdl, "ChangeWindowSize() can be run only in windowed mode !");
+}
 
+/* switch between fullscreen and windowed mode */
+void SwitchScreenMode(void)
+{
+  int window = (screen->flags & SDL_FULLSCREEN);
+  SDL_Surface* oldscreen = screen;
+
+  screen = SDL_SetVideoMode(window ? win_res_x : fs_res_x,
+                            window ? win_res_y : fs_res_y,
+                            PIXEL_BITS,
+                            screen->flags ^ SDL_FULLSCREEN);
+
   if (screen == NULL)
   {
     fprintf(stderr,
@@ -424,11 +483,11 @@
   }
   else
   {
-    SDL_FreeSurface(oldscreen);
+    //success, no need to free the old video surface
+    DEBUGMSG(debug_sdl, "Switched screen mode to %s\n", window ? "windowed" : "fullscreen");
     oldscreen = NULL;
     SDL_UpdateRect(screen, 0, 0, 0, 0);
   }
-
 }
 
 /*
@@ -477,7 +536,7 @@
   Uint8 r4, g4, b4, a4;
   Uint8 r, g, b, a;
 
-  tmdprintf("\nEntering zoom():\n");
+  DEBUGMSG(debug_sdl, "Entering zoom():\n");
 
   /* Create surface for zoom: */
 
@@ -498,9 +557,9 @@
 //    exit(1);
   }
 
-  tmdprintf("orig surface %dx%d, %d bytes per pixel\n",
+  DEBUGMSG(debug_sdl, "zoom(): orig surface %dx%d, %d bytes per pixel\n",
             src->w, src->h, src->format->BytesPerPixel);
-  tmdprintf("new surface %dx%d, %d bytes per pixel\n",
+  DEBUGMSG(debug_sdl, "zoom(): new surface %dx%d, %d bytes per pixel\n",
             s->w, s->h, s->format->BytesPerPixel);
 
   /* Now assign function pointers to correct functions based */
@@ -575,7 +634,7 @@
   SDL_UnlockSurface(s);
   SDL_UnlockSurface(src);
 
-  tmdprintf("\nLeaving zoom():\n");
+  DEBUGMSG(debug_sdl, "Leaving zoom():\n");
 
   return s;
 }
@@ -623,7 +682,7 @@
 {
 #ifdef HAVE_LIBSDL_PANGO
 
-  tmdprintf("Setup_SDL_Text() - using SDL_Pango\n");
+  DEBUGMSG(debug_sdl, "Setup_SDL_Text() - using SDL_Pango\n");
 
   SDLPango_Init();
   if (!Set_SDL_Pango_Font_Size(DEFAULT_MENU_FONT_SIZE))
@@ -635,7 +694,7 @@
 
 #else
 /* using SDL_ttf: */
-  tmdprintf("Setup_SDL_Text() - using SDL_ttf\n");
+  DEBUGMSG(debug_sdl, "Setup_SDL_Text() - using SDL_ttf\n");
 
   if (TTF_Init() < 0)
   {
@@ -704,10 +763,8 @@
     return NULL;
   }
 
-#ifdef TUXMATH_DEBUG
-  fprintf( stderr, "\nEntering BlackOutline(): \n");
-  fprintf( stderr, "BlackOutline of \"%s\"\n", t );
-#endif
+  DEBUGMSG(debug_sdl, "Entering BlackOutline():\n");
+  DEBUGMSG(debug_sdl, "BlackOutline of \"%s\"\n", t );
 
 #ifdef HAVE_LIBSDL_PANGO
   Set_SDL_Pango_Font_Size(size);
@@ -780,9 +837,7 @@
   out = SDL_DisplayFormatAlpha(bg);
   SDL_FreeSurface(bg);
 
-#ifdef TUXMATH_DEBUG
-  fprintf( stderr, "\nLeaving BlackOutline(): \n");
-#endif
+  DEBUGMSG(debug_sdl, "\nLeaving BlackOutline(): \n");
 
   return out;
 }
@@ -916,7 +971,7 @@
   {
     char buf[64];
 
-    tmdprintf("Setting font size to %d\n", size);
+    DEBUGMSG(debug_sdl, "Setting font size to %d\n", size);
 
     if(context != NULL)
       SDLPango_FreeContext(context);
@@ -1035,9 +1090,7 @@
 
   if (f)
   {
-#ifdef TUXMATH_DEBUG
-    fprintf(stderr, "LoadFont(): %s loaded successfully\n\n", fontfile);
-#endif
+    DEBUGMSG(debug_sdl, "LoadFont(): %s loaded successfully\n\n", fontfile);
     return f;
   }
   else
@@ -1048,8 +1101,3 @@
 }
 #endif
 
-
-
-
-
-

Modified: tuxmath/branches/lan/src/SDL_extras.h
===================================================================
--- tuxmath/branches/lan/src/SDL_extras.h	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/SDL_extras.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -29,22 +29,31 @@
 
 
 /* Non-text graphics functions: */
-void DrawButton(SDL_Rect* target_rect, int radius, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
-void RoundCorners(SDL_Surface* s, Uint16 radius);
-SDL_Surface* Flip(SDL_Surface *in, int x, int y);
-int  inRect(SDL_Rect r, int x, int y);
-void DarkenScreen(Uint8 bits);
-void SwitchScreenMode(void);
-SDL_EventType WaitForEvent(SDL_EventMask events);
-SDL_Surface* Blend(SDL_Surface *S1, SDL_Surface *S2,float gamma);
-SDL_Surface* zoom(SDL_Surface* src, int new_w, int new_h);
+void            DrawButton(SDL_Rect* target_rect, int radius, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
+SDL_Surface*    CreateButton(int w, int h, int radius, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
+void            RoundCorners(SDL_Surface* s, Uint16 radius);
 
+SDL_Surface*    Flip(SDL_Surface *in, int x, int y);
+SDL_Surface*    Blend(SDL_Surface *S1, SDL_Surface *S2, float gamma);
+
+void            FreeSurfaceArray(SDL_Surface** surfs, int length);
+int             inRect(SDL_Rect r, int x, int y);
+void            SetRect(SDL_Rect* rect, const float* pos);
+void            UpdateRect(SDL_Surface* surf, SDL_Rect* rect);
+
+void            DarkenScreen(Uint8 bits);
+void            ChangeWindowSize(int new_res_x, int new_res_y);
+void            SwitchScreenMode(void);
+
+SDL_EventType   WaitForEvent(SDL_EventMask events);
+SDL_Surface*    zoom(SDL_Surface* src, int new_w, int new_h);
+
 /*Text rendering functions: */
-int Setup_SDL_Text(void);
-void Cleanup_SDL_Text(void);
-SDL_Surface* BlackOutline(const char* t, int size, SDL_Color* c);
-SDL_Surface* SimpleText(const char *t, int size, SDL_Color* col);
-SDL_Surface* SimpleTextWithOffset(const char *t, int size, SDL_Color* col, int *glyph_offset);
+int             Setup_SDL_Text(void);
+void            Cleanup_SDL_Text(void);
+SDL_Surface*    BlackOutline(const char* t, int size, SDL_Color* c);
+SDL_Surface*    SimpleText(const char *t, int size, SDL_Color* col);
+SDL_Surface*    SimpleTextWithOffset(const char *t, int size, SDL_Color* col, int *glyph_offset);
 
 
 #endif

Modified: tuxmath/branches/lan/src/SDL_rotozoom.c
===================================================================
--- tuxmath/branches/lan/src/SDL_rotozoom.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/SDL_rotozoom.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -493,6 +493,10 @@
     tColorRGBA *pc, *sp;
     int gap;
 
+    c00.r = c00.g = c00.b = c00.a = 0;
+    c01.r = c01.g = c01.b = c01.a = 0;
+    c10.r = c10.g = c10.b = c10.a = 0;
+    c11.r = c11.g = c11.b = c11.a = 0;
     /*
      * Variable setup 
      */

Modified: tuxmath/branches/lan/src/campaign.c
===================================================================
--- tuxmath/branches/lan/src/campaign.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/campaign.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -64,13 +64,13 @@
       }
       else if (gameresult == GAME_OVER_ERROR)
       {
-        tmdprintf("Error!\n");
+        DEBUGMSG(debug_game, "Error!\n");
         endcampaign = 1;
       }
 #ifndef TESTING_CAMPAIGN
       else if (gameresult == GAME_OVER_ESCAPE)
       {
-        tmdprintf("hit escape\n");
+        DEBUGMSG(debug_game, "hit escape\n");
         endcampaign = 1;
       }
 #endif      
@@ -194,15 +194,15 @@
   SDL_FillRect(screen, NULL, 0);
   //TransWipe(black, RANDOM_WIPE, 10, 20);
   //show this stage's text
-  tmdprintf("Briefing\n");
+  DEBUGMSG(debug_game, "Briefing\n");
 
   SDL_BlitSurface(icon, NULL, screen, NULL);
 
   linewrap_list(briefings[stage], wrapped_lines, 40, MAX_LINES, MAX_LINEWIDTH);
   scroll_text(wrapped_lines, textarea, 1);
 
-  tmdprintf("Finished briefing\n");
-  
+  DEBUGMSG(debug_game, "Finished briefing\n");
+
   SDL_FreeSurface(loadedsprite);
   SDL_FreeSurface(icon);
 }

Modified: tuxmath/branches/lan/src/convert_utf.c
===================================================================
--- tuxmath/branches/lan/src/convert_utf.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/convert_utf.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -47,7 +47,7 @@
     return 0;
   }
 
-  tmdprintf("ConvertFromUTF8(): UTF8_word = %s\n", UTF8_word);
+  DEBUGMSG(debug_convert_utf, "ConvertFromUTF8(): UTF8_word = %s\n", UTF8_word);
 
   /* NOTE although we *should* be just able to pass "wchar_t" as the out_type, */
   /* iconv_open() segfaults on Windows if this is done - grrr....             */
@@ -64,7 +64,7 @@
   SDL_iconv_close(conv_descr);
   wcsncpy(wide_word, temp_wchar, max_length);
 
-  tmdprintf("ConvertToUTF8(): wide_word = %S\n", wide_word);
+  DEBUGMSG(debug_convert_utf, "ConvertToUTF8(): wide_word = %S\n", wide_word);
 
   return wcslen(wide_word);
 }
@@ -91,7 +91,7 @@
   size_t in_length = (size_t)UTF_BUF_LENGTH;
   size_t out_length = (size_t)UTF_BUF_LENGTH;
 
-  tmdprintf("ConvertToUTF8(): wide_word = %S\n", wide_word);
+  DEBUGMSG(debug_convert_utf, "ConvertToUTF8(): wide_word = %S\n", wide_word);
 
   if(max_length > UTF_BUF_LENGTH)
   {
@@ -116,7 +116,7 @@
   SDL_iconv_close(conv_descr);
   strncpy(UTF8_word, temp_UTF8, max_length);
 
-  tmdprintf("ConvertToUTF8(): UTF8_word = %s\n", UTF8_word);
+  DEBUGMSG(debug_convert_utf, "ConvertToUTF8(): UTF8_word = %s\n", UTF8_word);
 
   return strlen(UTF8_word);
 }

Modified: tuxmath/branches/lan/src/credits.c
===================================================================
--- tuxmath/branches/lan/src/credits.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/credits.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -105,11 +105,11 @@
   {" "},
   {N_("These rights include the freedom to study, copy, modify, and redistribute the program.")},
   {" "},
-  {N_("A full copy of the GPL is included with the documenation for this program.")},
+  {N_("A full copy of the GPL is included with the documentation for this program.")},
   {" "},
   {N_("For more information about Free Software and the GNU GPL, visit:")},
   {"http://www.fsf.org"},
-  {NULL}
+  {" "}
 };
 
 
@@ -472,7 +472,7 @@
           clearing = 1; //scroll to blank            
         }            
         else
-          tmdprintf("text[line]: %s\n", text[line]);
+          DEBUGMSG(debug_titlescreen, "text[line]: %s\n", text[line]);
       }
     }
 
@@ -583,8 +583,8 @@
   if (!str || *str == '\0')
     return;
 
-  tmdprintf("Entering draw_text(%s)\n", str);
-  
+  DEBUGMSG(debug_titlescreen, "Entering draw_text(%s)\n", str);
+
   if (str[0] == '-') //highlight text
   {
     str++;
@@ -606,6 +606,6 @@
   dest.x -= surf->w / 2; //center text
   SDL_BlitSurface(surf, NULL, screen, &dest);
   SDL_FreeSurface(surf);
-  tmdprintf("done\n");
+  DEBUGMSG(debug_titlescreen, "done\n");
 }
 #endif

Modified: tuxmath/branches/lan/src/factoroids.c
===================================================================
--- tuxmath/branches/lan/src/factoroids.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/factoroids.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -234,9 +234,7 @@
   counter = 0;
   tux_img = IMG_TUX_CONSOLE1;
 
-  #ifdef TUXMATH_DEBUG
-     fprintf(stderr, "Entering factors():\n");
-  #endif
+  DEBUGMSG(debug_factoroids, "Entering factors():\n");
 
   FF_game = FACTOROIDS_GAME;
   
@@ -316,11 +314,7 @@
   counter = 0;
   tux_img = IMG_TUX_CONSOLE1;
 
-  
-  #ifdef TUXMATH_DEBUG
-     fprintf(stderr, "Entering factors():\n");
-  #endif
-  
+  DEBUGMSG(debug_factoroids, "Entering factors():\n");
   /*****Initalizing the Factor activiy *****/
   FF_game = FRACTIONS_GAME;
 
@@ -1230,9 +1224,6 @@
   SDL_Rect dest_message;
   SDL_Event event;
 
-#ifdef TUXMATH_DEBUG
-  //print_exit_conditions();
-#endif
 
   /* TODO: need better "victory" screen with animation, special music, etc., */
   /* as well as options to review missed questions, play again using missed  */
@@ -1286,9 +1277,7 @@
 
     case GAME_OVER_ERROR:
     {
-#ifdef TUXMATH_DEBUG
-      printf("\ngame() exiting with error");
-#endif
+      DEBUGMSG(debug_factoroids, "game() exiting with error");
     }
     case GAME_OVER_LOST:
     case GAME_OVER_OTHER:
@@ -1713,9 +1702,7 @@
 
   s1 = s2 = s3 = s4 = NULL;
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "ShowMessage() - creating text\n" );
-#endif
+  DEBUGMSG(debug_factoroids, "ShowMessage() - creating text\n" );
 
   if (str1)
     s1 = BlackOutline(str1, DEFAULT_MENU_FONT_SIZE, &white);
@@ -1727,11 +1714,8 @@
   if (str4)
     s4 = BlackOutline(str4, DEFAULT_MENU_FONT_SIZE, &white);
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "ShowMessage() - drawing screen\n" );
-#endif
+  DEBUGMSG(debug_factoroids, "ShowMessage() - drawing screen\n" );
 
-
   /* Draw lines of text (do after drawing Tux so text is in front): */
   if (s1)
   {
@@ -2202,10 +2186,6 @@
   /* This SHOULD NOT HAPPEN and means we have a bug somewhere. */
  /* if (!MC_ListQuestionsLeft() && !num_comets_alive)
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nListQuestionsLeft() = %d", MC_ListQuestionsLeft());
-    printf("\nnum_comets_alive = %d", num_comets_alive);
-    #endif 
     return GAME_OVER_ERROR;
   }
   */

Modified: tuxmath/branches/lan/src/fileops.c
===================================================================
--- tuxmath/branches/lan/src/fileops.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/fileops.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -294,9 +294,7 @@
   get_user_data_dir_with_subdir(opt_path);
   strcat(opt_path, OPTIONS_FILENAME);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_user_config_file() full path to config file is: = %s\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_user_config_file() full path to config file is: = %s\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
@@ -331,11 +329,8 @@
     free(last_config_file_name);
   last_config_file_name = strdup(filename);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_named_config_file() filename is: = %s\n", filename);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_named_config_file() filename is: = %s\n", filename);
 
-
   /* First look in current working directory:  */
   getcwd(opt_path, PATH_MAX); /* get current working directory */
   /* add separating '/' unless cwd is '/' : */
@@ -345,18 +340,12 @@
   }
   strcat(opt_path, filename); /* tack on filename              */
 
+  DEBUGMSG(debug_fileops, "In read_named_config_file() checking for %s (cwd)\n", opt_path);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_named_config_file() checking for %s (cwd)\n", opt_path);
-  #endif
-
-
   fp = fopen(opt_path, "r");  /* try to open file */
   if (fp) /* file exists */
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nFound %s\n", opt_path);
-    #endif
+    DEBUGMSG(debug_fileops, "Found %s\n", opt_path);
 
     if (read_config_file(fp, USER_CONFIG_FILE))
     {
@@ -384,16 +373,12 @@
     strcat(opt_path, filename);
   }
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_named_config_file() checking for %s (abs)\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_named_config_file() checking for %s (abs)\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nFound %s\n", opt_path);
-    #endif
+    DEBUGMSG(debug_fileops, "Found %s\n", opt_path);
 
     if (read_config_file(fp, USER_CONFIG_FILE))
     {
@@ -414,16 +399,12 @@
   strcat(opt_path, "/missions/");
   strcat(opt_path, filename);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_named_config_file() checking for %s (missions)\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_named_config_file() checking for %s (missions)\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nFound %s\n", opt_path);
-    #endif
+    DEBUGMSG(debug_fileops, "Found %s\n", opt_path);
 
     if (read_config_file(fp, USER_CONFIG_FILE))
     {
@@ -443,16 +424,12 @@
   strcat(opt_path, "/missions/lessons/");
   strcat(opt_path, filename);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_named_config_file() checking for %s (missions/lessons)\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_named_config_file() checking for %s (missions/lessons)\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nFound %s\n", opt_path);
-    #endif
+    DEBUGMSG(debug_fileops, "Found %s\n", opt_path);
 
     if (read_config_file(fp, USER_CONFIG_FILE))
     {
@@ -472,16 +449,12 @@
   strcat(opt_path, "/missions/arcade/");
   strcat(opt_path, filename);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_named_config_file() checking for %s (missions/arcade)\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_named_config_file() checking for %s (missions/arcade)\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nFound %s\n", opt_path);
-    #endif
+    DEBUGMSG(debug_fileops, "Found %s\n", opt_path);
 
     if (read_config_file(fp, USER_CONFIG_FILE))
     {
@@ -501,16 +474,12 @@
   get_user_data_dir_with_subdir(opt_path);
   strcat(opt_path, filename);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_named_config_file() checking for %s (.tuxmath)\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_named_config_file() checking for %s (.tuxmath)\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nFound %s\n", opt_path);
-    #endif
+    DEBUGMSG(debug_fileops, "Found %s\n", opt_path);
 
     if (read_config_file(fp, USER_CONFIG_FILE))
     {
@@ -532,16 +501,12 @@
   strcat(opt_path, "/");
   strcat(opt_path, filename);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_named_config_file() checking for %s (home)\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_named_config_file() checking for %s (home)\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nFound %s\n", opt_path);
-    #endif
+    DEBUGMSG(debug_fileops, "Found %s\n", opt_path);
 
     if (read_config_file(fp, USER_CONFIG_FILE))
     {
@@ -557,9 +522,7 @@
   }
 
   /* Could not find file (or read it if found) in any location: */
-  #ifdef TUXMATH_DEBUG
-  printf("\nread_named_config_file() could not find/read: %s\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "read_named_config_file() could not find/read: %s\n", opt_path);
   return 0;
 }
 
@@ -596,18 +559,13 @@
     return 0;
   }
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "lesson_path is: %s\n", lesson_path);
-#endif
+  DEBUGMSG(debug_fileops, "lesson_path is: %s\n", lesson_path);
 
   /* Believe we now have complete scandir() for all platforms :) */
   num_lessons = scandir(lesson_path, &lesson_list_dirents, is_lesson_file, alphasort);
 
+  DEBUGMSG(debug_fileops, "num_lessons is: %d\n", num_lessons);
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "num_lessons is: %d\n", num_lessons);
-#endif
-
   if (num_lessons < 0) {
     perror("scanning lesson directory");
     num_lessons = 0;
@@ -642,9 +600,7 @@
     if (nchars < 0 || nchars >= NAME_BUF_SIZE)
       continue;
 
-#ifdef TUXMATH_DEBUG
-    fprintf(stderr, "Found lesson file %d:\t%s\n", lessons, lesson_list_filenames[lessons]);
-#endif
+    DEBUGMSG(debug_fileops, "Found lesson file %d:\t%s\n", lessons, lesson_list_filenames[lessons]);
 
     /* load the name for the lesson from the file ... (1st line) */
     tempFile = fopen(lesson_list_filenames[lessons], "r");
@@ -740,9 +696,7 @@
   get_user_data_dir_with_subdir(opt_path);
   strcat(opt_path, GOLDSTAR_FILENAME);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_goldstars() full path to file is: = %s\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_goldstars() full path to file is: = %s\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
@@ -776,9 +730,7 @@
   get_user_data_dir_with_subdir(opt_path);
   strcat(opt_path, GOLDSTAR_FILENAME);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn write_goldstars() full path to file is: = %s\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In write_goldstars() full path to file is: = %s\n", opt_path);
 
   fp = fopen(opt_path, "w");
   if (fp)
@@ -808,9 +760,7 @@
   get_user_data_dir_with_subdir(opt_path);
   strcat(opt_path, HIGHSCORE_FILENAME);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_high_scores() full path to file is: = %s\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_high_scores() full path to file is: = %s\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
@@ -856,9 +806,7 @@
     strncpy(opt_path,high_scores_file_path,PATH_MAX);
   strcat(opt_path, HIGHSCORE_FILENAME);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn read_high_scores() full path to file is: = %s\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In read_high_scores() full path to file is: = %s\n", opt_path);
 
   fp = fopen(opt_path, "r");
   if (fp) /* file exists */
@@ -933,9 +881,7 @@
     strncpy(opt_path,high_scores_file_path,PATH_MAX);
   strcat(opt_path, HIGHSCORE_FILENAME);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn write_high_scores() full path to file is: = %s\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In write_high_scores() full path to file is: = %s\n", opt_path);
 
   fp = fopen(opt_path, "a");
   if (fp)
@@ -1062,17 +1008,13 @@
   char buf[PATH_MAX];
   char *parameter, *param_begin, *param_end, *value, *value_end;
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nEntering read_config_file()\n");
-  #endif
+  DEBUGMSG(debug_fileops, "Entering read_config_file()\n");
 
   /* get out if file pointer invalid: */
   if(!fp)
   {
-    #ifdef TUXMATH_DEBUG
-    printf("config file pointer invalid!\n");
-    printf("Leaving read_config_file()\n");
-    #endif
+    DEBUGMSG(debug_fileops, "config file pointer invalid!\n");
+    DEBUGMSG(debug_fileops, "Leaving read_config_file()\n");
 
     fprintf(stderr, "config file pointer invalid!\n");
     return 0;
@@ -1084,9 +1026,6 @@
   /* read in a line at a time: */
   while (fgets (buf, PATH_MAX, fp))
   { 
-    #ifdef TUXMATH_DEBUG
-    //printf("Beginning fgets() loop\n");
-    #endif
     /* "parameter" and "value" will contain the non-whitespace chars */
     /* before and after the '=' sign, respectively.  e.g.:           */
     /*                                                               */
@@ -1098,9 +1037,6 @@
     /* ignore comment lines */
     if ((buf[0] == ';') || (buf[0] == '#'))
     {
-      #ifdef TUXMATH_DEBUG
-      //printf("Skipping comment line\n");
-      #endif
       continue;
     }
  
@@ -1140,10 +1076,6 @@
 
     if (!value || (value == buf))
     {
-      #ifdef TUXMATH_DEBUG
-      //fprintf(stderr, "Error while reading prefs - line with no '='!\n");
-      #endif
-
       free(parameter);
       continue;
     }
@@ -1169,8 +1101,8 @@
     /* terminate string here: */
     *value_end = 0;
 
-    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));
+    DEBUGMSG(debug_fileops, "parameter = '%s'\t, length = %zu\n", parameter, strlen(parameter));
+    DEBUGMSG(debug_fileops, "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! */
     
@@ -1413,13 +1345,12 @@
       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);
-  printf("Leaving read_config_file()\n");
-  #endif
 
+  DEBUGMSG(debug_fileops, "After file read in:\n");
+  DEBUGCODE(debug_fileops)
+    write_config_file(stdout, 0);
+  DEBUGMSG(debug_fileops, "Leaving read_config_file()\n");
+
   return 1;
 }
 
@@ -1462,9 +1393,7 @@
   get_user_data_dir_with_subdir(opt_path);
   strcat(opt_path, OPTIONS_FILENAME);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn write_user_config_file() full path to config file is: = %s\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In write_user_config_file() full path to config file is: = %s\n", opt_path);
 
   /* save settings: */
   fp = fopen(opt_path, "w");
@@ -1718,14 +1647,13 @@
     "############################################################\n\n";
     
   }
-  
-  tmdprintf("\nEntering write_config_file()\n");
+  DEBUGMSG(debug_fileops, "Entering write_config_file()\n");
 
   /* get out if file pointer null */
   if(!fp)
   {
     fprintf (stderr, "write_config_file() - file pointer invalid/n");
-    tmdprintf("Leaving write_config_file()\n");
+    DEBUGMSG(debug_fileops, "Leaving write_config_file()\n");
     return 0;
   }
   
@@ -1944,9 +1872,7 @@
   /* print options pertaining to math questions from MathCards: */
 //  MC_PrintMathOptions(fp, 1);
 
-  #ifdef TUXMATH_DEBUG
-  printf("Leaving write_config_file()\n");
-  #endif
+  DEBUGMSG(debug_fileops, "Leaving write_config_file()\n");
 
   return 1;
 }
@@ -1967,6 +1893,8 @@
   char filepath1[PATH_MAX];
   char filepath2[PATH_MAX];
 
+  DEBUGMSG(debug_fileops,"Entering write_pregame_summary.\n")
+
   /* Make sure tuxmath dir exists or can be created: */
   if (!find_tuxmath_dir())
   {
@@ -1986,9 +1914,7 @@
   fp = fopen(filepath1, "r");
   if (fp)
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nIn write_pregame_summary() - removing oldest summary file\n");
-    #endif
+    DEBUGMSG(debug_fileops,"\nIn write_pregame_summary() - removing oldest summary file\n")
 
     fclose(fp);
     remove(filepath1);
@@ -2038,10 +1964,12 @@
     fprintf(fp, "\n\nNumber of Questions: %d", MC_StartingListLength());
 
     fclose(fp);
+    DEBUGMSG(debug_fileops,"Leaving write_pregame_summary.\n")
     return 1;
   }
   else /* Couldn't write file for some reason: */
   {
+    DEBUGMSG(debug_fileops,"Can't write_pregame_summary.\n")
     return 0;
   }
 }
@@ -2168,17 +2096,13 @@
   /* find $HOME */
   get_user_data_dir_with_subdir(opt_path);
 
-  #ifdef TUXMATH_DEBUG
-  printf("\nIn find_tuxmath_dir() tuxmath dir is: = %s\n", opt_path);
-  #endif
+  DEBUGMSG(debug_fileops, "In find_tuxmath_dir() tuxmath dir is: = %s\n", opt_path);
 
   /* find out if directory exists - if not, create it: */
   dir_ptr = opendir(opt_path);
   if (dir_ptr)  /* don't leave DIR* open if it was already there */
   {
-    #ifdef TUXMATH_DEBUG
-    printf("\nIn find_tuxmath_dir() tuxmath dir opened OK\n");
-    #endif
+    DEBUGMSG(debug_fileops, "In find_tuxmath_dir() tuxmath dir opened OK\n");
 
     closedir(dir_ptr);
     return 1;
@@ -2196,17 +2120,13 @@
     fp = fopen(opt_path, "r");
     if (fp)
     {
-      #ifdef TUXMATH_DEBUG
-      printf("\nIn find_tuxmath_dir() - removing old .tuxmath file\n");
-      #endif
+      DEBUGMSG(debug_fileops, "In find_tuxmath_dir() - removing old .tuxmath file\n");
 
       fclose(fp);
       remove(opt_path);
     }
 
-    #ifdef TUXMATH_DEBUG
-    printf("\nIn find_tuxmath_dir() - trying to create .tuxmath dir\n");
-    #endif
+    DEBUGMSG(debug_fileops, "In find_tuxmath_dir() - trying to create .tuxmath dir\n");
 
     //status = mkdir(opt_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
 
@@ -2216,9 +2136,7 @@
     status = mkdir(opt_path);
 #endif
 
-    #ifdef TUXMATH_DEBUG
-    printf("\nIn find_tuxmath_dir() - mkdir returned: %d\n", status);
-    #endif
+    DEBUGMSG(debug_fileops, "In find_tuxmath_dir() - mkdir returned: %d\n", status);
 
     /* mkdir () returns 0 if successful */
     if (0 == status)

Modified: tuxmath/branches/lan/src/fileops.h
===================================================================
--- tuxmath/branches/lan/src/fileops.h	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/fileops.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -27,40 +27,13 @@
 
 /* Names for images (formerly in images.h) */
 enum {
-  IMG_STANDBY,
-  IMG_MENU_BKG,
-  IMG_MENU_TITLE,
-//  IMG_LOADING,
   IMG_TITLE,
   IMG_LEFT,
   IMG_LEFT_GRAY,
   IMG_RIGHT,
   IMG_RIGHT_GRAY,
-//  IMG_OPTIONS,
   IMG_TUX4KIDS,
   IMG_NBS,
-//  IMG_TUX_HELMET1,
-//  IMG_TUX_HELMET2,
-//  IMG_TUX_HELMET3,
-//  IMG_PLAY,
-//  IMG_CMD_OPTIONS,
-//  IMG_CMD_CREDITS,
-//  IMG_CMD_QUIT,
-/*  IMG_OPT_ADDITION,
-  IMG_OPT_SUBTRACTION,
-  IMG_OPT_MULTIPLICATION,
-  IMG_OPT_DIVISION,
-  IMG_OPT_MAX_ANSWER,
-  IMG_OPT_SPEED,
-  IMG_OPT_Q_RANGE,
-  IMG_OPT_RNG_1_5,
-  IMG_OPT_RNG_1_5_ON,
-  IMG_OPT_RNG_6_12,
-  IMG_OPT_RNG_6_12_ON,
-  IMG_OPT_RNG_13_20,
-  IMG_OPT_RNG_13_20_ON,
-  IMG_OPT_CHECK,
-  IMG_OPT_CHECK_ON,*/
   IMG_CITY_BLUE,
   IMG_CITY_BLUE_EXPL1,
   IMG_CITY_BLUE_EXPL2,
@@ -90,35 +63,9 @@
   IMG_CITY_RED_EXPL5,
   IMG_CITY_RED_DEAD,
   IMG_SHIELDS,
-  IMG_COMET1,
-  IMG_COMET2,
-  IMG_COMET3,
-  IMG_COMETEX8,
-  COMET_EXPL_END = IMG_COMETEX8,
-  IMG_COMETEX7,
-  IMG_COMETEX6,
-  IMG_COMETEX5,
-  IMG_COMETEX4,
-  IMG_COMETEX3,
-  IMG_COMETEX2,
-  IMG_COMETEX1,
-  COMET_EXPL_START = IMG_COMETEX1,
   IMG_MINI_COMET1,
   IMG_MINI_COMET2,
   IMG_MINI_COMET3,
-  IMG_BONUS_COMET1,
-  IMG_BONUS_COMET2,
-  IMG_BONUS_COMET3,
-  IMG_BONUS_COMETEX8,
-  BONUS_COMET_EXPL_END = IMG_BONUS_COMETEX8,
-  IMG_BONUS_COMETEX7,
-  IMG_BONUS_COMETEX6,
-  IMG_BONUS_COMETEX5,
-  IMG_BONUS_COMETEX4,
-  IMG_BONUS_COMETEX3,
-  IMG_BONUS_COMETEX2,
-  IMG_BONUS_COMETEX1,
-  BONUS_COMET_EXPL_START = IMG_BONUS_COMETEX1,
   IMG_NUMS,
   IMG_LEDNUMS,
   IMG_LED_NEG_SIGN,
@@ -127,7 +74,6 @@
   IMG_DEMO_SMALL,
   IMG_KEYPAD,
   IMG_KEYPAD_NO_NEG,
-//  IMG_CONSOLE,
   IMG_CONSOLE_LED,
   IMG_CONSOLE_BASH,
   IMG_TUX_CONSOLE1,
@@ -197,6 +143,15 @@
   NUM_IMAGES
 };
 
+/* Names for animated images (sprites) */
+enum {
+  IMG_COMET,
+  IMG_BONUS_COMET,
+  IMG_COMET_EXPL,
+  IMG_BONUS_COMET_EXPL,
+  NUM_SPRITES
+};
+
 /* Names for game sounds (formerly in sounds.h): */
 enum {
   SND_HARP,

Modified: tuxmath/branches/lan/src/fileops_media.c
===================================================================
--- tuxmath/branches/lan/src/fileops_media.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/fileops_media.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -22,150 +22,132 @@
   int i;
 
   static char* image_filenames[NUM_IMAGES] = {
-  DATA_PREFIX "/images/status/standby.png",
-  DATA_PREFIX "/images/title/menu_bkg.jpg",
-  DATA_PREFIX "/images/title/title1.png",
-  DATA_PREFIX "/images/status/title.png",
-  DATA_PREFIX "/images/status/left.png",
-  DATA_PREFIX "/images/status/left_gray.png",
-  DATA_PREFIX "/images/status/right.png",
-  DATA_PREFIX "/images/status/right_gray.png",
-  DATA_PREFIX "/images/status/tux4kids.png",
-  DATA_PREFIX "/images/status/nbs.png",
-  DATA_PREFIX "/images/cities/city-blue.png",
-  DATA_PREFIX "/images/cities/csplode-blue-1.png",
-  DATA_PREFIX "/images/cities/csplode-blue-2.png",
-  DATA_PREFIX "/images/cities/csplode-blue-3.png",
-  DATA_PREFIX "/images/cities/csplode-blue-4.png",
-  DATA_PREFIX "/images/cities/csplode-blue-5.png",
-  DATA_PREFIX "/images/cities/cdead-blue.png",
-  DATA_PREFIX "/images/cities/city-green.png",
-  DATA_PREFIX "/images/cities/csplode-green-1.png",
-  DATA_PREFIX "/images/cities/csplode-green-2.png",
-  DATA_PREFIX "/images/cities/csplode-green-3.png",
-  DATA_PREFIX "/images/cities/csplode-green-4.png",
-  DATA_PREFIX "/images/cities/csplode-green-5.png",
-  DATA_PREFIX "/images/cities/cdead-green.png",
-  DATA_PREFIX "/images/cities/city-orange.png",
-  DATA_PREFIX "/images/cities/csplode-orange-1.png",
-  DATA_PREFIX "/images/cities/csplode-orange-2.png",
-  DATA_PREFIX "/images/cities/csplode-orange-3.png",
-  DATA_PREFIX "/images/cities/csplode-orange-4.png",
-  DATA_PREFIX "/images/cities/csplode-orange-5.png",
-  DATA_PREFIX "/images/cities/cdead-orange.png",
-  DATA_PREFIX "/images/cities/city-red.png",
-  DATA_PREFIX "/images/cities/csplode-red-1.png",
-  DATA_PREFIX "/images/cities/csplode-red-2.png",
-  DATA_PREFIX "/images/cities/csplode-red-3.png",
-  DATA_PREFIX "/images/cities/csplode-red-4.png",
-  DATA_PREFIX "/images/cities/csplode-red-5.png",
-  DATA_PREFIX "/images/cities/cdead-red.png",
-  DATA_PREFIX "/images/cities/shields.png",
-  DATA_PREFIX "/images/comets/comet1.png",
-  DATA_PREFIX "/images/comets/comet2.png",
-  DATA_PREFIX "/images/comets/comet3.png",
-  DATA_PREFIX "/images/comets/cometex3.png",
-  DATA_PREFIX "/images/comets/cometex3.png",
-  DATA_PREFIX "/images/comets/cometex2.png",
-  DATA_PREFIX "/images/comets/cometex2.png",
-  DATA_PREFIX "/images/comets/cometex1a.png",
-  DATA_PREFIX "/images/comets/cometex1a.png",
-  DATA_PREFIX "/images/comets/cometex1.png",
-  DATA_PREFIX "/images/comets/cometex1.png",
-  DATA_PREFIX "/images/comets/mini_comet1.png",
-  DATA_PREFIX "/images/comets/mini_comet2.png",
-  DATA_PREFIX "/images/comets/mini_comet3.png",
-  DATA_PREFIX "/images/comets/bonus_comet1.png",
-  DATA_PREFIX "/images/comets/bonus_comet2.png",
-  DATA_PREFIX "/images/comets/bonus_comet3.png",
-  DATA_PREFIX "/images/comets/bonus_cometex3.png",
-  DATA_PREFIX "/images/comets/bonus_cometex3.png",
-  DATA_PREFIX "/images/comets/bonus_cometex2.png",
-  DATA_PREFIX "/images/comets/bonus_cometex2.png",
-  DATA_PREFIX "/images/comets/bonus_cometex1a.png",
-  DATA_PREFIX "/images/comets/bonus_cometex1a.png",
-  DATA_PREFIX "/images/comets/bonus_cometex1.png",
-  DATA_PREFIX "/images/comets/bonus_cometex1.png",
-  DATA_PREFIX "/images/status/nums.png",
-  DATA_PREFIX "/images/status/lednums.png",
-  DATA_PREFIX "/images/status/led_neg_sign.png",
-  DATA_PREFIX "/images/status/paused.png",
-  DATA_PREFIX "/images/status/demo.png",
-  DATA_PREFIX "/images/status/demo-small.png",
-  DATA_PREFIX "/images/status/keypad.png",
-  DATA_PREFIX "/images/status/keypad_no_neg.png",
-  DATA_PREFIX "/images/tux/console_led.png",
-  DATA_PREFIX "/images/tux/console_bash.png",
-  DATA_PREFIX "/images/tux/tux-console1.png",
-  DATA_PREFIX "/images/tux/tux-console2.png",
-  DATA_PREFIX "/images/tux/tux-console3.png",
-  DATA_PREFIX "/images/tux/tux-console4.png",
-  DATA_PREFIX "/images/tux/tux-relax1.png",
-  DATA_PREFIX "/images/tux/tux-relax2.png",
-  DATA_PREFIX "/images/tux/tux-egypt1.png",
-  DATA_PREFIX "/images/tux/tux-egypt2.png",
-  DATA_PREFIX "/images/tux/tux-egypt3.png",
-  DATA_PREFIX "/images/tux/tux-egypt4.png",
-  DATA_PREFIX "/images/tux/tux-drat.png",
-  DATA_PREFIX "/images/tux/tux-yipe.png",
-  DATA_PREFIX "/images/tux/tux-yay1.png",
-  DATA_PREFIX "/images/tux/tux-yay2.png",
-  DATA_PREFIX "/images/tux/tux-yes1.png",
-  DATA_PREFIX "/images/tux/tux-yes2.png",
-  DATA_PREFIX "/images/tux/tux-sit.png",
-  DATA_PREFIX "/images/tux/tux-fist1.png",
-  DATA_PREFIX "/images/tux/tux-fist2.png",
-  DATA_PREFIX "/images/penguins/flapdown.png",
-  DATA_PREFIX "/images/penguins/flapup.png",
-  DATA_PREFIX "/images/penguins/incoming.png",
-  DATA_PREFIX "/images/penguins/grumpy.png",
-  DATA_PREFIX "/images/penguins/worried.png",
-  DATA_PREFIX "/images/penguins/standing-up.png",
-  DATA_PREFIX "/images/penguins/sitting-down.png",
-  DATA_PREFIX "/images/penguins/walk-on1.png",
-  DATA_PREFIX "/images/penguins/walk-on2.png",
-  DATA_PREFIX "/images/penguins/walk-on3.png",
-  DATA_PREFIX "/images/penguins/walk-off1.png",
-  DATA_PREFIX "/images/penguins/walk-off2.png",
-  DATA_PREFIX "/images/penguins/walk-off3.png",
-  DATA_PREFIX "/images/igloos/melted3.png",
-  DATA_PREFIX "/images/igloos/melted2.png",
-  DATA_PREFIX "/images/igloos/melted1.png",
-  DATA_PREFIX "/images/igloos/half.png",
-  DATA_PREFIX "/images/igloos/intact.png",
-  DATA_PREFIX "/images/igloos/rebuilding1.png",
-  DATA_PREFIX "/images/igloos/rebuilding2.png",
-  DATA_PREFIX "/images/igloos/steam1.png",
-  DATA_PREFIX "/images/igloos/steam2.png",
-  DATA_PREFIX "/images/igloos/steam3.png",
-  DATA_PREFIX "/images/igloos/steam4.png",
-  DATA_PREFIX "/images/igloos/steam5.png",
-  DATA_PREFIX "/images/igloos/cloud.png",
-  DATA_PREFIX "/images/igloos/snow1.png",
-  DATA_PREFIX "/images/igloos/snow2.png",
-  DATA_PREFIX "/images/igloos/snow3.png",
-  DATA_PREFIX "/images/igloos/extra_life.png",
-  DATA_PREFIX "/images/status/wave.png",
-  DATA_PREFIX "/images/status/score.png",
-  DATA_PREFIX "/images/status/stop.png",
-  DATA_PREFIX "/images/status/numbers.png",
-  DATA_PREFIX "/images/status/gameover.png",
-  DATA_PREFIX "/images/status/gameover_won.png",
-  DATA_PREFIX "/images/factoroids/gbstars.png",
-  DATA_PREFIX "/images/factoroids/asteroid1.png",
-  DATA_PREFIX "/images/factoroids/asteroid2.png",
-  DATA_PREFIX "/images/factoroids/asteroid3.png",
-  DATA_PREFIX "/images/factoroids/ship01.png",
-  DATA_PREFIX "/images/factoroids/factoroids.png",
-  DATA_PREFIX "/images/factoroids/factors.png",
-  DATA_PREFIX "/images/factoroids/tux.png",
-  DATA_PREFIX "/images/factoroids/good.png"
+  "status/title.png",
+  "status/left.png",
+  "status/left_gray.png",
+  "status/right.png",
+  "status/right_gray.png",
+  "status/tux4kids.png",
+  "status/nbs.png",
+  "cities/city-blue.png",
+  "cities/csplode-blue-1.png",
+  "cities/csplode-blue-2.png",
+  "cities/csplode-blue-3.png",
+  "cities/csplode-blue-4.png",
+  "cities/csplode-blue-5.png",
+  "cities/cdead-blue.png",
+  "cities/city-green.png",
+  "cities/csplode-green-1.png",
+  "cities/csplode-green-2.png",
+  "cities/csplode-green-3.png",
+  "cities/csplode-green-4.png",
+  "cities/csplode-green-5.png",
+  "cities/cdead-green.png",
+  "cities/city-orange.png",
+  "cities/csplode-orange-1.png",
+  "cities/csplode-orange-2.png",
+  "cities/csplode-orange-3.png",
+  "cities/csplode-orange-4.png",
+  "cities/csplode-orange-5.png",
+  "cities/cdead-orange.png",
+  "cities/city-red.png",
+  "cities/csplode-red-1.png",
+  "cities/csplode-red-2.png",
+  "cities/csplode-red-3.png",
+  "cities/csplode-red-4.png",
+  "cities/csplode-red-5.png",
+  "cities/cdead-red.png",
+  "cities/shields.png",
+  "comets/mini_comet1.png",
+  "comets/mini_comet2.png",
+  "comets/mini_comet3.png",
+  "status/nums.png",
+  "status/lednums.png",
+  "status/led_neg_sign.png",
+  "status/paused.png",
+  "status/demo.png",
+  "status/demo-small.png",
+  "status/keypad.png",
+  "status/keypad_no_neg.png",
+  "tux/console_led.png",
+  "tux/console_bash.png",
+  "tux/tux-console1.png",
+  "tux/tux-console2.png",
+  "tux/tux-console3.png",
+  "tux/tux-console4.png",
+  "tux/tux-relax1.png",
+  "tux/tux-relax2.png",
+  "tux/tux-egypt1.png",
+  "tux/tux-egypt2.png",
+  "tux/tux-egypt3.png",
+  "tux/tux-egypt4.png",
+  "tux/tux-drat.png",
+  "tux/tux-yipe.png",
+  "tux/tux-yay1.png",
+  "tux/tux-yay2.png",
+  "tux/tux-yes1.png",
+  "tux/tux-yes2.png",
+  "tux/tux-sit.png",
+  "tux/tux-fist1.png",
+  "tux/tux-fist2.png",
+  "penguins/flapdown.png",
+  "penguins/flapup.png",
+  "penguins/incoming.png",
+  "penguins/grumpy.png",
+  "penguins/worried.png",
+  "penguins/standing-up.png",
+  "penguins/sitting-down.png",
+  "penguins/walk-on1.png",
+  "penguins/walk-on2.png",
+  "penguins/walk-on3.png",
+  "penguins/walk-off1.png",
+  "penguins/walk-off2.png",
+  "penguins/walk-off3.png",
+  "igloos/melted3.png",
+  "igloos/melted2.png",
+  "igloos/melted1.png",
+  "igloos/half.png",
+  "igloos/intact.png",
+  "igloos/rebuilding1.png",
+  "igloos/rebuilding2.png",
+  "igloos/steam1.png",
+  "igloos/steam2.png",
+  "igloos/steam3.png",
+  "igloos/steam4.png",
+  "igloos/steam5.png",
+  "igloos/cloud.png",
+  "igloos/snow1.png",
+  "igloos/snow2.png",
+  "igloos/snow3.png",
+  "igloos/extra_life.png",
+  "status/wave.png",
+  "status/score.png",
+  "status/stop.png",
+  "status/numbers.png",
+  "status/gameover.png",
+  "status/gameover_won.png",
+  "factoroids/gbstars.png",
+  "factoroids/asteroid1.png",
+  "factoroids/asteroid2.png",
+  "factoroids/asteroid3.png",
+  "factoroids/ship01.png",
+  "factoroids/factoroids.png",
+  "factoroids/factors.png",
+  "factoroids/tux.png",
+  "factoroids/good.png"
   };
 
-  /* Load images: */
+  static char* sprite_filenames[NUM_IMAGES] = {
+  "comets/comet",
+  "comets/bonus_comet",
+  "comets/cometex",
+  "comets/bonus_cometex"
+  };
+
+  /* Load static images: */
   for (i = 0; i < NUM_IMAGES; i++)
   {
-    images[i] = LoadImageFromFile(image_filenames[i]);
+    images[i] = LoadImage(image_filenames[i], IMG_ALPHA);
 
     if (images[i] == NULL)
     {
@@ -178,9 +160,26 @@
     }
   }
 
+  /* Load animated graphics: */
+  for (i = 0; i < NUM_SPRITES; i++)
+  {
+    sprites[i] = LoadSprite(sprite_filenames[i], IMG_ALPHA);
+
+    if (sprites[i] == NULL)
+    {
+      fprintf(stderr,
+              "\nError: I couldn't load a graphics file:\n"
+              "%s\n"
+              "The Simple DirectMedia error that occured was:\n"
+              "%s\n\n", sprite_filenames[i], SDL_GetError());
+      return 0;
+    }
+  }
+
+
   glyph_offset = 0;
 
-#ifdef REPLACE_WAVESCORE  
+#ifdef REPLACE_WAVESCORE
   /* Replace the "WAVE" and "SCORE" with translate-able versions */
   SDL_FreeSurface(images[IMG_WAVE]);
   images[IMG_WAVE] = SimpleTextWithOffset(_("WAVE"), 28, &white, &glyph_offset);

Modified: tuxmath/branches/lan/src/game.c
===================================================================
--- tuxmath/branches/lan/src/game.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/game.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -221,10 +221,8 @@
 /******************************************************/
 
 
-#ifdef TUXMATH_DEBUG
 static void print_exit_conditions(void);
 static void print_status(void);
-#endif
 
 
 /* --- MAIN GAME FUNCTION!!! --- */
@@ -232,11 +230,10 @@
 
 int game(void)
 {
-//  Uint32 last_time, now_time;
   char buf[NET_BUF_LEN];
   char command[NET_BUF_LEN];
 
-  tmdprintf("Entering game():\n");
+  DEBUGMSG(debug_game, "Entering game():\n");
 
   //see if the option matches the actual screen
   if (Opts_GetGlobalOpt(FULLSCREEN) == !(screen->flags & SDL_FULLSCREEN) )
@@ -345,9 +342,7 @@
   while(GAME_IN_PROGRESS == game_status);
   /* END OF MAIN GAME LOOP! */
 
-#ifdef TUXMATH_DEBUG
-  print_exit_conditions();
-#endif
+  DEBUGCODE(debug_game) print_exit_conditions();
 
   /* TODO: need better "victory" screen with animation, special music, etc., */
   /* as well as options to review missed questions, play again using missed  */
@@ -427,11 +422,7 @@
     }
 
     case GAME_OVER_ERROR:
-    {
-#ifdef TUXMATH_DEBUG
-      printf("\ngame() exiting with error");
-#endif
-    }
+      DEBUGMSG(debug_game, "game() exiting with error:\n");
     case GAME_OVER_LOST:
     case GAME_OVER_OTHER:
     {
@@ -706,10 +697,10 @@
 void game_set_start_message(const char* m1, const char* m2, 
                             const char* m3, const char* m4)
 {
-  game_set_message(&s1, m1, -1, RES_Y * 2 / 10);
-  game_set_message(&s2, m2, screen->w / 2 - 40, RES_Y * 3 / 10);
-  game_set_message(&s3, m3, screen->w / 2 - 40, RES_Y * 4 / 10);
-  game_set_message(&s4, m4, screen->w / 2 - 40, RES_Y * 5 / 10);
+  game_set_message(&s1, m1, -1, screen->h * 2 / 10);
+  game_set_message(&s2, m2, screen->w / 2 - 40, screen->h * 3 / 10);
+  game_set_message(&s3, m3, screen->w / 2 - 40, screen->h * 4 / 10);
+  game_set_message(&s4, m4, screen->w / 2 - 40, screen->h * 5 / 10);
   start_message_chosen = 1;
 }
 
@@ -719,8 +710,8 @@
 {
   int i,img;
   
-  tmdprintf("Entering game_initialize()\n");
-
+  DEBUGMSG(debug_game,"Entering game_initialize()\n");
+  
   /* Clear window: */
   SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
   SDL_Flip(screen);
@@ -745,12 +736,12 @@
 
   if(!Opts_LanMode())
   {
-    tmdprintf("Calling MC_StartGame()\n");
     if (!MC_StartGame())
     {
       fprintf(stderr, "\nMC_StartGame() failed!");
       return 0;
     }
+    DEBUGMSG(debug_mathcards | debug_game,"MC_StartGame() finished.\n")
   }
 
   /* Start out with our "comets" empty: */
@@ -786,7 +777,8 @@
       }
     }
   }
-  
+  DEBUGMSG(debug_game,"Flashcards allocated.\n");
+   
   cities = (city_type *) malloc(NUM_CITIES * sizeof(city_type));
   if (cities == NULL)
   {
@@ -881,8 +873,9 @@
   if (Opts_BonusCometInterval())
   {
     bonus_comet_counter = Opts_BonusCometInterval() + 1;
-    tmdprintf("\nInitializing with bonus_comet_counter = %d\n",bonus_comet_counter);
+    DEBUGMSG(debug_game,"\nInitializing with bonus_comet_counter = %d\n",bonus_comet_counter);
   }
+
   extra_life_earned = 0;
   cloud.status = EXTRA_LIFE_OFF;
 
@@ -957,7 +950,7 @@
   }
 #endif
 
-  tmdprintf("Leaving game():\n");
+  DEBUGMSG(debug_game, "Leaving game():\n");
 }
 
 
@@ -1052,7 +1045,7 @@
 
   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
+  while ((comets[0].expl == -1) && !(quit_help = help_renderframe_exit()));  // wait 3 secs
   if (quit_help)
     return;
   game_set_message(&s4,_("Notice the answer"),left_edge,comets[0].y-100);
@@ -1180,7 +1173,7 @@
 //  char ansstr[MC_ANSWER_LEN];
 
   comets[0].alive = 1;
-  comets[0].expl = 0;
+  comets[0].expl = -1;
   comets[0].answer = atoi(ans_str);
   num_comets_alive = 1;
   comets[0].city = 0;
@@ -1293,7 +1286,7 @@
     picked_comet = (rand() % MAX_COMETS);
 
     if (!(comets[picked_comet].alive &&
-          comets[picked_comet].expl < COMET_EXPL_END)
+          comets[picked_comet].expl == -1)
         || comets[picked_comet].y < 80)
     {
       picked_comet = -1;
@@ -1305,9 +1298,8 @@
       if ((rand() % 3) < 1)
         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);
-      #endif
+      DEBUGMSG(debug_game, "Demo mode, comet %d attacked with answer %d\n", picked_comet,demo_answer);
+
       /* handle negative answer: */
       if (demo_answer < 0)
       {
@@ -1351,9 +1343,8 @@
     else
     {
       /* "Press Return" */
-      #ifdef TUXMATH_DEBUG
-      printf("Demo mode firing with these digits: %d%d%d\n",digits[0],digits[1],digits[2]);
-      #endif
+      DEBUGMSG(debug_game, "Demo mode firing with these digits: %d%d%d\n",
+               digits[0], digits[1], digits[2]);
       doing_answer = 1;
       picked_comet = -1;
     }
@@ -1394,9 +1385,8 @@
 
   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].expl == -1 &&
         //comets[i].answer == num &&
         0 == strncmp(comets[i].flashcard.answer_string, ans, MC_MAX_DIGITS+1) &&
         comets[i].y > lowest_y)
@@ -1434,7 +1424,7 @@
 
 
     /* Destroy comet: */
-    comets[lowest].expl = COMET_EXPL_START;
+    comets[lowest].expl = 0;
     comets[lowest].zapped = 1;
     /* Fire laser: */
     laser.alive = LASER_START;
@@ -1597,12 +1587,12 @@
       if (comets[i].bonus)
       {
         comets[i].y += speed * Opts_BonusSpeedRatio() *
-                       city_expl_height / (RES_Y - images[IMG_CITY_BLUE]->h);
+                       city_expl_height / (screen->h - images[IMG_CITY_BLUE]->h);
       }
       else /* Regular comet: */
       {
         comets[i].y += speed *
-                       city_expl_height / (RES_Y - images[IMG_CITY_BLUE]->h);
+                       city_expl_height / (screen->h - images[IMG_CITY_BLUE]->h);
       }
 
       /* Does it threaten a city? */
@@ -1611,7 +1601,7 @@
 
       /* Did it hit a city? */
       if (comets[i].y >= city_expl_height &&
-          comets[i].expl < COMET_EXPL_END)
+          comets[i].expl == -1)
       {
         /* Tell MathCards about it - question not answered correctly: */
         if(Opts_LanMode())
@@ -1689,27 +1679,24 @@
         tux_anim_frame = ANIM_FRAME_START;
 
         /* Destroy comet: */
-        comets[i].expl = COMET_EXPL_START;
+        comets[i].expl = 0;
       }
 
       /* Handle comet explosion animation: */
-      if (comets[i].expl >= COMET_EXPL_END)
+      if (comets[i].expl >= 0)
       {
-        comets[i].expl--;
-        if (comets[i].expl < COMET_EXPL_END) {
+        comets[i].expl++;
+        if (comets[i].expl >= sprites[IMG_COMET_EXPL]->num_frames * 2) {
           comets[i].alive = 0;
+          comets[i].expl = -1;
           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);
-#endif
+            DEBUGMSG(debug_game, "bonus_comet_counter is now %d\n",bonus_comet_counter);
           }
           if (comets[i].bonus && comets[i].zapped) {
             playsound(SND_EXTRA_LIFE);
             extra_life_earned = 1;
-#ifdef TUXMATH_DEBUG
-            printf("\nExtra life earned!");
-#endif
+            DEBUGMSG(debug_game, "Extra life earned!");
           }
         }
       }
@@ -1978,9 +1965,9 @@
 
   if (cloud.status == EXTRA_LIFE_ON)
     return 1;
-#ifdef TUXMATH_DEBUG
-  print_status();
-#endif
+  DEBUGCODE(debug_game)
+    print_status();
+    
   if (extra_life_earned) {
     /* Check to see if any ingloo has been hit */
     fewest_hits_left = 2;
@@ -1999,9 +1986,9 @@
     cloud.y = screen->h/3;
     cloud.city = fewest_index;
     bonus_comet_counter = Opts_BonusCometInterval()+1;
-#ifdef TUXMATH_DEBUG
-    printf("\nBonus comet counter restored to %d\n",bonus_comet_counter);
-#endif
+    
+    DEBUGMSG(debug_game, "Bonus comet counter restored to %d\n",bonus_comet_counter);
+
     if (cloud.city < NUM_CITIES/2)
       cloud.x = -images[IMG_CLOUD]->w/2;  /* come in from the left */
     else
@@ -2014,27 +2001,29 @@
       cloud.snowflake_x[i] = - snow_width/2  + (rand() % snow_width);
       cloud.snowflake_size[i] = rand() % 3;
     }
-#ifdef TUXMATH_DEBUG
-    print_status();
-#endif
+    DEBUGCODE(debug_game)
+      print_status();
     return 1;
-  } else
+  }
+  else
     return 0;
 }
 
+
 void game_handle_extra_life(void)
 {
   // This handles the animation sequence during the rebuilding of an igloo
-  int i,igloo_top,num_below_igloo,direction;
+  int i, igloo_top, num_below_igloo, direction;
 
   if (cloud.status == EXTRA_LIFE_ON) {
 
-#ifdef TUXMATH_DEBUG
-     if (penguins[cloud.city].status == PENGUIN_WALKING_OFF) {
-       print_status();
-       pause_game();
-     }
-#endif
+    DEBUGCODE(debug_game)
+    {
+      if (penguins[cloud.city].status == PENGUIN_WALKING_OFF) {
+        print_status();
+        pause_game();
+      }
+    }
 
     // Get the cloud moving in the right direction, if not yet "parked"
     direction = 2*(cloud.city < NUM_CITIES/2) - 1;
@@ -2143,13 +2132,13 @@
     fgcolor = SDL_MapRGB(screen->format, 64, 96, 64);
   if (old_wave != wave)
   {
-    tmdprintf("Wave %d\n", wave);
+    DEBUGMSG(debug_game,"Wave %d\n", wave);
     old_wave = wave;
     bgcolor = SDL_MapRGB(screen->format,
                          64,
                          64 + ((wave * 32) % 192),
                          128 - ((wave * 16) % 128) );
-    tmdprintf("Filling screen with color %d\n", bgcolor);
+    DEBUGMSG(debug_game,"Filling screen with color %d\n", bgcolor);
   }
 
   if (current_bkgd() == NULL || (current_bkgd()->w != screen->w && 
@@ -2183,7 +2172,8 @@
 void game_draw_comets(void)
 {
 
-  int i, img;
+  int i;
+  SDL_Surface* img = NULL;
   SDL_Rect dest;
   char* comet_str;
 
@@ -2192,10 +2182,10 @@
   {
     if (comets[i].alive && !comets[i].bonus)
     {
-      if (comets[i].expl < COMET_EXPL_END)
+      if (comets[i].expl == -1)
       {
         /* Decide which image to display: */
-        img = IMG_COMET1 + ((frame + i) % 3);
+        img = sprites[IMG_COMET]->frame[(frame + i) % sprites[IMG_COMET]->num_frames];
         /* Display the formula (flashing, in the bottom half
                    of the screen) */
         if (comets[i].y < screen->h / 2 || frame % 8 < 6)
@@ -2209,17 +2199,18 @@
       }
       else
       {
-        img = comets[i].expl;
+        /* show each frame of explosion twice */
+        img = sprites[IMG_COMET_EXPL]->frame[comets[i].expl / 2];
         comet_str = comets[i].flashcard.answer_string;
       }
 
       /* Draw it! */
-      dest.x = comets[i].x - (images[img]->w / 2);
-      dest.y = comets[i].y - images[img]->h;
-      dest.w = images[img]->w;
-      dest.h = images[img]->h;
+      dest.x = comets[i].x - (img->w / 2);
+      dest.y = comets[i].y - img->h;
+      dest.w = img->w;
+      dest.h = img->h;
 
-      SDL_BlitSurface(images[img], NULL, screen, &dest);
+      SDL_BlitSurface(img, NULL, screen, &dest);
       if (comet_str != NULL)
       {
         draw_nums(comet_str, comets[i].x, comets[i].y);
@@ -2232,10 +2223,10 @@
   {
     if (comets[i].alive && comets[i].bonus)
     {
-      if (comets[i].expl < COMET_EXPL_END)
+      if (comets[i].expl == -1)
       {
         /* Decide which image to display: */
-        img = IMG_COMET1 + ((frame + i) % 3);
+        img = sprites[IMG_BONUS_COMET]->frame[(frame + i) % sprites[IMG_BONUS_COMET]->num_frames];
         /* Display the formula (flashing, in the bottom half
                    of the screen) */
         if (comets[i].y < screen->h / 2 || frame % 8 < 6)
@@ -2249,31 +2240,26 @@
       }
       else
       {
-        img = comets[i].expl;
+        img = sprites[IMG_BONUS_COMET_EXPL]->frame[comets[i].expl / 2];
         comet_str = comets[i].flashcard.answer_string;
       }
 
-      /* Move images[] index to bonus range: */
-      img += IMG_BONUS_COMET1 - IMG_COMET1;
-
       /* Draw it! */
-      dest.x = comets[i].x - (images[img]->w / 2);
-      dest.y = comets[i].y - images[img]->h;
-      dest.w = images[img]->w;
-      dest.h = images[img]->h;
-
-      SDL_BlitSurface(images[img], NULL, screen, &dest);
+      dest.x = comets[i].x - (img->w / 2);
+      dest.y = comets[i].y - img->h;
+      dest.w = img->w;
+      dest.h = img->h;
+      SDL_BlitSurface(img, NULL, screen, &dest);
       if (comet_str != NULL)
       {
         draw_nums(comet_str, comets[i].x, comets[i].y);
       }
     }
   }
+}
 
 
 
-}
-
 void game_draw_cities(void)
 {
   int i, j, current_layer, max_layer;
@@ -2486,10 +2472,18 @@
   {
     for (i = 0; i < mp_get_parameter(PLAYERS); ++i)
     {
+      SDL_Surface* score;
       snprintf(str, 64, "%s: %d", mp_get_player_name(i),mp_get_player_score(i));
-      SDL_Surface* score = BlackOutline(str, DEFAULT_MENU_FONT_SIZE, &white);
-      SDL_Rect loc = {screen->w - score->w, score->h * (i + 2), 0, 0};
-      SDL_BlitSurface(score, NULL, screen, &loc);
+      score = BlackOutline(str, DEFAULT_MENU_FONT_SIZE, &white);
+      if(score)
+      {
+        SDL_Rect loc;
+        loc.w = screen->w - score->w;
+        loc.h = score->h * (i + 2);
+        loc.x = 0;
+        loc.y = 0;
+        SDL_BlitSurface(score, NULL, screen, &loc);
+      }
     }
   }
   
@@ -2514,8 +2508,8 @@
         user_quit_received != GAME_OVER_ESCAPE &&
         user_quit_received != GAME_OVER_CHEATER)
     {
-    	 tmdprintf("Unexpected value %d for user_quit_received\n", user_quit_received);
-    	 return GAME_OVER_OTHER;
+      fprintf(stderr, "Unexpected value %d for user_quit_received\n", user_quit_received);
+      return GAME_OVER_OTHER;
     }
     return user_quit_received;    
   }
@@ -2540,7 +2534,7 @@
     // Should not get here!
     if (MC_MissionAccomplished())
     {
-      tmdprintf("Mission accomplished!\n");
+      DEBUGMSG(debug_game,"Mission accomplished!\n");
       return GAME_OVER_WON;
     }
 #endif
@@ -2549,7 +2543,7 @@
   {
     if (MC_MissionAccomplished())
     {
-      tmdprintf("Mission accomplished!\n");
+      DEBUGMSG(debug_game,"Mission accomplished!\n");
       return GAME_OVER_WON;
     }
   }
@@ -2580,19 +2574,15 @@
   /* Need to get out if no comets alive and MathCards has no questions left in list, */
   /* even though MathCards thinks there are still questions "in play".  */
   /* This SHOULD NOT HAPPEN and means we have a bug somewhere. */
-//  if (!MC_ListQuestionsLeft() && !num_comets_alive)
-//  {
-//    #ifdef TUXMATH_DEBUG
-//    printf("\nListQuestionsLeft() = %d", MC_ListQuestionsLeft());
-//    printf("\nnum_comets_alive = %d", num_comets_alive);
-//    #endif
-//    return GAME_OVER_ERROR;
-//  }
+  if (!MC_ListQuestionsLeft() && !num_comets_alive)
+  {
+    fprintf(stderr("Error - no questions left but game not over\n");
+    DEBUGMSG(debug_game, "ListQuestionsLeft() = %d ", MC_ListQuestionsLeft());
+    DEBUGMSG(debug_game, "num_comets_alive = %d", num_comets_alive);
+    return GAME_OVER_ERROR;
+  }
    
-   
-
-
-  /* If using demo mode, see if counter has run out: */
+   /* If using demo mode, see if counter has run out: */
   if (Opts_DemoMode())
   {
     if (demo_countdown <= 0 )
@@ -2603,7 +2593,7 @@
   return GAME_IN_PROGRESS;
 }
 
-#ifdef TUXMATH_DEBUG
+
 void print_exit_conditions(void)
 {
   printf("\ngame_status:\t");
@@ -2653,8 +2643,8 @@
     }
   }
 }
-#endif
 
+
 /* Reset stuff for the next level! */
 void reset_level(void)
 {
@@ -2877,7 +2867,7 @@
 
     if(i == TEST_COMETS)
     {
-      tmdprintf("add_comet() called but no question available in queue\n");
+      DEBUGMSG("add_comet() called but no question available in queue\n");
       return 0;
     } 
 #else
@@ -2897,9 +2887,13 @@
       return 0;
     }
   }
-  printf("In add_comet(), card is\n");
-  print_card(comets[found].flashcard);
 
+  DEBUGCODE(debug_game)
+  {
+    printf("In add_comet(), card is\n");
+    print_card(comets[found].flashcard);
+  }
+  
   /* Make sure question is "sane" before we add it: */
   if( (comets[found].flashcard.answer > 999)
     ||(comets[found].flashcard.answer < -999))
@@ -2912,7 +2906,6 @@
   /* If we make it to here, create a new comet!*/
   comets[found].answer = comets[found].flashcard.answer;
   comets[found].alive = 1;
-  printf("comet[%d].alive=1\n",found);
   num_comets_alive++;
 
   /* Pick a city to attack that was not attacked last time */
@@ -2934,29 +2927,21 @@
   /* Should it be a bonus comet? */
   comets[found].bonus = 0;
 
-#ifdef TUXMATH_DEBUG
-  printf("\nbonus_comet_counter is %d\n",bonus_comet_counter);
-#endif
+  DEBUGMSG(debug_game, "bonus_comet_counter is %d\n",bonus_comet_counter);
 
   if (bonus_comet_counter == 1)
   {
     bonus_comet_counter = 0;
     comets[found].bonus = 1;
     playsound(SND_BONUS_COMET);
-#ifdef TUXMATH_DEBUG
-    printf("\nCreated bonus comet");
-#endif
+    DEBUGMSG(debug_game, "Created bonus comet");
   }
 
-#ifdef TUXMATH_DEBUG
-  printf ("\nadd_comet(): formula string is: %s",
-              comets[found].flashcard.formula_string);
-  print_current_quests();
-#endif
-
+  DEBUGMSG(debug_game, "add_comet(): formula string is: %s", comets[found].flashcard.formula_string);
+  
   /* Record the time at which this comet was created */
   comets[found].time_started = SDL_GetTicks();
-//   }
+   
   /* comet slot found and question found so return successfully: */
   return 1;
 }
@@ -3576,12 +3561,13 @@
     /* Escape key - quit! */
     user_quit_received = GAME_OVER_ESCAPE;
   }
-#ifdef TUXMATH_DEBUG
-  if (key == SDLK_LEFTBRACKET) //a nice nonobvious/unused key
+  DEBUGCODE(debug_game)
   {
-    user_quit_received = GAME_OVER_CHEATER;
+    if (key == SDLK_LEFTBRACKET) //a nice nonobvious/unused key
+    {
+      user_quit_received = GAME_OVER_CHEATER;
+    }
   }
-#endif
   else if (key == SDLK_TAB
         || key == SDLK_p)
   {
@@ -3709,7 +3695,7 @@
 void add_score(int inc)
 {
   score += inc;
-  tmdprintf("Score is now: %d\n", score);
+  DEBUGMSG(debug_game,"Score is now: %d\n", score);
 }
 
 
@@ -3722,13 +3708,11 @@
   for (i = 0; i < MAX_COMETS; i++)
   {
     comets[i].alive = 0;
-    comets[i].expl = 0;
+    comets[i].expl = -1;
     comets[i].city = 0;
     comets[i].x = 0;
     comets[i].y = 0;
     comets[i].answer = 0;
-//    strncpy(comets[i].flashcard.formula_string, " ", max_formula_size);
-//    strncpy(comets[i].flashcard.answer_string, " ", max_answer_size);
     MC_ResetFlashCard(&(comets[i].flashcard) );
     comets[i].bonus = 0;
   }
@@ -3746,12 +3730,6 @@
     command[i] = buf[i];
   }
   command[i] = '\0';
-
-//#ifdef LAN_DEBUG
-//  printf("buf is %s\n", buf);
-//  printf("command is %s\n", command);
-//#endif
-
 }
 
 
@@ -3793,6 +3771,7 @@
   printf("\n");
 }
 
+
 void free_on_exit(void)
 {
   int i;
@@ -3810,8 +3789,8 @@
   int i, img;
   int old_city_expl_height = city_expl_height;
 
-  tmdprintf("Recalculating positions\n");
-
+  DEBUGMSG(debug_game,"Recalculating positions\n");
+  
   if (Opts_GetGlobalOpt(USE_IGLOOS))
     img = IMG_IGLOO_INTACT;
   else
@@ -3824,7 +3803,7 @@
     {
       cities[i].x = (((screen->w / (NUM_CITIES + 1)) * i) +
                      ((images[img] -> w) / 2));
-      tmdprintf("%d,", cities[i].x);
+      DEBUGMSG(debug_game,"%d,", cities[i].x);
     }
     else
     {
@@ -3832,7 +3811,7 @@
                    (screen->w / (NUM_CITIES + 1) *
                    (i - NUM_CITIES / 2) +
                     images[img]->w / 2);
-      tmdprintf("%d,", cities[i].x);
+      DEBUGMSG(debug_game,"%d,", cities[i].x);
     }
 
     penguins[i].x = cities[i].x;
@@ -3852,6 +3831,4 @@
     //else
     //  comets[i].y = comets[i].y * RES_Y / screen->h;
   }
-
-
 }

Modified: tuxmath/branches/lan/src/game.h
===================================================================
--- tuxmath/branches/lan/src/game.h	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/game.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -138,7 +138,6 @@
 };
 
 int game(void);
-
 void game_set_start_message(const char*, const char*, const char*, const char*);
 /* draw_nums() is used in options.c and factoroids.c/h so need extern linkage */
 

Modified: tuxmath/branches/lan/src/globals.h
===================================================================
--- tuxmath/branches/lan/src/globals.h	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/globals.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -13,7 +13,7 @@
 
   Part of "Tux4Kids" Project
   http://www.tux4kids.org/
-      
+
   Added March 2, 2006
 
   Copyright: See COPYING file that comes with this distribution
@@ -26,18 +26,42 @@
 #define GLOBALS_H
 
 #include "config.h"
-/* for conditional compilation of debugging output */
-//#define TUXMATH_DEBUG
+
+typedef enum { false, true } bool;
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
 /* for Tim's feedback speed control code           */
 //#define FEEDBACK_DEBUG
 //#define LINEBREAK
-/* nice inline debugging macro */
-#ifdef TUXMATH_DEBUG
-#define tmdprintf(...) printf(__VA_ARGS__)
-#else
-#define tmdprintf(...) 0
-#endif
 
+/* debug data (declared in options.c) */
+extern int debug_status;
+
+/* bitmasks for debugging options (declared in options.c) */
+extern const int debug_setup;
+extern const int debug_fileops;
+extern const int debug_loaders;
+extern const int debug_titlescreen;
+extern const int debug_menu;
+extern const int debug_menu_parser;
+extern const int debug_game;
+extern const int debug_factoroids;
+extern const int debug_lan;
+extern const int debug_mathcards;
+extern const int debug_sdl;
+extern const int debug_lessons;
+extern const int debug_highscore;
+extern const int debug_options;
+extern const int debug_convert_utf;
+extern const int debug_multiplayer;
+extern const int debug_all;
+
+/* debug macros */
+#define DEBUGCODE(mask) if((mask) & debug_status)
+#define DEBUGMSG(mask, ...) if((mask) & debug_status){ fprintf(stderr, __VA_ARGS__); fflush(stderr); }
+
 /* Maximum length of file path: */
 #define PATH_MAX 4096
 
@@ -103,11 +127,9 @@
 #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 PIXEL_BITS 32
 
-enum { 
+enum {
   CADET_HIGH_SCORE,
   SCOUT_HIGH_SCORE,
   RANGER_HIGH_SCORE,
@@ -133,3 +155,4 @@
 extern int num_lessons;
 
 #endif
+>>>>>>> .merge-right.r1476

Modified: tuxmath/branches/lan/src/highscore.c
===================================================================
--- tuxmath/branches/lan/src/highscore.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/highscore.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -13,13 +13,13 @@
 
 #include "tuxmath.h"
 #include "highscore.h"
+#include "menu.h"
 #include "titlescreen.h"
 #include "fileops.h"
 #include "setup.h"
 #include "options.h"
 #include "SDL_extras.h"
 #include "convert_utf.h"
-#include "network.h"
 
 
 typedef struct high_score_entry {
@@ -39,7 +39,6 @@
 {
   int i = 0;
   int finished = 0;
-  int tux_frame = 0;
   Uint32 frame = 0;
   Uint32 start = 0;
 
@@ -52,61 +51,20 @@
   char score_strings[HIGH_SCORES_SAVED][HIGH_SCORE_NAME_LENGTH + 10] = {{'\0'}};
 
   SDL_Rect score_rects[HIGH_SCORES_SAVED];
-  SDL_Rect leftRect, rightRect, stopRect, TuxRect, table_bg;
+  SDL_Rect table_bg;
 
-
   const int max_width = 300;
   int score_table_y = 100;
 
-  sprite* Tux = LoadSprite("tux/bigtux", IMG_ALPHA);
   const int title_font_size = 32;
   const int player_font_size = 14;
 
-
-  /* --- Set up the rects for drawing various things: ----------- */
-
-  /* Put arrow buttons in right lower corner, inset by 20 pixels */
-  /* with a 10 pixel space between:                              */
-  if (images[IMG_RIGHT])
-  {
-    rightRect.w = images[IMG_RIGHT]->w;
-    rightRect.h = images[IMG_RIGHT]->h;
-    rightRect.x = screen->w - images[IMG_RIGHT]->w - 20;
-    rightRect.y = screen->h - images[IMG_RIGHT]->h - 20;
-  }
-
-  if (images[IMG_LEFT])
-  {
-    leftRect.w = images[IMG_LEFT]->w;
-    leftRect.h = images[IMG_LEFT]->h;
-    leftRect.x = rightRect.x - 10 - images[IMG_LEFT]->w;
-    leftRect.y = screen->h - images[IMG_LEFT]->h - 20;
-  }
-
-  /* Red "Stop" circle in upper right corner to go back to main menu: */
-  if (images[IMG_STOP])
-  {
-    stopRect.w = images[IMG_STOP]->w;
-    stopRect.h = images[IMG_STOP]->h;
-    stopRect.x = screen->w - images[IMG_STOP]->w;
-    stopRect.y = 0;
-  }
-
-  if (Tux && Tux->frame[0]) /* make sure sprite has at least one frame */
-   {
-    TuxRect.w = Tux->frame[0]->w;
-    TuxRect.h = Tux->frame[0]->h;
-    TuxRect.x = 0;
-    TuxRect.y = screen->h - Tux->frame[0]->h;
-   }
-
-
   while (!finished)
   {
     start = SDL_GetTicks();
 
     /* Check for user events: */
-    while (SDL_PollEvent(&event)) 
+    while (SDL_PollEvent(&event))
     {
       switch (event.type)
       {
@@ -117,15 +75,15 @@
 
         case SDL_MOUSEBUTTONDOWN:
         /* "Stop" button - go to main menu: */
-        { 
-          if (inRect(stopRect, event.button.x, event.button.y ))
+        {
+          if (inRect(stop_rect, event.button.x, event.button.y ))
           {
             finished = 1;
             playsound(SND_TOCK);
           }
 
           /* "Left" button - go to previous page: */
-          if (inRect(leftRect, event.button.x, event.button.y))
+          if (inRect(prev_rect, event.button.x, event.button.y))
           {
             if (diff_level > CADET_HIGH_SCORE)
             {
@@ -138,7 +96,7 @@
           }
 
           /* "Right" button - go to next page: */
-          if (inRect( rightRect, event.button.x, event.button.y ))
+          if (inRect(next_rect, event.button.x, event.button.y ))
           {
             if (diff_level < (NUM_HIGH_SCORE_LEVELS-1))
             {
@@ -165,37 +123,31 @@
     /* If needed, redraw: */
     if (diff_level != old_diff_level)
     {
-      /* Draw background: */
-      if (current_bkg())
-        SDL_BlitSurface( current_bkg(), NULL, screen, NULL );
-      /* FIXME maybe add image of trophy or similar pic */
-      /* Draw Tux: */
-      if (Tux && Tux->frame[0]) /* make sure sprite has at least one frame */
-        SDL_BlitSurface(Tux->frame[0], NULL, screen, &TuxRect);
+      DrawTitleScreen();
       /* Draw controls: */
-      if (images[IMG_STOP])
-        SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
+      if (stop_button)
+        SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
       /* Draw regular or grayed-out left arrow: */
       if (diff_level == CADET_HIGH_SCORE)
       {
-        if (images[IMG_LEFT_GRAY])
-          SDL_BlitSurface(images[IMG_LEFT_GRAY], NULL, screen, &leftRect);
+        if (prev_gray)
+          SDL_BlitSurface(prev_gray, NULL, screen, &prev_rect);
       }
       else
       {
-        if (images[IMG_LEFT])
-          SDL_BlitSurface(images[IMG_LEFT], NULL, screen, &leftRect);
+        if (prev_arrow)
+          SDL_BlitSurface(prev_arrow, NULL, screen, &prev_rect);
       }
       /* Draw regular or grayed-out right arrow: */
       if (diff_level == NUM_HIGH_SCORE_LEVELS - 1)
       {
-        if (images[IMG_RIGHT_GRAY])
-          SDL_BlitSurface(images[IMG_RIGHT_GRAY], NULL, screen, &rightRect);
+        if (next_gray)
+          SDL_BlitSurface(next_gray, NULL, screen, &next_rect);
       }
       else
       {
-        if (images[IMG_RIGHT])
-          SDL_BlitSurface(images[IMG_RIGHT], NULL, screen, &rightRect);
+        if (next_arrow)
+          SDL_BlitSurface(next_arrow, NULL, screen, &next_rect);
       }
 
       /* Draw background shading for table: */
@@ -283,7 +235,6 @@
         /* Clear out old surfaces and update: */
         if (score_surfs[i])               /* this should not happen! */
           SDL_FreeSurface(score_surfs[i]);
-        
         if (HS_Score(diff_level, i) == Opts_LastScore() && frame % 5 < 2)
           score_surfs[i] = BlackOutline(N_(score_strings[i]), player_font_size, &yellow);
         else
@@ -292,7 +243,6 @@
         /* Get out if BlackOutline() fails: */
         if (!score_surfs[i])
           continue;
-         
         /* Set up entries in vertical column: */
         if (0 == i)
           score_rects[i].y = score_table_y;
@@ -313,26 +263,8 @@
       old_diff_level = diff_level;
     }
 
+    HandleTitleScreenAnimations();
 
-    /* --- make tux blink --- */
-    switch (frame % TUX6)
-    {
-      case 0:    tux_frame = 1; break;
-      case TUX1: tux_frame = 2; break;
-      case TUX2: tux_frame = 3; break;
-      case TUX3: tux_frame = 4; break;                        
-      case TUX4: tux_frame = 3; break;
-      case TUX5: tux_frame = 2; break;
-      default: tux_frame = 0;
-    }
-
-    if (Tux && tux_frame)
-    {
-      SDL_BlitSurface(Tux->frame[tux_frame - 1], NULL, screen, &TuxRect);
-      SDL_UpdateRect(screen, TuxRect.x, TuxRect.y, TuxRect.w, TuxRect.h);
-    }
-
-
     /* Wait so we keep frame rate constant: */
     while ((SDL_GetTicks() - start) < 33)
     {
@@ -340,8 +272,6 @@
     }
     frame++;
   }  // End of while (!finished) loop
-
-  FreeSprite(Tux);
 }
 
 
@@ -354,21 +284,16 @@
   NameEntry(pl_name, _("You Are In The Hall of Fame!"), _("Enter Your Name:"));
 }
 
-
-
 void NameEntry(char* pl_name, const char* heading, const char* sub)
 {
   char UTF8_buf[HIGH_SCORE_NAME_LENGTH * 3] = {'\0'};
 
   SDL_Rect loc;
   SDL_Rect redraw_rect;
-  SDL_Rect TuxRect,
-           stopRect;
 
   int redraw = 0;
   int first_draw = 1;
   int finished = 0;
-  int tux_frame = 0;
   Uint32 frame = 0;
   Uint32 start = 0;
   wchar_t wchar_buf[HIGH_SCORE_NAME_LENGTH + 1] = {'\0'};
@@ -377,42 +302,16 @@
   const int BG_WIDTH = 400;
   const int BG_HEIGHT = 200;
 
-  sprite* Tux = LoadSprite("tux/bigtux", IMG_ALPHA);
-
   if (!pl_name)
     return;
-    
 
   /* We need to get Unicode vals from SDL keysyms */
   SDL_EnableUNICODE(SDL_ENABLE);
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "\nEnter HighScoreNameEntry()\n" );
-#endif
+  DEBUGMSG(debug_highscore, "Enter HighScoreNameEntry()\n" );
 
+  DrawTitleScreen();
 
-  /* Draw background: */
-  if (current_bkg())
-    SDL_BlitSurface(current_bkg(), NULL, screen, NULL);
-
-  /* Red "Stop" circle in upper right corner to go back to main menu: */
-  if (images[IMG_STOP])
-  {
-    stopRect.w = images[IMG_STOP]->w;
-    stopRect.h = images[IMG_STOP]->h;
-    stopRect.x = screen->w - images[IMG_STOP]->w;
-    stopRect.y = 0;
-    SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
-  }
-
-  if (Tux && Tux->frame[0]) /* make sure sprite has at least one frame */
-  {
-    TuxRect.w = Tux->frame[0]->w;
-    TuxRect.h = Tux->frame[0]->h;
-    TuxRect.x = 0;
-    TuxRect.y = screen->h - Tux->frame[0]->h;
-  }
-
   /* Draw translucent background for text: */
   {
     SDL_Rect bg_rect;
@@ -456,12 +355,11 @@
   SDL_UpdateRect(screen, 0, 0, 0, 0);
 
 
-
   while (!finished)
   {
     start = SDL_GetTicks();
 
-    while (SDL_PollEvent(&event)) 
+    while (SDL_PollEvent(&event))
     {
       switch (event.type)
       {
@@ -472,8 +370,8 @@
 
         case SDL_MOUSEBUTTONDOWN:
         /* "Stop" button - go to main menu: */
-        { 
-          if (inRect(stopRect, event.button.x, event.button.y ))
+        {
+          if (inRect(stop_rect, event.button.x, event.button.y ))
           {
             finished = 1;
             playsound(SND_TOCK);
@@ -482,10 +380,8 @@
         }
         case SDL_KEYDOWN:
         {
-#ifdef TUXMATH_DEBUG
-          fprintf(stderr, "Before keypress, string is %S\tlength = %d\n",
-                  wchar_buf, (int)wcslen(wchar_buf));
-#endif
+          DEBUGMSG(debug_highscore, "Before keypress, string is %S\tlength = %d\n",
+                   wchar_buf, (int)wcslen(wchar_buf));
           switch (event.key.keysym.sym)
           {
             case SDLK_ESCAPE:
@@ -513,14 +409,12 @@
               {
                 wchar_buf[(int)wcslen(wchar_buf)] = event.key.keysym.unicode;
                 redraw = 1;
-              } 
+              }
             }
           }  /* end  'switch (event.key.keysym.sym)'  */
 
-#ifdef TUXMATH_DEBUG
-          fprintf(stderr, "After keypress, string is %S\tlength = %d\n",
-                    wchar_buf, (int)wcslen(wchar_buf));
-#endif
+          DEBUGMSG(debug_highscore, "After keypress, string is %S\tlength = %d\n",
+                   wchar_buf, (int)wcslen(wchar_buf));
             /* Now draw name, if needed: */
           if (redraw)
           {
@@ -570,24 +464,8 @@
         }
       }
     }
- 
-    /* --- make tux blink --- */
-    switch (frame % TUX6)
-    {
-      case 0:    tux_frame = 1; break;
-      case TUX1: tux_frame = 2; break;
-      case TUX2: tux_frame = 3; break;
-      case TUX3: tux_frame = 4; break;                        
-      case TUX4: tux_frame = 3; break;
-      case TUX5: tux_frame = 2; break;
-      default: tux_frame = 0;
-    }
 
-    if (Tux && tux_frame)
-    {
-      SDL_BlitSurface(Tux->frame[tux_frame - 1], NULL, screen, &TuxRect);
-      SDL_UpdateRect(screen, TuxRect.x, TuxRect.y, TuxRect.w, TuxRect.h);
-    }
+    HandleTitleScreenAnimations();
 
     /* Wait so we keep frame rate constant: */
     while ((SDL_GetTicks() - start) < 33)
@@ -597,8 +475,6 @@
     frame++;
   }  // End of while (!finished) loop
 
-  FreeSprite(Tux);
-
   /* Turn off SDL Unicode lookup (because has some overhead): */
   SDL_EnableUNICODE(SDL_DISABLE);
 
@@ -606,6 +482,240 @@
   strncpy((char*)pl_name, (char*)UTF8_buf, HIGH_SCORE_NAME_LENGTH * 3);
 }
 
+
+
+
+/* Zero-out the array before use: */
+void initialize_scores(void)
+{
+  int i, j;
+  for (i = 0; i < NUM_HIGH_SCORE_LEVELS; i++)
+  {
+    for (j = 0; j < HIGH_SCORES_SAVED; j++)
+    {
+      high_scores[i][j].score = 0;
+      strcpy(high_scores[i][j].name, "");
+    }
+  }
+}
+
+/* Test to see where a new score ranks on the list.      */
+/* The return value is the index value - add one to get  */
+/* the common-language place on the list.                */
+int check_score_place(int diff_level, int new_score)
+{
+  int i = 0;
+
+  /* Make sure diff_level is valid: */
+  if (diff_level < 0
+   || diff_level >= NUM_HIGH_SCORE_LEVELS)
+  {
+    fprintf(stderr, "In insert_score(), diff_level invalid!\n");
+    return 0;
+  }
+
+  /* Find correct place in list: */
+  for (i = 0; i < HIGH_SCORES_SAVED; i++)
+  {
+    if (new_score > high_scores[diff_level][i].score)
+      break;
+  }
+
+  return i;  /* So if we return HIGH_SCORES_SAVED, the score did not */
+             /* make the list.                                       */
+}
+
+/* Put a new high score entry into the table for the corresponding */
+/* difficulty level - returns 1 if successful.                     */ 
+int insert_score(char* playername, int diff_level, int new_score)
+{
+  int i = 0;
+  int insert_place;
+
+  insert_place = check_score_place(diff_level, new_score);
+
+  if (HIGH_SCORES_SAVED == insert_place) /* Score didn't make the top 10 */
+  {
+    return 0;
+  }
+
+  /* Move lower entries down: */
+  for (i = HIGH_SCORES_SAVED - 1; i > insert_place; i--)
+  {
+    high_scores[diff_level][i].score =
+            high_scores[diff_level][i - 1].score;
+    strncpy(high_scores[diff_level][i].name,
+            high_scores[diff_level][i - 1].name,
+            HIGH_SCORE_NAME_LENGTH);
+  }
+
+  /* Now put in new entry: */
+  high_scores[diff_level][insert_place].score = new_score;
+  strncpy(high_scores[diff_level][insert_place].name,
+          playername,
+          HIGH_SCORE_NAME_LENGTH);
+  return 1;
+}
+
+
+void print_high_scores(FILE* fp)
+{
+  int i, j;
+
+  fprintf(fp, "\nHigh Scores:\n");
+
+  for (i = 0; i < NUM_HIGH_SCORE_LEVELS; i++)
+  {
+    switch(i)
+    {    
+      case CADET_HIGH_SCORE:
+      {
+        fprintf(fp, "\nSpace Cadet:\n");
+        break;
+      }
+      case SCOUT_HIGH_SCORE:
+      {
+        fprintf(fp, "\nScout:\n");
+        break;
+      }
+      case RANGER_HIGH_SCORE:
+      {
+        fprintf(fp, "\nRanger:\n");
+        break;
+      }
+      case ACE_HIGH_SCORE:
+      {
+        fprintf(fp, "\nAce:\n");
+        break;
+      }
+      case COMMANDO_HIGH_SCORE:
+      {
+        fprintf(fp, "\nCommando:\n");
+        break;
+      }
+      case FACTORS_HIGH_SCORE:
+      {
+        fprintf(fp, "\nFactors:\n");
+        break;
+      }
+      case FRACTIONS_HIGH_SCORE:
+      {
+        fprintf(fp, "\nFractions:\n");
+        break;
+      }
+    }
+
+    for (j = 0; j < HIGH_SCORES_SAVED; j++)
+    {
+      fprintf(fp, "%d.\t%s\t%d\n",
+              j + 1,                  //Convert to common-language ordinals
+              high_scores[i][j].name,
+              high_scores[i][j].score);
+    }
+  }
+}
+
+
+int read_high_scores_fp(FILE* fp)
+{
+  char buf[PATH_MAX];
+  char* token;
+  const char delimiters[] = "\t";
+
+  char* name_read;
+  int score_read;
+  int diff_level;
+
+  DEBUGMSG(debug_highscore, "Entering read_high_scores_fp()\n");
+
+  /* get out if file pointer invalid: */
+  if(!fp)
+  {
+    fprintf(stderr, "In read_high_scores_fp(), file pointer invalid!\n");
+    return 0;
+  }
+
+  /* make sure we start at beginning: */
+  rewind(fp);
+
+  /* read in a line at a time: */
+  while (fgets (buf, PATH_MAX, fp))
+  { 
+    /* Ignore comment lines: */
+    if ((buf[0] == ';') || (buf[0] == '#'))
+    {
+      continue;
+    }
+    /* Split up line with strtok()to get needed values,  */ 
+    /* then call insert_score() for each line.           */
+    token = strtok(buf, delimiters);
+    if (!token)
+      continue;
+    diff_level = atoi(token);
+    if (diff_level >= NUM_HIGH_SCORE_LEVELS)
+      continue;
+
+    token = strtok(NULL, delimiters);
+    if (!token)
+      continue; 
+    score_read = atoi(token);
+    /* Note that name can contain spaces - \t is only delimiter: */
+    name_read = strtok(NULL, delimiters);
+    /* Now insert entry: */
+    insert_score(name_read, diff_level, score_read); 
+  }
+  return 1;
+}
+
+
+/* Return the score associated with a table entry:    */
+/* Note: the place is given as the array index, i.e.  */
+/* 0 for the top of the list.                         */
+int HS_Score(int diff_level, int place)
+{
+  /* Make sure diff_level is valid: */
+  if (diff_level < 0
+   || diff_level >= NUM_HIGH_SCORE_LEVELS)
+  {
+    fprintf(stderr, "In HS_Score(), diff_level = %d, invalid!\n", diff_level);
+    return -1;
+  }
+
+  /* Make sure place is valid: */
+  if (place < 0
+   || place >= HIGH_SCORES_SAVED)
+  {
+    fprintf(stderr, "In HS_Score(), place invalid!\n");
+    return -1;
+  }
+
+  return high_scores[diff_level][place].score;
+}
+
+
+/* Return (pointer to) the name associated with a table entry:  */
+char* HS_Name(int diff_level, int place)
+{
+  /* Make sure diff_level is valid: */
+  if (diff_level < 0
+   || diff_level >= NUM_HIGH_SCORE_LEVELS)
+  {
+    fprintf(stderr, "In HS_Score(), diff_level invalid!\n");
+    return NULL;
+  }
+
+  /* Make sure place is valid: */
+  if (place < 0
+   || place >= HIGH_SCORES_SAVED)
+  {
+    fprintf(stderr, "In HS_Score(), place invalid!\n");
+    return NULL;
+  }
+
+  return high_scores[diff_level][place].name;
+}
+
+
 void Ready(const char* heading)
 {
   SDL_Rect loc;
@@ -1305,3 +1415,721 @@
 
   return high_scores[diff_level][place].name;
 }
+=======
+/*
+*  C Implementation: highscore.c
+*
+* Description: Implementation of high score tables for tuxmath.
+*
+*
+* Author: David Bruce <dbruce at tampabay.rr.com>, (C) 2007
+*
+* Copyright: See COPYING file that comes with this distribution
+* (Briefly, GNU GPL version 2 or greater).
+*/
+#include <string.h>
+
+#include "tuxmath.h"
+#include "highscore.h"
+#include "menu.h"
+#include "titlescreen.h"
+#include "fileops.h"
+#include "setup.h"
+#include "options.h"
+#include "SDL_extras.h"
+#include "convert_utf.h"
+
+
+typedef struct high_score_entry {
+  int score;
+  char name[HIGH_SCORE_NAME_LENGTH];
+} high_score_entry;
+
+
+high_score_entry high_scores[NUM_HIGH_SCORE_LEVELS][HIGH_SCORES_SAVED];
+
+/* Local function prototypes: */
+
+
+
+/* Display high scores: */
+void DisplayHighScores(int level)
+{
+  int i = 0;
+  int finished = 0;
+  Uint32 frame = 0;
+  Uint32 start = 0;
+
+  int diff_level = level;
+  int old_diff_level = -1; //So table gets refreshed first time through
+  /* Surfaces, char buffers, and rects for table: */
+  SDL_Surface* score_surfs[HIGH_SCORES_SAVED] = {NULL};
+
+  /* 10 spaces should be enough room for place and score on each line: */
+  char score_strings[HIGH_SCORES_SAVED][HIGH_SCORE_NAME_LENGTH + 10] = {{'\0'}};
+
+  SDL_Rect score_rects[HIGH_SCORES_SAVED];
+  SDL_Rect table_bg;
+
+  const int max_width = 300;
+  int score_table_y = 100;
+
+  const int title_font_size = 32;
+  const int player_font_size = 14;
+
+  while (!finished)
+  {
+    start = SDL_GetTicks();
+
+    /* Check for user events: */
+    while (SDL_PollEvent(&event))
+    {
+      switch (event.type)
+      {
+        case SDL_QUIT:
+        {
+          cleanup();
+        }
+
+        case SDL_MOUSEBUTTONDOWN:
+        /* "Stop" button - go to main menu: */
+        {
+          if (inRect(stop_rect, event.button.x, event.button.y ))
+          {
+            finished = 1;
+            playsound(SND_TOCK);
+          }
+
+          /* "Left" button - go to previous page: */
+          if (inRect(prev_rect, event.button.x, event.button.y))
+          {
+            if (diff_level > CADET_HIGH_SCORE)
+            {
+              diff_level--;
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+              {
+                playsound(SND_TOCK);
+              }
+            }
+          }
+
+          /* "Right" button - go to next page: */
+          if (inRect(next_rect, event.button.x, event.button.y ))
+          {
+            if (diff_level < (NUM_HIGH_SCORE_LEVELS-1))
+            {
+              diff_level++;
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+              {
+                playsound(SND_TOCK);
+              }
+            }
+          }
+          break;
+        }
+
+
+        case SDL_KEYDOWN:
+        {
+          finished = 1;
+          playsound(SND_TOCK);
+        }
+      }
+    }
+
+
+    /* If needed, redraw: */
+    if (diff_level != old_diff_level)
+    {
+      DrawTitleScreen();
+      /* Draw controls: */
+      if (stop_button)
+        SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
+      /* Draw regular or grayed-out left arrow: */
+      if (diff_level == CADET_HIGH_SCORE)
+      {
+        if (prev_gray)
+          SDL_BlitSurface(prev_gray, NULL, screen, &prev_rect);
+      }
+      else
+      {
+        if (prev_arrow)
+          SDL_BlitSurface(prev_arrow, NULL, screen, &prev_rect);
+      }
+      /* Draw regular or grayed-out right arrow: */
+      if (diff_level == NUM_HIGH_SCORE_LEVELS - 1)
+      {
+        if (next_gray)
+          SDL_BlitSurface(next_gray, NULL, screen, &next_rect);
+      }
+      else
+      {
+        if (next_arrow)
+          SDL_BlitSurface(next_arrow, NULL, screen, &next_rect);
+      }
+
+      /* Draw background shading for table: */
+      table_bg.x = (screen->w)/2 - (max_width + 20)/2 + 50; //don't draw over Tux
+      table_bg.y = 5;
+      table_bg.w = max_width + 20;
+      table_bg.h = screen->h - 10 - images[IMG_RIGHT]->h;
+      DrawButton(&table_bg, 25, SEL_RGBA);
+
+      /* Draw difficulty level heading: */
+      {
+        SDL_Surface* srfc = NULL;
+        SDL_Rect text_rect, button_rect;
+
+        srfc = BlackOutline(_("Hall Of Fame"), title_font_size, &yellow);
+        if (srfc)
+        {
+          button_rect.x = text_rect.x = (screen->w)/2 - (srfc->w)/2 + 50;
+          button_rect.y = text_rect.y = 10;
+          button_rect.w = text_rect.w = srfc->w;
+          button_rect.h = text_rect.h = srfc->h;
+          /* add margin to button and draw: */
+          button_rect.x -= 10;
+          button_rect.w += 20;
+          DrawButton(&button_rect, 15, 0, 0, 32, 192);
+          /* Now blit text and free surface: */
+          SDL_BlitSurface(srfc, NULL, screen, &text_rect);
+          SDL_FreeSurface(srfc);
+          srfc = NULL;
+        }
+
+        switch (diff_level)
+        {
+          case CADET_HIGH_SCORE:
+            srfc = BlackOutline(_("Space Cadet"), title_font_size, &white);
+            break;
+          case SCOUT_HIGH_SCORE:
+            srfc = BlackOutline(_("Scout"), title_font_size, &white);
+            break;
+          case RANGER_HIGH_SCORE:
+            srfc = BlackOutline(_("Ranger"), title_font_size, &white);
+            break;
+          case ACE_HIGH_SCORE:
+            srfc = BlackOutline(_("Ace"), title_font_size, &white);
+            break;
+          case COMMANDO_HIGH_SCORE:
+            srfc = BlackOutline(_("Commando"), title_font_size, &white);
+            break;
+          case FACTORS_HIGH_SCORE:
+            srfc = BlackOutline(_("Factors"), title_font_size, &white);
+            break;
+          case FRACTIONS_HIGH_SCORE:
+            srfc = BlackOutline(_("Fractions"), title_font_size, &white);
+            break;
+          default:
+            srfc = BlackOutline(_("Space Cadet"), title_font_size, &white);
+        }
+
+        if (srfc)
+        {
+          text_rect.x = (screen->w)/2 - (srfc->w)/2 + 50; 
+          text_rect.y += text_rect.h; /* go to bottom of first line */
+          text_rect.w = srfc->w;
+          text_rect.h = srfc->h;
+          SDL_BlitSurface(srfc, NULL, screen, &text_rect);
+          SDL_FreeSurface(srfc);
+          srfc = NULL;
+          /* note where score table will start: */
+          score_table_y = text_rect.y + text_rect.h;
+        }
+      }
+
+
+      /* Generate and draw desired table: */
+
+      for (i = 0; i < HIGH_SCORES_SAVED; i++)
+      {
+        /* Get data for entries: */
+        sprintf(score_strings[i],
+                "%d.    %d     %s",
+                i + 1,                  /* Add one to get common-language place number */
+                HS_Score(diff_level, i),
+                HS_Name(diff_level, i));
+
+        /* Clear out old surfaces and update: */
+        if (score_surfs[i])               /* this should not happen! */
+          SDL_FreeSurface(score_surfs[i]);
+        if (HS_Score(diff_level, i) == Opts_LastScore() && frame % 5 < 2)
+          score_surfs[i] = BlackOutline(N_(score_strings[i]), player_font_size, &yellow);
+        else
+          score_surfs[i] = BlackOutline(N_(score_strings[i]), player_font_size, &white);
+
+        /* Get out if BlackOutline() fails: */
+        if (!score_surfs[i])
+          continue;
+        /* Set up entries in vertical column: */
+        if (0 == i)
+          score_rects[i].y = score_table_y;
+        else
+          score_rects[i].y = score_rects[i - 1].y + score_rects[i - 1].h;
+
+        score_rects[i].x = (screen->w)/2 - max_width/2 + 50;
+        score_rects[i].h = score_surfs[i]->h;
+        score_rects[i].w = max_width;
+
+        SDL_BlitSurface(score_surfs[i], NULL, screen, &score_rects[i]);
+        SDL_FreeSurface(score_surfs[i]);
+        score_surfs[i] = NULL;
+      }
+      /* Update screen: */
+      SDL_UpdateRect(screen, 0, 0, 0, 0);
+
+      old_diff_level = diff_level;
+    }
+
+    HandleTitleScreenAnimations();
+
+    /* Wait so we keep frame rate constant: */
+    while ((SDL_GetTicks() - start) < 33)
+    {
+      SDL_Delay(20);
+    }
+    frame++;
+  }  // End of while (!finished) loop
+}
+
+
+/* Display screen to allow player to enter name for high score table:     */
+/* The pl_name argument *must* point to a validly allocated string array  */
+/* at least three times HIGH_SCORE_NAME_LENGTH because UTF-8 is a         */
+/* multibyte encoding.                                                    */
+void HighScoreNameEntry(char* pl_name)
+{
+  NameEntry(pl_name, _("You Are In The Hall of Fame!"), _("Enter Your Name:"));
+}
+
+void NameEntry(char* pl_name, const char* heading, const char* sub)
+{
+  char UTF8_buf[HIGH_SCORE_NAME_LENGTH * 3] = {'\0'};
+
+  SDL_Rect loc;
+  SDL_Rect redraw_rect;
+
+  int redraw = 0;
+  int first_draw = 1;
+  int finished = 0;
+  Uint32 frame = 0;
+  Uint32 start = 0;
+  wchar_t wchar_buf[HIGH_SCORE_NAME_LENGTH + 1] = {'\0'};
+  const int NAME_FONT_SIZE = 32;
+  const int BG_Y = 100;
+  const int BG_WIDTH = 400;
+  const int BG_HEIGHT = 200;
+
+  if (!pl_name)
+    return;
+
+  /* We need to get Unicode vals from SDL keysyms */
+  SDL_EnableUNICODE(SDL_ENABLE);
+
+  DEBUGMSG(debug_highscore, "Enter HighScoreNameEntry()\n" );
+
+  DrawTitleScreen();
+
+  /* Draw translucent background for text: */
+  {
+    SDL_Rect bg_rect;
+    bg_rect.x = (screen->w)/2 - BG_WIDTH/2;
+    bg_rect.y = BG_Y;
+    bg_rect.w = BG_WIDTH;
+    bg_rect.h = BG_HEIGHT;
+    DrawButton(&bg_rect, 15, REG_RGBA);
+
+    bg_rect.x += 10;
+    bg_rect.y += 10;
+    bg_rect.w -= 20;
+    bg_rect.h = 60;
+    DrawButton(&bg_rect, 10, SEL_RGBA);
+  }
+
+  /* Draw heading: */
+  {
+    SDL_Surface* s = BlackOutline(_(heading),
+                                  DEFAULT_MENU_FONT_SIZE, &white);
+    if (s)
+    {
+      loc.x = (screen->w/2) - (s->w/2);
+      loc.y = 110;
+      SDL_BlitSurface(s, NULL, screen, &loc);
+      SDL_FreeSurface(s);
+    }
+
+    s = BlackOutline(_(sub),
+                     DEFAULT_MENU_FONT_SIZE, &white);
+    if (s)
+    {
+      loc.x = (screen->w/2) - (s->w/2);
+      loc.y = 140;
+      SDL_BlitSurface(s, NULL, screen, &loc);
+      SDL_FreeSurface(s);
+    }
+  }
+
+  /* and update: */
+  SDL_UpdateRect(screen, 0, 0, 0, 0);
+
+
+  while (!finished)
+  {
+    start = SDL_GetTicks();
+
+    while (SDL_PollEvent(&event))
+    {
+      switch (event.type)
+      {
+        case SDL_QUIT:
+        {
+          cleanup();
+        }
+
+        case SDL_MOUSEBUTTONDOWN:
+        /* "Stop" button - go to main menu: */
+        {
+          if (inRect(stop_rect, event.button.x, event.button.y ))
+          {
+            finished = 1;
+            playsound(SND_TOCK);
+            break;
+          }
+        }
+        case SDL_KEYDOWN:
+        {
+          DEBUGMSG(debug_highscore, "Before keypress, string is %S\tlength = %d\n",
+                   wchar_buf, (int)wcslen(wchar_buf));
+          switch (event.key.keysym.sym)
+          {
+            case SDLK_ESCAPE:
+            case SDLK_RETURN:
+            case SDLK_KP_ENTER:
+            {
+              finished = 1;
+              playsound(SND_TOCK);
+              break;
+            }
+            case SDLK_BACKSPACE:
+            {
+              if (wcslen(wchar_buf) > 0)
+                wchar_buf[(int)wcslen(wchar_buf) - 1] = '\0';
+              redraw = 1;
+              break;
+            }
+
+            /* For any other keys, if the key has a Unicode value, */
+            /* we add it to our string:                            */
+            default:
+            {
+              if ((event.key.keysym.unicode > 0)
+              && (wcslen(wchar_buf) < HIGH_SCORE_NAME_LENGTH)) 
+              {
+                wchar_buf[(int)wcslen(wchar_buf)] = event.key.keysym.unicode;
+                redraw = 1;
+              }
+            }
+          }  /* end  'switch (event.key.keysym.sym)'  */
+
+          DEBUGMSG(debug_highscore, "After keypress, string is %S\tlength = %d\n",
+                   wchar_buf, (int)wcslen(wchar_buf));
+            /* Now draw name, if needed: */
+          if (redraw)
+          {
+            SDL_Surface* s = NULL;
+            redraw = 0;
+
+            /* Convert text to UTF-8 so BlackOutline() can handle it: */
+   //         wcstombs((char*) UTF8_buf, wchar_buf, HIGH_SCORE_NAME_LENGTH * 3);
+            ConvertToUTF8(wchar_buf, UTF8_buf, HIGH_SCORE_NAME_LENGTH * 3);
+            /* Redraw background and shading in area where we drew text last time: */ 
+            if (!first_draw)
+            {
+              SDL_BlitSurface(current_bkg(), &redraw_rect, screen, &redraw_rect);
+              DrawButton(&redraw_rect, 0, REG_RGBA);
+              SDL_UpdateRect(screen,
+                             redraw_rect.x,
+                             redraw_rect.y,
+                             redraw_rect.w,
+                             redraw_rect.h);
+            }
+
+            s = BlackOutline(UTF8_buf, NAME_FONT_SIZE, &yellow);
+            if (s)
+            {
+              /* set up loc and blit: */
+              loc.x = (screen->w/2) - (s->w/2);
+              loc.y = 200;
+              SDL_BlitSurface(s, NULL, screen, &loc);
+
+              /* Remember where we drew so we can update background next time through:  */
+              /* (for some reason we need to update a wider area to get clean image)    */
+              redraw_rect.x = loc.x - 20;
+              redraw_rect.y = loc.y - 10;
+              redraw_rect.h = s->h + 20;
+              redraw_rect.w = s->w + 40;
+              first_draw = 0;
+
+              SDL_UpdateRect(screen,
+                             redraw_rect.x,
+                             redraw_rect.y,
+                             redraw_rect.w,
+                             redraw_rect.h);
+              SDL_FreeSurface(s);
+              s = NULL;
+            }
+          }
+        }
+      }
+    }
+
+    HandleTitleScreenAnimations();
+
+    /* Wait so we keep frame rate constant: */
+    while ((SDL_GetTicks() - start) < 33)
+    {
+      SDL_Delay(20);
+    }
+    frame++;
+  }  // End of while (!finished) loop
+
+  /* Turn off SDL Unicode lookup (because has some overhead): */
+  SDL_EnableUNICODE(SDL_DISABLE);
+
+  /* Now copy name into location pointed to by arg: */ 
+  strncpy((char*)pl_name, (char*)UTF8_buf, HIGH_SCORE_NAME_LENGTH * 3);
+}
+
+
+
+
+/* Zero-out the array before use: */
+void initialize_scores(void)
+{
+  int i, j;
+  for (i = 0; i < NUM_HIGH_SCORE_LEVELS; i++)
+  {
+    for (j = 0; j < HIGH_SCORES_SAVED; j++)
+    {
+      high_scores[i][j].score = 0;
+      strcpy(high_scores[i][j].name, "");
+    }
+  }
+}
+
+/* Test to see where a new score ranks on the list.      */
+/* The return value is the index value - add one to get  */
+/* the common-language place on the list.                */
+int check_score_place(int diff_level, int new_score)
+{
+  int i = 0;
+
+  /* Make sure diff_level is valid: */
+  if (diff_level < 0
+   || diff_level >= NUM_HIGH_SCORE_LEVELS)
+  {
+    fprintf(stderr, "In insert_score(), diff_level invalid!\n");
+    return 0;
+  }
+
+  /* Find correct place in list: */
+  for (i = 0; i < HIGH_SCORES_SAVED; i++)
+  {
+    if (new_score > high_scores[diff_level][i].score)
+      break;
+  }
+
+  return i;  /* So if we return HIGH_SCORES_SAVED, the score did not */
+             /* make the list.                                       */
+}
+
+/* Put a new high score entry into the table for the corresponding */
+/* difficulty level - returns 1 if successful.                     */ 
+int insert_score(char* playername, int diff_level, int new_score)
+{
+  int i = 0;
+  int insert_place;
+
+  insert_place = check_score_place(diff_level, new_score);
+
+  if (HIGH_SCORES_SAVED == insert_place) /* Score didn't make the top 10 */
+  {
+    return 0;
+  }
+
+  /* Move lower entries down: */
+  for (i = HIGH_SCORES_SAVED - 1; i > insert_place; i--)
+  {
+    high_scores[diff_level][i].score =
+            high_scores[diff_level][i - 1].score;
+    strncpy(high_scores[diff_level][i].name,
+            high_scores[diff_level][i - 1].name,
+            HIGH_SCORE_NAME_LENGTH);
+  }
+
+  /* Now put in new entry: */
+  high_scores[diff_level][insert_place].score = new_score;
+  strncpy(high_scores[diff_level][insert_place].name,
+          playername,
+          HIGH_SCORE_NAME_LENGTH);
+  return 1;
+}
+
+
+void print_high_scores(FILE* fp)
+{
+  int i, j;
+
+  fprintf(fp, "\nHigh Scores:\n");
+
+  for (i = 0; i < NUM_HIGH_SCORE_LEVELS; i++)
+  {
+    switch(i)
+    {    
+      case CADET_HIGH_SCORE:
+      {
+        fprintf(fp, "\nSpace Cadet:\n");
+        break;
+      }
+      case SCOUT_HIGH_SCORE:
+      {
+        fprintf(fp, "\nScout:\n");
+        break;
+      }
+      case RANGER_HIGH_SCORE:
+      {
+        fprintf(fp, "\nRanger:\n");
+        break;
+      }
+      case ACE_HIGH_SCORE:
+      {
+        fprintf(fp, "\nAce:\n");
+        break;
+      }
+      case COMMANDO_HIGH_SCORE:
+      {
+        fprintf(fp, "\nCommando:\n");
+        break;
+      }
+      case FACTORS_HIGH_SCORE:
+      {
+        fprintf(fp, "\nFactors:\n");
+        break;
+      }
+      case FRACTIONS_HIGH_SCORE:
+      {
+        fprintf(fp, "\nFractions:\n");
+        break;
+      }
+    }
+
+    for (j = 0; j < HIGH_SCORES_SAVED; j++)
+    {
+      fprintf(fp, "%d.\t%s\t%d\n",
+              j + 1,                  //Convert to common-language ordinals
+              high_scores[i][j].name,
+              high_scores[i][j].score);
+    }
+  }
+}
+
+
+int read_high_scores_fp(FILE* fp)
+{
+  char buf[PATH_MAX];
+  char* token;
+  const char delimiters[] = "\t";
+
+  char* name_read;
+  int score_read;
+  int diff_level;
+
+  DEBUGMSG(debug_highscore, "Entering read_high_scores_fp()\n");
+
+  /* get out if file pointer invalid: */
+  if(!fp)
+  {
+    fprintf(stderr, "In read_high_scores_fp(), file pointer invalid!\n");
+    return 0;
+  }
+
+  /* make sure we start at beginning: */
+  rewind(fp);
+
+  /* read in a line at a time: */
+  while (fgets (buf, PATH_MAX, fp))
+  { 
+    /* Ignore comment lines: */
+    if ((buf[0] == ';') || (buf[0] == '#'))
+    {
+      continue;
+    }
+    /* Split up line with strtok()to get needed values,  */ 
+    /* then call insert_score() for each line.           */
+    token = strtok(buf, delimiters);
+    if (!token)
+      continue;
+    diff_level = atoi(token);
+    if (diff_level >= NUM_HIGH_SCORE_LEVELS)
+      continue;
+
+    token = strtok(NULL, delimiters);
+    if (!token)
+      continue; 
+    score_read = atoi(token);
+    /* Note that name can contain spaces - \t is only delimiter: */
+    name_read = strtok(NULL, delimiters);
+    /* Now insert entry: */
+    insert_score(name_read, diff_level, score_read); 
+  }
+  return 1;
+}
+
+
+/* Return the score associated with a table entry:    */
+/* Note: the place is given as the array index, i.e.  */
+/* 0 for the top of the list.                         */
+int HS_Score(int diff_level, int place)
+{
+  /* Make sure diff_level is valid: */
+  if (diff_level < 0
+   || diff_level >= NUM_HIGH_SCORE_LEVELS)
+  {
+    fprintf(stderr, "In HS_Score(), diff_level = %d, invalid!\n", diff_level);
+    return -1;
+  }
+
+  /* Make sure place is valid: */
+  if (place < 0
+   || place >= HIGH_SCORES_SAVED)
+  {
+    fprintf(stderr, "In HS_Score(), place invalid!\n");
+    return -1;
+  }
+
+  return high_scores[diff_level][place].score;
+}
+
+
+/* Return (pointer to) the name associated with a table entry:  */
+char* HS_Name(int diff_level, int place)
+{
+  /* Make sure diff_level is valid: */
+  if (diff_level < 0
+   || diff_level >= NUM_HIGH_SCORE_LEVELS)
+  {
+    fprintf(stderr, "In HS_Score(), diff_level invalid!\n");
+    return NULL;
+  }
+
+  /* Make sure place is valid: */
+  if (place < 0
+   || place >= HIGH_SCORES_SAVED)
+  {
+    fprintf(stderr, "In HS_Score(), place invalid!\n");
+    return NULL;
+  }
+
+  return high_scores[diff_level][place].name;
+}
+>>>>>>> .merge-right.r1476

Modified: tuxmath/branches/lan/src/lessons.c
===================================================================
--- tuxmath/branches/lan/src/lessons.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/lessons.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -35,9 +35,7 @@
   const char delimiters[] = "\t\n\r"; /* this will keep newline chars out of string */
   int i;
 
-#ifdef TUXMATH_DEBUG
-  printf("\nEntering read_goldstars_fp()\n");
-#endif
+  DEBUGMSG(debug_lessons, "Entering read_goldstars_fp()\n");
 
   /* get out if file pointer invalid: */
   if(!fp)
@@ -96,9 +94,7 @@
 {
   int i = 0;
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "\nEntering write_goldstars_fp()\n");
-#endif
+  DEBUGMSG(debug_lessons, "Entering write_goldstars_fp()\n");
 
   /* get out if file pointer invalid: */
   if(!fp)
@@ -112,11 +108,9 @@
 
   for (i = 0; i < num_lessons; i++)
   {
-#ifdef TUXMATH_DEBUG
-    printf("i = %d\nfilename = %s\ngoldstar = %d\n",
-           i, lesson_list_filenames[i],
-           lesson_list_goldstars[i]);
-#endif
+    DEBUGMSG(debug_lessons, "i = %d\nfilename = %s\ngoldstar = %d\n",
+             i, lesson_list_filenames[i],
+             lesson_list_goldstars[i]);
 
     if(lesson_list_goldstars[i] == 1)
     {

Modified: tuxmath/branches/lan/src/loaders.c
===================================================================
--- tuxmath/branches/lan/src/loaders.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/loaders.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -1,71 +1,81 @@
-/***************************************************************************
- -  file: loaders.c
- -  description: Functions to load multimedia for Tux Typing
-                             -------------------
-    begin                : Thu May 4 2000
-    copyright            : (C) 2000 by Sam Hart
-                         : (C) 2003 by Jesse Andrews
-    email                : tuxtype-dev at tux4kids.net
+/*
+  loaders.c
 
-    Modified for use in tuxmath by David Bruce - 2006.
-    email                : <dbruce at tampabay.rr.com>
-                           <tuxmath-devel at lists.sourceforge.net>
- ***************************************************************************/
+  Functions responsible for loading multimedia.
 
-/***************************************************************************
- *                                                                         *
- *   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.                                   *
- *                                                                         *
- ***************************************************************************/
+  begin                : Thu May 4 2000
+  copyright            : (C) 2000 by Sam Hart
+                       : (C) 2003 by Jesse Andrews
+  email                : tuxtype-dev at tux4kids.net
 
-//#include "globals.h"
-//#include "funcs.h"
+  Modified for use in tuxmath by David Bruce - 2006.
+  email                : <dbruce at tampabay.rr.com>
+                         <tuxmath-devel at lists.sourceforge.net>
 
-#include "tuxmath.h"     // for TUXMATH_DEBUG
+  Modified to support SVG by Boleslaw Kulbabinski - 2009
+  email                : <bkulbabinski at gmail.com>
+
+  Part of "Tux4Kids" Project
+  http://www.tux4kids.com/
+
+  Copyright: See COPYING file that comes with this distribution.
+*/
+
 #include "loaders.h"
-#include "setup.h"  // for cleanup_on_error()
+#include "globals.h"
+#include "tuxmath.h"
+#include "setup.h"       // for cleanup_on_error()
 #include "SDL_extras.h"
 
-/* FIXME Doesn't seem to work consistently on all versions of Windows */
+#ifdef HAVE_RSVG
+#include<librsvg/rsvg.h>
+#include<librsvg/rsvg-cairo.h>
+#endif
+
+/* local functions */
+int             check_file(const char* file);
+
+#ifdef HAVE_RSVG
+SDL_Surface*    load_svg(const char* file_name, int width, int height, const char* layer_name);
+sprite*         load_svg_sprite(const char* file_name, int width, int height);
+SDL_Surface*    render_svg_from_handle(RsvgHandle* file_handle, int width, int height, const char* layer_name);
+void            get_svg_dimensions(const char* file_name, int* width, int* height);
+#endif
+
+SDL_Surface*    load_image(const char* file_name, int mode, int w, int h, bool proportional);
+void            fit_in_rectangle(int* width, int* height, int max_width, int max_height);
+SDL_Surface*    set_format(SDL_Surface* img, int mode);
+sprite*         load_sprite(const char* name, int mode, int w, int h, bool proportional);
+
+
+
 /* check to see if file exists, if so return true */
 // int checkFile( const char *file ) {
 //         static struct stat fileStats;
-// 
 //         fileStats.st_mode = 0;
-// 
 //         stat( file, &fileStats );
-//                 
 //         return (S_IFREG & fileStats.st_mode);
 // }
 
 
 /* Returns 1 if valid file, 2 if valid dir, 0 if neither: */
-int checkFile(const char* file)
+int check_file(const char* file)
 {
   FILE* fp = NULL;
   DIR* dp = NULL;
 
   if (!file)
   {
-    fprintf(stderr, "CheckFile(): invalid char* argument!");
+    DEBUGMSG(debug_loaders, "check_file(): invalid char* argument!\n");
     return 0;
   }
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "CheckFile() - checking: %s\n", file);
-#endif
+  DEBUGMSG(debug_loaders, "check_file(): checking: %s\n", file);
 
   dp = opendir(file);
   if (dp)
   {
-
-#ifdef TUXMATH_DEBUG
-    fprintf(stderr, "Opened successfully as DIR\n");
-#endif
-
+    DEBUGMSG(debug_loaders, "check_file(): Opened successfully as DIR\n");
     closedir(dp);
     return 2;
   }
@@ -73,68 +83,102 @@
   fp = fopen(file, "r");
   if (fp)
   {
-
-#ifdef TUXMATH_DEBUG
-    fprintf(stderr, "Opened successfully as FILE\n");
-#endif
-
+    DEBUGMSG(debug_loaders, "check_file(): Opened successfully as FILE\n");
     fclose(fp);
     return 1;
   }
 
-  fprintf(stderr, "Unable to open '%s' as either FILE or DIR\n", file);
+  DEBUGMSG(debug_loaders, "check_file(): Unable to open '%s' as either FILE or DIR\n", file);
   return 0;
 }
 
 
-int max( int n1, int n2 ) {
-  return (n1 > n2 ? n1 : n2);
-}
-
 #ifdef HAVE_RSVG
-/***********************
-    SVG related functions
-************************/
-#include<librsvg/rsvg.h>
-#include<librsvg/rsvg-cairo.h>
 
-/* Load an SVG file and resize it to given dimensions.
-   if width or height is set to 0 no resizing is applied
+/* Load a layer of SVG file and resize it to given dimensions.
+   If width or height is negative no resizing is applied.
+   If layer = NULL then the whole image is loaded.
+   layer_name must be preceded with a '#' symbol.
+   Return NULL on failure.
    (partly based on TuxPaint's SVG loading function) */
-SDL_Surface* LoadSVGOfDimensions(char* filename, int width, int height)
+SDL_Surface* load_svg(const char* file_name, int width, int height, const char* layer_name)
 {
-  cairo_surface_t* temp_surf;
-  cairo_t* context;
+  SDL_Surface* dest;
   RsvgHandle* file_handle;
-  RsvgDimensionData dimensions;
-  SDL_Surface* dest;
-  float scale_x;
-  float scale_y;
-  int bpp = 32;
-  Uint32 Rmask, Gmask, Bmask, Amask;
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "LoadSVGOfDimensions(): looking for %s\n", filename);
-#endif
+  DEBUGMSG(debug_loaders, "load_svg(): loading %s\n", file_name);
 
   rsvg_init();
 
-  file_handle = rsvg_handle_new_from_file(filename, NULL);
-  if(file_handle == NULL)
+  file_handle = rsvg_handle_new_from_file(file_name, NULL);
+  if(NULL == file_handle)
   {
-#ifdef TUXMATH_DEBUG
-    fprintf(stderr, "LoadSVGOfDimensions(): file %s not found\n", filename);
-#endif
+    DEBUGMSG(debug_loaders, "load_svg(): file %s not found\n", file_name);
     rsvg_term();
     return NULL;
   }
 
+  dest = render_svg_from_handle(file_handle, width, height, layer_name);
+
+  g_object_unref(file_handle);
+  rsvg_term();
+
+  return dest;
+}
+
+sprite* load_svg_sprite(const char* file_name, int width, int height)
+{
+  RsvgHandle* file_handle;
+  sprite* new_sprite;
+  char lay_name[20];
+  int i;
+
+  DEBUGMSG(debug_loaders, "load_svg_sprite(): loading sprite from %s\n", file_name);
+
+  rsvg_init();
+
+  file_handle = rsvg_handle_new_from_file(file_name, NULL);
+  if(NULL == file_handle)
+  {
+    DEBUGMSG(debug_loaders, "load_svg_sprite(): file %s not found\n", file_name);
+    rsvg_term();
+    return NULL;
+  }
+
+  new_sprite = malloc(sizeof(sprite));
+  new_sprite->default_img = render_svg_from_handle(file_handle, width, height, "#default");
+
+  /* get number of frames from description */
+  sscanf(rsvg_handle_get_desc(file_handle), "%d", &new_sprite->num_frames);
+  DEBUGMSG(debug_loaders, "load_svg_sprite(): loading %d frames\n", new_sprite->num_frames);
+
+  for(i = 0; i < new_sprite->num_frames; i++)
+  {
+    sprintf(lay_name, "#frame%d", i);
+    new_sprite->frame[i] = render_svg_from_handle(file_handle, width, height, lay_name);
+  }
+
+  g_object_unref(file_handle);
+  rsvg_term();
+
+  return new_sprite;
+}
+
+/* render a layer of SVG file and resize it to given dimensions.
+   If width or height is negative no resizing is applied. */
+SDL_Surface* render_svg_from_handle(RsvgHandle* file_handle, int width, int height, const char* layer_name)
+{
+  RsvgDimensionData dimensions;
+  cairo_surface_t* temp_surf;
+  cairo_t* context;
+  SDL_Surface* dest;
+  float scale_x, scale_y;
+  Uint32 Rmask, Gmask, Bmask, Amask;
+
   rsvg_handle_get_dimensions(file_handle, &dimensions);
-#ifdef TUXMATH_DEBUG
-    fprintf(stderr, "SVG is %d x %d\n", dimensions.width, dimensions.height);
-#endif
 
-  if(width <= 0 || height <= 0)
+  /* set scale_x and scale_y */
+  if(width < 0 || height < 0)
   {
     width = dimensions.width;
     height = dimensions.height;
@@ -147,17 +191,21 @@
     scale_y = (float)height / dimensions.height;
   }
 
-  /* FIXME: We assume that our bpp = 32 */
+  /* set color masks */
+  Rmask = screen->format->Rmask;
+  Gmask = screen->format->Gmask;
+  Bmask = screen->format->Bmask;
+  if(screen->format->Amask == 0)
+    /* find a free byte to use for Amask */
+    Amask = ~(Rmask | Gmask | Bmask);
+  else
+    Amask = screen->format->Amask;
 
-  /* rmask, gmask, bmask, amask defined in SDL_extras.h do not work !
-     are those (taken from TuxPaint) dependent on endianness ? */
-  Rmask = 0x00ff0000;
-  Gmask = 0x0000ff00;
-  Bmask = 0x000000ff;
-  Amask = 0xff000000;
+  DEBUGMSG(debug_loaders, "render_svg_from_handle(): color masks: R=%u, G=%u, B=%u, A=%u\n",
+        Rmask, Gmask, Bmask, Amask);
 
   dest = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA,
-        width, height, bpp, Rmask, Gmask, Bmask, Amask);
+        width, height, screen->format->BitsPerPixel, Rmask, Gmask, Bmask, Amask);
 
   SDL_LockSurface(dest);
   temp_surf = cairo_image_surface_create_for_data(dest->pixels,
@@ -166,288 +214,382 @@
   context = cairo_create(temp_surf);
   if(cairo_status(context) != CAIRO_STATUS_SUCCESS)
   {
-#ifdef TUXMATH_DEBUG
-    fprintf(stderr, "LoadSVGOfDimensions(): error rendering SVG from %s\n", filename);
-#endif
-    g_object_unref(file_handle);
+    DEBUGMSG(debug_loaders, "render_svg_from_handle(): error rendering SVG\n");
     cairo_surface_destroy(temp_surf);
-    rsvg_term();
     return NULL;
   }
 
   cairo_scale(context, scale_x, scale_y);
-  rsvg_handle_render_cairo(file_handle, context);
 
+  /* render appropriate layer */
+  rsvg_handle_render_cairo_sub(file_handle, context, layer_name);
+
   SDL_UnlockSurface(dest);
-
-  g_object_unref(file_handle);
   cairo_surface_destroy(temp_surf);
   cairo_destroy(context);
-  rsvg_term();
 
   return dest;
 }
 
-#endif
-
-/***********************
-        LoadImageFromFile : Simply load an image from given file
-        or its SVG equivalent (if present). Return NULL if loading failed.
-************************/
-SDL_Surface* LoadImageFromFile(char *datafile)
+void get_svg_dimensions(const char* file_name, int* width, int* height)
 {
-  SDL_Surface* tmp_pic = NULL;
+  RsvgHandle* file_handle;
+  RsvgDimensionData dimensions;
 
-#ifdef HAVE_RSVG
-  char svgfn[PATH_MAX];
-#endif
+  rsvg_init();
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "LoadImageFromFile(): looking in %s\n", datafile);
-#endif
+  file_handle = rsvg_handle_new_from_file(file_name, NULL);
+  if(file_handle == NULL)
+  {
+    DEBUGMSG(debug_loaders, "get_svg_dimensions(): file %s not found\n", file_name);
+    rsvg_term();
+    return;
+  }
 
-#ifdef HAVE_RSVG
-  /* This is just an ugly workaround to test SVG
-     before any scaling routines are implemented */
+  rsvg_handle_get_dimensions(file_handle, &dimensions);
 
-  /* change extension into .svg */
-  char* dotpos = strrchr(datafile, '.');
-  strncpy(svgfn, datafile, dotpos - datafile);
-  svgfn[dotpos - datafile] = '\0';
-  strcat(svgfn, ".svg");
+  *width = dimensions.width;
+  *height = dimensions.height;
 
-  /* try to load an SVG equivalent */
-  tmp_pic = LoadSVGOfDimensions(svgfn, 0, 0);
-#endif
+  g_object_unref(file_handle);
+  rsvg_term();
+}
 
-  if(tmp_pic == NULL)
-    /* Try to load image with SDL_image: */
-    tmp_pic = IMG_Load(datafile);
+#endif /* HAVE_RSVG */
 
-  return tmp_pic;
+/* Load an image without resizing it */
+SDL_Surface* LoadImage(const char* file_name, int mode)
+{
+  return LoadScaledImage(file_name, mode, -1, -1);
 }
 
-/* FIXME checkFile() not working right in Win32 - skipping. */
-/***********************
-        LoadImage : Load an image and set transparent if requested
-************************/
-SDL_Surface* LoadImage( char *datafile, int mode )
+/* LoadScaledImage : Load an image and resize it to given dimensions.
+   If width or height is negative no resizing is applied.
+   The loader (load_svg() or IMG_Load()) is chosen depending on file extension,
+   If an SVG file is not found try to load its PNG equivalent
+   (unless IMG_NO_PNG_FALLBACK is set) */
+SDL_Surface* LoadScaledImage(const char* file_name, int mode, int width, int height)
 {
-  SDL_Surface* tmp_pic = NULL;
+  return load_image(file_name, mode, width, height, false);
+}
+
+/* LoadImageOfBoundingBox : Same as LoadScaledImage but preserve image proportions
+   and fit it into max_width x max_height rectangle.
+   Returned surface is not necessarily max_width x max_height ! */
+SDL_Surface* LoadImageOfBoundingBox(const char* file_name, int mode, int max_width, int max_height)
+{
+  return load_image(file_name, mode, max_width, max_height, true);
+}
+
+
+/* load_image : helper function used by LoadScaledImage and LoadImageOfBoundingBox */
+SDL_Surface* load_image(const char* file_name, int mode, int w, int h, bool proportional)
+{
+  SDL_Surface* loaded_pic = NULL;
   SDL_Surface* final_pic = NULL;
-
   char fn[PATH_MAX];
+  int fn_len;
+  int width = -1, height = -1;
+  bool is_svg = true;
 
-  sprintf( fn, "%s/images/%s", DATA_PREFIX, datafile );
+  if(NULL == file_name)
+  {
+    DEBUGMSG(debug_loaders, "load_image(): file_name is NULL, exiting.\n");
+    return NULL;
+  }
 
+  /* run loader depending on file extension */
 
-  tmp_pic = LoadImageFromFile(fn);
+  /* add path prefix */
+  snprintf(fn, PATH_MAX, "%s/images/%s", DATA_PREFIX, file_name);
+  fn_len = strlen(fn);
 
-  if (NULL == tmp_pic) /* Could not load image: */
+  if(strcmp(fn + fn_len - 4, ".svg"))
   {
+    DEBUGMSG(debug_loaders, "load_image(): %s is not an SVG, loading using IMG_Load()\n", fn);
+    loaded_pic = IMG_Load(fn);
+    is_svg = false;
+    if (NULL == loaded_pic)
+    {
+      is_svg = true;
+      DEBUGMSG(debug_loaders, "load_image(): Trying to load SVG equivalent of %s\n", fn);
+      sprintf(strrchr(fn, '.'), ".svg");
+    }
+  }
+  if (is_svg)
+  {
+#ifdef HAVE_RSVG
+    DEBUGMSG(debug_loaders, "load_image(): trying to load %s as SVG.\n", fn);
+    if(proportional)
+    {
+      get_svg_dimensions(fn, &width, &height);
+      if(width > 0 && height > 0)
+        fit_in_rectangle(&width, &height, w, h);
+    }
+    else
+    {
+      width = w;
+      height = h;
+    }
+    loaded_pic = load_svg(fn, width, height, NULL);
+#endif
+
+    if(loaded_pic == NULL)
+    {
+#ifdef HAVE_RSVG
+      DEBUGMSG(debug_loaders, "load_image(): failed to load %s as SVG.\n", fn);
+#else
+      DEBUGMSG(debug_loaders, "load_image(): SVG support not available.\n");
+#endif
+      if(mode & IMG_NO_PNG_FALLBACK)
+      {
+        DEBUGMSG(debug_loaders, "load_image(): %s : IMG_NO_PNG_FALLBACK is set.\n", fn);
+      }
+      else
+      {
+        DEBUGMSG(debug_loaders, "load_image(): Trying to load PNG equivalent of %s\n", fn);
+        strcpy(fn + fn_len - 3, "png");
+
+        loaded_pic = IMG_Load(fn);
+        is_svg = false;
+      }
+    }
+  }
+
+  if (NULL == loaded_pic) /* Could not load image: */
+  {
     if (mode & IMG_NOT_REQUIRED)
-    { 
-#ifdef TUXMATH_DEBUG
-      fprintf(stderr, "Warning: could not load optional graphics file %s\n", datafile);
-#endif
+    {
+      DEBUGMSG(debug_loaders, "load_image(): Warning: could not load optional graphics file %s\n", file_name);
       return NULL;  /* Allow program to continue */
     }
     /* If image was required, exit from program: */
-    fprintf(stderr, "ERROR could not load required graphics file %s\n", datafile);
+    fprintf(stderr, "load_image(): ERROR could not load required graphics file %s\n", file_name);
     fprintf(stderr, "%s", SDL_GetError() );
     cleanup_on_error();
   }
+  else if(!is_svg && w > 0 && h > 0)
+  {
+    if(proportional)
+    {
+      width = loaded_pic->w;
+      height = loaded_pic->h;
+      fit_in_rectangle(&width, &height, w, h);
+    }
+    else
+    {
+      width = w;
+      height = h;
+    }
+    final_pic = zoom(loaded_pic, width, height);
+    SDL_FreeSurface(loaded_pic);
+    loaded_pic = final_pic;
+    final_pic = NULL;
+  }
 
-  /* "else" - now setup the image to the proper format */
+  final_pic = set_format(loaded_pic, mode);
+  SDL_FreeSurface(loaded_pic);
+  DEBUGMSG(debug_loaders, "Leaving load_image()\n\n");
+
+  return final_pic;
+}
+
+/* adjust width and height to fit in max_width x max_height rectangle
+   but preserve their proportion */
+void fit_in_rectangle(int* width, int* height, int max_width, int max_height)
+{
+  float scale_w, scale_h;
+
+  if(width != 0 && height != 0)
+  {
+    scale_w = (float) max_width / (*width);
+    scale_h = (float) max_height / (*height);
+    *width *= min(scale_w, scale_h);
+    *height *= min(scale_w, scale_h);
+  }
+}
+
+SDL_Surface* set_format(SDL_Surface* img, int mode)
+{
   switch (mode & IMG_MODES)
   {
     case IMG_REGULAR:
-    { 
-
-      final_pic = SDL_DisplayFormat(tmp_pic);
-      SDL_FreeSurface(tmp_pic);
-      break;
+    {
+      DEBUGMSG(debug_loaders, "set_format(): handling IMG_REGULAR mode.\n");
+      return SDL_DisplayFormat(img);
     }
 
     case IMG_ALPHA:
     {
-
-      final_pic = SDL_DisplayFormatAlpha(tmp_pic);
-      SDL_FreeSurface(tmp_pic);
-      break;
+      DEBUGMSG(debug_loaders, "set_format(): handling IMG_ALPHA mode.\n");
+      return SDL_DisplayFormatAlpha(img);
     }
 
     case IMG_COLORKEY:
     {
-
-      SDL_LockSurface(tmp_pic);
-      SDL_SetColorKey(tmp_pic, (SDL_SRCCOLORKEY | SDL_RLEACCEL),
-                      SDL_MapRGB(tmp_pic->format, 255, 255, 0));
-      final_pic = SDL_DisplayFormat(tmp_pic);
-      SDL_FreeSurface(tmp_pic);
-      break;
+      DEBUGMSG(debug_loaders, "set_format(): handling IMG_COLORKEY mode.\n");
+      SDL_LockSurface(img);
+      SDL_SetColorKey(img, (SDL_SRCCOLORKEY | SDL_RLEACCEL),
+                      SDL_MapRGB(img->format, 255, 255, 0));
+      return SDL_DisplayFormat(img);
     }
 
     default:
     {
-#ifdef TUXMATH_DEBUG
-      fprintf(stderr, "Image mode not recognized\n");
-#endif
-      SDL_FreeSurface(tmp_pic);
+      DEBUGMSG(debug_loaders, "set_format(): Image mode not recognized\n");
     }
   }
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "Leaving LoadImage()\n\n");
-#endif
-  return final_pic;
+
+  return NULL;
 }
 
-/***********************
-        LoadBkgd() : a wrapper for LoadImage() that scales the
-        image to the size of the screen using zoom(), taken
-        from TuxPaint
-************************/
-SDL_Surface* LoadBkgd(char* datafile)
+
+/* LoadBkgd() : a wrapper for LoadImage() that optimizes
+   the format of background image */
+SDL_Surface* LoadBkgd(const char* file_name, int width, int height)
 {
-  SDL_Surface* orig;
-  orig = IMG_Load(datafile);
+  SDL_Surface* orig = NULL;
+  SDL_Surface* final_pic = NULL;
 
+  orig = LoadScaledImage(file_name, IMG_REGULAR, width, height);
+
   if (!orig)
   {
-    tmdprintf("In LoadBkgd(), LoadImage() returned NULL on %s\n",
-              datafile);
+    DEBUGMSG(debug_loaders, "In LoadBkgd(), LoadImage() returned NULL on %s\n",
+             file_name);
     return NULL;
   }
 
-  if ((orig->w == screen->w)
-   && (orig->h == screen->h))
-  {
-    tmdprintf("No zoom required - return bkgd as is\n");
-    return orig;
-  }
-  else
-  { 
-    tmdprintf("Image is %dx%d\n", orig->w, orig->h);
-    tmdprintf("Screen is %dx%d\n", screen->w, screen->h);
-    tmdprintf("Calling zoom() to rescale\n");
-    return zoom(orig, screen->w, screen->h);
-  }
+  /* turn off transparency, since it's the background */
+  SDL_SetAlpha(orig, SDL_RLEACCEL, SDL_ALPHA_OPAQUE);
+  final_pic = SDL_DisplayFormat(orig); /* optimize the format */
+  SDL_FreeSurface(orig);
+
+  return final_pic;
 }
 
-/**********************
-LoadBothBkgds() : loads two scaled images: one for the user's native 
-resolution and one for 640x480 fullscreen. 
-Returns: the number of images that were scaled
-Now we also optimize the format for best performance
-**********************/
-int LoadBothBkgds(char* datafile, SDL_Surface** fs_bkgd, SDL_Surface** win_bkgd)
+/* LoadBothBkgds() : loads two scaled images: one for the fullscreen mode
+   (fs_res_x,fs_rex_y) and one for the windowed mode (win_res_x,win_rex_y)
+   Now we also optimize the format for best performance */
+void LoadBothBkgds(const char* file_name, SDL_Surface** fs_bkgd, SDL_Surface** win_bkgd)
 {
-  int ret = 0;
-  SDL_Surface* orig = NULL;
-  SDL_Surface* tmp = NULL;
+  DEBUGMSG(debug_loaders, "Entering LoadBothBkgds()\n");
+  *fs_bkgd = LoadBkgd(file_name, fs_res_x, fs_res_y);
+  *win_bkgd = LoadBkgd(file_name, win_res_x, win_res_y);
+}
 
-  tmdprintf("Entering LoadBothBkgds()\n");
-  orig = LoadImage(datafile, IMG_REGULAR);
-  tmdprintf("Scaling %dx%d to: %dx%d, %dx%d\n", 
-           orig->w, orig->h, RES_X, RES_Y, fs_res_x, fs_res_y);
-  if (orig->w == RES_X && orig->h == RES_Y)
-  {
-    *win_bkgd = orig;
-  }
-  else
-  {
-    *win_bkgd = zoom(orig, RES_X, RES_Y);
-    ++ret;
-  }
-  
-  if (orig->w == fs_res_x && orig->h == fs_res_y)
-  {
-    *fs_bkgd = orig;
-  }
-  else
-  {
-    *fs_bkgd = zoom(orig, fs_res_x, fs_res_y);
-    ++ret;
-  }
-  
-  if (ret == 2) //orig won't be used at all
-    SDL_FreeSurface(orig);
 
-  // Optimize images before we leave:
-  // turn off transparency, since it's the background:
-  if (*fs_bkgd)  //avoid segfault...
-  {
-    SDL_SetAlpha(*fs_bkgd, SDL_RLEACCEL,SDL_ALPHA_OPAQUE);
-    tmp = SDL_DisplayFormat(*fs_bkgd);  // optimize the format
-    SDL_FreeSurface(*fs_bkgd);
-    *fs_bkgd = tmp;
-  }
-  if (*win_bkgd)
-  {
-    SDL_SetAlpha(*win_bkgd, SDL_RLEACCEL,SDL_ALPHA_OPAQUE);
-    tmp = SDL_DisplayFormat(*win_bkgd);  // optimize the format
-    SDL_FreeSurface(*win_bkgd);
-    *win_bkgd = tmp;
-  }
+sprite* LoadSprite(const char* name, int mode)
+{
+  return LoadScaledSprite(name, mode, -1, -1);
+}
 
-  tmdprintf("%d images scaled\nLeaving LoadBothBkgds()\n", ret);
-  return ret;
+sprite* LoadScaledSprite(const char* name, int mode, int width, int height)
+{
+  return load_sprite(name, mode, width, height, false);
 }
 
+sprite* LoadSpriteOfBoundingBox(const char* name, int mode, int max_width, int max_height)
+{
+  return load_sprite(name, mode, max_width, max_height, true);
+}
 
-sprite* FlipSprite( sprite *in, int X, int Y ) {
-  sprite *out;
+sprite* load_sprite(const char* name, int mode, int w, int h, bool proportional)
+{
+  sprite *new_sprite = NULL;
+  char fn[PATH_MAX];
+  int i, width, height;
 
-  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;
-}
+#ifdef HAVE_RSVG
+  /* check if SVG sprite file is present */
+  sprintf(fn, "%s/images/%s.svg", DATA_PREFIX, name);
+  if(1 == check_file(fn))
+  {
+    if(proportional)
+    {
+      get_svg_dimensions(fn, &width, &height);
+      if(width > 0 && height > 0)
+        fit_in_rectangle(&width, &height, w, h);
+    }
+    else
+    {
+      width = w;
+      height = h;
+    }
 
+    new_sprite = load_svg_sprite(fn, width, height);
 
-sprite* LoadSprite( char* name, int MODE ) {
-  sprite *new_sprite;
-  char fn[PATH_MAX];
-  int x;
+    if(new_sprite)
+    {
+      set_format(new_sprite->default_img, mode);
+      for(i = 0; i < new_sprite->num_frames; i++)
+        set_format(new_sprite->frame[i], mode);
+      new_sprite->cur = 0;
+    }
+  }
+#endif
 
-  /* JA --- HACK check out what has changed with new code */
+  if(!new_sprite)
+  {
+    /* SVG sprite was not loaded, try to load it frame by frame from PNG files */
+    new_sprite = malloc(sizeof(sprite));
 
-  new_sprite = malloc(sizeof(sprite));
+    sprintf(fn, "%sd.png", name);  // The 'd' means the default image
+    if(proportional)
+      new_sprite->default_img = LoadImageOfBoundingBox(fn, mode | IMG_NOT_REQUIRED, w, h);
+    else
+      new_sprite->default_img = LoadScaledImage(fn, mode | IMG_NOT_REQUIRED, w, h);
 
-  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;
-          }
+    if(!new_sprite->default_img)
+      DEBUGMSG(debug_loaders, "load_sprite(): failed to load default image for %s\n", name);
+
+    for(i = 0; i < MAX_SPRITE_FRAMES; i++)
+    {
+      sprintf(fn, "%s%d.png", name, i);
+      if(proportional)
+        new_sprite->frame[i] = LoadImageOfBoundingBox(fn, mode | IMG_NOT_REQUIRED, w, h);
+      else
+        new_sprite->frame[i] = LoadScaledImage(fn, mode | IMG_NOT_REQUIRED, w, h);
+
+      if(new_sprite->frame[i] == NULL)
+      {
+        new_sprite->cur = 0;
+        new_sprite->num_frames = i;
+        break;
+      }
+      else
+        DEBUGMSG(debug_loaders, "load_sprite(): loaded frame %d of %s\n", i, name);
+    }
   }
 
-
-  
   return new_sprite;
 }
 
+sprite* FlipSprite(sprite* in, int X, int Y)
+{
+  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;
+}
 
-void FreeSprite(sprite* gfx )
+void FreeSprite(sprite* gfx)
 {
   int x;
   if (!gfx)
     return;
 
-  tmdprintf("Freeing image at %p", gfx);
+  DEBUGMSG(debug_loaders, "Freeing image at %p", gfx);
   for (x = 0; x < gfx->num_frames; x++)
   {
-    tmdprintf(".");
+    DEBUGMSG(debug_loaders, ".");
     if (gfx->frame[x])
     {
       SDL_FreeSurface(gfx->frame[x]);
@@ -461,21 +603,21 @@
     gfx->default_img = NULL;
   }
 
-  tmdprintf("FreeSprite() - done\n");
+  DEBUGMSG(debug_loaders, "FreeSprite() - done\n");
   free(gfx);
 }
 
-void next_frame(sprite* s)
+void NextFrame(sprite* s)
 {
   if (s && s->num_frames)
     s->cur = (s->cur + 1) % s->num_frames;
 }
 
-/***************************
-        LoadSound : Load a sound/music patch from a file.
-****************************/
+
+
+/* LoadSound : Load a sound/music patch from a file. */
 Mix_Chunk* LoadSound( char *datafile )
-{ 
+{
   Mix_Chunk* tempChunk = NULL;
   char fn[PATH_MAX];
 
@@ -489,17 +631,14 @@
   return tempChunk;
 }
 
-/************************
-        LoadMusic : Load
-        music from a datafile
-*************************/
-Mix_Music *LoadMusic(char *datafile )
-{ 
+/* LoadMusic : Load music from a datafile */
+Mix_Music* LoadMusic(char *datafile )
+{
   char fn[PATH_MAX];
   Mix_Music* tempMusic = NULL;
 
   sprintf( fn , "%s/sounds/%s", DATA_PREFIX, datafile );
-  if (1 != checkFile(fn))
+  if (1 != check_file(fn))
   {
     fprintf(stderr, "LoadMusic(): %s not found\n\n", fn);
     return NULL;
@@ -514,3 +653,4 @@
   }
   return tempMusic;
 }
+

Modified: tuxmath/branches/lan/src/loaders.h
===================================================================
--- tuxmath/branches/lan/src/loaders.h	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/loaders.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -1,17 +1,21 @@
-//
-// C++ Interface: loaders
-//
-// Description: 
-//
-//
-// Author: David Bruce <davidstuartbruce at gmail.com>, (C) 2009
-//
-// Copyright: See COPYING file that comes with this distribution
-//
-//
-#ifndef LOADERS_C
-#define LOADERS_C
+/*
+  loaders.h
 
+  Functions responsible for loading multimedia.
+  (interface)
+
+  Author: David Bruce <davidstuartbruce at gmail.com>, (C) 2009
+          Boleslaw Kulbabinski <bkulbabinski at gmail.com>, (C) 2009
+
+  Part of "Tux4Kids" Project
+  http://www.tux4kids.com/
+
+  Copyright: See COPYING file that comes with this distribution.
+*/
+
+#ifndef LOADERS_H
+#define LOADERS_H
+
 #include "tuxmath.h"
 
 #include <string.h>
@@ -22,35 +26,31 @@
 #include <sys/stat.h>
 #include <dirent.h>
 
-#define MAX_SPRITE_FRAMES 30
 
-#define IMG_REGULAR  0x01
-#define IMG_COLORKEY 0x02
-#define IMG_ALPHA    0x04
-#define IMG_MODES    0x07
-#define IMG_NOT_REQUIRED 0x10
-#define IMG_NO_THEME     0x20
+#define IMG_REGULAR         0x01
+#define IMG_COLORKEY        0x02
+#define IMG_ALPHA           0x04
+#define IMG_MODES           0x07
 
-typedef struct {
-  SDL_Surface *frame[MAX_SPRITE_FRAMES];
-  SDL_Surface *default_img;
-  int num_frames;
-  int cur;
-} sprite;
+#define IMG_NOT_REQUIRED    0x10
+#define IMG_NO_PNG_FALLBACK 0x20
 
 
-/* in loaders.c (from tuxtype): */
-int         checkFile( const char *file );
-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);
-sprite*      LoadSprite( char* name, int MODE );
-sprite*      FlipSprite( sprite* in, int X, int Y );
-void         FreeSprite( sprite* gfx );
-Mix_Music*   LoadMusic( char *datafile );
-void next_frame(sprite* s);
+SDL_Surface* LoadImage(const char* file_name, int mode);
+SDL_Surface* LoadScaledImage(const char* file_name, int mode, int width, int height);
+SDL_Surface* LoadImageOfBoundingBox(const char* file_name, int mode, int max_width, int max_height);
 
-#endif
+SDL_Surface* LoadBkgd(const char* file_name, int width, int height);
+void         LoadBothBkgds(const char* file_name, SDL_Surface** fs_bkgd, SDL_Surface** win_bkgd);
+
+sprite*      LoadSprite(const char* name, int mode);
+sprite*      LoadScaledSprite(const char* name, int mode, int width, int height);
+sprite*      LoadSpriteOfBoundingBox(const char* name, int mode, int max_width, int max_height);
+sprite*      FlipSprite(sprite* in, int X, int Y);
+void         FreeSprite(sprite* gfx);
+void         NextFrame(sprite* s);
+
+Mix_Chunk*   LoadSound(char* datafile);
+Mix_Music*   LoadMusic(char *datafile);
+
+#endif /* LOADERS_H */

Modified: tuxmath/branches/lan/src/mathcards.c
===================================================================
--- tuxmath/branches/lan/src/mathcards.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/mathcards.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -392,11 +392,11 @@
   answered_wrong = 0;
   questions_pending = 0;
 
-  #ifdef MC_DEBUG
-  print_counters();
-  #endif
+  if (debug_status & debug_mathcards) {
+    print_counters();
+  }
 
-  /* make sure list now exists and has non-zero length: */
+/* make sure list now exists and has non-zero length: */
   if (question_list && quest_list_length)
   {
     mcdprintf("\nGame set up successfully");
@@ -454,11 +454,11 @@
     answered_wrong = 0;
     questions_pending = 0;
 
-    #ifdef MC_DEBUG
-    print_counters();
-    print_list(stdout, question_list);
-    printf("\nLeaving MC_StartGameUsingWrongs()\n");
-    #endif
+    if (debug_status & debug_mathcards) {
+      print_counters();
+      print_list(stdout, question_list);
+      printf("\nLeaving MC_StartGameUsingWrongs()\n");
+    }
 
     return 1;
   }
@@ -515,12 +515,12 @@
   questions_pending++;
   active_quests = append_node(active_quests, ptr);
 
-  #ifdef MC_DEBUG
-  printf("\nnext question is:");
-  print_card(*fc);
-  print_counters();
-  printf("\n\nLeaving MC_NextQuestion()\n");
-  #endif
+  if (debug_status & debug_mathcards) {
+    printf("\nnext question is:");
+    print_card(*fc);
+    print_counters();
+    printf("\n\nLeaving MC_NextQuestion()\n");
+  }
 
   return 1;
 }
@@ -555,10 +555,10 @@
     return 0;
   }
 
-#ifdef MC_DEBUG
-  printf("\nMatching question is:");
-  print_card(quest->card);
-#endif
+  if (debug_status & debug_mathcards) {
+    printf("\nQuestion was:");
+    print_card(*fc);
+  }
 
   //We found a matching question, now we take it out of the 
   //"active_quests" list and either put it back into the 
@@ -588,11 +588,11 @@
     unanswered--;
   }
 
-#ifdef MC_DEBUG
-  print_counters();
-  printf("\nLeaving MC_AnsweredCorrectly()\n");
-#endif
-
+   if (debug_status & debug_mathcards) {
+    print_counters();
+    printf("\nLeaving MC_AnsweredCorrectly()\n");
+  }
+  
   return 1;
 }
 
@@ -643,10 +643,10 @@
 
     mcdprintf("\nAdding %d copies to question_list:", math_opts->iopts[COPIES_REPEATED_WRONGS]);
 
-#ifdef MC_DEBUG
-    printf("\nCard to be added is:");
-    print_card(quest->card);
-#endif
+    if (debug_status & debug_mathcards) {
+      print_counters();
+      printf("\nLeaving MC_AnsweredCorrectly()\n");
+    }
 
     /* can put in more than one copy (to drive the point home!) */
     for (i = 0; i < math_opts->iopts[COPIES_REPEATED_WRONGS]; i++)
@@ -685,10 +685,10 @@
     free_node(quest);
   }
 
-#ifdef MC_DEBUG
-  print_counters();
-  printf("\nLeaving MC_NotAnswered_Correctly()\n");
-#endif
+  if (debug_status & debug_mathcards) {
+    print_counters();
+    printf("\nLeaving MC_NotAnswered_Correctly()\n");
+  }
 
   return 1;
 }
@@ -752,9 +752,7 @@
       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
+      DEBUGMSG(debug_mathcards,"\nError: allocation for time_per_question_list failed\n");
       return 0;
     }
     time_per_question_list = newlist;
@@ -1585,9 +1583,10 @@
                     +  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
+    
+    if (debug_status & debug_mathcards) {
+      print_card(ret);
+    }
   }
   //TODO comparison problems (e.g. "6 ? 9", "<")
 
@@ -1804,9 +1803,8 @@
   MC_MathQuestion* end_of_list = NULL;
   MC_MathQuestion* tnode = NULL;
 
-#ifdef MC_DEBUG
-  MC_PrintMathOptions(stdout, 0);
-#endif
+  if (debug_status & debug_mathcards)
+    MC_PrintMathOptions(stdout, 0);
 
   if (!(MC_GetOpt(ARITHMETIC_ALLOWED) ||
       MC_GetOpt(TYPING_PRACTICE_ALLOWED) ||

Modified: tuxmath/branches/lan/src/mathcards.h
===================================================================
--- tuxmath/branches/lan/src/mathcards.h	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/mathcards.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -12,6 +12,8 @@
         Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
 
 */
+
+
 #ifndef MATHCARDS_H
 #define MATHCARDS_H
 
@@ -19,7 +21,7 @@
 
 #define MC_DEBUG
 #ifdef MC_DEBUG
-#define mcdprintf(...) printf(__VA_ARGS__)
+#define mcdprintf(...) DEBUGMSG(debug_mathcards,__VA_ARGS__)
 #else
 #define mcdprintf(...) 0
 #endif
@@ -224,7 +226,7 @@
 int MC_NextWrongQuest(MC_FlashCard* q);
 
 /*  Returns 1 if all have been answered correctly,        */
-/* 0 otherwise.                                           */
+/*  0 otherwise.                                          */
 int MC_MissionAccomplished(void);
 
 /*  Returns number of questions left (either in list      */
@@ -281,4 +283,5 @@
 /* Reorganize formula_string and answer_string to render the same equation
    in a different format */
 void reformat_arithmetic(MC_FlashCard* card, MC_Format f);
+
 #endif

Added: tuxmath/branches/lan/src/menu.c
===================================================================
--- tuxmath/branches/lan/src/menu.c	                        (rev 0)
+++ tuxmath/branches/lan/src/menu.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -0,0 +1,1491 @@
+/*
+  menu.c
+
+  Functions responsible for loading, parsing and displaying game menu.
+
+  Part of "Tux4Kids" Project
+  http://www.tux4kids.com/
+
+  Author: Boleslaw Kulbabinski <bkulbabinski at gmail.com>, (C) 2009
+
+  (Functions responsible for running specific activities
+   are moved from titlescreen.c)
+
+  Copyright: See COPYING file that comes with this distribution.
+*/
+
+#include "menu.h"
+#include "SDL_extras.h"
+#include "titlescreen.h"
+#include "highscore.h"
+#include "factoroids.h"
+#include "credits.h"
+#include "multiplayer.h"
+#include "mathcards.h"
+#include "campaign.h"
+#include "game.h"
+#include "options.h"
+#include "fileops.h"
+#include "setup.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+/* create string array of activities' names */
+#define X(name) #name
+char* activities[] = { ACTIVITIES };
+#undef X
+
+/* we may use a few separate menu trees */
+typedef enum {
+  MENU_MAIN,
+  MENU_DIFFICULTY,
+  MENU_LESSONS,
+  MENU_LOGIN,
+  N_OF_MENUS
+} MenuType;
+
+MenuNode* menus[N_OF_MENUS];
+
+/* actions available while viewing the menu */
+enum { NONE, CLICK, PAGEUP, PAGEDOWN, STOP_ESC, RESIZED };
+
+/* stop button, left and right arrow positions do not
+   depend on currently displayed menu */
+SDL_Rect menu_rect, stop_rect, prev_rect, next_rect;
+SDL_Surface *stop_button, *prev_arrow, *next_arrow, *prev_gray, *next_gray;
+
+/*TODO: move these constants into a config file (maybe together with
+  titlescreen paths and rects ? ) */
+const float menu_pos[4] = {0.38, 0.23, 0.55, 0.72};
+const float stop_pos[4] = {0.94, 0.0, 0.06, 0.06};
+const float prev_pos[4] = {0.87, 0.93, 0.06, 0.06};
+const float next_pos[4] = {0.94, 0.93, 0.06, 0.06};
+const char* stop_path = "status/stop.svg";
+const char* prev_path = "status/left.svg";
+const char* next_path = "status/right.svg";
+const char* prev_gray_path = "status/left_gray.svg";
+const char* next_gray_path = "status/right_gray.svg";
+const float button_gap = 0.2, text_h_gap = 0.4, text_w_gap = 0.5, button_radius = 0.27;
+const int min_font_size = 8, default_font_size = 20, max_font_size = 40;
+
+/* font size used in current resolution */
+int curr_font_size;
+
+/* menu title rect */
+SDL_Rect menu_title_rect;
+
+/* buffer size used when reading attributes or names */
+const int buf_size = 128;
+
+
+
+/* local functions */
+MenuNode*       create_empty_node();
+char*           get_attribute_name(const char* token);
+char*           get_attribute_value(const char* token);
+void            read_attributes(FILE* xml_file, MenuNode* node);
+MenuNode*       load_menu_from_file(FILE* xml_file, MenuNode* parent);
+void            free_menu(MenuNode* menu);
+MenuNode*       create_one_level_menu(int items, char** item_names, char* title, char* trailer);
+
+int             handle_activity(int act, int param);
+int             run_academy(void);
+int             run_arcade(int choice);
+int             run_custom_game(void);
+void            run_multiplayer(int mode, int difficulty);
+int             run_factoroids(int choice);
+
+int             run_menu(MenuNode* menu, bool return_choice);
+SDL_Surface**   render_buttons(MenuNode* menu, bool selected);
+void            prerender_menu(MenuNode* menu);
+char*           find_longest_text(MenuNode* menu, int* length);
+void            set_font_size();
+void            prerender_all();
+
+
+
+/*
+  functions responsible for parsing menu files
+  and creating menu trees
+*/
+
+/* creates new MenuNode struct with all fields set to NULL (or 0) */
+MenuNode* create_empty_node()
+{
+  MenuNode* new_node = malloc(sizeof(MenuNode));
+  new_node->parent = NULL;
+  new_node->title = NULL;
+  new_node->icon_name = NULL;
+  new_node->icon = NULL;
+  new_node->submenu_size = 0;
+  new_node->submenu = NULL;
+  new_node->activity = 0;
+  new_node->param = 0;
+  new_node->first_entry = 0;
+  new_node->show_title = false;
+
+  return new_node;
+}
+
+/* read attributes and fill appropriate node fields */
+void read_attributes(FILE* xml_file, MenuNode* node)
+{
+  char attr_name[buf_size];
+  char attr_val[buf_size];
+  int i;
+
+  /* read tokens until closing '>' is found */
+  do
+  {
+    fscanf(xml_file, " %[^=\n]", attr_name);
+
+    DEBUGMSG(debug_menu_parser, "read_attributes(): read attribute name: %s\n", attr_name);
+    if(strchr(attr_name, '>'))
+      break;
+
+    fscanf(xml_file, "=\"%[^\"]\"", attr_val);
+    DEBUGMSG(debug_menu_parser, "read_attributes(): read attribute value: %s\n", attr_val);
+
+    if(strcmp(attr_name, "title") == 0)
+      node->title = strdup(attr_val);
+    else if(strcmp(attr_name, "entries") == 0)
+      node->submenu_size = atoi(attr_val);
+    else if(strcmp(attr_name, "param") == 0)
+      node->param = atoi(attr_val);
+    else if(strcmp(attr_name, "sprite") == 0)
+      node->icon_name = strdup(attr_val);
+    else if(strcmp(attr_name, "run") == 0)
+    {
+      for(i = 0; i < N_OF_ACTIVITIES; i++)
+        if(strcmp(attr_val, activities[i]) == 0)
+          node->activity = i;
+    }
+    else
+      DEBUGMSG(debug_menu_parser, "read_attributes(): unknown attribute %s , omitting\n", attr_name);
+
+  } while(strchr(attr_val, '>') == NULL);
+}
+
+/* recursively read and parse given xml menu file and create menu tree
+   return NULL in case of problems */
+MenuNode* load_menu_from_file(FILE* xml_file, MenuNode* parent)
+{
+  MenuNode* new_node = create_empty_node();
+  char buffer[buf_size];
+  int i;
+
+  new_node->parent = parent;
+
+  DEBUGMSG(debug_menu_parser, "entering load_menu_from_file()\n");
+  fscanf(xml_file, " < %s", buffer);
+
+  if(strcmp(buffer, "menu") == 0)
+  {
+    read_attributes(xml_file, new_node);
+    if(new_node->title == NULL)
+    {
+      DEBUGMSG(debug_menu_parser, "load_menu_from_file(): no title attribute, exiting\n");
+      return NULL;
+    }
+
+    if(new_node->submenu_size > 0)
+    {
+      new_node->submenu = malloc(new_node->submenu_size * sizeof(MenuNode));
+      for(i = 0; i < new_node->submenu_size; i++)
+        new_node->submenu[i] = load_menu_from_file(xml_file, new_node);
+    }
+
+    fscanf(xml_file, " </%[^>\n]> ", buffer);
+    if(strcmp(buffer, "menu") != 0)
+      DEBUGMSG(debug_menu_parser, "load_menu_from_file(): warning - no closing menu tag, found %s instead\n", buffer);
+  }
+  else if(strcmp(buffer, "item") == 0)
+  {
+    read_attributes(xml_file, new_node);
+    if(new_node->title == NULL)
+    {
+      DEBUGMSG(debug_menu_parser, "load_menu_from_file(): no title attribute, exiting\n");
+      return NULL;
+    }
+  }
+  else
+  {
+    DEBUGMSG(debug_menu_parser, "load_menu_from_file(): unknown tag: %s\n, exiting\n", buffer);
+    return NULL;
+  }
+
+  DEBUGMSG(debug_menu_parser, "load_menu_from_file(): node loaded successfully\n");
+  return new_node;
+}
+
+/* recursively free all non-NULL pointers in a menu tree */
+void free_menu(MenuNode* menu)
+{
+  int i;
+
+  DEBUGMSG(debug_menu, "entering free_menu()\n");
+  if(menu != NULL)
+  {
+    if(menu->title != NULL)
+      free(menu->title);
+    if(menu->icon_name != NULL)
+      free(menu->icon_name);
+    if(menu->icon != NULL)
+      FreeSprite(menu->icon);
+
+    if(menu->submenu != NULL)
+    {
+      for(i = 0; i < menu->submenu_size; i++)
+        if(menu->submenu[i] != NULL)
+        {
+          free_menu(menu->submenu[i]);
+          menu->submenu[i] = NULL;
+        }
+      free(menu->submenu);
+    }
+
+    free(menu);
+  }
+}
+
+/* create a simple one-level menu without sprites.
+   all given strings are copied */
+MenuNode* create_one_level_menu(int items, char** item_names, char* title, char* trailer)
+{
+  MenuNode* menu = create_empty_node();
+  int i;
+
+  if(title)
+  {
+    menu->title = strdup(title);
+    menu->show_title = true;
+  }
+  menu->submenu_size = items + (trailer ? 1 : 0);
+  menu->submenu = (MenuNode**) malloc(menu->submenu_size * sizeof(MenuNode*));
+  for(i = 0; i < items; i++)
+  {
+    menu->submenu[i] = create_empty_node();
+    menu->submenu[i]->title = strdup(item_names[i]);
+    menu->submenu[i]->activity = i;
+  }
+
+  if(trailer)
+  {
+    menu->submenu[items] = create_empty_node();
+    menu->submenu[items]->title = strdup(trailer);
+    menu->submenu[items]->activity = items;
+  }
+
+  return menu;
+}
+
+/*
+  handlers for specific game activities
+*/
+
+/* return QUIT if user decided to quit the application while running an activity
+   return 0 otherwise */
+int handle_activity(int act, int param)
+{
+  DEBUGMSG(debug_menu, "entering handle_activity()\n");
+
+  switch(act)
+  {
+    case RUN_CAMPAIGN:
+      start_campaign();
+      break;
+
+    case RUN_ACADEMY:
+      if(run_academy() == QUIT)
+        return QUIT;
+      break;
+
+    case RUN_ARCADE:
+      run_arcade(param);
+      break;
+
+    case RUN_CUSTOM:
+      run_custom_game();
+      break;
+
+    case RUN_HALL_OF_FAME:
+      DisplayHighScores(CADET_HIGH_SCORE);
+      break;
+
+    case RUN_SCORE_SWEEP:
+      run_multiplayer(0, param);
+      break;
+
+    case RUN_ELIMINATION:
+      run_multiplayer(1, param);
+      break;
+
+    case RUN_HELP:
+      Opts_SetHelpMode(1);
+      Opts_SetDemoMode(0);
+      if (Opts_GetGlobalOpt(MENU_MUSIC))  //Turn menu music off for game
+        {audioMusicUnload();}
+      game();
+      if (Opts_GetGlobalOpt(MENU_MUSIC)) //Turn menu music back on
+        audioMusicLoad( "tuxi.ogg", -1 );
+      Opts_SetHelpMode(0);
+      break;
+
+    case RUN_FACTORS:
+      run_factoroids(0);
+      break;
+
+    case RUN_FRACTIONS:
+      run_factoroids(1);
+      break;
+
+    case RUN_DEMO:
+      if(read_named_config_file("demo"))
+      {
+        audioMusicUnload();
+        game();
+        if (Opts_GetGlobalOpt(MENU_MUSIC))
+          audioMusicLoad( "tuxi.ogg", -1 );
+      }
+      else
+        fprintf(stderr, "\nCould not find demo config file\n");
+      break;
+
+    case RUN_INFO:
+      ShowMessage(_("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"));
+      break;
+
+    case RUN_CREDITS:
+      credits();
+      break;
+
+    case RUN_QUIT:
+      return QUIT;
+  }
+
+  return 0;
+}
+
+int run_academy(void)
+{
+  int chosen_lesson = -1;
+
+  chosen_lesson = run_menu(menus[MENU_LESSONS], true);
+  while (chosen_lesson >= 0)
+  {
+    if (Opts_GetGlobalOpt(MENU_SOUND))
+      playsound(SND_POP);
+
+    /* Re-read global settings first in case any settings were */
+    /* clobbered by other lesson or arcade games this session: */
+    read_global_config_file();
+    /* Now read the selected file and play the "mission": */
+    if (read_named_config_file(lesson_list_filenames[chosen_lesson]))
+    {
+      if (Opts_GetGlobalOpt(MENU_MUSIC))  //Turn menu music off for game
+        {audioMusicUnload();}
+
+      game();
+
+      /* If successful, display Gold Star for this lesson! */
+      if (MC_MissionAccomplished())
+      {
+        lesson_list_goldstars[chosen_lesson] = 1;
+       /* and save to disk: */
+        write_goldstars();
+      }
+
+      if (Opts_GetGlobalOpt(MENU_MUSIC)) //Turn menu music back on
+        {audioMusicLoad("tuxi.ogg", -1);}
+    }
+    else  // Something went wrong - could not read lesson config file:
+    {
+      fprintf(stderr, "\nCould not find file: %s\n", lesson_list_filenames[chosen_lesson]);
+      chosen_lesson = -1;
+    }
+    // Let the user choose another lesson; start with the screen and
+    // selection that we ended with
+    chosen_lesson = run_menu(menus[MENU_LESSONS], true);
+  }
+  return chosen_lesson;
+}
+
+int run_arcade(int choice)
+{
+  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
+    };
+
+  int hs_table;
+
+  if (choice < NUM_MATH_COMMAND_LEVELS) {
+    // Play arcade game
+    if (read_named_config_file(arcade_config_files[choice]))
+    {
+      audioMusicUnload();
+      game();
+      RenderTitleScreen();
+      if (Opts_GetGlobalOpt(MENU_MUSIC))
+        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)
+      {
+        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]);
+
+        DEBUGCODE(debug_titlescreen)
+          print_high_scores(stderr);
+      }
+    }
+    else {
+      fprintf(stderr, "\nCould not find %s config file\n",arcade_config_files[choice]);
+    }
+  }
+  return 0;
+}
+
+int run_custom_game(void)
+{
+  const char *s1, *s2, *s3, *s4;
+  s1 = _("Edit 'options' file in your home directory");
+  s2 = _("to create customized game!");
+  s3 = _("Press a key or click your mouse to start game.");
+  s4 = _("See README.txt for more information");
+  ShowMessage(s1, s2, s3, s4);
+
+  if (read_user_config_file()) {
+    if (Opts_GetGlobalOpt(MENU_MUSIC))
+      audioMusicUnload();
+
+    game();
+    write_user_config_file();
+
+    if (Opts_GetGlobalOpt(MENU_MUSIC))
+      audioMusicLoad( "tuxi.ogg", -1 );
+  }
+
+  return 0;
+}
+
+void run_multiplayer(int mode, int difficulty)
+{
+  int nplayers = 0;
+  char npstr[HIGH_SCORE_NAME_LENGTH * 3];
+
+  while (nplayers <= 0 || nplayers > MAX_PLAYERS)
+  {
+    NameEntry(npstr, _("How many kids are playing?"),
+                     _("(Between 2 and 4 players)"));
+    nplayers = atoi(npstr);
+  }
+
+  mp_set_parameter(PLAYERS, nplayers);
+  mp_set_parameter(MODE, mode);
+  mp_set_parameter(DIFFICULTY, difficulty);
+  mp_run_multiplayer();
+}
+
+int run_factoroids(int choice)
+{
+  const int factoroids_high_score_tables[2] =
+    {FACTORS_HIGH_SCORE, FRACTIONS_HIGH_SCORE};
+  int hs_table;
+
+  audioMusicUnload();
+  if(choice == 0)
+    factors();
+  else
+    fractions();
+
+	if (Opts_GetGlobalOpt(MENU_MUSIC))
+    audioMusicLoad( "tuxi.ogg", -1 );
+
+	hs_table = factoroids_high_score_tables[choice];
+	if (check_score_place(hs_table, Opts_LastScore()) < HIGH_SCORES_SAVED){
+	  char player_name[HIGH_SCORE_NAME_LENGTH * 3];
+	  /* Get name from player: */
+	  HighScoreNameEntry(&player_name[0]);
+	  insert_score(player_name, hs_table, Opts_LastScore());
+	  /* Show the high scores. Note the user will see his/her */
+	  /* achievement even if (in the meantime) another player */
+	  /* has in fact already bumped this score off the table. */
+	  DisplayHighScores(hs_table);
+	  /* save to disk: */
+	  /* See "On File Locking" in fileops.c */
+	  append_high_score(hs_table,Opts_LastScore(),&player_name[0]);
+    DEBUGCODE(debug_titlescreen)
+	    print_high_scores(stderr);
+	}
+  else {
+	  fprintf(stderr, "\nCould not find config file\n");
+  }
+
+  return 0;
+}
+
+/* Display the menu and run the event loop.
+   if return_choice = true then return chosen value instead of
+   running handle_activity()
+   this function is a modified copy of choose_menu_item() */
+int run_menu(MenuNode* root, bool return_choice)
+{
+  SDL_Surface** menu_item_unselected = NULL;
+  SDL_Surface** menu_item_selected = NULL;
+  SDL_Surface* title_surf;
+  SDL_Event event;
+  MenuNode* menu = root;
+  MenuNode* tmp_node;
+
+  SDL_Rect tmp_rect;
+  sprite* tmp_sprite;
+  int i;
+  int stop = 0;
+  int items;
+
+  int action = NONE;
+
+  Uint32 frame_start = 0;       //For keeping frame rate constant
+  Uint32 frame_now = 0;
+  Uint32 frame_counter = 0;
+  int loc = -1;                  //The currently selected menu item
+  int old_loc = -1;
+  int click_flag = 1;
+
+  for(;;) /* one loop body execution for one menu page */
+  {
+    DEBUGMSG(debug_menu, "run_menu(): drawing whole new menu page\n");
+
+    DrawTitleScreen();
+    /* render buttons for current menu page */
+    menu_item_unselected = render_buttons(menu, false);
+    menu_item_selected = render_buttons(menu, true);
+    items = min(menu->entries_per_screen, menu->submenu_size - menu->first_entry);
+
+    DEBUGMSG(debug_menu, "run_menu(): drawing %d buttons\n", items);
+    for(i = 0; i < items; i++)
+    {
+      if(loc == i)
+        SDL_BlitSurface(menu_item_selected[i], NULL, screen, &menu->submenu[menu->first_entry + i]->button_rect);
+      else
+        SDL_BlitSurface(menu_item_unselected[i], NULL, screen, &menu->submenu[menu->first_entry + i]->button_rect);
+      if(menu->submenu[menu->first_entry + i]->icon)
+        SDL_BlitSurface(menu->submenu[menu->first_entry + i]->icon->default_img, NULL, screen, &menu->submenu[menu->first_entry + i]->icon_rect);
+    }
+
+    SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
+
+    if(menu->entries_per_screen < menu->submenu_size)
+    {
+      /* display arrows */
+      if(menu->first_entry > 0)
+        SDL_BlitSurface(prev_arrow, NULL, screen, &prev_rect);
+      else
+        SDL_BlitSurface(prev_gray, NULL, screen, &prev_rect);
+      if(menu->first_entry + items < menu->submenu_size)
+        SDL_BlitSurface(next_arrow, NULL, screen, &next_rect);
+      else
+        SDL_BlitSurface(next_gray, NULL, screen, &next_rect);
+    }
+
+    if(menu->show_title)
+    {
+      menu_title_rect = menu->submenu[0]->button_rect;
+      menu_title_rect.y = menu_rect.y - menu_title_rect.h;
+      title_surf = BlackOutline(_(menu->title), curr_font_size, &red);
+      SDL_BlitSurface(title_surf, NULL, screen, &menu_title_rect);
+      SDL_FreeSurface(title_surf);
+    }
+    SDL_UpdateRect(screen, 0, 0, 0, 0);
+
+    SDL_WM_GrabInput(SDL_GRAB_OFF);
+
+    while (SDL_PollEvent(&event));  // clear pending events
+
+    /******** Main loop: *********/
+    stop = false;
+    DEBUGMSG(debug_menu, "run_menu(): entering menu loop\n");
+    while (!stop)
+    {
+      frame_start = SDL_GetTicks();         /* For keeping frame rate constant.*/
+
+      action = NONE;
+      while (!stop && SDL_PollEvent(&event))
+      {
+        switch (event.type)
+        {
+          case SDL_QUIT:
+          {
+            FreeSurfaceArray(menu_item_unselected, items);
+            FreeSurfaceArray(menu_item_selected, items);
+            return QUIT;
+          }
+
+          case SDL_MOUSEMOTION:
+          {
+            loc = -1;
+            for (i = 0; i < items; i++)
+            {
+              if (inRect(menu->submenu[menu->first_entry + i]->button_rect, event.motion.x, event.motion.y))
+              {
+                if (Opts_GetGlobalOpt(MENU_SOUND) && old_loc != i)
+                  playsound(SND_TOCK);
+                loc = i;
+                break;   /* from for loop */
+              }
+            }
+
+            /* "Left" button - make click if button active: */
+            if(inRect(prev_rect, event.motion.x, event.motion.y)
+               && menu->first_entry > 0 && Opts_GetGlobalOpt(MENU_SOUND))
+            {
+              if(click_flag)
+              {
+                playsound(SND_TOCK);
+                click_flag = 0;
+              }
+            }
+
+            /* "Right" button - make click if button active: */
+            else if(inRect(next_rect, event.motion.x, event.motion.y)
+               && menu->first_entry + items < menu->submenu_size
+               && Opts_GetGlobalOpt(MENU_SOUND))
+            {
+              if(click_flag)
+              {
+                playsound(SND_TOCK);
+                click_flag = 0;
+              }
+            }
+
+            /* "stop" button */
+            else if (inRect(stop_rect, event.motion.x, event.motion.y )
+               && Opts_GetGlobalOpt(MENU_SOUND))
+            {
+              if(click_flag)
+              {
+                playsound(SND_TOCK);
+                click_flag = 0;
+              }
+            }
+
+            else  // Mouse outside of arrow rects - re-enable click sound:
+              click_flag = 1;
+
+            break;
+          }
+
+          case SDL_MOUSEBUTTONDOWN:
+          {
+            loc = -1;  // By default, don't be in any entry
+            for (i = 0; i < items; i++)
+            {
+              if (inRect(menu->submenu[menu->first_entry + i]->button_rect, event.motion.x, event.motion.y))
+              {
+                // Play sound if loc is being changed:
+                if (Opts_GetGlobalOpt(MENU_SOUND))
+                  playsound(SND_POP);
+                loc = i;
+                action = CLICK;
+                break;   /* from for loop */
+              }
+            }
+
+            /* "Left" button */
+            if (inRect(prev_rect, event.motion.x, event.motion.y)
+               && menu->first_entry > 0)
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                playsound(SND_POP);
+              action = PAGEUP;
+            }
+
+            /* "Right" button - go to next page: */
+            else if (inRect(next_rect, event.motion.x, event.motion.y )
+               && menu->first_entry + items < menu->submenu_size)
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                playsound(SND_POP);
+              action = PAGEDOWN;
+            }
+
+            /* "Stop" button - go to main menu: */
+            else if (inRect(stop_rect, event.button.x, event.button.y ))
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                playsound(SND_POP);
+              action = STOP_ESC;
+            }
+
+            break;
+          } /* End of case SDL_MOUSEDOWN */
+
+          case SDL_KEYDOWN:
+          {
+            /* Proceed according to particular key pressed: */
+            switch (event.key.keysym.sym)
+            {
+              case SDLK_ESCAPE:
+              {
+                action = STOP_ESC;
+                break;
+              }
+
+              case SDLK_RETURN:
+              case SDLK_SPACE:
+              case SDLK_KP_ENTER:
+              {
+                if (Opts_GetGlobalOpt(MENU_SOUND))
+                  playsound(SND_POP);
+                action = CLICK;
+                break;
+              }
+
+              /* Go to previous page, if present: */
+              case SDLK_LEFT:
+              case SDLK_PAGEUP:
+              {
+                if (Opts_GetGlobalOpt(MENU_SOUND))
+                  playsound(SND_TOCK);
+                if (menu->first_entry > 0)
+                  action = PAGEUP;
+                break;
+              }
+
+              /* Go to next page, if present: */
+              case SDLK_RIGHT:
+              case SDLK_PAGEDOWN:
+              {
+                if (Opts_GetGlobalOpt(MENU_SOUND))
+                  playsound(SND_TOCK);
+                if (menu->first_entry + items < menu->submenu_size)
+                  action = PAGEDOWN;
+                break;
+              }
+
+              /* Go up one entry, if present: */
+              case SDLK_UP:
+              {
+                if (Opts_GetGlobalOpt(MENU_SOUND))
+                  playsound(SND_TOCK);
+                if (loc > 0)
+                  loc--;
+                else if (menu->submenu_size <= menu->entries_per_screen) 
+                  loc = menu->submenu_size - 1;  // wrap around if only 1 screen
+                else if (menu->first_entry > 0)
+                {
+                  loc = menu->entries_per_screen - 1;
+                  action = PAGEUP;
+                }
+                break;
+              }
+
+              case SDLK_DOWN:
+              {
+                if (Opts_GetGlobalOpt(MENU_SOUND))
+                  playsound(SND_TOCK);
+                if (loc + 1 < min(menu->submenu_size, menu->entries_per_screen))
+                  loc++;
+                else if (menu->submenu_size <= menu->entries_per_screen) 
+                  loc = 0;  // wrap around if only 1 screen
+                else if (menu->first_entry + menu->entries_per_screen < menu->submenu_size)
+                {
+                  loc = 0;
+                  action = PAGEDOWN;
+                }
+                break;
+              }
+
+              /* Change window size (used only to debug) */
+              case SDLK_F5:
+              case SDLK_F6:
+              case SDLK_F7:
+              case SDLK_F8:
+              {
+                /* these keys are available only if in debug mode */
+                DEBUGCODE(debug_titlescreen | debug_menu)
+                {
+                  switch(event.key.keysym.sym)
+                  {
+                    case SDLK_F5:
+                    {
+                      /* decrease screen width */
+                      ChangeWindowSize(win_res_x - 50, win_res_y);
+                      break;
+                    }
+                    case SDLK_F6:
+                    {
+                      /* increase screen width */
+                      ChangeWindowSize(win_res_x + 50, win_res_y);
+                      break;
+                    }
+                    case SDLK_F7:
+                    {
+                      /* decrease screen height */
+                      ChangeWindowSize(win_res_x, win_res_y - 50);
+                      break;
+                    }
+                    case SDLK_F8:
+                    {
+                      /* increase screen height */
+                      ChangeWindowSize(win_res_x, win_res_y + 50);
+                      break;
+                    }
+                    default:
+                      break;
+                  }
+                  action = RESIZED;
+                }
+                break;
+              }
+
+              /* Toggle screen mode: */
+              case SDLK_F10:
+              {
+                SwitchScreenMode();
+                action = RESIZED;
+                break;
+              }
+
+              /* Toggle menu music: */
+              case SDLK_F11:
+              {
+                if (Opts_GetGlobalOpt(MENU_MUSIC))
+                {
+                  audioMusicUnload( );
+                  Opts_SetGlobalOpt(MENU_MUSIC, 0);
+                }
+                else
+                {
+                  Opts_SetGlobalOpt(MENU_MUSIC, 1);
+                  audioMusicLoad("tuxi.ogg", -1);
+                }
+                break;
+              }
+
+              default:
+              {
+                /* Some other key - do nothing. */
+              }
+
+              break;  /* To get out of _outer_ switch/case statement */
+            }  /* End of key switch statement */
+          }  // End of case SDL_KEYDOWN in outer switch statement
+        }  // End event switch statement
+
+        if (old_loc != loc) {
+          DEBUGMSG(debug_menu, "run_menu(): changed button focus, old=%d, new=%d\n", old_loc, loc);
+          if(old_loc >= 0 && old_loc < items)
+          {
+            tmp_rect = menu->submenu[old_loc + menu->first_entry]->button_rect;
+            SDL_BlitSurface(menu_item_unselected[old_loc], NULL, screen, &tmp_rect);
+            if(menu->submenu[menu->first_entry + old_loc]->icon)
+              SDL_BlitSurface(menu->submenu[menu->first_entry + old_loc]->icon->default_img, NULL, screen, &menu->submenu[menu->first_entry + old_loc]->icon_rect);
+            SDL_UpdateRect(screen, tmp_rect.x, tmp_rect.y, tmp_rect.w, tmp_rect.h);
+          }
+          if(loc >= 0 && loc < items)
+          {
+            tmp_rect = menu->submenu[loc + menu->first_entry]->button_rect;
+            SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &tmp_rect);
+            if(menu->submenu[menu->first_entry + loc]->icon)
+            {
+              SDL_BlitSurface(menu->submenu[menu->first_entry + loc]->icon->default_img, NULL, screen, &menu->submenu[menu->first_entry + loc]->icon_rect);
+              menu->submenu[menu->first_entry + loc]->icon->cur = 0;
+            }
+            SDL_UpdateRect(screen, tmp_rect.x, tmp_rect.y, tmp_rect.w, tmp_rect.h);
+          }
+          old_loc = loc;
+        }
+
+        if(HandleTitleScreenEvents(&event))
+          stop = true;
+
+        switch(action)
+        {
+          case RESIZED:
+            RenderTitleScreen();
+            menu->first_entry = 0;
+            prerender_all();
+            stop = true;
+            break;
+
+          case CLICK:
+            if(loc < 0 || loc >= items)
+            {
+              DEBUGMSG(debug_menu, "run_menu(): incorrect location for CLICK action (%d) !\n", loc);
+            }
+            else
+            {
+              tmp_node = menu->submenu[menu->first_entry + loc];
+              if(tmp_node->submenu_size == 0)
+              {
+                if(return_choice)
+                {
+                  FreeSurfaceArray(menu_item_unselected, items);
+                  FreeSurfaceArray(menu_item_selected, items);
+                  return tmp_node->activity;
+                }
+                else
+                {
+                  if(tmp_node->activity == RUN_MAIN_MENU)
+                  {
+                    /* go back to the root of this menu */
+                    menu = root;
+                  }
+                  else
+                  {
+                    if(handle_activity(tmp_node->activity, tmp_node->param) == QUIT)
+                    {
+                      DEBUGMSG(debug_menu, "run_menu(): handle_activity() returned QUIT message, exiting.\n");
+                      FreeSurfaceArray(menu_item_unselected, items);
+                      FreeSurfaceArray(menu_item_selected, items);
+                      return QUIT;
+                    }
+                  }
+                }
+              }
+              else
+              {
+                menu->first_entry = 0;
+                menu = tmp_node;
+                menu->first_entry = 0;
+              }
+              stop = true;
+            }
+            break;
+
+          case STOP_ESC:
+            if(menu->parent == NULL)
+            {
+              FreeSurfaceArray(menu_item_unselected, items);
+              FreeSurfaceArray(menu_item_selected, items);
+              return STOP;
+            }
+            else
+              menu = menu->parent;
+            stop = true;
+            break;
+
+          case PAGEUP:
+            menu->first_entry -= menu->entries_per_screen;
+            stop = true;
+            break;
+
+          case PAGEDOWN:
+            menu->first_entry += menu->entries_per_screen;
+            stop = true;
+            break;
+        }
+
+      }  // End of SDL_PollEvent while loop
+
+      if(stop)
+        break;
+
+      if(!stop && frame_counter % 5 == 0 && loc >= 0 && loc < items)
+      {
+        tmp_sprite = menu->submenu[menu->first_entry + loc]->icon;
+        if(tmp_sprite)
+        {
+          SDL_BlitSurface(menu_item_selected[loc], NULL, screen, &menu->submenu[menu->first_entry + loc]->icon_rect);
+          SDL_BlitSurface(tmp_sprite->frame[tmp_sprite->cur], NULL, screen, &menu->submenu[menu->first_entry + loc]->icon_rect);
+          UpdateRect(screen, &menu->submenu[menu->first_entry + loc]->icon_rect);
+          NextFrame(tmp_sprite);
+        }
+      }
+
+      HandleTitleScreenAnimations();
+
+      /* Wait so we keep frame rate constant: */
+      frame_now = SDL_GetTicks();
+      if (frame_now < frame_start)
+        frame_start = frame_now;  // in case the timer wraps around
+      if((frame_now - frame_start) < 1000 / MAX_FPS)
+        SDL_Delay(1000 / MAX_FPS - (frame_now - frame_start));
+
+      frame_counter++;
+    } // End of while(!stop) loop
+
+    /* free button surfaces */
+    DEBUGMSG(debug_menu, "run_menu(): freeing %d button surfaces\n", items);
+    FreeSurfaceArray(menu_item_unselected, items);
+    FreeSurfaceArray(menu_item_selected, items);
+  }
+
+  return QUIT;
+}
+
+/* return button surfaces that are currently displayed (without sprites) */
+SDL_Surface** render_buttons(MenuNode* menu, bool selected)
+{
+  SDL_Surface** menu_items = NULL;
+  SDL_Rect curr_rect;
+  SDL_Surface* tmp_surf = NULL;
+  int i;
+  int items = min(menu->entries_per_screen, menu->submenu_size - menu->first_entry);
+
+  menu_items = (SDL_Surface**) malloc(items * sizeof(SDL_Surface*));
+  if(NULL == menu_items)
+  {
+    DEBUGMSG(debug_menu, "render_buttons(): failed to allocate memory for buttons!\n");
+    return NULL;  // error
+  }
+
+  for (i = 0; i < items; i++)
+  {
+    curr_rect = menu->submenu[menu->first_entry + i]->button_rect;
+    menu_items[i] = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
+                                          curr_rect.w,
+                                          curr_rect.h,
+                                          32,
+                                          rmask, gmask, bmask, amask);
+
+    SDL_BlitSurface(screen, &curr_rect, menu_items[i], NULL);
+    /* button */
+    if(selected)
+      tmp_surf = CreateButton(curr_rect.w, curr_rect.h, button_radius * curr_rect.h, SEL_RGBA);
+    else
+      tmp_surf = CreateButton(curr_rect.w, curr_rect.h, button_radius * curr_rect.h, REG_RGBA);
+
+    SDL_BlitSurface(tmp_surf, NULL, menu_items[i], NULL);
+    SDL_FreeSurface(tmp_surf);
+
+    /* text */
+    tmp_surf = BlackOutline(_(menu->submenu[menu->first_entry + i]->title),
+                            curr_font_size, selected ? &yellow : &white);
+    SDL_BlitSurface(tmp_surf, NULL, menu_items[i], &menu->submenu[menu->first_entry + i]->text_rect);
+    SDL_FreeSurface(tmp_surf);
+  }
+
+  return menu_items;
+}
+
+/* recursively load sprites and calculate button rects
+   to fit into current screen */
+void prerender_menu(MenuNode* menu)
+{
+  SDL_Surface* temp_surf;
+  MenuNode* curr_node;
+  int i, imod, max_text_h = 0, max_text_w = 0;
+  int button_h, button_w;
+  bool found_icons = false;
+  char filename[buf_size];
+
+  if(NULL == menu)
+  {
+    DEBUGMSG(debug_menu, "prerender_menu(): NULL pointer, exiting !\n");
+    return;
+  }
+
+  if(0 == menu->submenu_size)
+  {
+    DEBUGMSG(debug_menu, "prerender_menu(): no submenu, exiting.\n");
+    return;
+  }
+
+  for(i = 0; i < menu->submenu_size; i++)
+  {
+    if(menu->submenu[i]->icon_name)
+      found_icons = true;
+    temp_surf = NULL;
+    temp_surf = SimpleText(_(menu->submenu[i]->title), curr_font_size, &black);
+    if(temp_surf)
+    {
+      max_text_h = max(max_text_h, temp_surf->h);
+      max_text_w = max(max_text_w, temp_surf->w);
+      SDL_FreeSurface(temp_surf);
+    }
+  }
+
+  button_h = (1.0 + 2.0 * text_h_gap) * max_text_h;
+  button_w = max_text_w + ( (found_icons ? 1.0 : 0.0) + 2.0 * text_w_gap) * button_h;
+
+  menu->entries_per_screen = (int) ( (menu_rect.h - button_gap * button_h) /
+                                   ( (1.0 + button_gap) * button_h ) );
+
+  for(i = 0; i < menu->submenu_size; i++)
+  {
+    curr_node = menu->submenu[i];
+    curr_node->button_rect.x = menu_rect.x;
+    imod = i % menu->entries_per_screen;
+    curr_node->button_rect.y = menu_rect.y + imod * button_h + (imod + 1) * button_gap * button_h;
+    curr_node->button_rect.w = button_w;
+    curr_node->button_rect.h = button_h;
+
+    curr_node->icon_rect = curr_node->button_rect;
+    curr_node->icon_rect.w = curr_node->icon_rect.h;
+
+    curr_node->text_rect.x = ( (found_icons ? 1.0 : 0.0) + text_w_gap) * curr_node->icon_rect.w;
+    curr_node->text_rect.y = text_h_gap * max_text_h;
+    curr_node->text_rect.h = max_text_h;
+    curr_node->text_rect.w = max_text_w;
+
+    if(curr_node->icon)
+      FreeSprite(curr_node->icon);
+
+    if(curr_node->icon_name)
+    {
+      sprintf(filename, "sprites/%s", curr_node->icon_name);
+      DEBUGMSG(debug_menu, "prerender_menu(): loading sprite %s for item #%d.\n", filename, i);
+      curr_node->icon = LoadSpriteOfBoundingBox(filename, IMG_ALPHA, button_h, button_h);
+    }
+    else
+      DEBUGMSG(debug_menu, "prerender_menu(): no sprite for item #%d.\n", i);
+
+    prerender_menu(menu->submenu[i]);
+  }
+}
+
+char* find_longest_text(MenuNode* menu, int* length)
+{
+  SDL_Surface* text = NULL;
+  char *ret = NULL, *temp = NULL;
+  int i;
+
+  if(menu->submenu_size == 0)
+  {
+    text = SimpleText(_(menu->title), curr_font_size, &black);
+    if(text->w > *length)
+    {
+      *length = text->w;
+      ret = menu->title;
+    }
+    SDL_FreeSurface(text);
+  }
+  else
+  {
+    for(i = 0; i < menu->submenu_size; i++)
+    {
+      temp = find_longest_text(menu->submenu[i], length);
+      if(temp)
+        ret = temp;
+    }
+  }
+  return ret;
+}
+
+/* find the longest text in all existing menus and binary search
+   for the best font size */
+void set_font_size()
+{
+  char* longest = NULL;
+  char* temp;
+  SDL_Surface* surf;
+  int length = 0, i, min_f, max_f, mid_f;
+
+  curr_font_size = default_font_size;
+
+  for(i = 0; i < N_OF_MENUS; i++)
+  {
+    if(menus[i])
+    {
+      temp = find_longest_text(menus[i], &length);
+      if(temp)
+        longest = temp;
+    }
+  }
+
+  if(!longest)
+    return;
+
+  min_f = min_font_size;
+  max_f = max_font_size;
+
+  while(min_f < max_f)
+  {
+    mid_f = (min_f + max_f) / 2;
+    surf = SimpleText(_(longest), mid_f, &black);
+    if(surf->w + (1.0 + 2.0 * text_w_gap) * (1.0 + 2.0 * text_h_gap) * surf->h < menu_rect.w)
+      min_f = mid_f + 1;
+    else
+      max_f = mid_f;
+    SDL_FreeSurface(surf);
+  }
+
+  curr_font_size = min_f;
+}
+
+/* prerender arrows, stop button and all non-NULL menus from menus[] array
+   this function should be invoked after every resolution change */
+void prerender_all()
+{
+  int i;
+
+  SetRect(&menu_rect, menu_pos);
+
+  SetRect(&stop_rect, stop_pos);
+  if(stop_button)
+    SDL_FreeSurface(stop_button);
+  stop_button = LoadImageOfBoundingBox(stop_path, IMG_ALPHA, stop_rect.w, stop_rect.h);
+  /* move button to the right */
+  stop_rect.x = screen->w - stop_button->w;
+
+  SetRect(&prev_rect, prev_pos);
+  if(prev_arrow)
+    SDL_FreeSurface(prev_arrow);
+  prev_arrow = LoadImageOfBoundingBox(prev_path, IMG_ALPHA, prev_rect.w, prev_rect.h);
+  if(prev_gray)
+    SDL_FreeSurface(prev_gray);
+  prev_gray = LoadImageOfBoundingBox(prev_gray_path, IMG_ALPHA, prev_rect.w, prev_rect.h);
+  /* move button to the right */
+  prev_rect.x += prev_rect.w - prev_arrow->w;
+
+  SetRect(&next_rect, next_pos);
+  if(next_arrow)
+    SDL_FreeSurface(next_arrow);
+  next_arrow = LoadImageOfBoundingBox(next_path, IMG_ALPHA, next_rect.w, next_rect.h);
+  if(next_gray)
+    SDL_FreeSurface(next_gray);
+  next_gray = LoadImageOfBoundingBox(next_gray_path, IMG_ALPHA, next_rect.w, next_rect.h);
+
+  set_font_size();
+
+  for(i = 0; i < N_OF_MENUS; i++)
+    if(menus[i])
+      prerender_menu(menus[i]);
+}
+
+/* load menu trees from disk and prerender them */
+void LoadMenus(void)
+{
+  FILE* menu_file = NULL;
+  int i;
+
+  for(i = 0; i < N_OF_MENUS; i++)
+    menus[i] = NULL;
+
+  /* main menu */
+  menu_file = fopen(DATA_PREFIX "/menus/main_menu.xml", "r");
+  if(menu_file == NULL)
+  {
+    DEBUGMSG(debug_menu, "LoadMenus(): Could not load main menu file !\n");
+  }
+  else
+  {
+    menus[MENU_MAIN] = load_menu_from_file(menu_file, NULL);
+    fclose(menu_file);
+  }
+
+  /* difficulty menu */
+  menu_file = fopen(DATA_PREFIX "/menus/level_menu.xml", "r");
+  if(menu_file == NULL)
+  {
+    DEBUGMSG(debug_menu, "LoadMenus(): Could not load level menu file !\n");
+  }
+  else
+  {
+    menus[MENU_DIFFICULTY] = load_menu_from_file(menu_file, NULL);
+    fclose(menu_file);
+  }
+
+  prerender_all();
+}
+
+
+
+/* create login menu tree, run it and set the user home directory
+   -1 indicates that the user wants to quit without logging in,
+    0 indicates that a choice has been made. */
+int RunLoginMenu(void)
+{
+  int n_login_questions = 0;
+  char **user_login_questions = NULL;
+  char *title = NULL;
+  int n_users = 0;
+  char **user_names = NULL;
+  int chosen_login = -1;
+  int level;
+  int i;
+  char *trailer_quit = "Quit";
+  char *trailer_back = "Back";
+  char *trailer = NULL;
+  SDLMod mod;
+
+  DEBUGMSG(debug_menu, "Entering RunLoginMenu()");
+  // Check for & read user_login_questions file
+  n_login_questions = read_user_login_questions(&user_login_questions);
+
+  // Check for & read user_menu_entries file
+  n_users = read_user_menu_entries(&user_names);
+
+  if (n_users == 0)
+    return 0;   // a quick exit, there's only one user
+
+  // Check for a highscores file
+  if (high_scores_found_in_user_dir())
+    set_high_score_path();
+
+  level = 0;
+
+  if (n_login_questions > 0)
+    title = user_login_questions[0];
+
+  menus[MENU_LOGIN] = create_one_level_menu(n_users, user_names, title, trailer_quit);
+
+  while (n_users) {
+    // Get the user choice
+    set_font_size();
+    prerender_menu(menus[MENU_LOGIN]);
+    chosen_login = run_menu(menus[MENU_LOGIN], true);
+    // Determine whether there were any modifier (CTRL) keys pressed
+    mod = SDL_GetModState();
+    if (chosen_login < 0 || chosen_login == n_users) {
+      // 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);
+        free_menu(menus[MENU_LOGIN]);
+        menus[MENU_LOGIN] = NULL;
+        return -1;
+      }
+      else {
+        // Go back up one level of the directory tree
+        user_data_dirname_up();
+        level--;
+      }
+    }
+    else {
+      // User chose an entry, set it up
+      user_data_dirname_down(user_names[chosen_login]);
+      level++;
+    }
+    // Check for a highscores file
+    if (high_scores_found_in_user_dir())
+      set_high_score_path();
+    // Free the entries from the previous menu
+    for (i = 0; i < n_users; i++)
+      free(user_names[i]);
+    free(user_names);
+    user_names = NULL;
+    // If the CTRL key was pressed, choose this as the identity, even
+    // if there is a lower level to the hierarchy
+    if (mod & KMOD_CTRL)
+      break;
+    // Set the title appropriately for the next menu
+    if (level < n_login_questions)
+      title = user_login_questions[level];
+    else
+      title = NULL;
+    if (level == 0)
+      trailer = trailer_quit;
+    else
+      trailer = trailer_back;
+    // Check to see if there are more choices to be made
+    n_users = read_user_menu_entries(&user_names);
+    free_menu(menus[MENU_LOGIN]);
+    menus[MENU_LOGIN] = create_one_level_menu(n_users, user_names, title, trailer);
+  }
+
+  // The user home directory is set, clean up remaining memory
+  for (i = 0; i < n_login_questions; i++)
+    free(user_login_questions[i]);
+  free(user_login_questions);
+  free_menu(menus[MENU_LOGIN]);
+  menus[MENU_LOGIN] = NULL;
+
+  // Signal success
+  return 0;
+}
+
+/* run main menu. If this function ends it means that tuxmath is going to quit */
+void RunMainMenu(void)
+{
+  int i;
+  MenuNode* tmp_node;
+  DEBUGMSG(debug_menu, "Entering RunMainMenu()\n");
+
+   /* lessons menu */
+  DEBUGMSG(debug_menu, "LoadMenus(): Generating lessons submenu. (%d lessons)\n", num_lessons);
+
+  tmp_node = create_empty_node();
+  tmp_node->submenu_size = num_lessons;
+  tmp_node->submenu = (MenuNode**) malloc(num_lessons * sizeof(MenuNode*));
+  for(i = 0; i < num_lessons; i++)
+  {
+    tmp_node->submenu[i] = create_empty_node();
+    tmp_node->submenu[i]->icon_name = strdup(lesson_list_goldstars[i] ? "goldstar" : "no_goldstar");
+    tmp_node->submenu[i]->title = (char*) malloc( (strlen(lesson_list_titles[i]) + 1) * sizeof(char) );
+    strcpy(tmp_node->submenu[i]->title, lesson_list_titles[i]);
+    tmp_node->submenu[i]->activity = i;
+  }
+  menus[MENU_LESSONS] = tmp_node;
+  set_font_size();
+  prerender_menu(menus[MENU_LESSONS]);
+  //prerender_all();
+
+  run_menu(menus[MENU_MAIN], false);
+  DEBUGMSG(debug_menu, "Leaving RunMainMenu()\n");
+}
+
+/* free all loaded menu trees */
+void UnloadMenus(void)
+{
+  int i;
+
+  DEBUGMSG(debug_menu, "entering UnloadMenus()\n");
+
+  if(stop_button)
+  {
+    SDL_FreeSurface(stop_button);
+    stop_button = NULL;
+  }
+
+  if(prev_arrow)
+  {
+    SDL_FreeSurface(prev_arrow);
+    prev_arrow = NULL;
+  }
+
+  if(next_arrow)
+  {
+    SDL_FreeSurface(next_arrow);
+    next_arrow = NULL;
+  }
+
+  for(i = 0; i < N_OF_MENUS; i++)
+    if(menus[i] != NULL)
+    {
+      DEBUGMSG(debug_menu, "UnloadMenus(): freeing menu #%d\n", i);
+      free_menu(menus[i]);
+    }
+
+  DEBUGMSG(debug_menu, "leaving UnloadMenus()\n");
+}
+

Added: tuxmath/branches/lan/src/menu.h
===================================================================
--- tuxmath/branches/lan/src/menu.h	                        (rev 0)
+++ tuxmath/branches/lan/src/menu.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -0,0 +1,103 @@
+/*
+  menu.h
+
+  Functions responsible for loading, parsing and displaying game menu.
+  (interface)
+
+  Part of "Tux4Kids" Project
+  http://www.tux4kids.com/
+
+  Author: Boleslaw Kulbabinski <bkulbabinski at gmail.com>, (C) 2009
+
+  Copyright: See COPYING file that comes with this distribution.
+*/
+
+#ifndef MENU_H
+#define MENU_H
+
+#include "SDL.h"
+#include "globals.h"
+#include "loaders.h"
+
+/* titlescreen & menu frame rate */
+#define MAX_FPS                    30
+/* number of "real" frames per one sprite frame */
+#define SPRITE_FRAME_DELAY         6
+
+/* these are all menu choices that are available in tuxmath.
+   By using a define we can create both an enum and
+   a string array without writing these names twice */
+#define QUIT -2
+#define STOP -1
+
+#define ACTIVITIES \
+  X( RUN_QUIT ),\
+  X( RUN_ACADEMY ),\
+  X( RUN_CAMPAIGN ),\
+  X( RUN_ARCADE ),\
+  X( RUN_CUSTOM ),\
+  X( RUN_MAIN_MENU ),\
+  X( RUN_LAN_HOST ),\
+  X( RUN_LAN_JOIN ),\
+  X( RUN_SCORE_SWEEP ),\
+  X( RUN_ELIMINATION ),\
+  X( RUN_FACTORS ),\
+  X( RUN_FRACTIONS ),\
+  X( RUN_HELP ),\
+  X( RUN_DEMO ),\
+  X( RUN_INFO ),\
+  X( RUN_CREDITS ),\
+  X( RUN_HALL_OF_FAME ),\
+  X( RUN_SPACE_CADET ),\
+  X( RUN_SCOUT ),\
+  X( RUN_RANGER ),\
+  X( RUN_ACE ),\
+  X( RUN_COMMANDO ),\
+  X( N_OF_ACTIVITIES )  /* this one has to be the last one */
+
+/* create enum */
+#define X(name) name
+enum { ACTIVITIES };
+#undef X
+
+struct mNode {
+  struct mNode* parent;
+
+  char* title;
+  int font_size;
+
+  char* icon_name;
+  sprite* icon;
+
+  SDL_Rect button_rect;
+  SDL_Rect icon_rect;
+  SDL_Rect text_rect;
+
+  /* submenu_size = 0 if no submenu */
+  int submenu_size;
+  struct mNode** submenu;
+
+  /* these fields are used only if submenu_size = 0 */
+  int activity;
+  int param;
+
+  /* these fields are used only if submenu_size > 0 */
+  bool show_title;
+  int entries_per_screen;
+  int first_entry;
+};
+
+typedef struct mNode MenuNode;
+
+/* used also by highscore.c */
+extern SDL_Rect menu_rect, stop_rect, prev_rect, next_rect;
+extern SDL_Surface *stop_button, *prev_arrow, *next_arrow, *prev_gray, *next_gray;
+
+/* global functions */
+void LoadMenus(void);
+int RunLoginMenu(void);
+void RunMainMenu(void);
+void UnloadMenus(void);
+
+#endif // MENU_H
+

Modified: tuxmath/branches/lan/src/multiplayer.c
===================================================================
--- tuxmath/branches/lan/src/multiplayer.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/multiplayer.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -32,7 +32,7 @@
 {
   if (inprogress)
   {
-    tmdprintf("Oops, tried to set param %d in the middle of a game\n", param);
+    DEBUGMSG(debug_multiplayer, "Oops, tried to set param %d in the middle of a game\n", param);
     return;
   }
   params[param] = value;
@@ -84,7 +84,7 @@
       
       if (activeplayers <= 1) //last man standing!
       {
-        tmdprintf("%d wins\n", currentplayer);
+        DEBUGMSG(debug_multiplayer, "%d wins\n", currentplayer);
         winners[0] = currentplayer;
         done = 1;
       }
@@ -112,20 +112,22 @@
     //sort out winners
     for (i = 0; i < params[PLAYERS]; ++i)
     {
+      hiscore = 0;
       for (currentplayer = 0; currentplayer < params[PLAYERS]; ++currentplayer)
       {
-        if (pscores[currentplayer] > hiscore)
+        if (pscores[currentplayer] >= hiscore)
         {
           hiscore = pscores[currentplayer];
           currentwinner = currentplayer;
         }
       winners[i] = currentwinner;
-      pscores[currentwinner] = 0;
+      pscores[currentwinner] = -1;
       }
     }
   }
-  
-  tmdprintf("Game over; showing winners\n");
+
+  DEBUGMSG(debug_multiplayer, "Game over; showing winners\n");
+
   showWinners(winners, params[PLAYERS]);
   cleanupMP();
 }
@@ -134,7 +136,7 @@
 {
   if (playernum > params[PLAYERS])
   {
-    tmdprintf("No player %d!\n", playernum);
+    DEBUGMSG(debug_multiplayer, "No player %d!\n", playernum);
     return 0;
   }
   return pscores[playernum];
@@ -144,7 +146,7 @@
 {
   if (playernum > params[PLAYERS])
   {
-    tmdprintf("No player %d!\n", playernum);
+    DEBUGMSG(debug_multiplayer, "No player %d!\n", playernum);
     return 0;
   }
   return pnames[playernum];
@@ -164,19 +166,25 @@
 void showWinners(int* winners, int num)
 {
   int skip = 0;
+  int i = 0;
   const int boxspeed = 3;
-  char text[HIGH_SCORE_NAME_LENGTH + strlen(" wins!")];
+  int sectionlength = num * (HIGH_SCORE_NAME_LENGTH + strlen(" wins!\n"));
+  char text[sectionlength];
   SDL_Rect box = {screen->w / 2, screen->h / 2, 0, 0};
   SDL_Rect center = box;
   SDL_Event evt;
 
   const char* winnername = (winners[0] == -1 ? "Nobody" : pnames[winners[0]] );
   
-  tmdprintf("%s", pnames[winners[0]] );
-  tmdprintf("%d\n", snprintf(text, HIGH_SCORE_NAME_LENGTH + strlen(" wins!"),
-                    "%s wins!", winnername) );
-  tmdprintf("Win text: %s\n", text);
+  snprintf(text, HIGH_SCORE_NAME_LENGTH + strlen(" wins!"),
+                    "%s wins!\n", winnername);
+  for (i = 1; i < num; ++i)
+  {
+    snprintf(strchr(text, '\0'), sectionlength, _("Then %s\n"), pnames[winners[i]]);
+  }
 
+  DEBUGMSG(debug_multiplayer, "%s Win text: %s\n", pnames[winners[0]], text);
+
   DarkenScreen(1);
 
   while (box.h < screen->h || box.w < screen->w)
@@ -209,6 +217,7 @@
 int initMP()
 {
   int i;
+  int success = 1;
   char nrstr[HIGH_SCORE_NAME_LENGTH * 3];
   int nplayers = params[PLAYERS];
 
@@ -220,10 +229,15 @@
     "multiplay/commando"
   };
 
-  tmdprintf("Reading in difficulty settings...\n");
-  if (!read_global_config_file() ||
-      !read_named_config_file("multiplay/mpoptions") ||
-      !read_named_config_file(config_files[params[DIFFICULTY]]) )
+  DEBUGMSG(debug_multiplayer, "Reading in difficulty settings...\n");
+
+  success *= read_global_config_file();
+
+  success *= read_named_config_file("multiplay/mpoptions");
+
+  success *= read_named_config_file(config_files[params[DIFFICULTY]]);
+
+  if (!success)
   {
     printf("Couldn't read in settings for %s\n",
            config_files[params[DIFFICULTY]] );

Modified: tuxmath/branches/lan/src/options.c
===================================================================
--- tuxmath/branches/lan/src/options.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/options.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -13,7 +13,7 @@
 
   Part of "Tux4Kids" Project
   http://www.tux4kids.com
-      
+
   August 26, 2001 - July 11, 2007
 */
 
@@ -30,6 +30,7 @@
 #include "fileops.h"
 #include "setup.h"
 #include "game.h"
+#include "globals.h"
 //#include "tuxmath.h"
 
 /* FIXME figure out what oper_override is supposed to do and make sure */
@@ -37,6 +38,28 @@
 
 //int opers[NUM_OPERS], range_enabled[NUM_Q_RANGES];
 
+/* global debug masks */
+int debug_status;
+
+/* bitmasks for debugging options */
+const int debug_setup          = 1 << 0;
+const int debug_fileops        = 1 << 1;
+const int debug_loaders        = 1 << 2;
+const int debug_titlescreen    = 1 << 3;
+const int debug_menu           = 1 << 4;
+const int debug_menu_parser    = 1 << 5;
+const int debug_game           = 1 << 6;
+const int debug_factoroids     = 1 << 7;
+const int debug_lan            = 1 << 8;
+const int debug_mathcards      = 1 << 9;
+const int debug_sdl            = 1 << 10;
+const int debug_lessons        = 1 << 11;
+const int debug_highscore      = 1 << 12;
+const int debug_options        = 1 << 13;
+const int debug_convert_utf    = 1 << 14;
+const int debug_multiplayer    = 1 << 15;
+const int debug_all            = ~0;
+
 /* extern'd constants */
 
 const char* const OPTION_TEXT[NUM_GLOBAL_OPTS+1] = {
@@ -59,8 +82,8 @@
   0,
   1
 };
-  
 
+
 /* file scope only now that accessor functions used: */
 static game_option_type* game_options;
 static global_option_type* global_options;
@@ -96,7 +119,8 @@
   global_options->iopts[FULLSCREEN] = DEFAULT_FULLSCREEN;
   global_options->iopts[USE_KEYPAD] = DEFAULT_USE_KEYPAD;
   global_options->iopts[USE_IGLOOS] = DEFAULT_USE_IGLOOS;
-  strncpy(game_options->current_font_name, DEFAULT_FONT_NAME, sizeof(game_options->current_font_name));
+  strncpy(game_options->current_font_name, DEFAULT_FONT_NAME,
+          sizeof(game_options->current_font_name));
   game_options->lan_mode = DEFAULT_LAN_MODE;
   game_options->use_bkgd = DEFAULT_USE_BKGD;
   game_options->help_mode = DEFAULT_HELP_MODE;
@@ -125,9 +149,8 @@
   game_options->num_cities = DEFAULT_NUM_CITIES;   /* MUST BE AN EVEN NUMBER! */
   game_options->max_city_colors = DEFAULT_MAX_CITY_COLORS;
 
-  #ifdef TUXMATH_DEBUG
-  print_game_options(stdout, 0);
-  #endif
+  DEBUGCODE(debug_options)
+    print_game_options(stdout, 0);
 
   return 1;
 }
@@ -152,7 +175,7 @@
     if (0 == strcasecmp(text, OPTION_TEXT[i]) )
       return i;
   }
-  tmdprintf("'%s' isn't a global option\n", text);
+  DEBUGMSG(debug_options, "'%s' isn't a global option\n", text);
   return -1;
 }
 
@@ -168,8 +191,7 @@
 {
   if (index < NUM_GLOBAL_OPTS)
     return global_options->iopts[index];
-    
-  tmdprintf("Invalid global option index: %d\n", index);
+  DEBUGMSG(debug_options, "Invalid global option index: %d\n", index);
   return 0;
 }
 
@@ -185,7 +207,7 @@
   if (index < NUM_GLOBAL_OPTS)
     global_options->iopts[index] = val;
   else
-    tmdprintf("Invalid global option index: %d\n", index);
+    DEBUGMSG(debug_options, "Invalid global option index: %d\n", index);
 }
   
 
@@ -222,19 +244,18 @@
 //  global_options->iopts[FULLSCREEN] = int_to_bool(val);
 //}
 
+void Opts_SetLanMode(int val)
+{
+  game_options->lan_mode = int_to_bool(val);
+}
+ 
+
 void Opts_SetFontName(char* font_name)
 {
   if (font_name && font_name[0] != '\0')
   strncpy(game_options->current_font_name, font_name, sizeof(game_options->current_font_name));
 }
 
-
-void Opts_SetLanMode(int val)
-{
-  game_options->lan_mode = int_to_bool(val);
-}
-
-
 void Opts_SetUseBkgd(int val)
 {
   game_options->use_bkgd = int_to_bool(val);
@@ -596,28 +617,28 @@
 //  return global_options->iopts[FULLSCREEN];
 //}
 
-const char* Opts_FontName(void)
+
+int Opts_LanMode(void)
 {
   if (!game_options)
   {
-    fprintf(stderr, "\nOpts_FontName(): game_options not valid!\n");
-    return NULL;
+    fprintf(stderr, "\nOpts_LanMode(): game_options not valid!\n");
+    return GAME_OPTS_INVALID;
   }
-  return (const char*) game_options->current_font_name;
+  return game_options->lan_mode;
 }
+ 
 
-
-int Opts_LanMode(void)
+const char* Opts_FontName(void)
 {
   if (!game_options)
   {
-    fprintf(stderr, "\nOpts_LanMode(): game_options not valid!\n");
-    return GAME_OPTS_INVALID;
+    fprintf(stderr, "\nOpts_FontName(): game_options not valid!\n");
+    return NULL;
   }
-  return game_options->lan_mode;
+  return (const char*) game_options->current_font_name;
 }
 
-
 int Opts_UseBkgd(void)
 {
   if (!game_options)

Modified: tuxmath/branches/lan/src/scandir.c
===================================================================
--- tuxmath/branches/lan/src/scandir.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/scandir.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -29,9 +29,9 @@
 #include "scandir.h"
 
 /*-----------------------------------------------------------------------
- * Here come alphasort and scandir for BeOS and SunOS
+ * Here come alphasort and scandir for BeOS/Haiku and SunOS
  *-----------------------------------------------------------------------*/
-#if defined(__BEOS__) || (defined(__sun) && defined(__SVR4))
+#if defined(__BEOS__) || defined(__HAIKU__) || (defined(__sun) && defined(__SVR4))
 
 #undef DIRSIZ
 

Modified: tuxmath/branches/lan/src/scandir.h
===================================================================
--- tuxmath/branches/lan/src/scandir.h	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/scandir.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -19,7 +19,7 @@
 #define dirent direct
 #endif
 
-#if defined(__BEOS__) || (defined(__sun) && defined(__SVR4)) || defined(WIN32)
+#if defined(__BEOS__) || defined(__HAIKU__) || (defined(__sun) && defined(__SVR4)) || defined(WIN32)
 extern int alphasort(const void *d1, const void *d2);
 extern int scandir(const char *dirname, struct dirent ***namelist, int (*sdfilter)(struct dirent *), int (*dcomp)(const void *, const void *));
 #endif

Modified: tuxmath/branches/lan/src/setup.c
===================================================================
--- tuxmath/branches/lan/src/setup.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/setup.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -37,7 +37,7 @@
 #endif
 
 #include "SDL_image.h"
-#include "transtruct.h"
+
 #include "options.h"
 #include "tuxmath.h"
 #include "mathcards.h"
@@ -45,6 +45,7 @@
 #include "fileops.h"
 #include "loaders.h"
 #include "game.h"
+#include "menu.h"
 #include "titlescreen.h"
 #include "highscore.h"
 #include "SDL_extras.h"
@@ -57,11 +58,17 @@
 /* Global data used in setup.c:              */
 /* (These are now 'extern'd in "tuxmath.h") */
 
-int fs_res_x = RES_X;
-int fs_res_y = RES_Y;
+/* window size */
+int win_res_x = 640;
+int win_res_y = 480;
 
+/* full screen size (set in initialize_SDL() ) */
+int fs_res_x = 0;
+int fs_res_y = 0;
+
 SDL_Surface* screen;
 SDL_Surface* images[NUM_IMAGES];
+sprite* sprites[NUM_SPRITES];
 /* Need special handling to generate flipped versions of images. This
    is a slightly ugly hack arising from the use of the enum trick for
    NUM_IMAGES. */
@@ -85,7 +92,6 @@
 Mix_Music* musics[NUM_MUSICS];
 #endif
 
-
 /* Local function prototypes: */
 void initialize_options(void);
 void handle_command_args(int argc, char* argv[]);
@@ -116,7 +122,7 @@
   initialize_SDL();
   /* Read image and sound files: */
   load_data_files();
- /* Generate flipped versions of walking images */
+  /* Generate flipped versions of walking images */
   generate_flipped_images();
   /* Generate blended images (e.g., igloos) */
   generate_blended_images();
@@ -197,9 +203,8 @@
     /* (can still proceed).         */
   }
 
-#ifdef TUXMATH_DEBUG
-  print_high_scores(stdout);
-#endif
+  DEBUGCODE(debug_setup)
+    print_high_scores(stdout);
 }
 
 
@@ -400,7 +405,66 @@
       Opts_SetSpeed(strtod(argv[i + 1], (char **) NULL));
       i++;
     }
-
+    else if (strcmp(argv[i], "--debug-all") == 0)
+    {
+      debug_status |= debug_all;
+    }
+    else if (strcmp(argv[i], "--debug-setup") == 0)
+    {
+      debug_status |= debug_setup;
+    }
+    else if (strcmp(argv[i], "--debug-fileops") == 0)
+    {
+      debug_status |= debug_fileops;
+    }
+    else if (strcmp(argv[i], "--debug-loaders") == 0)
+    {
+      debug_status |= debug_loaders;
+    }
+    else if (strcmp(argv[i], "--debug-titlescreen") == 0)
+    {
+      debug_status |= debug_titlescreen;
+    }
+    else if (strcmp(argv[i], "--debug-menu") == 0)
+    {
+      debug_status |= debug_menu;
+    }
+    else if (strcmp(argv[i], "--debug-menu-parser") == 0)
+    {
+      debug_status |= debug_menu_parser;
+    }
+    else if (strcmp(argv[i], "--debug-game") == 0)
+    {
+      debug_status |= debug_game;
+    }
+    else if (strcmp(argv[i], "--debug-factoroids") == 0)
+    {
+      debug_status |= debug_factoroids;
+    }
+    else if (strcmp(argv[i], "--debug-lan") == 0)
+    {
+      debug_status |= debug_lan;
+    }
+    else if (strcmp(argv[i], "--debug-mathcards") == 0)
+    {
+      debug_status |= debug_mathcards;
+    }
+    else if (strcmp(argv[i], "--debug-sdl") == 0)
+    {
+      debug_status |= debug_sdl;
+    }
+    else if (strcmp(argv[i], "--debug-lessons") == 0)
+    {
+      debug_status |= debug_lessons;
+    }
+    else if (strcmp(argv[i], "--debug-highscore") == 0)
+    {
+      debug_status |= debug_highscore;
+    }
+    else if (strcmp(argv[i], "--debug-options") == 0)
+    {
+      debug_status |= debug_options;
+    }
     else
     /* TODO try to match unrecognized strings to config file names */
     {
@@ -411,6 +475,7 @@
     }
   }/* end of command-line args */
 
+  DEBUGMSG(debug_setup,"debug_status: %x", debug_status);
 
   if (Opts_DemoMode() && Opts_GetGlobalOpt(USE_KEYPAD))
   {
@@ -479,11 +544,11 @@
       Opts_SetSoundHWAvailable(1);
     else
       frequency = format = channels = 0; //more helpful than garbage
-    tmdprintf("Sound mixer: frequency = %d, "
-                    "format = %x, "
-                    "channels = %d, "
-                    "n_timesopened = %d\n",
-                    frequency,format,channels,n_timesopened);
+    DEBUGMSG(debug_setup, "Sound mixer: frequency = %d, "
+                          "format = %x, "
+                          "channels = %d, "
+                          "n_timesopened = %d\n",
+                          frequency,format,channels,n_timesopened);
   }
 
   #endif
@@ -494,17 +559,17 @@
     if (videoInfo->hw_available)
     {
       surfaceMode = SDL_HWSURFACE;
-      tmdprintf("HW mode\n");
+      DEBUGMSG(debug_setup, "HW mode\n");
     }
     else
     {
       surfaceMode = SDL_SWSURFACE;
-      tmdprintf("SW mode\n");
+      DEBUGMSG(debug_setup, "SW mode\n");
     }
 
     // Determine the current resolution: this will be used as the
     // fullscreen resolution, if the user wants fullscreen.
-    tmdprintf("Current resolution: w %d, h %d.\n",videoInfo->current_w,videoInfo->current_h);
+    DEBUGMSG(debug_setup, "Current resolution: w %d, h %d.\n",videoInfo->current_w,videoInfo->current_h);
     fs_res_x = videoInfo->current_w;
     fs_res_y = videoInfo->current_h;
 
@@ -523,7 +588,7 @@
 
     if (!Opts_GetGlobalOpt(FULLSCREEN))
     {
-      screen = SDL_SetVideoMode(RES_X, RES_Y, PIXEL_BITS, surfaceMode);
+      screen = SDL_SetVideoMode(win_res_x, win_res_y, PIXEL_BITS, surfaceMode);
     }
 
     if (screen == NULL)
@@ -714,6 +779,7 @@
     n_timesopened--;
   }
 
+  UnloadMenus();
 
   // Finally, quit SDL
   SDL_Quit();

Modified: tuxmath/branches/lan/src/titlescreen.c
===================================================================
--- tuxmath/branches/lan/src/titlescreen.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/titlescreen.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -1,54 +1,39 @@
-/***************************************************************************
- -  file: titlescreen.c
- -  description: splash, title and menu screen functionality
-                            ------------------
-    begin                : Thur May 4 2000
-    copyright            : (C) 2000 by Sam Hart
-                         : (C) 2003 by Jesse Andrews
-    email                : tuxtype-dev at tux4kids.net
+/*
+  titlescreen.c
 
-    Modified for use in tuxmath by David Bruce - 2006-2007.
-    email                : <dbruce at tampabay.rr.com>
-                           <tuxmath-devel at lists.sourceforge.net>
-    Also significantly enhanced by Tim Holy - 2007
-***************************************************************************/
+  Splash, background and title screen items.
 
-/***************************************************************************
- *                                                                         *
- *   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.                                   *
- *                                                                         *
- ***************************************************************************/
-  
-// titlescreen.h has all of the tuxtype-related stuff:
+  begin                : Thur May 4 2000
+  copyright            : (C) 2000 by Sam Hart
+                       : (C) 2003 by Jesse Andrews
+  email                : tuxtype-dev at tux4kids.net
+
+  Modified for use in tuxmath by David Bruce - 2006-2007.
+  email                : <dbruce at tampabay.rr.com>
+                         <tuxmath-devel at lists.sourceforge.net>
+
+  Also significantly enhanced by Tim Holy - 2007
+
+  Part of "Tux4Kids" Project
+  http://www.tux4kids.com/
+
+  Copyright: See COPYING file that comes with this distribution.
+*/
+
 #include "titlescreen.h"
 
-// tuxmath includes:
 #include "tuxmath.h"
 #include "options.h"
 #include "fileops.h"
-#include "game.h"
-#include "campaign.h"
-#include "factoroids.h"
-#include "multiplayer.h"
-#include "transtruct.h"
-#include "mathcards.h"
-#include "setup.h"     //for cleanup()
-#include "network.h"
+#include "setup.h"
 #include "loaders.h"
-#include "credits.h"
-#include "highscore.h"
-#include "convert_utf.h" // for wide char to UTF-8 conversion
 #include "SDL_extras.h"
+#include "menu.h"
 
 /* --- Data Structure for Dirty Blitting --- */
 SDL_Rect srcupdate[MAX_UPDATES];
 SDL_Rect dstupdate[MAX_UPDATES];
 int numupdates = 0; // tracks how many blits to be done
-char host[1024]="NULL";
-char player_name[1024];
 
 // Colors we use:
 SDL_Color black;
@@ -58,7 +43,7 @@
 SDL_Color white;
 SDL_Color yellow;
 
-// Type needed for TransWipe():
+// Type needed for trans_wipe():
 struct blit {
     SDL_Surface *src;
     SDL_Rect *srcrect;
@@ -70,134 +55,80 @@
 char **lesson_list_titles = NULL;
 char **lesson_list_filenames = NULL;
 int num_lessons = 0;
-//int n=0;
 
+/*TODO: move these constants into a config file
+  (together with menu.c constants ? ) */
+const float title_pos[4] = {0.0, 0.0, 0.3, 0.25};
+const float tux_pos[4]   = {0.0, 0.6, 0.3, 0.4};
+const char* bkg_path     = "title/menu_bkg.jpg";
+const char* standby_path = "status/standby.svg";
+const char* title_path   = "title/title1.svg";
+const char* egg_path     = "title/egg.svg";
+const char* tux_path     = "tux/bigtux";
+/* beak coordinates relative to tux rect */
+const float beak_pos[4]  = {0.36, 0.21, 0.27, 0.14};
 
-/* --- media for menus --- */
 
-enum {
-  SPRITE_TRAINING,
-  SPRITE_ARCADE,
-  SPRITE_HELP,
-  SPRITE_CUSTOM,
-  SPRITE_OPTIONS,
-  SPRITE_CADET,
-  SPRITE_SCOUT,
-  SPRITE_RANGER,
-  SPRITE_ACE,
-  SPRITE_COMMANDO,
-  SPRITE_QUIT,
-  SPRITE_MAIN,
-  SPRITE_GOLDSTAR,
-  SPRITE_NO_GOLDSTAR,
-  SPRITE_TROPHY,
-  SPRITE_CREDITS,
-  SPRITE_ALONE,
-  SPRITE_LAN,
-  SPRITE_FRIENDS,
-  SPRITE_FACTOROIDS,
-  SPRITE_FACTORS,
-  SPRITE_FRACTIONS,
-  SPRITE_CAMPAIGN,
-  SPRITE_SSWEEP,
-  SPRITE_ELIMINATION,
-  SPRITE_SERVER,
-  SPRITE_CLIENT,
-  N_SPRITES};
+SDL_Event event;
 
-const char* menu_sprite_files[N_SPRITES] =
-{
-  "lesson",
-  "comet",
-  "help",
-  "tux_config",
-  "tux_config_brown",
-  "tux_helmet_yellow",
-  "tux_helmet_green",
-  "tux_helmet_blue",
-  "tux_helmet_red",
-  "tux_helmet_black",
-  "quit",
-  "main",
-  "goldstar",
-  "no_goldstar",
-  "trophy",
-  "credits",
-  "alone", 
-  "lan",
-  "friends", 
-  "factoroids",
-  "factors",
-  "fractions",
-  "fleet",
-  "nums",
-  "exclamation"
-};
+/* screen dimensions to which titlescreen graphics are currently rendered */
+int curr_res_x = -1;
+int curr_res_y = -1;
 
-sprite **sprite_list = NULL;
+/* titlescreen items */
+SDL_Surface* win_bkg = NULL;
+SDL_Surface* fs_bkg = NULL;
 
+SDL_Surface* logo = NULL;
 sprite* Tux = NULL;
+SDL_Surface* title = NULL;
 
-
-SDL_Event event;
-
-/* --- locations we need --- */
-
-SDL_Rect dest,
-         Tuxdest,
-         Titledest,
-         stopRect,
-         Backrect,
-         Tuxback,
-         Titleback,
-         cursor,
-         beak;
-
-/* The background image scaled to windowed 640x480 */
-SDL_Surface* bkg = NULL;
-/* The background image scaled to fullscreen dimensions */
-SDL_Surface* scaled_bkg = NULL;
 /* "Easter Egg" cursor */
 SDL_Surface* egg = NULL;
 int egg_active = 0; //are we currently using the egg cursor?
 
+/* locations we need */
+SDL_Rect bkg_rect,
+         logo_rect,
+         tux_rect,
+         title_rect,
+         cursor,
+         beak;
 
 SDL_Surface* current_bkg()
   /* This syntax makes my brain start to explode! */
-  { return screen->flags & SDL_FULLSCREEN ? scaled_bkg : bkg; }
+  { return screen->flags & SDL_FULLSCREEN ? fs_bkg : win_bkg; }
 
+void set_current_bkg(SDL_Surface* new_bkg)
+{
+  if(screen->flags & SDL_FULLSCREEN)
+  {
+    if(fs_bkg != NULL)
+      SDL_FreeSurface(fs_bkg);
+    fs_bkg = new_bkg;
+  }
+  else
+  {
+    if(win_bkg != NULL)
+      SDL_FreeSurface(win_bkg);
+    win_bkg = new_bkg;
+  }
+}
+
 /* Local function prototypes: */
-void TitleScreen_load_menu(void);
-void TitleScreen_unload_menu(void);
-int TitleScreen_load_media(void);
-void TitleScreen_unload_media(void);
 void NotImplemented(void);
-void TransWipe(SDL_Surface* newbkg, int type, int var1, int var2);
-void UpdateScreen(int* frame);
-void AddRect(SDL_Rect* src, SDL_Rect* dst);
-void InitEngine(void);
-void ShowMessage(const char* str1, const char* str2, const char* str3, const char* str4);
-void RecalcTitlePositions();
-void RecalcMenuPositions(int*, int, menu_options*, void (*)(menu_options*),
-                         SDL_Rect**, SDL_Rect**, SDL_Rect**,
-                         SDL_Rect**, SDL_Rect**, SDL_Rect**,
-                         SDL_Rect*, SDL_Rect*);
-void set_buttons_max_width(SDL_Rect *, SDL_Rect *, int);
 
-int run_login_menu(void);
-int run_main_menu(void);
-int run_game_menu(void);
-int run_multiplay_menu(void);
-int run_lessons_menu(void);
-int run_arcade_menu(void);
-int run_campaign_menu(void);
-int run_custom_menu(void);
-int run_activities_menu(void);
-int run_options_menu(void);
-int run_lan_menu(void);
-int run_server_menu(void);
+void free_titlescreen(void);
+
+void trans_wipe(SDL_Surface* newbkg, int type, int var1, int var2);
+void init_blits(void);
+void update_screen(int* frame);
+void add_rect(SDL_Rect* src, SDL_Rect* dst);
+
 int handle_easter_egg(const SDL_Event* evt);
 
+
+
 /***********************************************************/
 /*                                                         */
 /*       "Public functions" (callable throughout program)  */
@@ -205,56 +136,64 @@
 /***********************************************************/
 
 
-
-/****************************************
-* TitleScreen: Display the title screen *
-****************************************/
-
-/* display title screen, get input */
-
+/* Display Tux4Kids logo, then animate title screen
+   items onto the screen and run main menu */
 void TitleScreen(void)
 {
+  Uint32 start_time = 0;
+  SDL_Rect tux_anim, title_anim;
+  int i, tux_pix_skip, title_pix_skip, curr_time;
 
-  Uint32 start = 0;
-
-  int i,TuxPixSkip,TitlePixSkip;
-//  int n_subdirs;
-//  char **subdir_names;
-
-
   if (Opts_UsingSound())
   {
     Opts_SetGlobalOpt(MENU_SOUND, 1);
     Opts_SetGlobalOpt(MENU_MUSIC, 1);
-//    menu_music = localsettings.menu_music;
   }
 
-  InitEngine();  //set up pointers for blitting structure.
+  start_time = SDL_GetTicks();
+  logo = LoadImage(standby_path, IMG_REGULAR);
 
-  start = SDL_GetTicks();
-
-
-  /* StandbyScreen: Display the Standby screen: */
-  if (images[IMG_STANDBY])
+  /* display the Standby screen */
+  if(logo)
   {
-    // Center horizontally
-    dest.x = ((screen->w) / 2) - (images[IMG_STANDBY]->w) / 2;
-    // Center vertically
-    dest.y = ((screen->h) / 2) - (images[IMG_STANDBY]->h) / 2;
-    dest.w = images[IMG_STANDBY]->w;
-    dest.h = images[IMG_STANDBY]->h;
+    /* Center horizontally and vertically */
+    logo_rect.x = (screen->w - logo->w) / 2;
+    logo_rect.y = (screen->h - logo->h) / 2;
 
+    logo_rect.w = logo->w;
+    logo_rect.h = logo->h;
+
     SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
-    SDL_BlitSurface(images[IMG_STANDBY], NULL, screen, &dest);
+    SDL_BlitSurface(logo, NULL, screen, &logo_rect);
     SDL_UpdateRect(screen, 0, 0, 0, 0);
-    // Play "harp" greeting sound lifted from Tux Paint:
+    /* Play "harp" greeting sound lifted from Tux Paint */
     playsound(SND_HARP);
- }
+    SDL_FreeSurface(logo);
+    /* load menus */
+    LoadMenus();
+  }
 
+  /* load backgrounds */
+  LoadBothBkgds(bkg_path, &fs_bkg, &win_bkg);
+  if(fs_bkg == NULL || win_bkg == NULL)
+  {
+    fprintf(stderr, "Backgrounds were not properly loaded, exiting");
+    if(fs_bkg)
+      SDL_FreeSurface(fs_bkg);
+    if(win_bkg)
+      SDL_FreeSurface(win_bkg);
+    return;
+  }
 
-  /* --- wait  --- */
+  /* load titlescreen images */
+  if(RenderTitleScreen() == 0)
+  {
+    fprintf(stderr, "Media was not properly loaded, exiting");
+    return;
+  }
 
-  while ((SDL_GetTicks() - start) < 2000)
+  /* --- wait  --- */
+  while ((SDL_GetTicks() - start_time) < 2000)
   {
     /* Check to see if user pressed escape */
     if (SDL_PollEvent(&event)
@@ -265,123 +204,72 @@
     }
     SDL_Delay(50);
   }
-#ifndef TUXMATH_DEBUG //in case of a freeze, this traps the cursor
-  SDL_WM_GrabInput(SDL_GRAB_ON); // User input goes to TuxMath, not window manager
-#endif
+
+  /* NOTE: do we need this ? */
+  DEBUGCODE(debug_titlescreen)
+    SDL_WM_GrabInput(SDL_GRAB_OFF); /* in case of a freeze, this traps the cursor */
+  else
+    SDL_WM_GrabInput(SDL_GRAB_ON);  /* User input goes to TuxMath, not window manager */
   SDL_ShowCursor(1);
 
 
-  /***************************
-  * Tux and Title animations *
-  ***************************/
+  /* Tux and Title animations */
+  DEBUGMSG(debug_titlescreen, "TitleScreen(): Now Animating Tux and Title onto the screen\n" );
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "->Now Animating Tux and Title onto the screen\n" );
-#endif
-
-  /* Load media and menu data: */
-  /* FIXME should get out if needed media not loaded OK */
-  if (TitleScreen_load_media() == 0) {
-    fprintf(stderr,"Media was not properly loaded, exiting");
-    return;
-  }
-
-  /* Draw background, if it loaded OK: */
-  if (current_bkg() )
+  /* Draw background (center it if it's smaller than screen) */
+  if(current_bkg())
   {
-    Backrect.x = (screen->w - current_bkg()->w) / 2;
-    Backrect.y = (screen->h - current_bkg()->h) / 2;
-    Backrect.w = current_bkg()->w;
-    Backrect.h = current_bkg()->h;
-    /* FIXME not sure TransWipe() works in Windows: */
-    TransWipe(current_bkg(), RANDOM_WIPE, 10, 20);
-    /* Make sure background gets drawn (since TransWipe() doesn't */
+    /* FIXME not sure trans_wipe() works in Windows: */
+    trans_wipe(current_bkg(), RANDOM_WIPE, 10, 20);
+    /* Make sure background gets drawn (since trans_wipe() doesn't */
     /* seem to work reliably as of yet):                          */
-    SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect);
-
+    SDL_BlitSurface(current_bkg(), NULL, screen, &bkg_rect);
   }
-  /* Red "Stop" circle in upper right corner to go back to main menu: */
-  if (images[IMG_STOP])
-  {
-    stopRect.w = images[IMG_STOP]->w;
-    stopRect.h = images[IMG_STOP]->h;
-    stopRect.x = screen->w - images[IMG_STOP]->w;
-    stopRect.y = 0;
-    SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
-  }
-  SDL_UpdateRect(screen, 0, 0, 0, 0);
 
   /* --- Pull tux & logo onscreen --- */
-  /* NOTE we wind up with Tuxdest.y == (screen->h)  - (Tux->frame[0]->h), */
-  /* a 	nd Titledest.x == 0.                                                */
-  if (current_bkg()
-   && images[IMG_MENU_TITLE]
-   && images[IMG_STOP]
-   && Tux && Tux->frame[0])
+  if(title && Tux && Tux->frame[0])
   {
+    /* final tux & title positioins are already calculated,
+       start outside the screen */
+    tux_anim = tux_rect;
+    tux_anim.y = screen->h;
 
-    Tuxdest.x = 0;
-    Tuxdest.y = screen->h;
-    /*
-    Tuxback.x = Tuxdest.x - Backrect.x;
-    Tuxback.y = Tuxdest.y - Backrect.y;
-    */
-    Tuxdest.w = Tuxback.w = Tux->frame[0]->w;
-    Tuxdest.h = Tuxback.h = Tux->frame[0]->h;
+    title_anim = title_rect;
+    title_anim.x = screen->w;
 
-
-    Titledest.x = screen->w;
-    Titledest.y = 10;
-    /*
-    Titleback.x = Titledest.x - Backrect.x;
-    Titleback.y = Titledest.y - Backrect.y;
-    */
-    Titledest.w = Titleback.w = images[IMG_MENU_TITLE]->w;
-    Titledest.h = Titleback.h = images[IMG_MENU_TITLE]->h;
-
-    TuxPixSkip = Tux->frame[0]->h / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
-    TitlePixSkip = (screen->w) / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
-
-    for (i = 0; i < (PRE_ANIM_FRAMES * PRE_FRAME_MULT); i++)
+    for(i = 0; i < ANIM_FRAMES; i++)
     {
-      start = SDL_GetTicks();
+      start_time = SDL_GetTicks();
 
-      //Draw the entire background, over a black screen if necessary
-      if (current_bkg()->w != screen->w || current_bkg()->h != screen->h)
+      /* Draw the entire background, over a black screen if necessary */
+      if(current_bkg()->w != screen->w || current_bkg()->h != screen->h)
         SDL_FillRect(screen, &screen->clip_rect, 0);
-      SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect);
 
-      Tuxdest.y -= TuxPixSkip;
-      //Tuxback.y -= Tux->frame[0]->h / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
-      Titledest.x -= TitlePixSkip;
-      //Titleback.y -= (screen->w) / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
+      SDL_BlitSurface(current_bkg(), NULL, screen, &bkg_rect);
 
-      SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
-      SDL_BlitSurface(images[IMG_MENU_TITLE], NULL, screen, &Titledest);
-      SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
+      /* calculate shifts */
+      tux_pix_skip = (tux_anim.y - tux_rect.y) / (ANIM_FRAMES - i);
+      tux_anim.y -= tux_pix_skip;
+      title_pix_skip = (title_anim.x - title_rect.x) / (ANIM_FRAMES - i);
+      title_anim.x -= title_pix_skip;
 
-      SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
-      SDL_UpdateRect(screen, Titledest.x, Titledest.y, Titledest.w + TitlePixSkip, Titledest.h);
-      SDL_UpdateRect(screen, stopRect.x, stopRect.y, stopRect.w, stopRect.h);
+      /* update screen */
+      SDL_BlitSurface(Tux->frame[0], NULL, screen, &tux_anim);
+      SDL_BlitSurface(title, NULL, screen, &title_anim);
 
-      while ((SDL_GetTicks() - start) < 33)
-      {
-        SDL_Delay(2);
-      }
-    }
+      SDL_UpdateRect(screen, tux_anim.x, tux_anim.y, tux_anim.w,
+          min(tux_anim.h + tux_pix_skip, screen->h - tux_anim.y));
+      SDL_UpdateRect(screen, title_anim.x, title_anim.y,
+          min(title_anim.w + title_pix_skip, screen->w - title_anim.x), title_anim.h);
 
-
+      curr_time = SDL_GetTicks();
+      if((curr_time - start_time) < 1000 / ANIM_FPS)
+        SDL_Delay(1000 / ANIM_FPS - (curr_time - start_time));
+    }
   }
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "Tux and Title are in place now\n");
-#endif
+  DEBUGMSG(debug_titlescreen, "TitleScreen(): Tux and Title are in place now\n");
 
-  //location of Tux's beak
-  beak.x = Tuxdest.x + 70;
-  beak.y = Tuxdest.y + 60;
-  beak.w = beak.h = 50;
-
   /* Start playing menu music if desired: */
   if (Opts_GetGlobalOpt(MENU_MUSIC))
   {
@@ -389,101 +277,194 @@
   }
 
   /* If necessary, have the user log in */
-  if (run_login_menu() != -1) {
+  if (RunLoginMenu() != -1) {
     /* Finish parsing user options */
     initialize_options_user();
     /* Start the main menu */
-    run_main_menu();
+    RunMainMenu();
   }
 
   /* User has selected quit, clean up */
+  DEBUGMSG(debug_titlescreen, "TitleScreen(): Freeing title screen images\n");
+  free_titlescreen();
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "->>Freeing title screen images\n");
-#endif
+  DEBUGMSG(debug_titlescreen, "leaving TitleScreen()\n");
+}
 
-  TitleScreen_unload_media();
-
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr,"->TitleScreen():END \n");
-#endif
-
+void DrawTitleScreen(void)
+{
+  SDL_BlitSurface(current_bkg(), NULL, screen, &bkg_rect);
+  SDL_BlitSurface(Tux->frame[0], NULL, screen, &tux_rect);
+  SDL_BlitSurface(title, NULL, screen, &title_rect);
+  //SDL_UpdateRect(screen, 0, 0, 0, 0);
 }
 
+/* Render and position all titlescreen items to match current
+   screen size. Rendering is done only if needed.
+   This function must be called after every resolution change
+   returns 1 on success, 0 on failure */
+int RenderTitleScreen(void)
+{
+  SDL_Surface* new_bkg = NULL;
 
+  if(curr_res_x != screen->w || curr_res_y != screen->h)
+  {
+    /* we need to rerender titlescreen items */
+    DEBUGMSG(debug_titlescreen, "Re-rendering titlescreen items.\n");
 
+    /* we keep two backgrounds to make screen mode switch faster */
+    if(current_bkg()->w != screen->w || current_bkg()->h != screen->h)
+    {
+      new_bkg = LoadBkgd(bkg_path, screen->w, screen->h);
+      if(new_bkg == NULL)
+      {
+        DEBUGMSG(debug_titlescreen, "RenderTitleScreen(): Failed to load new background.\n");
+        return 0;
+      }
+      else
+      {
+        DEBUGMSG(debug_titlescreen, "RenderTitleScreen(): New background loaded.\n");
+        set_current_bkg(new_bkg);
+      }
+    }
 
-/***********************************************************/
-/*                                                         */
-/*    "Private functions" (callable only from this file)   */
-/*                                                         */
-/***********************************************************/
+    bkg_rect = current_bkg()->clip_rect;
+    bkg_rect.x = (screen->w - bkg_rect.w) / 2;
+    bkg_rect.y = (screen->h - bkg_rect.h) / 2;
 
+    /* Tux in lower left corner of the screen */
+    SetRect(&tux_rect, tux_pos);
+    Tux = LoadSpriteOfBoundingBox(tux_path, IMG_ALPHA, tux_rect.w, tux_rect.h);
+    if(Tux && Tux->frame[0])
+    {
+      tux_rect.w = Tux->frame[0]->clip_rect.w;
+      tux_rect.h = Tux->frame[0]->clip_rect.h;
+    }
+    else
+    {
+      DEBUGMSG(debug_titlescreen, "RenderTitleScreen(): Failed to load Tux image.\n");
+      return 0;
+    }
 
-// 1 = success, 0 = failure
-int TitleScreen_load_media(void)
-{
-  char fn[PATH_MAX];
-  int i;
+    /* "Tux, of math command" title in upper right corner */
+    SetRect(&title_rect, title_pos);
+    title = LoadImageOfBoundingBox(title_path, IMG_ALPHA, title_rect.w, title_rect.h);
+    if(title)
+    {
+      title_rect.w = title->clip_rect.w;
+      title_rect.h = title->clip_rect.h;
+    }
+    else
+    {
+      DEBUGMSG(debug_titlescreen, "RenderTitleScreen(): Failed to load title image.\n");
+      return 0;
+    }
 
-
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "Entering TitleScreen_load_media():\n");
+    /* easter egg */
+#ifdef HAVE_RSVG
+    egg = LoadImage(egg_path, IMG_ALPHA | IMG_NOT_REQUIRED);
+#else
+    egg = LoadImage(egg_path, IMG_COLORKEY | IMG_NOT_REQUIRED);
 #endif
 
-  Tux = LoadSprite("tux/bigtux", IMG_ALPHA);
+    beak.x = tux_rect.x + beak_pos[0] * tux_rect.w;
+    beak.y = tux_rect.y + beak_pos[1] * tux_rect.h;
+    beak.w = beak_pos[2] * tux_rect.w;
+    beak.h = beak_pos[3] * tux_rect.h;
 
-  SDL_ShowCursor(1);
+    curr_res_x = screen->w;
+    curr_res_y = screen->h;
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "loading sprites\n");
-#endif
-
-  sprite_list = (sprite**) malloc(N_SPRITES*sizeof(sprite*));
-  if (sprite_list == NULL)
-    return 0;
-
-  for (i = 0; i < N_SPRITES; i++) {
-    /* --- load animated icon for menu item --- */
-    sprintf(fn, "sprites/%s", menu_sprite_files[i]);
-    sprite_list[i] = LoadSprite(fn, IMG_ALPHA);
+    DEBUGMSG(debug_titlescreen, "Leaving RenderTitleScreen().\n");
   }
-  egg = LoadImage("title/egg.png",
-                  IMG_COLORKEY | IMG_NOT_REQUIRED);
-  LoadBothBkgds("title/menu_bkg.jpg", &scaled_bkg, &bkg);
   return 1;
 }
 
 
+/* handle titlescreen events (easter egg)
+   this function should be called from event loops
+   return 1 if events require full redraw */
+int HandleTitleScreenEvents(const SDL_Event* evt)
+{
+  return handle_easter_egg(evt);
+}
 
-
-void TitleScreen_unload_menu(void)
+/* handle all titlescreen blitting
+   this function should be called after every animation frame */
+void HandleTitleScreenAnimations()
 {
-  int i;
+  static int frame_counter = 0;
+  int tux_frame;
 
-  for (i = 0; i < N_SPRITES; i++)
+  /* --- make Tux blink --- */
+  switch (frame_counter % TUX6)
   {
-    tmdprintf("Freeing image %d: ", i);
-    FreeSprite(sprite_list[i]);
-    sprite_list[i] = NULL;
+    case 0:    tux_frame = 1; break;
+    case TUX1: tux_frame = 2; break;
+    case TUX2: tux_frame = 3; break;
+    case TUX3: tux_frame = 4; break;
+    case TUX4: tux_frame = 3; break;
+    case TUX5: tux_frame = 2; break;
+    default: tux_frame = 0;
   }
-  free(sprite_list);
-  tmdprintf("Images freed\n");
-  sprite_list = NULL;
+
+  if (Tux && tux_frame)
+  {
+    /* Redraw background to keep edges anti-aliased properly: */
+    SDL_BlitSurface(current_bkg(),&tux_rect, screen, &tux_rect);
+    SDL_BlitSurface(Tux->frame[tux_frame - 1], NULL, screen, &tux_rect);
+    UpdateRect(screen, &tux_rect);
+  }
+
+  if (egg_active) { //if we need to, draw the egg cursor
+    //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);
+    UpdateRect(screen, &cursor);
+  }
+
+  frame_counter++;
 }
 
 
+/***********************************************************/
+/*                                                         */
+/*    "Private functions" (callable only from this file)   */
+/*                                                         */
+/***********************************************************/
 
-void TitleScreen_unload_media(void)
+
+void free_titlescreen(void)
 {
-  tmdprintf("Unloading media\n");
+  DEBUGMSG(debug_titlescreen, "Entering free_titlescreen()\n");
+
   FreeSprite(Tux);
   Tux = NULL;
-  TitleScreen_unload_menu();
 
-  SDL_FreeSurface(egg);
-  SDL_FreeSurface(bkg);
-  SDL_FreeSurface(scaled_bkg);
+  if(egg)
+  {
+    SDL_FreeSurface(egg);
+    egg = NULL;
+  }
+
+  if(title)
+  {
+    SDL_FreeSurface(title);
+    title = NULL;
+  }
+
+  if(fs_bkg)
+  {
+    SDL_FreeSurface(fs_bkg);
+    fs_bkg = NULL;
+  }
+
+  if(win_bkg)
+  {
+    SDL_FreeSurface(win_bkg);
+    win_bkg = NULL;
+  }
 }
 
 
@@ -510,15 +491,12 @@
   SDL_Surface *s1, *s2, *s3, *s4;
   SDL_Rect loc;
   int finished = 0;
-  int tux_frame = 0;
   Uint32 frame = 0;
   Uint32 start = 0;
 
   s1 = s2 = s3 = s4 = NULL;
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "ShowMessage() - creating text\n" );
-#endif
+  DEBUGMSG(debug_titlescreen, "ShowMessage() - creating text\n" );
 
   if (str1)
     s1 = BlackOutline(str1, DEFAULT_MENU_FONT_SIZE, &white);
@@ -529,29 +507,13 @@
   if (str4)
     s4 = BlackOutline(str4, DEFAULT_MENU_FONT_SIZE, &white);
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "ShowMessage() - drawing screen\n" );
-#endif
+  DEBUGMSG(debug_titlescreen, "ShowMessage() - drawing screen\n" );
 
-  /* Redraw background: */
-  if (current_bkg() )
-    SDL_BlitSurface( current_bkg(), NULL, screen, &Backrect );
-
+  DrawTitleScreen();
   /* Red "Stop" circle in upper right corner to go back to main menu: */
-  if (images[IMG_STOP])
-  {
-    stopRect.w = images[IMG_STOP]->w;
-    stopRect.h = images[IMG_STOP]->h;
-    stopRect.x = screen->w - images[IMG_STOP]->w;
-    stopRect.y = 0;
-    SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
-  }
+  if (stop_button)
+    SDL_BlitSurface(stop_button, NULL, screen, &stop_rect);
 
-  if (Tux && Tux->num_frames) /* make sure sprite has at least one frame */
-  {
-    SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
-  }
-
   /* Draw lines of text (do after drawing Tux so text is in front): */
   if (s1)
   {
@@ -595,7 +557,7 @@
         case SDL_MOUSEBUTTONDOWN:
         /* "Stop" button - go to main menu: */
         {
-          if (inRect(stopRect, event.button.x, event.button.y ))
+          if (inRect(stop_rect, event.button.x, event.button.y ))
           {
             finished = 1;
             playsound(SND_TOCK);
@@ -610,25 +572,8 @@
       }
     }
 
-    /* --- make tux blink --- */
-    switch (frame % TUX6)
-    {
-      case 0:    tux_frame = 1; break;
-      case TUX1: tux_frame = 2; break;
-      case TUX2: tux_frame = 3; break;
-      case TUX3: tux_frame = 4; break;
-      case TUX4: tux_frame = 3; break;
-      case TUX5: tux_frame = 2; break;
-      default: tux_frame = 0;
-    }
+    HandleTitleScreenAnimations();
 
-    if (Tux && tux_frame)
-    {
-      SDL_BlitSurface(Tux->frame[tux_frame - 1], NULL, screen, &Tuxdest);
-//      SDL_UpdateRect(screen, Tuxdest.x+37, Tuxdest.y+40, 70, 45);
-      SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
-
-    }
     /* Wait so we keep frame rate constant: */
     while ((SDL_GetTicks() - start) < 33)
     {
@@ -643,1805 +588,202 @@
   SDL_FreeSurface(s4);
 }
 
+/* Was in playgame.c in tuxtype: */
 
-void main_scmo(menu_options* mo) //set custom menu opts for main
+/* trans_wipe: Performs various wipes to new bkgs
+   Given a wipe request type, and any variables
+   that wipe requires, will perform a wipe from
+   the current screen image to a new one. */
+void trans_wipe(SDL_Surface* newbkg, int type, int var1, int var2)
 {
-  mo->ygap = 15;
-}
+  int i, j, x1, x2, y1, y2;
+  int step1, step2, step3, step4;
+  int frame;
+  SDL_Rect src;
+  SDL_Rect dst;
 
-int run_main_menu(void)
-{
-  const char* menu_text[7] =
-    {N_("Play Alone"),
-     N_("LAN Game"),
-     N_("Play With Friends"),
-     N_("Factoroids!"),
-     N_("Help"),
-     N_("More Options"),
-     N_("Quit")};
-  sprite* sprites[7] =
-    {NULL, NULL, NULL, NULL, NULL, NULL,NULL};
-  menu_options menu_opts;
-  int choice,ret;
-
-  // Set up the sprites
-  sprites[0] = sprite_list[SPRITE_ALONE];
-  sprites[1] = sprite_list[SPRITE_LAN];
-  sprites[2] = sprite_list[SPRITE_FRIENDS];
-  sprites[3] = sprite_list[SPRITE_FACTOROIDS];
-  sprites[4] = sprite_list[SPRITE_HELP];
-  sprites[5] = sprite_list[SPRITE_OPTIONS];
-  sprites[6] = sprite_list[SPRITE_QUIT];
-  
-  //set_default_menu_options(&menu_opts);
-  //menu_opts.ytop = 100;
-  //menu_opts.ygap = 15;
-
-  //This function takes care of all the drawing and receives
-  //user input:
-  choice = choose_menu_item(menu_text,sprites,7,NULL,main_scmo);
-
-  while (choice >= 0) {
-    switch (choice) {
-      case 0: {
-        // All single player modes
-        ret = run_game_menu();
-        break;
-      }
-      case 1: {
-        ret = run_lan_menu();
-        break;
-      }
-      case 2: {
-        // Multiplayer games
-        ret = run_multiplay_menu();
-        break;
-      }
-      case 3: {
-        // Factroids et. al.
-        ret = run_activities_menu();
-        break;
-      }
-      case 4: {
-        // Help
-        Opts_SetHelpMode(1);
-        Opts_SetDemoMode(0);
-        if (Opts_GetGlobalOpt(MENU_MUSIC))  //Turn menu music off for game
-          {audioMusicUnload();}
-        game();
-        RecalcTitlePositions();
-        if (Opts_GetGlobalOpt(MENU_MUSIC)) //Turn menu music back on
-          {audioMusicLoad( "tuxi.ogg", -1 );}
-        Opts_SetHelpMode(0);
-        break;
-      }
-      case 5: {
-        // More options
-        ret = run_options_menu();
-        break;
-      }
-      case 6: {
-        // Quit
-        tmdprintf("Exiting main menu\n");
-        return 0;
-      }    
-    }
-    menu_opts.starting_entry = choice;
-    choice = choose_menu_item(menu_text,sprites,7,NULL,main_scmo);
+  if (!screen)
+  {
+    DEBUGMSG(debug_titlescreen, "trans_wipe(): screen not valid!\n");
+    return;
   }
-  return 0;
-}
-                                                     
-#define NUM_GAME_MENU_ITEMS 5
-int run_game_menu(void)
-{
-  const char* menu_text[NUM_GAME_MENU_ITEMS] =
-    {N_("Math Command Training Academy"),
-     N_("Math Command Fleet Missions"),          
-     N_("Play Arcade Game"),
-     N_("Play Custom Game"),
-     N_("Main menu")};
 
-  sprite* sprites[NUM_GAME_MENU_ITEMS] = {NULL, NULL, NULL, NULL, NULL};
-
-  int ret, choice = 0;
-
-  sprites[0] = sprite_list[SPRITE_TRAINING];
-  sprites[1] = sprite_list[SPRITE_CAMPAIGN];
-  sprites[2] = sprite_list[SPRITE_ARCADE];
-  sprites[3] = sprite_list[SPRITE_CUSTOM];
-  sprites[4] = sprite_list[SPRITE_MAIN];
-
-  while (choice >= 0) {
-    choice = choose_menu_item(menu_text,sprites,NUM_GAME_MENU_ITEMS,NULL,NULL);
-    switch (choice) {
-      case 0:
-        ret = run_lessons_menu();
-        break;
-      case 1:
-        ret = start_campaign();
-        break;
-      case 2:
-        ret = run_arcade_menu();
-        break;
-      case 3:
-        ret = run_custom_menu();
-        break;
-      case 4:
-        return 0;
-      default:
-        tmdprintf("choose_menu_item() returned %d--returning\n", choice);
-        return 0;
-    }
-  }
-  return 0;
-}
-
-/*
-Set up and start a turn-based multiplayer game. Some funky heap issues so
-quarantine it behind the return for the time being.
-*/
-int run_multiplay_menu(void)
-{
-  int nplayers = 0;
-  int mode = -1;
-  int difficulty = -1;
-  char npstr[HIGH_SCORE_NAME_LENGTH * 3];
-  
-
-  const char* menu_text[3] =
-    {N_("Score Sweep"),
-     N_("Elimination"),
-     N_("Main menu")};
-
-  //just leech settings from arcade modes
-  const char* diff_menu_text[NUM_MATH_COMMAND_LEVELS + 1] =
-    {N_("Space Cadet"),
-     N_("Scout"),
-     N_("Ranger"),
-     N_("Ace"),
-     N_("Commando"),
-     N_("Main menu")};
-
-
-  sprite* modesprites[3] = {NULL, NULL, NULL};
-  sprite* diffsprites[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
-  // Set up the sprites
-  modesprites[0] = sprite_list[SPRITE_SSWEEP];
-  modesprites[1] = sprite_list[SPRITE_ELIMINATION];
-  modesprites[2] = sprite_list[SPRITE_MAIN];
-  
-  diffsprites[0] = sprite_list[SPRITE_CADET];
-  diffsprites[1] = sprite_list[SPRITE_SCOUT];
-  diffsprites[2] = sprite_list[SPRITE_RANGER];
-  diffsprites[3] = sprite_list[SPRITE_ACE];
-  diffsprites[4] = sprite_list[SPRITE_COMMANDO];
-  diffsprites[5] = sprite_list[SPRITE_MAIN];
-
-  while (1)
+  if (!newbkg)
   {
-    //choose difficulty
-    difficulty = choose_menu_item(diff_menu_text, diffsprites, 
-                 NUM_MATH_COMMAND_LEVELS + 1, NULL, NULL);
-
-    if (difficulty == -1 || difficulty >= NUM_MATH_COMMAND_LEVELS)
-      break; //user chose main menu or hit escape
-
-    //choose mode
-    mode = choose_menu_item(menu_text,modesprites,3,NULL,NULL);
-    if (mode == 2 || mode == -1)
-      break;
-
-    //ask how many players
-    while (nplayers <= 0 || nplayers > MAX_PLAYERS)
-    {
-      NameEntry(npstr, _("How many kids are playing?"),
-                       _("(Between 2 and 4 players)"));
-      nplayers = atoi(npstr);
-    }
-
-
-    mp_set_parameter(PLAYERS, nplayers);
-    mp_set_parameter(MODE, mode);
-    mp_set_parameter(DIFFICULTY, difficulty);
-
-    //RUN!
-    mp_run_multiplayer();
+    DEBUGMSG(debug_titlescreen, "trans_wipe(): newbkg not valid!\n");
+    return;
   }
 
-  return 0;
-}
+  init_blits();
 
-///////////////////////////   LAN game menu()////////////
+  numupdates = 0;
+  frame = 0;
 
+  if(newbkg->w == screen->w && newbkg->h == screen->h) {
+    if( type == RANDOM_WIPE )
+      type = (RANDOM_WIPE * ((float) rand()) / (RAND_MAX+1.0));
 
-int run_lan_menu(void)
-{
-  int mode = -1;
-  int servers_found = 0;  
+    switch( type ) {
+      case WIPE_BLINDS_VERT: {
+        DEBUGMSG(debug_titlescreen, "trans_wipe(): Doing 'WIPE_BLINDS_VERT'\n");
+        /*var1 isnum ofdivisions
+          var2is howmany framesanimation shouldtake */
+        if(var1 <1 )var1 =1;
+        if( var2< 1) var2= 1;
+        step1= screen->w/ var1;
+        step2= step1/ var2;
 
-  const char* menu_text[3] =
-    {N_("Host"),
-     N_("Join"),
-     N_("Main menu")};
-
-  sprite* modesprites[3] = {NULL, NULL, NULL};
-  // Set up the sprites
-  modesprites[0] = sprite_list[SPRITE_SERVER];
-  modesprites[1] = sprite_list[SPRITE_CLIENT];
-  modesprites[2] = sprite_list[SPRITE_MAIN];
-  
-  while (1)
-  {
-    //choose mode
-    mode = choose_menu_item(menu_text, modesprites, 3, NULL, NULL);
-    if (mode == 2 || mode == -1)
-      break;
-
-//    if(mode == 0)                     //chooses Host
-//    run_server_menu();
-    
-    if(mode == 1)
-    {
-      if(detecting_servers(_("Detecting Servers"), _("Please Wait")))
-      {
-        int stdby;
-        char buf[256];
-	snprintf(buf, 256, _("Connected to server: %s"), LAN_ConnectedServerName());
-        NameEntry(player_name, buf, _("Enter your Name:"));
-        LAN_SetName(player_name);
-        Ready(_("Click OK when Ready"));
-        LAN_StartGame();
-        stdby = Standby(_("Waiting For Other Players"),_("To Connect"));
-        if (stdby == 1)
+        for(i= 0;i <=var2; i++)
         {
-          Opts_SetLanMode(1);  // Tells game() we are playing over network
-          game();
-          Opts_SetLanMode(0);  // Go back to local play
-        }
-        else
-        {
-          ShowMessage(NULL, _("Sorry, game already in progress."), NULL, NULL);
-        }  
-      }
-      else
-      {
-        ShowMessage(NULL, _("Sorry, no server could be found."), NULL, NULL);
-        break;
-      }
-    }   
-  }
+          for(j= 0;j <=var1; j++)
+          {
+            x1= step1* (j- 0.5)- i* step2+ 1;
+            x2= step1* (j- 0.5)+ i* step2+ 1;
+            src.x= x1;
+            src.y= 0;
+            src.w= step2;
+            src.h= screen->h;
+            dst.x= x2;
+            dst.y= 0;
+            dst.w= step2;
+            dst.h= screen->h;
 
-  return 0;
+            SDL_BlitSurface(newbkg,&src, screen,&src);
+            SDL_BlitSurface(newbkg, &dst,screen, &dst);
 
-}
-
-/*Dont think we need this..*/
-//int run_server_menu(void)
-//{
-
-//  int difficulty = -1;
- //  n=1;
-//   int g;
-  //just leech settings from arcade modes
-//  const char* diff_menu_text[NUM_MATH_COMMAND_LEVELS + 1] =
-//    {N_("Space Cadet"),
-//     N_("Scout"),
-//     N_("Ranger"),
-//     N_("Ace"),      
-//     N_("Commando"),
-//     N_("Main menu")};
- 
-  
-
-//   sprite* diffsprites[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
-  
- 
-//  diffsprites[0] = sprite_list[SPRITE_CADET];
-//  diffsprites[1] = sprite_list[SPRITE_SCOUT];
-//  diffsprites[2] = sprite_list[SPRITE_RANGER];
-//  diffsprites[3] = sprite_list[SPRITE_ACE];
-//  diffsprites[4] = sprite_list[SPRITE_COMMANDO];
-//  diffsprites[5] = sprite_list[SPRITE_MAIN];
-
-//     while (1)
-//  {
-    //choose difficulty
-//    difficulty = choose_menu_item(diff_menu_text,diffsprites,6,NULL,NULL);
-//     if (difficulty == -1 || difficulty >= NUM_MATH_COMMAND_LEVELS)
-//     { break;} //user chose main menu or hit escape
-//     else
-//     {NameEntry(port, _("Enter the PORT"),
-//                       _(""));
-    
-//       game();}
-//    break;
-//   }
-//   return 0;
-
-
-//}
-
-
-
-
-int run_arcade_menu(void)
-{
-  const char* menu_text[7] =
-    {N_("Space Cadet"),
-     N_("Scout"),
-     N_("Ranger"),
-     N_("Ace"),
-     N_("Commando"),
-     N_("Hall Of Fame"),
-     N_("Main menu")};               
-  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;
-
-  // Set up the sprites
-  sprites[0] = sprite_list[SPRITE_CADET];
-  sprites[1] = sprite_list[SPRITE_SCOUT];
-  sprites[2] = sprite_list[SPRITE_RANGER];
-  sprites[3] = sprite_list[SPRITE_ACE];
-  sprites[4] = sprite_list[SPRITE_COMMANDO];
-  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, 7, NULL, NULL);
-
-  while (choice >= 0) {
-    if (choice < NUM_MATH_COMMAND_LEVELS) {
-      // Play arcade game
-      if (read_named_config_file(arcade_config_files[choice]))
-      {
-        audioMusicUnload();
-	Opts_SetLanMode(0);
-        game();
-        RecalcTitlePositions();
-        if (Opts_GetGlobalOpt(MENU_MUSIC)) {
-          audioMusicLoad( "tuxi.ogg", -1 );
+            add_rect(&src,&src);
+            add_rect(&dst, &dst);
+          }
+          update_screen(&frame);
         }
-        /* 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){
 
-          char player_name[HIGH_SCORE_NAME_LENGTH * 3];
+        src.x= 0;
+        src.y= 0;
+        src.w= screen->w;
+        src.h= screen->h;
+        SDL_BlitSurface(newbkg,NULL, screen,&src);
+        SDL_Flip(screen);
 
-          /* 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);
-#endif
-        }
-      } else {
-        fprintf(stderr, "\nCould not find %s config file\n",arcade_config_files[choice]);
+        break;
       }
+      case WIPE_BLINDS_HORIZ:{
+        DEBUGMSG(debug_titlescreen, "trans_wipe(): Doing 'WIPE_BLINDS_HORIZ'\n");
+        /* var1is numof divisions
+         var2 ishow manyframes animationshould take*/
+        if( var1< 1) var1= 1;
+        if(var2 <1 )var2 =1;
+        step1 =screen->h /var1;
+        step2 =step1 /var2;
 
-    } else if (choice == NUM_MATH_COMMAND_LEVELS) {
-      // Display the Hall of Fame
-      DisplayHighScores(CADET_HIGH_SCORE);
-    }
-    else {
-      // Return to main menu
-      return 0;
-    }
-    set_default_menu_options(&menu_opts);
-    menu_opts.starting_entry = choice;
-    choice = choose_menu_item(menu_text,sprites,7,NULL, NULL);
-  }
+        for(i =0; i<= var2;i++) {
+          for(j= 0;j <=var1; j++){
+            y1 =step1 *(j -0.5) -i *step2 +1;
+            y2 =step1 *(j -0.5) +i *step2 +1;
+            src.x =0;
+            src.y =y1;
+            src.w =screen->w;
+            src.h =step2;
+            dst.x =0;
+            dst.y =y2;
+            dst.w =screen->w;
+            dst.h =step2;
 
-  return 0;
-}
+            SDL_BlitSurface(newbkg, &src,screen, &src);
+            SDL_BlitSurface(newbkg,&dst, screen,&dst);
 
-
-int run_custom_menu(void)
-{
-  const char *s1, *s2, *s3, *s4;
-  s1 = _("Edit 'options' file in your home directory");
-  s2 = _("to create customized game!");
-  s3 = _("Press a key or click your mouse to start game.");
-  s4 = _("See README.txt for more information");
-  ShowMessage(s1, s2, s3, s4);
-
-  if (read_user_config_file()) {
-    if (Opts_GetGlobalOpt(MENU_MUSIC))
-      audioMusicUnload();
-
-    game();
-    RecalcTitlePositions();
-    write_user_config_file();
-
-    if (Opts_GetGlobalOpt(MENU_MUSIC))
-      audioMusicLoad( "tuxi.ogg", -1 );
-  }
-
-  return 0;
-}
-
-int run_activities_menu(void)
-{ 
-  const char* menu_text[3] =
-    {N_("Factors"),
-     N_("Fractions"),
-     N_("Main menu")};
-  const int factoroids_high_score_tables[2] =
-    {FACTORS_HIGH_SCORE, FRACTIONS_HIGH_SCORE};
-  sprite* sprites[3] =
-    {NULL, NULL, NULL};
-  menu_options menu_opts;
-  int choice, hs_table;
-
-  // Set up the sprites
-  sprites[0] = sprite_list[SPRITE_FACTORS];
-  sprites[1] = sprite_list[SPRITE_FRACTIONS];
-  sprites[2] = 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, 3, NULL, NULL);
-
-  while (choice >= 0) {
-    switch(choice){
-      case 0:
-          audioMusicUnload();
-          factors();
-	  
-	  if (Opts_GetGlobalOpt(MENU_MUSIC)) {
-	      audioMusicLoad( "tuxi.ogg", -1 );
-	  }
-	  break;
-      case 1:
-          audioMusicUnload(); 
-          fractions();
-	  
-	  if (Opts_GetGlobalOpt(MENU_MUSIC)) {
-	     audioMusicLoad( "tuxi.ogg", -1 );
-	  }
-	  break;
-     case 2:
-          // Return to main menu
-          return 0;
-    }
-
-	hs_table = factoroids_high_score_tables[choice];
-	if (check_score_place(hs_table, Opts_LastScore()) < HIGH_SCORES_SAVED){
-
-	  char player_name[HIGH_SCORE_NAME_LENGTH * 3];
-
-	  /* Get name from player: */
-	  HighScoreNameEntry(&player_name[0]);
-	  insert_score(player_name, hs_table, Opts_LastScore());
-	  /* Show the high scores. Note the user will see his/her */
-	  /* achievement even if (in the meantime) another player */
-	  /* has in fact already bumped this score off the table. */
-	  DisplayHighScores(hs_table);
-	  /* save to disk: */
-	  /* See "On File Locking" in fileops.c */
-	  append_high_score(hs_table,Opts_LastScore(),&player_name[0]);
-
-#ifdef TUXMATH_DEBUG
-	  print_high_scores(stderr);
-#endif
-	}
-       else {
-	fprintf(stderr, "\nCould not find config file\n");
-      }  
-
-    menu_opts.starting_entry = choice;
-    choice = choose_menu_item(menu_text,sprites,3,NULL,NULL);
-
-
-  }
-
-
-  return 0; 
-}
-
-
-int run_options_menu(void)
-{
-  /*
-    // Use the following version if we get "Settings" implemented
-  const unsigned char* menu_text[5] =
-    {(const unsigned char*)N_("Settings"),
-     (const unsigned char*)N_("Demo"),
-     (const unsigned char*)N_("Credits"),
-     (const unsigned char*)N_("Project Info"),
-     (const unsigned char*)N_("Main Menu")};
-  sprite* sprites[5] =
-    {NULL, NULL, NULL, NULL, NULL};
-  */
-  const char* menu_text[4] =
-    {N_("Demo"),
-     N_("Project Info"),
-     N_("Credits"),
-     N_("Main Menu")};
-
-  sprite* sprites[4] =
-    {NULL, NULL, NULL, NULL};
-  int n_menu_entries = 4;
-  menu_options menu_opts;
-  int choice;
-
-  // Set up the sprites
-  sprites[0] = sprite_list[SPRITE_ARCADE];
-  sprites[1] = sprite_list[SPRITE_HELP];
-  sprites[2] = sprite_list[SPRITE_CREDITS];
-  sprites[3] = 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, n_menu_entries, NULL, NULL);
-
-  while (choice >= 0) {
-    switch (choice) {
-      /*
-    case 0: {
-      // Settings
-      NotImplemented();
-      break;
-      }*/
-    case 0: {
-      // Demo
-      if (read_named_config_file("demo"))
-      {
-        audioMusicUnload();
-        game();
-        RecalcTitlePositions();
-        if (Opts_GetGlobalOpt(MENU_MUSIC)) {
-          audioMusicLoad( "tuxi.ogg", -1 );
+            add_rect(&src, &src);
+            add_rect(&dst,&dst);
+          }
+          update_screen(&frame);
         }
-      } else {
-        fprintf(stderr, "\nCould not find demo config file\n");
-      }
 
-      break;
-    }
-    case 1: {
-      // 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"));
-      break;
-    }
-    case 2: {
-      // Credits
-      //TitleScreen_unload_media();
-      credits();
-      //TitleScreen_load_media();
-      break;
-    }
-    case 3: {
-      // Main menu
-      return 0;
-    }
-    }
+        src.x =0;
+        src.y =0;
+        src.w =screen->w;
+        src.h =screen->h;
+        SDL_BlitSurface(newbkg, NULL,screen, &src);
+        SDL_Flip(screen);
 
-    set_default_menu_options(&menu_opts);
-    menu_opts.starting_entry = choice;
-    choice = choose_menu_item(menu_text,sprites,n_menu_entries,NULL,NULL);
-  }
-
-  return 0;
-}
-
-
-void lessons_scmo(menu_options* mo)
-{
-mo->ytop = 30;
-}
-/* Display a list of tuxmath config files in the missions directory   */
-/* and allow the player to pick one (AKA "Lessons").                  */
-
-/* returns 0 if user pressed escape
- *         1 if config was set correctly
- */
-int run_lessons_menu(void)
-{
-  int chosen_lesson = -1;
-  menu_options menu_opts;
-  sprite** star_sprites = NULL;
-
-  /* Set up sprites (as long as gold star list is valid) */
-  if (lesson_list_goldstars != NULL)
-  {
-    int i;
-    star_sprites = (sprite**)malloc(num_lessons * sizeof(sprite*));
-    for (i = 0; i < num_lessons; i++)
-    {
-      if (lesson_list_goldstars[i])
-        star_sprites[i] = sprite_list[SPRITE_GOLDSTAR];
-      else
-        star_sprites[i] = sprite_list[SPRITE_NO_GOLDSTAR];
-    }
-  }
-//  set_default_menu_options(&menu_opts);
-//  ytop = 30;
-
-  //This function takes care of all the drawing and receives
-  //user input:
-  chosen_lesson = choose_menu_item((const char**)lesson_list_titles, star_sprites, num_lessons, NULL, &lessons_scmo);
-
-  while (chosen_lesson >= 0)
-  {
-    if (Opts_GetGlobalOpt(MENU_SOUND))
-      playsound(SND_POP);
-
-    /* Re-read global settings first in case any settings were */
-    /* clobbered by other lesson or arcade games this session: */
-    read_global_config_file();
-    /* Now read the selected file and play the "mission": */
-    if (read_named_config_file(lesson_list_filenames[chosen_lesson]))
-    {
-      if (Opts_GetGlobalOpt(MENU_MUSIC))  //Turn menu music off for game
-        {audioMusicUnload();}
-
-      Opts_SetLanMode(0); 
-      game();
-      RecalcTitlePositions();
-
-      /* If successful, display Gold Star for this lesson! */
-      if (MC_MissionAccomplished())
-      {
-        lesson_list_goldstars[chosen_lesson] = 1;
-        star_sprites[chosen_lesson] = sprite_list[SPRITE_GOLDSTAR];
-       /* and save to disk: */
-        write_goldstars();
+        break;
       }
+      case WIPE_BLINDS_BOX:{
+        DEBUGMSG(debug_titlescreen, "trans_wipe(): Doing 'WIPE_BLINDS_BOX'\n");
+        /* var1is numof divisions
+         var2 ishow manyframes animationshould take*/
+        if( var1< 1) var1= 1;
+        if(var2 <1 )var2 =1;
+        step1 =screen->w /var1;
+        step2 =step1 /var2;
+        step3 =screen->h /var1;
+        step4 =step1 /var2;
 
-      if (Opts_GetGlobalOpt(MENU_MUSIC)) //Turn menu music back on
-        {audioMusicLoad("tuxi.ogg", -1);}
-    }
-    else  // Something went wrong - could not read lesson config file:
-    {
-      fprintf(stderr, "\nCould not find file: %s\n", lesson_list_filenames[chosen_lesson]);
-      chosen_lesson = -1;
-    }
-    // Let the user choose another lesson; start with the screen and
-    // selection that we ended with
-    set_default_menu_options(&menu_opts);
-    menu_opts.starting_entry = chosen_lesson;
-    chosen_lesson = choose_menu_item((const char**)lesson_list_titles, star_sprites, num_lessons, &menu_opts, &lessons_scmo);
-  }
-  if (star_sprites)
-  {
-    free(star_sprites);
-    star_sprites = NULL;
-  }
+        for(i =0; i<= var2;i++) {
+          for(j= 0;j <=var1; j++){
+            x1 =step1 *(j -0.5) -i *step2 +1;
+            x2 =step1 *(j -0.5) +i *step2 +1;
+            src.x =x1;
+            src.y =0;
+            src.w =step2;
+            src.h =screen->h;
+            dst.x =x2;
+            dst.y =0;
+            dst.w =step2;
+            dst.h =screen->h;
 
-  if (chosen_lesson < 0)
-    return 0;
-  else
-    return 1;
-}
+            SDL_BlitSurface(newbkg, &src,screen, &src);
+            SDL_BlitSurface(newbkg,&dst, screen,&dst);
 
-
-/* Sets the user home directory in a tree of possible users     */
-/* -1 indicates that the user wants to quit without logging in, */
-/* 0 indicates that a choice has been made.                     */
-int run_login_menu(void)
-{
-  int n_login_questions = 0;
-  char **user_login_questions = NULL;
-  int n_users = 0;
-  char **user_names = NULL;
-  menu_options menu_opts;
-  int chosen_login = -1;
-  int level;
-  int i;
-  char *trailer_quit = "Quit";
-  char *trailer_back = "Back";
-  SDLMod mod;
-
-  // Check for & read user_login_questions file
-  n_login_questions = read_user_login_questions(&user_login_questions);
-
-  // Check for & read user_menu_entries file
-  n_users = read_user_menu_entries(&user_names);
-
-  if (n_users == 0)
-    return 0;   // a quick exit, there's only one user
-
-  // Check for a highscores file
-  if (high_scores_found_in_user_dir())
-    set_high_score_path();
-
-  level = 0;
-  set_default_menu_options(&menu_opts);
-  if (n_login_questions > 0)
-    menu_opts.title = user_login_questions[0];
-  menu_opts.trailer = trailer_quit;
-
-  while (n_users) {
-    // Get the user choice
-    chosen_login = choose_menu_item((const char**)user_names, NULL, n_users, &menu_opts, NULL);
-    // Determine whether there were any modifier (CTRL) keys pressed
-    mod = SDL_GetModState();
-    if (chosen_login == -1 || chosen_login == n_users) {
-      // 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;
-      }
-      else {
-        // Go back up one level of the directory tree
-        user_data_dirname_up();
-        level--;
-        menu_opts.starting_entry = -1;
-      }
-    }
-    else {
-      // User chose an entry, set it up
-      user_data_dirname_down(user_names[chosen_login]);
-      level++;
-      menu_opts.starting_entry = 0;
-    }
-    // Check for a highscores file
-    if (high_scores_found_in_user_dir())
-      set_high_score_path();
-    // Free the entries from the previous menu
-    for (i = 0; i < n_users; i++)
-      free(user_names[i]);
-    free(user_names);
-    user_names = NULL;
-    // If the CTRL key was pressed, choose this as the identity, even
-    // if there is a lower level to the hierarchy
-    if (mod & KMOD_CTRL)
-      break;
-    // Set the title appropriately for the next menu
-    if (level < n_login_questions)
-      menu_opts.title = user_login_questions[level];
-    else
-      menu_opts.title = NULL;
-    if (level == 0)
-      menu_opts.trailer = trailer_quit;
-    else
-      menu_opts.trailer = trailer_back;
-    // Check to see if there are more choices to be made
-    n_users = read_user_menu_entries(&user_names);
-  }
-
-  // The user home directory is set, clean up remaining memory
-  for (i = 0; i < n_login_questions; i++)
-    free(user_login_questions[i]);
-  free(user_login_questions);
-
-  // Signal success
-  return 0;
-}
-
-
-/****************************************************************/
-/* choose_menu_item: menu navigation utility function           */
-/* (the function returns the index for the selected menu item)  */
-/* -1 indicates that the user pressed escape                    */
-/****************************************************************/
-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;
-  SDL_Surface **menu_item_selected = NULL;
-  // Display region for menu choices
-  SDL_Rect *menu_text_rect = NULL;
-  // Translucent mouse "buttons" around menu text
-  SDL_Rect *menu_button_rect = NULL;
-  // Menu sprite locations
-  SDL_Rect *menu_sprite_rect = NULL;
-
-  // The section of the background that the menu rects actually cover
-  SDL_Rect *back_text_rect = NULL,
-           *back_button_rect = NULL,
-           *back_sprite_rect = NULL;
-  SDL_Rect left_arrow_rect, right_arrow_rect;
-  SDL_Rect temp_rect; //temporary copy of a dest rect that may be written to by SDL_BlitSurface
-
-  menu_options menu_opts;
-
-  Uint32 frame_counter = 0;
-  Uint32 frame_start = 0;       //For keeping frame rate constant
-  Uint32 frame_now = 0;
-  int stop = 0;
-  int loc = 0;                  //The currently selected menu item
-  int old_loc = 1;
-  int loc_screen_start = 0;     //The number of the top entry on current screen
-  int old_loc_screen_start = 0;
-  int redraw = 0;
-  int n_entries_per_screen = 0;
-  int buttonheight = 0;
-  int i = 0;
-  int imod = 0;                 // i % n_entries_per_screen
-  int tux_frame = 0;
-  int click_flag = 1;
-  int use_sprite = 0;
-  int warp_mouse = 0;
-  int title_offset = 0;
-  int have_trailer = 0;
-
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "Entering choose_menu_item():\n");
-#endif
-
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr,"%d menu entries:\n",n_menu_entries);
-  for (i = 0; i < n_menu_entries; i++)
-    fprintf(stderr,"%s\n",menu_text[i]);
-#endif
-
-  if (custom_mo == NULL)
-    set_default_menu_options(&menu_opts);
-  else
-    menu_opts = *custom_mo;
-  if (set_custom_menu_opts != NULL)
-    set_custom_menu_opts(&menu_opts);
-
-  tmdprintf("Allocating memory\n");
-  /**** Memory allocation for menu text  ****/
-  title_offset = 0;
-  if (menu_opts.title != NULL)
-    title_offset = 1;
-  if (menu_opts.trailer != NULL)
-    have_trailer = 1;
-  menu_item_unselected = (SDL_Surface**)malloc((n_menu_entries+title_offset+have_trailer) * sizeof(SDL_Surface*));
-  menu_item_selected = (SDL_Surface**)malloc((n_menu_entries+title_offset+have_trailer) * sizeof(SDL_Surface*));
-  if (menu_item_unselected == NULL || menu_item_selected == NULL) {
-    free(menu_item_unselected);
-    free(menu_item_selected);
-    return -2;  // error
-  }
-
-  /**** Render the menu choices                               ****/
-  if (title_offset)
-  {
-    menu_item_unselected[0] = BlackOutline( _(menu_opts.title), DEFAULT_MENU_FONT_SIZE, &red);
-    // It will never be selected, so we don't have to do anything for selected.
-    menu_item_selected[0] = NULL;
-  }
-  for (i = 0; i < n_menu_entries; i++)
-  {
-    menu_item_unselected[i+title_offset] = BlackOutline( _(menu_text[i]), DEFAULT_MENU_FONT_SIZE, &white );
-    menu_item_selected[i+title_offset] = BlackOutline( _(menu_text[i]), DEFAULT_MENU_FONT_SIZE, &yellow);
-  }
-  if (have_trailer) {
-    menu_item_unselected[n_menu_entries+title_offset] = BlackOutline( _(menu_opts.trailer), DEFAULT_MENU_FONT_SIZE, &white );
-    menu_item_selected[n_menu_entries+title_offset] = BlackOutline( _(menu_opts.trailer), DEFAULT_MENU_FONT_SIZE, &yellow);
-  }
-  // We won't need the menu_text again, so now we can keep track of
-  // the total entries including the title & trailer
-  n_menu_entries += title_offset+have_trailer;
-
-//  recalcMenuPositions();
-
-  /**** Calculate the menu item heights and the number of     ****/
-  /**** entries per screen                                    ****/
-  if (menu_opts.buttonheight <= 0) {
-    buttonheight = 0;
-    for (i = 0; i < n_menu_entries; i++)
-      if (buttonheight < menu_item_unselected[i]->h)
-        buttonheight = menu_item_unselected[i]->h;
-    buttonheight += 10;
-  } else
-    buttonheight = menu_opts.buttonheight;
-
-  // First try using the whole screen; if we need more than one
-  // screen, then we have to save space for the arrows by respecting
-  // ybottom
-  n_entries_per_screen = (int) (screen->h - menu_opts.ytop+menu_opts.ygap)/(buttonheight + menu_opts.ygap);
-  if (n_entries_per_screen < n_menu_entries)
-    n_entries_per_screen = (int) (menu_opts.ybottom - menu_opts.ytop+menu_opts.ygap)/(buttonheight + menu_opts.ygap);
-
-  if (n_entries_per_screen > n_menu_entries)
-    n_entries_per_screen = n_menu_entries;
-
-  /**** Memory allocation for current screen rects  ****/
-  menu_text_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
-  menu_button_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
-  back_text_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
-  back_button_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
-  if (menu_text_rect == NULL || menu_button_rect == NULL ||
-      back_text_rect == NULL || back_button_rect == NULL) {
-    free(menu_text_rect);
-    free(menu_button_rect);
-    free(back_text_rect);
-    free(back_button_rect);
-    return -2;
-  }
-  if (menu_sprites != NULL) {
-    menu_sprite_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
-    back_sprite_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
-    if (menu_sprite_rect == NULL || back_sprite_rect == NULL) {
-      free(menu_sprite_rect);
-      free(back_sprite_rect);
-      return -2;
-    }
-  }
-
-  /**** Define the locations of graphical elements on the screen ****/
-  /* Arrow buttons in right lower corner, inset by 20 pixels     */
-  /* with a 10 pixel space between:                              */
-  if (images[IMG_RIGHT])
-  {
-    right_arrow_rect.w = images[IMG_RIGHT]->w;
-    right_arrow_rect.h = images[IMG_RIGHT]->h;
-    right_arrow_rect.x = screen->w - images[IMG_RIGHT]->w - 20;
-    right_arrow_rect.y = screen->h - images[IMG_RIGHT]->h - 20;
-  }
-
-  if (images[IMG_LEFT])
-  {
-    left_arrow_rect.w = images[IMG_LEFT]->w;
-    left_arrow_rect.h = images[IMG_LEFT]->h;
-    left_arrow_rect.x = right_arrow_rect.x - 10 - images[IMG_LEFT]->w;
-    left_arrow_rect.y = screen->h - images[IMG_LEFT]->h - 20;
-  }
-  /* Red "Stop" circle in upper right corner to go back to main menu: */
-  if (images[IMG_STOP])
-  {
-    stopRect.w = images[IMG_STOP]->w;
-    stopRect.h = images[IMG_STOP]->h;
-    stopRect.x = screen->w - images[IMG_STOP]->w;
-    stopRect.y = 0;
-  }
-
-  /* Set initial menu rect sizes. The widths will change depending      */
-  /* on the size of the text displayed in each rect.  Set the widths    */
-  /* for the current screen of menu items.                              */
-  loc = menu_opts.starting_entry + title_offset;  // Initially selected item
-  loc_screen_start = loc - (loc % n_entries_per_screen);
-  if (loc_screen_start < 0 || loc_screen_start*n_entries_per_screen > n_menu_entries)
-    loc_screen_start = 0;  // in case starting_entry was -1 (or wasn't set)
-  imod = loc-loc_screen_start;
-  for (i = 0; i < n_entries_per_screen; i++)
-  {
-    menu_button_rect[i].x = menu_opts.xleft;
-    menu_text_rect[i].x = menu_opts.xleft + 15;  // 15 is left gap
-    if (menu_sprites != NULL)
-      menu_text_rect[i].x += 60;  // 40 is sprite width, 20 is gap
-    if (i > 0)
-      menu_text_rect[i].y = menu_text_rect[i - 1].y + buttonheight + menu_opts.ygap;
-    else
-      menu_text_rect[i].y = menu_opts.ytop;
-    menu_button_rect[i].y = menu_text_rect[i].y-5;
-    menu_text_rect[i].h = buttonheight-10;
-    menu_button_rect[i].h = buttonheight;
-    menu_button_rect[i].w = menu_text_rect[i].w = 0;
-    if (i + loc_screen_start < n_menu_entries) {
-      menu_text_rect[i].w = menu_item_unselected[i+loc_screen_start]->w;
-      menu_button_rect[i].w = menu_text_rect[i].w + 30;
-    }
-    if (menu_sprite_rect != NULL) {
-      menu_sprite_rect[i].x = menu_button_rect[i].x+3;
-      menu_sprite_rect[i].y = menu_button_rect[i].y+3;
-      menu_sprite_rect[i].w = 40;
-      menu_sprite_rect[i].h = 50;
-    }
-  }
-
-  if (menu_opts.button_same_width)
-    set_buttons_max_width(menu_button_rect,back_button_rect,n_entries_per_screen);
-
-  for (i = 0; i < n_entries_per_screen; ++i)
-  {
-    if (menu_button_rect)
-    {
-      back_button_rect[i] = menu_button_rect[i];
-      back_button_rect[i].x -= Backrect.x;
-      back_button_rect[i].y -= Backrect.y;
-    }
-    if (menu_text_rect)
-    {
-      back_text_rect[i] = menu_text_rect[i];
-      back_text_rect[i].x -= Backrect.x;
-      back_text_rect[i].y -= Backrect.y;
-    }
-    if (menu_sprite_rect)
-    {
-      back_sprite_rect[i] = menu_sprite_rect[i];
-      back_sprite_rect[i].x -= Backrect.x;
-      back_sprite_rect[i].y -= Backrect.y;
-    }
-  }
-
-  /**** Draw background, title, and Tux:                            ****/
-  if (current_bkg() )
-    SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect);
-  if (images[IMG_MENU_TITLE])
-    SDL_BlitSurface(images[IMG_MENU_TITLE], NULL, screen, &Titledest);
-  if (Tux && Tux->frame[0])
-    SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
-  SDL_UpdateRect(screen, 0, 0, 0 ,0);
-
-  /* Move mouse to current button: */
-  cursor.x = menu_button_rect[imod].x + menu_button_rect[imod].w/2;
-  cursor.y = menu_button_rect[imod].y + menu_button_rect[imod].h/2;
-//  SDL_WarpMouse(cursor.x, cursor.y);
-  SDL_WM_GrabInput(SDL_GRAB_OFF);
-
-
-  /******** Main loop:                                *********/
-  redraw = 1;  // force a full redraw on first pass
-  old_loc_screen_start = loc_screen_start;
-  while (SDL_PollEvent(&event));  // clear pending events
-  while (!stop)
-  {
-    frame_start = SDL_GetTicks();         /* For keeping frame rate constant.*/
-
-    while (SDL_PollEvent(&event))
-    {
-      switch (event.type)
-      {
-        case SDL_QUIT:
-        {
-          cleanup();
-          //exit(0);
-          break;
-        }
-
-        case SDL_MOUSEMOTION:
-        {
-          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))
-            {
-              // Play sound if loc is being changed:
-              if (Opts_GetGlobalOpt(MENU_SOUND) && (old_loc != loc_screen_start + i))
-              {
-                playsound(SND_TOCK);
-              }
-              loc = loc_screen_start + i;
-              break;   /* from for loop */
-            }
+            add_rect(&src, &src);
+            add_rect(&dst,&dst);
+            y1 =step3 *(j -0.5) -i *step4 +1;
+            y2 =step3 *(j -0.5) +i *step4 +1;
+            src.x =0;
+            src.y =y1;
+            src.w =screen->w;
+            src.h =step4;
+            dst.x =0;
+            dst.y =y2;
+            dst.w =screen->w;
+            dst.h =step4;
+            SDL_BlitSurface(newbkg, &src,screen, &src);
+            SDL_BlitSurface(newbkg,&dst, screen,&dst);
+            add_rect(&src, &src);
+            add_rect(&dst,&dst);
           }
-
-          /* "Left" button - make click if button active: */
-          if (inRect(left_arrow_rect, event.motion.x, event.motion.y))
-          {
-            if (loc_screen_start - n_entries_per_screen >= 0)
-            {
-              if (Opts_GetGlobalOpt(MENU_SOUND) && click_flag)
-              {
-                playsound(SND_TOCK);
-                click_flag = 0;
-              }
-            }
-            break;  /* from case switch */
-          }
-
-          /* "Right" button - go to next page: */
-          else if (inRect(right_arrow_rect, event.motion.x, event.motion.y ))
-          {
-            if (loc_screen_start + n_entries_per_screen < n_menu_entries)
-            {
-              if (Opts_GetGlobalOpt(MENU_SOUND) && click_flag)
-              {
-                playsound(SND_TOCK);
-                click_flag = 0;
-              }
-            }
-            break;  /* from case switch */
-          }
-
-          else  // Mouse outside of arrow rects - re-enable click sound:
-          {
-            click_flag = 1;
-            break;  /* from case switch */
-          }
+          update_screen(&frame);
         }
 
-        case SDL_MOUSEBUTTONDOWN:
-        {
-          /* Choose a menu entry by mouse click */
-          for (i = 0; (i < n_entries_per_screen) && (loc_screen_start + i < n_menu_entries); i++)
-          {
-            if (inRect(menu_button_rect[i], event.button.x, event.button.y))
-            {
-              if (Opts_GetGlobalOpt(MENU_SOUND))
-              {
-                playsound(SND_POP);
-              }
+        src.x =0;
+        src.y =0;
+        src.w =screen->w;
+        src.h =screen->h;
+        SDL_BlitSurface(newbkg, NULL,screen, &src);
+        SDL_Flip(screen);
 
-              loc = loc_screen_start + i;
-              stop = 1;
-              break;
-            }
-          }
-
-          /* "Left" button - go to previous page: */
-          if (inRect(left_arrow_rect, event.button.x, event.button.y))
-          {
-            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
-              if (Opts_GetGlobalOpt(MENU_SOUND))
-              {
-                playsound(SND_TOCK);
-              }
-              break;
-            }
-          }
-
-          /* "Right" button - go to next page: */
-          if (inRect( right_arrow_rect, event.button.x, event.button.y ))
-          {
-            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
-              if (Opts_GetGlobalOpt(MENU_SOUND))
-              {
-                playsound(SND_TOCK);
-              }
-              break;
-            }
-          }
-
-          /* "Stop" button - go to main menu: */
-          if (inRect(stopRect, event.button.x, event.button.y ))
-          {
-            stop = 2;
-            playsound(SND_TOCK);
-            break;
-          }
-        } /* End of case SDL_MOUSEDOWN */
-
-
-        case SDL_KEYDOWN:
-        {
-          /* Proceed according to particular key pressed: */
-          switch (event.key.keysym.sym)
-          {
-            case SDLK_ESCAPE:
-            {
-              stop = 2;
-              break;
-            }
-
-            case SDLK_RETURN:
-            case SDLK_SPACE:
-            case SDLK_KP_ENTER:
-            {
-              if (Opts_GetGlobalOpt(MENU_SOUND))
-                playsound(SND_POP);
-              stop = 1;
-              break;
-            }
-
-
-            /* Go to previous page, if present: */
-            case SDLK_LEFT:
-            case SDLK_PAGEUP:
-            {
-              if (Opts_GetGlobalOpt(MENU_SOUND))
-                playsound(SND_TOCK);
-              if (loc_screen_start - n_entries_per_screen >= 0) {
-                loc_screen_start -= n_entries_per_screen;
-                loc = -1;
-              }
-              //  {loc = loc_screen_start - n_entries_per_screen;}
-              break;
-            }
-
-
-            /* Go to next page, if present: */
-            case SDLK_RIGHT:
-            case SDLK_PAGEDOWN:
-            {
-              if (Opts_GetGlobalOpt(MENU_SOUND))
-                playsound(SND_TOCK);
-              if (loc_screen_start + n_entries_per_screen < n_menu_entries) {
-                loc_screen_start += n_entries_per_screen;
-                loc = -1;
-              }
-              //  {loc = (loc_screen_start + n_entries_per_screen);}
-              break;
-            }
-
-            /* Go up one entry, if present: */
-            case SDLK_UP:
-            {
-              if (Opts_GetGlobalOpt(MENU_SOUND))
-                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;
-              break;
-            }
-
-
-            /* Go down one entry, if present: */
-            case SDLK_DOWN:
-            {
-              if (Opts_GetGlobalOpt(MENU_SOUND))
-                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;
-              break;
-           }
-
-
-            /* Toggle screen mode: */
-            case SDLK_F10:
-            {
-              SwitchScreenMode();
-              RecalcTitlePositions();
-              RecalcMenuPositions(&n_entries_per_screen,
-                                  n_menu_entries,
-                                  &menu_opts,
-                                  set_custom_menu_opts,
-                                  &menu_button_rect,
-                                  &menu_sprite_rect,
-                                  &menu_text_rect,
-                                  &back_button_rect,
-                                  &back_sprite_rect,
-                                  &back_text_rect,
-                                  &left_arrow_rect,
-                                  &right_arrow_rect);
-              //we're unsure how the entries might shuffle, so return to start
-              loc_screen_start = 0;
-              redraw = 1;
-              break;
-            }
-
-            /* Toggle menu music: */
-            case SDLK_F11:
-            {
-              if (Opts_GetGlobalOpt(MENU_MUSIC))
-              {
-                audioMusicUnload( );
-                Opts_SetGlobalOpt(MENU_MUSIC, 0);
-              }
-              else
-              {
-                Opts_SetGlobalOpt(MENU_MUSIC, 1);
-                audioMusicLoad("tuxi.ogg", -1);
-              }
-              break;
-            }
-#ifdef TESTING_CAMPAIGN
-            case SDLK_c:
-            {
-              start_campaign();
-              RecalcTitlePositions();
-              RecalcMenuPositions(&n_entries_per_screen,
-                                  n_menu_entries,
-                                  &menu_opts,
-                                  set_custom_menu_opts,
-                                  &menu_button_rect,
-                                  &menu_sprite_rect,
-                                  &menu_text_rect,
-                                  &back_button_rect,
-                                  &back_sprite_rect,
-                                  &back_text_rect,
-                                  &left_arrow_rect,
-                                  &right_arrow_rect);
-              redraw = 1;
-            }
-
-#endif
-            default:
-            {
-              /* Some other key - do nothing. */
-            }
-
-            break;  /* To get out of _outer_ switch/case statement */
-          }  /* End of key switch statement */
-        }  // End of case SDL_KEYDOWN in outer switch statement
-      }  // End event switch statement
-      if (handle_easter_egg(&event) )
-        redraw = 1;
-      else
-        ; //egg_active = 0;
-    }  // End SDL_PollEvent while loop
-
-
-
-    // Make sure the menu title is not selected
-    if (loc == 0 && title_offset)
-      loc = title_offset;
-
-    /* Redraw screen: */
-    if (loc >= 0)
-      loc_screen_start = loc - (loc % n_entries_per_screen);
-    if (old_loc_screen_start != loc_screen_start)
-      redraw = 1;
-    if (redraw)
-    {
-      tmdprintf("Updating entire screen\n");
-      /* This is a full-screen redraw */
-      /* Redraw background, title, stop button, and Tux: */
-      if (!current_bkg() || screen->flags & SDL_FULLSCREEN )
-        SDL_FillRect(screen, &screen->clip_rect, 0); //clear to black
-      if (current_bkg())
-        SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect);
-      if (images[IMG_MENU_TITLE])
-        SDL_BlitSurface(images[IMG_MENU_TITLE], NULL, screen, &Titledest);
-      if (images[IMG_STOP])
-        SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
-      if (Tux->frame[0])
-        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
-      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;
-        }
+        break;
       }
-
-      if (menu_opts.button_same_width)
-        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;
-      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]);
-      }
-
-      /* --- 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: */
-        {
-          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
-        {
-          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);
-    } else if (old_loc != loc) {
-      // 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);
-        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);
-      }
-      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);
-      }
-    } 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]);
-      }
+      default:
+        break;
     }
-
-    redraw = 0;
-
-    /* Move the mouse pointer if there is only a single screen */
-    if (warp_mouse && n_menu_entries <= n_entries_per_screen) {
-      imod = loc - loc_screen_start;
-      cursor.x = menu_button_rect[imod].x + (menu_button_rect[imod].w / 2);
-      cursor.y = menu_button_rect[imod].y + (3 * menu_button_rect[imod].h / 4);
-//      SDL_WarpMouse(cursor.x, cursor.y);
-      warp_mouse = 0;
-    }
-
-    old_loc = loc;
-    old_loc_screen_start = loc_screen_start;
-
-
-
-    /* --- make Tux blink --- */
-    switch (frame_counter % TUX6)
-    {
-      case 0:    tux_frame = 1; break;
-      case TUX1: tux_frame = 2; break;
-      case TUX2: tux_frame = 3; break;
-      case TUX3: tux_frame = 4; break;
-      case TUX4: tux_frame = 3; break;
-      case TUX5: tux_frame = 2; break;
-      default: tux_frame = 0;
-    }
-
-    if (Tux && tux_frame)
-    {
-      /* Redraw background to keep edges anti-aliased properly: */
-      SDL_BlitSurface(current_bkg(),&Tuxdest, screen, &Tuxdest);
-      SDL_BlitSurface(Tux->frame[tux_frame - 1], NULL, screen, &Tuxdest);
-      SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
-      //SDL_UpdateRect(screen, 0, 0, 0, 0);
-    }
-
-    if (egg_active) { //if we need to, draw the egg cursor
-      //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);
-    }
-
-    /* Wait so we keep frame rate constant: */
-    frame_now = SDL_GetTicks();
-    if (frame_now < frame_start)
-      frame_start = frame_now;  // in case the timer wraps around
-    if (frame_now - frame_start < 33)
-      SDL_Delay(33-(frame_now-frame_start));
-
-    frame_counter++;
-  }  // End !stop while loop
-
-
-  /***** User made a choice, clean up and return the choice.   ******/
-
-  /* --- clear graphics before leaving function --- */
-  for (i = 0; i < n_menu_entries; i++)
-  {
-    SDL_FreeSurface(menu_item_unselected[i]);
-    SDL_FreeSurface(menu_item_selected[i]);
   }
-  free(menu_item_unselected);
-  free(menu_item_selected);
-  free(menu_text_rect);
-  free(menu_button_rect);
-  free(back_text_rect);
-  free(back_button_rect);
-  free(menu_sprite_rect);
-  free(back_sprite_rect);
-
-  /* Return the value of the chosen item (-1 indicates escape) */
-  if (stop == 2)
-    return -1;
-  else
-    return loc - title_offset;
+  DEBUGMSG(debug_titlescreen, "trans_wipe(): FINISH\n");
 }
 
+/* InitEngine - Set up the update rectangle pointers
+   (user by trans_wipe() ) */
+void init_blits(void) {
+  int i;
 
-
-void set_buttons_max_width(SDL_Rect *menu_button_rect,
-                           SDL_Rect *back_button_rect, int n)
-{
-  int i,max;
-
-  max = 0;
-  for (i = 0; i < n; i++)
-    if (max < menu_button_rect[i].w)
-      max = menu_button_rect[i].w;
-
-  for (i = 0; i < n; i++)
-    menu_button_rect[i].w = back_button_rect[i].w = max;
-
-  tmdprintf("All buttons at width %d\n", max);
+  for (i = 0; i < MAX_UPDATES; ++i) {
+    blits[i].srcrect = &srcupdate[i];
+    blits[i].dstrect = &dstupdate[i];
+  }
 }
 
-// Was in playgame.c in tuxtype:
 
-/*************************************************/
-/* TransWipe: Performs various wipes to new bkgs */
-/*************************************************/
-/*
- * Given a wipe request type, and any variables
- * that wipe requires, will perform a wipe from
- * the current screen image to a new one.
- */
-void TransWipe(SDL_Surface* newbkg, int type, int var1, int var2)
-{
-    int i, j, x1, x2, y1, y2;
-    int step1, step2, step3, step4;
-    int frame;
-    SDL_Rect src;
-    SDL_Rect dst;
-
-    if (!screen)
-    {
-#ifdef TUXMATH_DEBUG
-      fprintf(stderr, "TransWipe(): screen not valid!\n");
-#endif
-      return;
-    }
-
-    if (!newbkg)
-    {
-#ifdef TUXMATH_DEBUG
-      fprintf(stderr, "TransWipe(): newbkg not valid!\n");
-#endif
-      return;
-    }
-
-    numupdates = 0;
-    frame = 0;
-
-    if(newbkg->w == screen->w && newbkg->h == screen->h) {
-        if( type == RANDOM_WIPE )
-            type = (RANDOM_WIPE * ((float) rand()) / (RAND_MAX+1.0));
-
-        switch( type ) {
-            case WIPE_BLINDS_VERT: {
- #ifdef TUXMATH_DEBUG
-                fprintf(stderr, "--+ Doing 'WIPE_BLINDS_VERT'\n");
-#endif
-                /* var1 is num of divisions
-                   var2 is how many frames animation should take */
-                if( var1 < 1 ) var1 = 1;
-                if( var2 < 1 ) var2 = 1;
-                step1 = screen->w / var1;
-                step2 = step1 / var2;
-
-                for(i = 0; i <= var2; i++)
-                {
-                    for(j = 0; j <= var1; j++)
-                    {
-                        x1 = step1 * (j - 0.5) - i * step2 + 1;
-                        x2 = step1 * (j - 0.5) + i * step2 + 1;
-                        src.x = x1;
-                        src.y = 0;
-                        src.w = step2;
-                        src.h = screen->h;
-                        dst.x = x2;
-                        dst.y = 0;
-                        dst.w = step2;
-                        dst.h = screen->h;
-
-                        SDL_BlitSurface(newbkg, &src, screen, &src);
-                        SDL_BlitSurface(newbkg, &dst, screen, &dst);
-
-                        AddRect(&src, &src);
-                        AddRect(&dst, &dst);
-                    }
-                    UpdateScreen(&frame);
-                }
-
-                src.x = 0;
-                src.y = 0;
-                src.w = screen->w;
-                src.h = screen->h;
-                SDL_BlitSurface(newbkg, NULL, screen, &src);
-                SDL_Flip(screen);
-
-                break;
-            } case WIPE_BLINDS_HORIZ: {
-#ifdef TUXMATH_DEBUG
-                fprintf(stderr, "--+ Doing 'WIPE_BLINDS_HORIZ'\n");
-#endif
-                /* var1 is num of divisions
-                   var2 is how many frames animation should take */
-                if( var1 < 1 ) var1 = 1;
-                if( var2 < 1 ) var2 = 1;
-                step1 = screen->h / var1;
-                step2 = step1 / var2;
-
-                for(i = 0; i <= var2; i++) {
-                    for(j = 0; j <= var1; j++) {
-                        y1 = step1 * (j - 0.5) - i * step2 + 1;
-                        y2 = step1 * (j - 0.5) + i * step2 + 1;
-                        src.x = 0;
-                        src.y = y1;
-                        src.w = screen->w;
-                        src.h = step2;
-                        dst.x = 0;
-                        dst.y = y2;
-                        dst.w = screen->w;
-                        dst.h = step2;
-
-                        SDL_BlitSurface(newbkg, &src, screen, &src);
-                        SDL_BlitSurface(newbkg, &dst, screen, &dst);
-
-                        AddRect(&src, &src);
-                        AddRect(&dst, &dst);
-                    }
-                    UpdateScreen(&frame);
-                }
-
-                src.x = 0;
-                src.y = 0;
-                src.w = screen->w;
-                src.h = screen->h;
-                SDL_BlitSurface(newbkg, NULL, screen, &src);
-                SDL_Flip(screen);
-
-                break;
-            } case WIPE_BLINDS_BOX: {
-#ifdef TUXMATH_DEBUG
-                fprintf(stderr, "--+ Doing 'WIPE_BLINDS_BOX'\n");
-#endif
-                /* var1 is num of divisions
-                   var2 is how many frames animation should take */
-                if( var1 < 1 ) var1 = 1;
-                if( var2 < 1 ) var2 = 1;
-                step1 = screen->w / var1;
-                step2 = step1 / var2;
-                step3 = screen->h / var1;
-                step4 = step1 / var2;
-
-                for(i = 0; i <= var2; i++) {
-                    for(j = 0; j <= var1; j++) {
-                        x1 = step1 * (j - 0.5) - i * step2 + 1;
-                        x2 = step1 * (j - 0.5) + i * step2 + 1;
-                        src.x = x1;
-                        src.y = 0;
-                        src.w = step2;
-                        src.h = screen->h;
-                        dst.x = x2;
-                        dst.y = 0;
-                        dst.w = step2;
-                        dst.h = screen->h;
-
-                        SDL_BlitSurface(newbkg, &src, screen, &src);
-                        SDL_BlitSurface(newbkg, &dst, screen, &dst);
-
-                        AddRect(&src, &src);
-                        AddRect(&dst, &dst);
-                        y1 = step3 * (j - 0.5) - i * step4 + 1;
-                        y2 = step3 * (j - 0.5) + i * step4 + 1;
-                        src.x = 0;
-                        src.y = y1;
-                        src.w = screen->w;
-                        src.h = step4;
-                        dst.x = 0;
-                        dst.y = y2;
-                        dst.w = screen->w;
-                        dst.h = step4;
-                        SDL_BlitSurface(newbkg, &src, screen, &src);
-                        SDL_BlitSurface(newbkg, &dst, screen, &dst);
-                        AddRect(&src, &src);
-                        AddRect(&dst, &dst);
-                    }
-                    UpdateScreen(&frame);
-                }
-
-                src.x = 0;
-                src.y = 0;
-                src.w = screen->w;
-                src.h = screen->h;
-                SDL_BlitSurface(newbkg, NULL, screen, &src);
-                SDL_Flip(screen);
-
-                break;
-            } default:
-                break;
-        }
-    }
-#ifdef TUXMATH_DEBUG
-      fprintf(stderr, "->TransWipe(): FINISH\n");
-#endif
-}
-
-
-
-/************************
-UpdateScreen : Update the screen and increment the frame num
-***************************/
-void UpdateScreen(int *frame) {
+/* update_screen : Update the screen and increment the frame num
+   (used by trans_wipe() ) */
+void update_screen(int *frame) {
   int i;
 
   /* -- First erase everything we need to -- */
@@ -2467,212 +809,31 @@
 }
 
 
-/******************************
-AddRect: Don't actually blit a surface,
-    but add a rect to be updated next
-    update
-*******************************/
-void AddRect(SDL_Rect* src, SDL_Rect* dst) {
-    /*borrowed from SL's alien (and modified)*/
+/* add_rect: Don't actually blit a surface,
+   but add a rect to be updated next update
+   (used by trans_wipe() ) */
+void add_rect(SDL_Rect* src, SDL_Rect* dst) {
+  /*borrowed from SL's alien (and modified)*/
 
-    struct blit    *update;
+  struct blit *update;
 
-    if (!src || !dst)
-    {
-#ifdef TUXMATH_DEBUG
-     fprintf(stderr, "AddRect(): src or dst invalid!\n");
-#endif
-      return;
-    }
-
-    update = &blits[numupdates++];
-
-    update->srcrect->x = src->x;
-    update->srcrect->y = src->y;
-    update->srcrect->w = src->w;
-    update->srcrect->h = src->h;
-    update->dstrect->x = dst->x;
-    update->dstrect->y = dst->y;
-    update->dstrect->w = dst->w;
-    update->dstrect->h = dst->h;
-    update->type = 'I';
-}
-
-/***********************
- InitEngine
- ***********************/
-void InitEngine(void) {
-    int i;
-
-    /* --- Set up the update rectangle pointers --- */
-
-    for (i = 0; i < MAX_UPDATES; ++i) {
-        blits[i].srcrect = &srcupdate[i];
-        blits[i].dstrect = &dstupdate[i];
-    }
-}
-
-
-void set_default_menu_options(menu_options *menu_opts)
-{
-  menu_opts->starting_entry = 0;
-  menu_opts->xleft = screen->w / 2 - screen->w * 3 / 32;
-  menu_opts->ytop = screen->h / 2 - 140;
-  // Leave room for arrows at the bottom:
-  menu_opts->ybottom = screen->h - images[IMG_LEFT]->h - 20;
-  menu_opts->buttonheight = -1;
-  menu_opts->ygap = 10;
-  menu_opts->button_same_width = 1;
-  menu_opts->title = NULL;
-  menu_opts->trailer = NULL;
-}
-
-/* Recalculate on-screen locations for title screen elements */
-void RecalcTitlePositions()
-{
-  Backrect = current_bkg()->clip_rect;
-  Backrect.x = (screen->w - Backrect.w) / 2;
-  Backrect.y = (screen->h - Backrect.h) / 2;
-
-  Titledest.x = 0;
-  Titledest.y = 0;
-
-  Tuxdest.x = 0;
-  Tuxdest.y = screen->h - Tuxdest.h;
-
-  beak.x = Tuxdest.x + 70;
-  beak.y = Tuxdest.y + 60;
-  beak.w = beak.h = 50;
-
-  stopRect.x = screen->w - stopRect.w;
-  stopRect.y = 0;
-}
-
-/* Recalculate on-screen locations for menus when screen dimensions change */
-/* Perhaps consider generalizing this for use in initial menu calculations? */
-void RecalcMenuPositions(int* numentries,
-                         int totalentries,
-                         menu_options* mo,
-                         void (*set_custom_menu_opts)(menu_options*),
-                         SDL_Rect** menu_button_rect,
-                         SDL_Rect** menu_sprite_rect,
-                         SDL_Rect** menu_text_rect,
-                         SDL_Rect** back_button_rect,
-                         SDL_Rect** back_sprite_rect,
-                         SDL_Rect** back_text_rect,
-                         SDL_Rect* left_arrow_rect,
-                         SDL_Rect* right_arrow_rect)
-{
-  int i;
-  SDL_Rect* old_mbr = *menu_button_rect;
-  SDL_Rect* old_msr = *menu_sprite_rect;
-  SDL_Rect* old_mtr = *menu_text_rect;
-  SDL_Rect* old_bbr = *back_button_rect;
-  SDL_Rect* old_bsr = *back_sprite_rect;
-  SDL_Rect* old_btr = *back_text_rect;
-
-  int old_ne = *numentries;
-  int buttonheight = old_mbr->h; //height shouldn't change
-  int textwidth = old_mtr->w; //neither should width =P
-
-  right_arrow_rect->x = screen->w - images[IMG_RIGHT]->w - 20;
-  right_arrow_rect->y = screen->h - images[IMG_RIGHT]->h - 20;
-  left_arrow_rect->x = right_arrow_rect->x - 10 - images[IMG_LEFT]->w;
-  left_arrow_rect->y = screen->h - images[IMG_LEFT]->h - 20;
-
-  set_default_menu_options(mo);
-  if (set_custom_menu_opts != NULL)
-    set_custom_menu_opts(mo);
-
-  *numentries     = (int)(screen->h - mo->ytop+mo->ygap)/(buttonheight + mo->ygap);
-  if (*numentries < totalentries)
-    *numentries = (int)(mo->ybottom - mo->ytop+mo->ygap)/(buttonheight + mo->ygap);
-  if (*numentries > totalentries)
-    *numentries = totalentries;
-
-
-
-
-  /**** Memory allocation for new screen rects  ****/
-  *menu_text_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
-  *menu_button_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
-  *menu_sprite_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
-  *back_text_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
-  *back_button_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
-  *back_sprite_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
-  if (*menu_text_rect == NULL ||
-      *back_text_rect == NULL ||
-      *menu_button_rect == NULL ||
-      *back_button_rect == NULL ||
-      *menu_sprite_rect == NULL ||
-      *back_sprite_rect == NULL) {
-    free(*menu_text_rect);
-    free(*menu_button_rect);
-    free(*menu_sprite_rect);
-    free(*back_text_rect);
-    free(*back_button_rect);
-    free(*back_sprite_rect);
-    *menu_text_rect = old_mtr;
-    *menu_button_rect = old_mbr;
-    *menu_sprite_rect = old_msr;
-    *numentries = old_ne;
+  if (!src || !dst)
+  {
+    DEBUGMSG(debug_titlescreen, "add_rect(): src or dst invalid!\n");
     return;
   }
-  else {
-    free(old_mtr);
-    free(old_mbr);
-    free(old_msr);
-    free(old_btr);
-    free(old_bbr);
-    free(old_bsr);
-  }
 
+  update = &blits[numupdates++];
 
-  //note: the [0] notation is merely to avoid typing out (*menu_xxx_rect)[i]
-  for (i = 0; i < *numentries; i++)
-  {
-    menu_button_rect[0][i].x = mo->xleft;
-    menu_text_rect[0][i].x = mo->xleft + 15;  // 15 is left gap
-    menu_text_rect[0][i].x += 60;  // for now, assume we have a sprite
-    if (i > 0)
-      menu_text_rect[0][i].y = menu_text_rect[0][i - 1].y + buttonheight + mo->ygap;
-    else
-      menu_text_rect[0][i].y = mo->ytop;
-
-    menu_button_rect[0][i].y = menu_text_rect[0][i].y - 5;
-    menu_text_rect[0][i].h = buttonheight - 10;
-    menu_button_rect[0][i].h = buttonheight;
-
-    menu_text_rect[0][i].w = textwidth;
-    menu_button_rect[0][i].w = menu_text_rect[0][i].w + 30;
-
-    if (menu_sprite_rect != NULL) {
-      menu_sprite_rect[0][i].x = menu_button_rect[0][i].x + 3;
-      menu_sprite_rect[0][i].y = menu_button_rect[0][i].y + 3;
-      menu_sprite_rect[0][i].w = 40;
-      menu_sprite_rect[0][i].h = 50;
-    }
-    tmdprintf("***Rects[%d]****\n", i);
-    tmdprintf("%3d %3d %3d %3d\n", menu_button_rect[0][i].x, menu_button_rect[0][i].y, menu_button_rect[0][i].w, menu_button_rect[0][i].h);
-    tmdprintf("%3d %3d %3d %3d\n", menu_text_rect[0][i].x, menu_text_rect[0][i].y, menu_text_rect[0][i].w, menu_text_rect[0][i].h);
-    tmdprintf("%3d %3d %3d %3d\n", menu_sprite_rect[0][i].x, menu_sprite_rect[0][i].y, menu_sprite_rect[0][i].w, menu_sprite_rect[0][i].h);
-    tmdprintf("***************\n");
-  }
-  for (i = 0; i < *numentries; ++i)
-  {
-    back_button_rect[0][i] = menu_button_rect[0][i];
-    back_button_rect[0][i].x -= Backrect.x;
-    back_button_rect[0][i].y -= Backrect.y;
-
-    back_text_rect[0][i] = menu_text_rect[0][i];
-    back_text_rect[0][i].x -= Backrect.x;
-    back_text_rect[0][i].y -= Backrect.y;
-
-    back_sprite_rect[0][i] = menu_sprite_rect[0][i];
-    back_sprite_rect[0][i].x -= Backrect.x;
-    back_sprite_rect[0][i].y -= Backrect.y;
-  }
-
+  update->srcrect->x = src->x;
+  update->srcrect->y = src->y;
+  update->srcrect->w = src->w;
+  update->srcrect->h = src->h;
+  update->dstrect->x = dst->x;
+  update->dstrect->y = dst->y;
+  update->dstrect->w = dst->w;
+  update->dstrect->h = dst->h;
+  update->type = 'I';
 }
 
 int handle_easter_egg(const SDL_Event* evt)
@@ -2699,7 +860,7 @@
       {
       SDL_ShowCursor(SDL_ENABLE);
       //SDL_FillRect(screen, &cursor, 0);
-      SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect); //cover egg up once more
+      SDL_BlitSurface(current_bkg(), NULL, screen, &bkg_rect); //cover egg up once more
       SDL_WarpMouse(cursor.x, cursor.y);
       SDL_UpdateRect(screen, cursor.x, cursor.y, cursor.w, cursor.h); //egg->x, egg->y, egg->w, egg->h);
       egg_active = 0;
@@ -2717,19 +878,18 @@
       //animate
       while (tuxframe != 0)
         {
-        SDL_BlitSurface(Tux->frame[--tuxframe], NULL, screen, &Tuxdest);
-        SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
+        SDL_BlitSurface(current_bkg(), &tux_rect, screen, &tux_rect);
+        SDL_BlitSurface(Tux->frame[--tuxframe], NULL, screen, &tux_rect);
+        SDL_UpdateRect(screen, tux_rect.x, tux_rect.y, tux_rect.w, tux_rect.h);
         SDL_Delay(GOBBLE_ANIM_MS / Tux->num_frames);
         }
 
       eggtimer = SDL_GetTicks() + EASTER_EGG_MS;
       egg_active = 1;
-      SDL_WarpMouse(Tuxdest.x + Tuxdest.w / 2, Tuxdest.y + Tuxdest.h - egg->h);
+      SDL_WarpMouse(tux_rect.x + tux_rect.w / 2, tux_rect.y + tux_rect.h - egg->h);
 
       }
 
     return 0;
     }
   }
-
-

Added: tuxmath/branches/lan/src/titlescreen.c.old
===================================================================
--- tuxmath/branches/lan/src/titlescreen.c.old	                        (rev 0)
+++ tuxmath/branches/lan/src/titlescreen.c.old	2009-09-03 22:06:06 UTC (rev 1477)
@@ -0,0 +1,2735 @@
+/***************************************************************************
+ -  file: titlescreen.c
+ -  description: splash, title and menu screen functionality
+                            ------------------
+    begin                : Thur May 4 2000
+    copyright            : (C) 2000 by Sam Hart
+                         : (C) 2003 by Jesse Andrews
+    email                : tuxtype-dev at tux4kids.net
+
+    Modified for use in tuxmath by David Bruce - 2006-2007.
+    email                : <dbruce at tampabay.rr.com>
+                           <tuxmath-devel at lists.sourceforge.net>
+    Also significantly enhanced by Tim Holy - 2007
+***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+  
+// titlescreen.h has all of the tuxtype-related stuff:
+#include "titlescreen.h"
+
+// tuxmath includes:
+#include "tuxmath.h"
+#include "options.h"
+#include "fileops.h"
+#include "game.h"
+#include "campaign.h"
+#include "factoroids.h"
+#include "multiplayer.h"
+#include "transtruct.h"
+#include "mathcards.h"
+#include "setup.h"     //for cleanup()
+#include "network.h"
+#include "loaders.h"
+#include "credits.h"
+#include "highscore.h"
+#include "convert_utf.h" // for wide char to UTF-8 conversion
+#include "SDL_extras.h"
+
+/* --- Data Structure for Dirty Blitting --- */
+SDL_Rect srcupdate[MAX_UPDATES];
+SDL_Rect dstupdate[MAX_UPDATES];
+int numupdates = 0; // tracks how many blits to be done
+char host[1024]="NULL";
+char player_name[1024];
+
+// Colors we use:
+SDL_Color black;
+SDL_Color gray;
+SDL_Color dark_blue;
+SDL_Color red;
+SDL_Color white;
+SDL_Color yellow;
+
+// Type needed for TransWipe():
+struct blit {
+    SDL_Surface *src;
+    SDL_Rect *srcrect;
+    SDL_Rect *dstrect;
+    unsigned char type;
+} blits[MAX_UPDATES];
+
+// Lessons available for play
+char **lesson_list_titles = NULL;
+char **lesson_list_filenames = NULL;
+int num_lessons = 0;
+//int n=0;
+
+
+/* --- media for menus --- */
+
+enum {
+  SPRITE_TRAINING,
+  SPRITE_ARCADE,
+  SPRITE_HELP,
+  SPRITE_CUSTOM,
+  SPRITE_OPTIONS,
+  SPRITE_CADET,
+  SPRITE_SCOUT,
+  SPRITE_RANGER,
+  SPRITE_ACE,
+  SPRITE_COMMANDO,
+  SPRITE_QUIT,
+  SPRITE_MAIN,
+  SPRITE_GOLDSTAR,
+  SPRITE_NO_GOLDSTAR,
+  SPRITE_TROPHY,
+  SPRITE_CREDITS,
+  SPRITE_ALONE,
+  SPRITE_LAN,
+  SPRITE_FRIENDS,
+  SPRITE_FACTOROIDS,
+  SPRITE_FACTORS,
+  SPRITE_FRACTIONS,
+  SPRITE_CAMPAIGN,
+  SPRITE_SSWEEP,
+  SPRITE_ELIMINATION,
+  SPRITE_SERVER,
+  SPRITE_CLIENT,
+  N_SPRITES};
+
+const char* menu_sprite_files[N_SPRITES] =
+{
+  "lesson",
+  "comet",
+  "help",
+  "tux_config",
+  "tux_config_brown",
+  "tux_helmet_yellow",
+  "tux_helmet_green",
+  "tux_helmet_blue",
+  "tux_helmet_red",
+  "tux_helmet_black",
+  "quit",
+  "main",
+  "goldstar",
+  "no_goldstar",
+  "trophy",
+  "credits",
+  "alone", 
+  "lan",
+  "friends", 
+  "factoroids",
+  "factors",
+  "fractions",
+  "fleet",
+  "nums",
+  "exclamation"
+};
+
+sprite **sprite_list = NULL;
+
+sprite* Tux = NULL;
+
+
+SDL_Event event;
+
+/* --- locations we need --- */
+
+SDL_Rect dest,
+         Tuxdest,
+         Titledest,
+         stopRect,
+         Backrect,
+         Tuxback,
+         Titleback,
+         cursor,
+         beak;
+
+/* The background image scaled to windowed 640x480 */
+SDL_Surface* bkg = NULL;
+/* The background image scaled to fullscreen dimensions */
+SDL_Surface* scaled_bkg = NULL;
+/* "Easter Egg" cursor */
+SDL_Surface* egg = NULL;
+int egg_active = 0; //are we currently using the egg cursor?
+
+
+SDL_Surface* current_bkg()
+  /* This syntax makes my brain start to explode! */
+  { return screen->flags & SDL_FULLSCREEN ? scaled_bkg : bkg; }
+
+/* Local function prototypes: */
+void TitleScreen_load_menu(void);
+void TitleScreen_unload_menu(void);
+int TitleScreen_load_media(void);
+void TitleScreen_unload_media(void);
+void NotImplemented(void);
+void TransWipe(SDL_Surface* newbkg, int type, int var1, int var2);
+void UpdateScreen(int* frame);
+void AddRect(SDL_Rect* src, SDL_Rect* dst);
+void InitEngine(void);
+void ShowMessage(const char* str1, const char* str2, const char* str3, const char* str4);
+void RecalcTitlePositions();
+void RecalcMenuPositions(int*, int, menu_options*, void (*)(menu_options*),
+                         SDL_Rect**, SDL_Rect**, SDL_Rect**,
+                         SDL_Rect**, SDL_Rect**, SDL_Rect**,
+                         SDL_Rect*, SDL_Rect*);
+void set_buttons_max_width(SDL_Rect *, SDL_Rect *, int);
+
+int run_login_menu(void);
+int run_main_menu(void);
+int run_game_menu(void);
+int run_multiplay_menu(void);
+int run_lessons_menu(void);
+int run_arcade_menu(void);
+int run_campaign_menu(void);
+int run_custom_menu(void);
+int run_activities_menu(void);
+int run_options_menu(void);
+int run_lan_menu(void);
+int run_server_menu(void);
+int handle_easter_egg(const SDL_Event* evt);
+
+/***********************************************************/
+/*                                                         */
+/*       "Public functions" (callable throughout program)  */
+/*                                                         */
+/***********************************************************/
+
+
+
+/****************************************
+* TitleScreen: Display the title screen *
+****************************************/
+
+/* display title screen, get input */
+
+void TitleScreen(void)
+{
+
+  Uint32 start = 0;
+
+  int i,TuxPixSkip,TitlePixSkip;
+//  int n_subdirs;
+//  char **subdir_names;
+
+
+  if (Opts_UsingSound())
+  {
+    Opts_SetGlobalOpt(MENU_SOUND, 1);
+    Opts_SetGlobalOpt(MENU_MUSIC, 1);
+//    menu_music = localsettings.menu_music;
+  }
+
+  InitEngine();  //set up pointers for blitting structure.
+
+  start = SDL_GetTicks();
+
+
+  /* StandbyScreen: Display the Standby screen: */
+  if (images[IMG_STANDBY])
+  {
+    // Center horizontally
+    dest.x = ((screen->w) / 2) - (images[IMG_STANDBY]->w) / 2;
+    // Center vertically
+    dest.y = ((screen->h) / 2) - (images[IMG_STANDBY]->h) / 2;
+    dest.w = images[IMG_STANDBY]->w;
+    dest.h = images[IMG_STANDBY]->h;
+
+    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
+    SDL_BlitSurface(images[IMG_STANDBY], NULL, screen, &dest);
+    SDL_UpdateRect(screen, 0, 0, 0, 0);
+    // Play "harp" greeting sound lifted from Tux Paint:
+    playsound(SND_HARP);
+ }
+
+
+  /* --- wait  --- */
+
+  while ((SDL_GetTicks() - start) < 2000)
+  {
+    /* Check to see if user pressed escape */
+    if (SDL_PollEvent(&event)
+     && event.type==SDL_KEYDOWN
+     && event.key.keysym.sym == SDLK_ESCAPE)
+    {
+      return;
+    }
+    SDL_Delay(50);
+  }
+#ifndef TUXMATH_DEBUG //in case of a freeze, this traps the cursor
+  SDL_WM_GrabInput(SDL_GRAB_ON); // User input goes to TuxMath, not window manager
+#endif
+  SDL_ShowCursor(1);
+
+
+  /***************************
+  * Tux and Title animations *
+  ***************************/
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr, "->Now Animating Tux and Title onto the screen\n" );
+#endif
+
+  /* Load media and menu data: */
+  /* FIXME should get out if needed media not loaded OK */
+  if (TitleScreen_load_media() == 0) {
+    fprintf(stderr,"Media was not properly loaded, exiting");
+    return;
+  }
+
+  /* Draw background, if it loaded OK: */
+  if (current_bkg() )
+  {
+    Backrect.x = (screen->w - current_bkg()->w) / 2;
+    Backrect.y = (screen->h - current_bkg()->h) / 2;
+    Backrect.w = current_bkg()->w;
+    Backrect.h = current_bkg()->h;
+    /* FIXME not sure TransWipe() works in Windows: */
+    TransWipe(current_bkg(), RANDOM_WIPE, 10, 20);
+    /* Make sure background gets drawn (since TransWipe() doesn't */
+    /* seem to work reliably as of yet):                          */
+    SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect);
+
+  }
+  /* Red "Stop" circle in upper right corner to go back to main menu: */
+  if (images[IMG_STOP])
+  {
+    stopRect.w = images[IMG_STOP]->w;
+    stopRect.h = images[IMG_STOP]->h;
+    stopRect.x = screen->w - images[IMG_STOP]->w;
+    stopRect.y = 0;
+    SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
+  }
+  SDL_UpdateRect(screen, 0, 0, 0, 0);
+
+  /* --- Pull tux & logo onscreen --- */
+  /* NOTE we wind up with Tuxdest.y == (screen->h)  - (Tux->frame[0]->h), */
+  /* a 	nd Titledest.x == 0.                                                */
+  if (current_bkg()
+   && images[IMG_MENU_TITLE]
+   && images[IMG_STOP]
+   && Tux && Tux->frame[0])
+  {
+
+    Tuxdest.x = 0;
+    Tuxdest.y = screen->h;
+    /*
+    Tuxback.x = Tuxdest.x - Backrect.x;
+    Tuxback.y = Tuxdest.y - Backrect.y;
+    */
+    Tuxdest.w = Tuxback.w = Tux->frame[0]->w;
+    Tuxdest.h = Tuxback.h = Tux->frame[0]->h;
+
+
+    Titledest.x = screen->w;
+    Titledest.y = 10;
+    /*
+    Titleback.x = Titledest.x - Backrect.x;
+    Titleback.y = Titledest.y - Backrect.y;
+    */
+    Titledest.w = Titleback.w = images[IMG_MENU_TITLE]->w;
+    Titledest.h = Titleback.h = images[IMG_MENU_TITLE]->h;
+
+    TuxPixSkip = Tux->frame[0]->h / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
+    TitlePixSkip = (screen->w) / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
+
+    for (i = 0; i < (PRE_ANIM_FRAMES * PRE_FRAME_MULT); i++)
+    {
+      start = SDL_GetTicks();
+
+      //Draw the entire background, over a black screen if necessary
+      if (current_bkg()->w != screen->w || current_bkg()->h != screen->h)
+        SDL_FillRect(screen, &screen->clip_rect, 0);
+      SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect);
+
+      Tuxdest.y -= TuxPixSkip;
+      //Tuxback.y -= Tux->frame[0]->h / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
+      Titledest.x -= TitlePixSkip;
+      //Titleback.y -= (screen->w) / (PRE_ANIM_FRAMES * PRE_FRAME_MULT);
+
+      SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
+      SDL_BlitSurface(images[IMG_MENU_TITLE], NULL, screen, &Titledest);
+      SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
+
+      SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
+      SDL_UpdateRect(screen, Titledest.x, Titledest.y, Titledest.w + TitlePixSkip, Titledest.h);
+      SDL_UpdateRect(screen, stopRect.x, stopRect.y, stopRect.w, stopRect.h);
+
+      while ((SDL_GetTicks() - start) < 33)
+      {
+        SDL_Delay(2);
+      }
+    }
+
+
+  }
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr, "Tux and Title are in place now\n");
+#endif
+
+  //location of Tux's beak
+  beak.x = Tuxdest.x + 70;
+  beak.y = Tuxdest.y + 60;
+  beak.w = beak.h = 50;
+
+  /* Start playing menu music if desired: */
+  if (Opts_GetGlobalOpt(MENU_MUSIC))
+  {
+    audioMusicLoad("tuxi.ogg", -1);
+  }
+
+  /* If necessary, have the user log in */
+  if (run_login_menu() != -1) {
+    /* Finish parsing user options */
+    initialize_options_user();
+    /* Start the main menu */
+    run_main_menu();
+  }
+
+  /* User has selected quit, clean up */
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr, "->>Freeing title screen images\n");
+#endif
+
+  TitleScreen_unload_media();
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr,"->TitleScreen():END \n");
+#endif
+
+}
+
+
+
+
+/***********************************************************/
+/*                                                         */
+/*    "Private functions" (callable only from this file)   */
+/*                                                         */
+/***********************************************************/
+
+
+// 1 = success, 0 = failure
+int TitleScreen_load_media(void)
+{
+  char fn[PATH_MAX];
+  int i;
+
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr, "Entering TitleScreen_load_media():\n");
+#endif
+
+  Tux = LoadSprite("tux/bigtux", IMG_ALPHA);
+
+  SDL_ShowCursor(1);
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr, "loading sprites\n");
+#endif
+
+  sprite_list = (sprite**) malloc(N_SPRITES*sizeof(sprite*));
+  if (sprite_list == NULL)
+    return 0;
+
+  for (i = 0; i < N_SPRITES; i++) {
+    /* --- load animated icon for menu item --- */
+    sprintf(fn, "sprites/%s", menu_sprite_files[i]);
+    sprite_list[i] = LoadSprite(fn, IMG_ALPHA);
+  }
+  egg = LoadImage("title/egg.png",
+                  IMG_COLORKEY | IMG_NOT_REQUIRED);
+  LoadBothBkgds("title/menu_bkg.jpg", &scaled_bkg, &bkg);
+  return 1;
+}
+
+
+
+
+void TitleScreen_unload_menu(void)
+{
+  int i;
+
+  for (i = 0; i < N_SPRITES; i++)
+  {
+    tmdprintf("Freeing image %d: ", i);
+    FreeSprite(sprite_list[i]);
+    sprite_list[i] = NULL;
+  }
+  free(sprite_list);
+  tmdprintf("Images freed\n");
+  sprite_list = NULL;
+}
+
+
+
+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);
+}
+
+
+
+void NotImplemented(void)
+{
+  const char *s1, *s2, *s3, *s4;
+
+  s1 = _("Work In Progress!");
+  s2 = _("This feature is not ready yet");
+  s3 = _("Discuss the future of TuxMath at");
+  s4 = N_("tuxmath-devel at lists.sourceforge.net");
+
+  ShowMessage(s1, s2, s3, s4);
+}
+
+
+
+
+
+/* FIXME add some background shading to improve legibility */
+void ShowMessage(const char* str1, const char* str2, const char* str3, const char* str4)
+{
+  SDL_Surface *s1, *s2, *s3, *s4;
+  SDL_Rect loc;
+  int finished = 0;
+  int tux_frame = 0;
+  Uint32 frame = 0;
+  Uint32 start = 0;
+
+  s1 = s2 = s3 = s4 = NULL;
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr, "ShowMessage() - creating text\n" );
+#endif
+
+  if (str1)
+    s1 = BlackOutline(str1, DEFAULT_MENU_FONT_SIZE, &white);
+  if (str2)
+    s2 = BlackOutline(str2, DEFAULT_MENU_FONT_SIZE, &white);
+  if (str3)
+    s3 = BlackOutline(str3, DEFAULT_MENU_FONT_SIZE, &white);
+  if (str4)
+    s4 = BlackOutline(str4, DEFAULT_MENU_FONT_SIZE, &white);
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr, "ShowMessage() - drawing screen\n" );
+#endif
+
+  /* Redraw background: */
+  if (current_bkg() )
+    SDL_BlitSurface( current_bkg(), NULL, screen, &Backrect );
+
+  /* Red "Stop" circle in upper right corner to go back to main menu: */
+  if (images[IMG_STOP])
+  {
+    stopRect.w = images[IMG_STOP]->w;
+    stopRect.h = images[IMG_STOP]->h;
+    stopRect.x = screen->w - images[IMG_STOP]->w;
+    stopRect.y = 0;
+    SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
+  }
+
+  if (Tux && Tux->num_frames) /* make sure sprite has at least one frame */
+  {
+    SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
+  }
+
+  /* Draw lines of text (do after drawing Tux so text is in front): */
+  if (s1)
+  {
+    loc.x = (screen->w / 2) - (s1->w/2); loc.y = 10;
+    SDL_BlitSurface( s1, NULL, screen, &loc);
+  }
+  if (s2)
+  {
+    loc.x = (screen->w / 2) - (s2->w/2); loc.y = 60;
+    SDL_BlitSurface( s2, NULL, screen, &loc);
+  }
+  if (s3)
+  {
+    //loc.x = 320 - (s3->w/2); loc.y = 300;
+    loc.x = (screen->w / 2) - (s3->w/2); loc.y = 110;
+    SDL_BlitSurface( s3, NULL, screen, &loc);
+  }
+  if (s4)
+  {
+    //loc.x = 320 - (s4->w/2); loc.y = 340;
+    loc.x = (screen->w / 2) - (s4->w/2); loc.y = 200;
+    SDL_BlitSurface( s4, NULL, screen, &loc);
+  }
+
+  /* and update: */
+  SDL_UpdateRect(screen, 0, 0, 0, 0);
+
+  while (!finished)
+  {
+    start = SDL_GetTicks();
+
+    while (SDL_PollEvent(&event))
+    {
+      switch (event.type)
+      {
+        case SDL_QUIT:
+        {
+          cleanup();
+        }
+
+        case SDL_MOUSEBUTTONDOWN:
+        /* "Stop" button - go to main menu: */
+        {
+          if (inRect(stopRect, event.button.x, event.button.y ))
+          {
+            finished = 1;
+            playsound(SND_TOCK);
+            break;
+          }
+        }
+        case SDL_KEYDOWN:
+        {
+          finished = 1;
+          playsound(SND_TOCK);
+        }
+      }
+    }
+
+    /* --- make tux blink --- */
+    switch (frame % TUX6)
+    {
+      case 0:    tux_frame = 1; break;
+      case TUX1: tux_frame = 2; break;
+      case TUX2: tux_frame = 3; break;
+      case TUX3: tux_frame = 4; break;
+      case TUX4: tux_frame = 3; break;
+      case TUX5: tux_frame = 2; break;
+      default: tux_frame = 0;
+    }
+
+    if (Tux && tux_frame)
+    {
+      SDL_BlitSurface(Tux->frame[tux_frame - 1], NULL, screen, &Tuxdest);
+//      SDL_UpdateRect(screen, Tuxdest.x+37, Tuxdest.y+40, 70, 45);
+      SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
+
+    }
+    /* Wait so we keep frame rate constant: */
+    while ((SDL_GetTicks() - start) < 33)
+    {
+      SDL_Delay(20);
+    }
+    frame++;
+  }  // End of while (!finished) loop
+
+  SDL_FreeSurface(s1);
+  SDL_FreeSurface(s2);
+  SDL_FreeSurface(s3);
+  SDL_FreeSurface(s4);
+}
+
+
+void main_scmo(menu_options* mo) //set custom menu opts for main
+{
+  mo->ygap = 15;
+}
+
+int run_main_menu(void)
+{
+  const char* menu_text[7] =
+    {N_("Play Alone"),
+     N_("LAN Game"),
+     N_("Play With Friends"),
+     N_("Factoroids!"),
+     N_("Help"),
+     N_("More Options"),
+     N_("Quit")};
+  sprite* sprites[7] =
+    {NULL, NULL, NULL, NULL, NULL, NULL,NULL};
+  menu_options menu_opts;
+  int choice,ret;
+
+  // Set up the sprites
+  sprites[0] = sprite_list[SPRITE_ALONE];
+  sprites[1] = sprite_list[SPRITE_LAN];
+  sprites[2] = sprite_list[SPRITE_FRIENDS];
+  sprites[3] = sprite_list[SPRITE_FACTOROIDS];
+  sprites[4] = sprite_list[SPRITE_HELP];
+  sprites[5] = sprite_list[SPRITE_OPTIONS];
+  sprites[6] = sprite_list[SPRITE_QUIT];
+  
+  //set_default_menu_options(&menu_opts);
+  //menu_opts.ytop = 100;
+  //menu_opts.ygap = 15;
+
+  //This function takes care of all the drawing and receives
+  //user input:
+  choice = choose_menu_item(menu_text,sprites,7,NULL,main_scmo);
+
+  while (choice >= 0) {
+    switch (choice) {
+      case 0: {
+        // All single player modes
+        ret = run_game_menu();
+        break;
+      }
+      case 1: {
+        ret = run_lan_menu();
+        break;
+      }
+      case 2: {
+        // Multiplayer games
+        ret = run_multiplay_menu();
+        break;
+      }
+      case 3: {
+        // Factroids et. al.
+        ret = run_activities_menu();
+        break;
+      }
+      case 4: {
+        // Help
+        Opts_SetHelpMode(1);
+        Opts_SetDemoMode(0);
+        if (Opts_GetGlobalOpt(MENU_MUSIC))  //Turn menu music off for game
+          {audioMusicUnload();}
+        game();
+        RecalcTitlePositions();
+        if (Opts_GetGlobalOpt(MENU_MUSIC)) //Turn menu music back on
+          {audioMusicLoad( "tuxi.ogg", -1 );}
+        Opts_SetHelpMode(0);
+        break;
+      }
+      case 5: {
+        // More options
+        ret = run_options_menu();
+        break;
+      }
+      case 6: {
+        // Quit
+        tmdprintf("Exiting main menu\n");
+        return 0;
+      }    
+    }
+    menu_opts.starting_entry = choice;
+    choice = choose_menu_item(menu_text,sprites,7,NULL,main_scmo);
+  }
+  return 0;
+}
+                                                     
+#define NUM_GAME_MENU_ITEMS 5
+int run_game_menu(void)
+{
+  const char* menu_text[NUM_GAME_MENU_ITEMS] =
+    {N_("Math Command Training Academy"),
+     N_("Math Command Fleet Missions"),          
+     N_("Play Arcade Game"),
+     N_("Play Custom Game"),
+     N_("Main menu")};
+
+  sprite* sprites[NUM_GAME_MENU_ITEMS] = {NULL, NULL, NULL, NULL, NULL};
+
+  int ret, choice = 0;
+
+  sprites[0] = sprite_list[SPRITE_TRAINING];
+  sprites[1] = sprite_list[SPRITE_CAMPAIGN];
+  sprites[2] = sprite_list[SPRITE_ARCADE];
+  sprites[3] = sprite_list[SPRITE_CUSTOM];
+  sprites[4] = sprite_list[SPRITE_MAIN];
+
+  while (choice >= 0) {
+    choice = choose_menu_item(menu_text,sprites,NUM_GAME_MENU_ITEMS,NULL,NULL);
+    switch (choice) {
+      case 0:
+        ret = run_lessons_menu();
+        break;
+      case 1:
+        ret = start_campaign();
+        break;
+      case 2:
+        ret = run_arcade_menu();
+        break;
+      case 3:
+        ret = run_custom_menu();
+        break;
+      case 4:
+        return 0;
+      default:
+        tmdprintf("choose_menu_item() returned %d--returning\n", choice);
+        return 0;
+    }
+  }
+  return 0;
+}
+
+/*
+Set up and start a turn-based multiplayer game. Some funky heap issues so
+quarantine it behind the return for the time being.
+*/
+int run_multiplay_menu(void)
+{
+  int nplayers = 0;
+  int mode = -1;
+  int difficulty = -1;
+  char npstr[HIGH_SCORE_NAME_LENGTH * 3];
+  
+
+  const char* menu_text[3] =
+    {N_("Score Sweep"),
+     N_("Elimination"),
+     N_("Main menu")};
+
+  //just leech settings from arcade modes
+  const char* diff_menu_text[NUM_MATH_COMMAND_LEVELS + 1] =
+    {N_("Space Cadet"),
+     N_("Scout"),
+     N_("Ranger"),
+     N_("Ace"),
+     N_("Commando"),
+     N_("Main menu")};
+
+
+  sprite* modesprites[3] = {NULL, NULL, NULL};
+  sprite* diffsprites[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
+  // Set up the sprites
+  modesprites[0] = sprite_list[SPRITE_SSWEEP];
+  modesprites[1] = sprite_list[SPRITE_ELIMINATION];
+  modesprites[2] = sprite_list[SPRITE_MAIN];
+  
+  diffsprites[0] = sprite_list[SPRITE_CADET];
+  diffsprites[1] = sprite_list[SPRITE_SCOUT];
+  diffsprites[2] = sprite_list[SPRITE_RANGER];
+  diffsprites[3] = sprite_list[SPRITE_ACE];
+  diffsprites[4] = sprite_list[SPRITE_COMMANDO];
+  diffsprites[5] = sprite_list[SPRITE_MAIN];
+
+  while (1)
+  {
+    //choose difficulty
+    difficulty = choose_menu_item(diff_menu_text, diffsprites, 
+                 NUM_MATH_COMMAND_LEVELS + 1, NULL, NULL);
+
+    if (difficulty == -1 || difficulty >= NUM_MATH_COMMAND_LEVELS)
+      break; //user chose main menu or hit escape
+
+    //choose mode
+    mode = choose_menu_item(menu_text,modesprites,3,NULL,NULL);
+    if (mode == 2 || mode == -1)
+      break;
+
+    //ask how many players
+    while (nplayers <= 0 || nplayers > MAX_PLAYERS)
+    {
+      NameEntry(npstr, _("How many kids are playing?"),
+                       _("(Between 2 and 4 players)"));
+      nplayers = atoi(npstr);
+    }
+
+
+    mp_set_parameter(PLAYERS, nplayers);
+    mp_set_parameter(MODE, mode);
+    mp_set_parameter(DIFFICULTY, difficulty);
+
+    //RUN!
+    mp_run_multiplayer();
+  }
+
+  return 0;
+}
+
+///////////////////////////   LAN game menu()////////////
+
+
+int run_lan_menu(void)
+{
+  int mode = -1;
+  int servers_found = 0;  
+
+  const char* menu_text[3] =
+    {N_("Host"),
+     N_("Join"),
+     N_("Main menu")};
+
+  sprite* modesprites[3] = {NULL, NULL, NULL};
+  // Set up the sprites
+  modesprites[0] = sprite_list[SPRITE_SERVER];
+  modesprites[1] = sprite_list[SPRITE_CLIENT];
+  modesprites[2] = sprite_list[SPRITE_MAIN];
+  
+  while (1)
+  {
+    //choose mode
+    mode = choose_menu_item(menu_text, modesprites, 3, NULL, NULL);
+    if (mode == 2 || mode == -1)
+      break;
+
+//    if(mode == 0)                     //chooses Host
+//    run_server_menu();
+    
+    if(mode == 1)
+    {
+      if(detecting_servers(_("Detecting Servers"), _("Please Wait")))
+      {
+        int stdby;
+        char buf[256];
+	snprintf(buf, 256, _("Connected to server: %s"), LAN_ConnectedServerName());
+        NameEntry(player_name, buf, _("Enter your Name:"));
+        LAN_SetName(player_name);
+        Ready(_("Click OK when Ready"));
+        LAN_StartGame();
+        stdby = Standby(_("Waiting For Other Players"),_("To Connect"));
+        if (stdby == 1)
+        {
+          Opts_SetLanMode(1);  // Tells game() we are playing over network
+          game();
+          Opts_SetLanMode(0);  // Go back to local play
+        }
+        else
+        {
+          ShowMessage(NULL, _("Sorry, game already in progress."), NULL, NULL);
+        }  
+      }
+      else
+      {
+        ShowMessage(NULL, _("Sorry, no server could be found."), NULL, NULL);
+        break;
+      }
+    }   
+  }
+
+  return 0;
+
+}
+
+/*Dont think we need this..*/
+//int run_server_menu(void)
+//{
+
+//  int difficulty = -1;
+ //  n=1;
+//   int g;
+  //just leech settings from arcade modes
+//  const char* diff_menu_text[NUM_MATH_COMMAND_LEVELS + 1] =
+//    {N_("Space Cadet"),
+//     N_("Scout"),
+//     N_("Ranger"),
+//     N_("Ace"),      
+//     N_("Commando"),
+//     N_("Main menu")};
+ 
+  
+
+//   sprite* diffsprites[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
+  
+ 
+//  diffsprites[0] = sprite_list[SPRITE_CADET];
+//  diffsprites[1] = sprite_list[SPRITE_SCOUT];
+//  diffsprites[2] = sprite_list[SPRITE_RANGER];
+//  diffsprites[3] = sprite_list[SPRITE_ACE];
+//  diffsprites[4] = sprite_list[SPRITE_COMMANDO];
+//  diffsprites[5] = sprite_list[SPRITE_MAIN];
+
+//     while (1)
+//  {
+    //choose difficulty
+//    difficulty = choose_menu_item(diff_menu_text,diffsprites,6,NULL,NULL);
+//     if (difficulty == -1 || difficulty >= NUM_MATH_COMMAND_LEVELS)
+//     { break;} //user chose main menu or hit escape
+//     else
+//     {NameEntry(port, _("Enter the PORT"),
+//                       _(""));
+    
+//       game();}
+//    break;
+//   }
+//   return 0;
+
+
+//}
+
+
+
+
+int run_arcade_menu(void)
+{
+  const char* menu_text[7] =
+    {N_("Space Cadet"),
+     N_("Scout"),
+     N_("Ranger"),
+     N_("Ace"),
+     N_("Commando"),
+     N_("Hall Of Fame"),
+     N_("Main menu")};               
+  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;
+
+  // Set up the sprites
+  sprites[0] = sprite_list[SPRITE_CADET];
+  sprites[1] = sprite_list[SPRITE_SCOUT];
+  sprites[2] = sprite_list[SPRITE_RANGER];
+  sprites[3] = sprite_list[SPRITE_ACE];
+  sprites[4] = sprite_list[SPRITE_COMMANDO];
+  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, 7, NULL, NULL);
+
+  while (choice >= 0) {
+    if (choice < NUM_MATH_COMMAND_LEVELS) {
+      // Play arcade game
+      if (read_named_config_file(arcade_config_files[choice]))
+      {
+        audioMusicUnload();
+	Opts_SetLanMode(0);
+        game();
+        RecalcTitlePositions();
+        if (Opts_GetGlobalOpt(MENU_MUSIC)) {
+          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){
+
+          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]);
+
+#ifdef TUXMATH_DEBUG
+          print_high_scores(stderr);
+#endif
+        }
+      } else {
+        fprintf(stderr, "\nCould not find %s config file\n",arcade_config_files[choice]);
+      }
+
+    } else if (choice == NUM_MATH_COMMAND_LEVELS) {
+      // Display the Hall of Fame
+      DisplayHighScores(CADET_HIGH_SCORE);
+    }
+    else {
+      // Return to main menu
+      return 0;
+    }
+    set_default_menu_options(&menu_opts);
+    menu_opts.starting_entry = choice;
+    choice = choose_menu_item(menu_text,sprites,7,NULL, NULL);
+  }
+
+  return 0;
+}
+
+
+int run_custom_menu(void)
+{
+  const char *s1, *s2, *s3, *s4;
+  s1 = _("Edit 'options' file in your home directory");
+  s2 = _("to create customized game!");
+  s3 = _("Press a key or click your mouse to start game.");
+  s4 = _("See README.txt for more information");
+  ShowMessage(s1, s2, s3, s4);
+
+  if (read_user_config_file()) {
+    if (Opts_GetGlobalOpt(MENU_MUSIC))
+      audioMusicUnload();
+
+    game();
+    RecalcTitlePositions();
+    write_user_config_file();
+
+    if (Opts_GetGlobalOpt(MENU_MUSIC))
+      audioMusicLoad( "tuxi.ogg", -1 );
+  }
+
+  return 0;
+}
+
+int run_activities_menu(void)
+{ 
+  const char* menu_text[3] =
+    {N_("Factors"),
+     N_("Fractions"),
+     N_("Main menu")};
+  const int factoroids_high_score_tables[2] =
+    {FACTORS_HIGH_SCORE, FRACTIONS_HIGH_SCORE};
+  sprite* sprites[3] =
+    {NULL, NULL, NULL};
+  menu_options menu_opts;
+  int choice, hs_table;
+
+  // Set up the sprites
+  sprites[0] = sprite_list[SPRITE_FACTORS];
+  sprites[1] = sprite_list[SPRITE_FRACTIONS];
+  sprites[2] = 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, 3, NULL, NULL);
+
+  while (choice >= 0) {
+    switch(choice){
+      case 0:
+          audioMusicUnload();
+          factors();
+	  
+	  if (Opts_GetGlobalOpt(MENU_MUSIC)) {
+	      audioMusicLoad( "tuxi.ogg", -1 );
+	  }
+	  break;
+      case 1:
+          audioMusicUnload(); 
+          fractions();
+	  
+	  if (Opts_GetGlobalOpt(MENU_MUSIC)) {
+	     audioMusicLoad( "tuxi.ogg", -1 );
+	  }
+	  break;
+     case 2:
+          // Return to main menu
+          return 0;
+    }
+
+	hs_table = factoroids_high_score_tables[choice];
+	if (check_score_place(hs_table, Opts_LastScore()) < HIGH_SCORES_SAVED){
+
+	  char player_name[HIGH_SCORE_NAME_LENGTH * 3];
+
+	  /* Get name from player: */
+	  HighScoreNameEntry(&player_name[0]);
+	  insert_score(player_name, hs_table, Opts_LastScore());
+	  /* Show the high scores. Note the user will see his/her */
+	  /* achievement even if (in the meantime) another player */
+	  /* has in fact already bumped this score off the table. */
+	  DisplayHighScores(hs_table);
+	  /* save to disk: */
+	  /* See "On File Locking" in fileops.c */
+	  append_high_score(hs_table,Opts_LastScore(),&player_name[0]);
+
+#ifdef TUXMATH_DEBUG
+	  print_high_scores(stderr);
+#endif
+	}
+       else {
+	fprintf(stderr, "\nCould not find config file\n");
+      }  
+
+    menu_opts.starting_entry = choice;
+    choice = choose_menu_item(menu_text,sprites,3,NULL,NULL);
+
+
+  }
+
+
+  return 0; 
+}
+
+
+int run_options_menu(void)
+{
+  /*
+    // Use the following version if we get "Settings" implemented
+  const unsigned char* menu_text[5] =
+    {(const unsigned char*)N_("Settings"),
+     (const unsigned char*)N_("Demo"),
+     (const unsigned char*)N_("Credits"),
+     (const unsigned char*)N_("Project Info"),
+     (const unsigned char*)N_("Main Menu")};
+  sprite* sprites[5] =
+    {NULL, NULL, NULL, NULL, NULL};
+  */
+  const char* menu_text[4] =
+    {N_("Demo"),
+     N_("Project Info"),
+     N_("Credits"),
+     N_("Main Menu")};
+
+  sprite* sprites[4] =
+    {NULL, NULL, NULL, NULL};
+  int n_menu_entries = 4;
+  menu_options menu_opts;
+  int choice;
+
+  // Set up the sprites
+  sprites[0] = sprite_list[SPRITE_ARCADE];
+  sprites[1] = sprite_list[SPRITE_HELP];
+  sprites[2] = sprite_list[SPRITE_CREDITS];
+  sprites[3] = 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, n_menu_entries, NULL, NULL);
+
+  while (choice >= 0) {
+    switch (choice) {
+      /*
+    case 0: {
+      // Settings
+      NotImplemented();
+      break;
+      }*/
+    case 0: {
+      // Demo
+      if (read_named_config_file("demo"))
+      {
+        audioMusicUnload();
+        game();
+        RecalcTitlePositions();
+        if (Opts_GetGlobalOpt(MENU_MUSIC)) {
+          audioMusicLoad( "tuxi.ogg", -1 );
+        }
+      } else {
+        fprintf(stderr, "\nCould not find demo config file\n");
+      }
+
+      break;
+    }
+    case 1: {
+      // 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"));
+      break;
+    }
+    case 2: {
+      // Credits
+      //TitleScreen_unload_media();
+      credits();
+      //TitleScreen_load_media();
+      break;
+    }
+    case 3: {
+      // Main menu
+      return 0;
+    }
+    }
+
+    set_default_menu_options(&menu_opts);
+    menu_opts.starting_entry = choice;
+    choice = choose_menu_item(menu_text,sprites,n_menu_entries,NULL,NULL);
+  }
+
+  return 0;
+}
+
+
+void lessons_scmo(menu_options* mo)
+{
+mo->ytop = 30;
+}
+/* Display a list of tuxmath config files in the missions directory   */
+/* and allow the player to pick one (AKA "Lessons").                  */
+
+/* returns 0 if user pressed escape
+ *         1 if config was set correctly
+ */
+int run_lessons_menu(void)
+{
+  int chosen_lesson = -1;
+  menu_options menu_opts;
+  sprite** star_sprites = NULL;
+
+  /* Set up sprites (as long as gold star list is valid) */
+  if (lesson_list_goldstars != NULL)
+  {
+    int i;
+    star_sprites = (sprite**)malloc(num_lessons * sizeof(sprite*));
+    for (i = 0; i < num_lessons; i++)
+    {
+      if (lesson_list_goldstars[i])
+        star_sprites[i] = sprite_list[SPRITE_GOLDSTAR];
+      else
+        star_sprites[i] = sprite_list[SPRITE_NO_GOLDSTAR];
+    }
+  }
+//  set_default_menu_options(&menu_opts);
+//  ytop = 30;
+
+  //This function takes care of all the drawing and receives
+  //user input:
+  chosen_lesson = choose_menu_item((const char**)lesson_list_titles, star_sprites, num_lessons, NULL, &lessons_scmo);
+
+  while (chosen_lesson >= 0)
+  {
+    if (Opts_GetGlobalOpt(MENU_SOUND))
+      playsound(SND_POP);
+
+    /* Re-read global settings first in case any settings were */
+    /* clobbered by other lesson or arcade games this session: */
+    read_global_config_file();
+    /* Now read the selected file and play the "mission": */
+    if (read_named_config_file(lesson_list_filenames[chosen_lesson]))
+    {
+      if (Opts_GetGlobalOpt(MENU_MUSIC))  //Turn menu music off for game
+        {audioMusicUnload();}
+
+      Opts_SetLanMode(0); 
+      game();
+      RecalcTitlePositions();
+
+      /* If successful, display Gold Star for this lesson! */
+      if (MC_MissionAccomplished())
+      {
+        lesson_list_goldstars[chosen_lesson] = 1;
+        star_sprites[chosen_lesson] = sprite_list[SPRITE_GOLDSTAR];
+       /* and save to disk: */
+        write_goldstars();
+      }
+
+      if (Opts_GetGlobalOpt(MENU_MUSIC)) //Turn menu music back on
+        {audioMusicLoad("tuxi.ogg", -1);}
+    }
+    else  // Something went wrong - could not read lesson config file:
+    {
+      fprintf(stderr, "\nCould not find file: %s\n", lesson_list_filenames[chosen_lesson]);
+      chosen_lesson = -1;
+    }
+    // Let the user choose another lesson; start with the screen and
+    // selection that we ended with
+    set_default_menu_options(&menu_opts);
+    menu_opts.starting_entry = chosen_lesson;
+    chosen_lesson = choose_menu_item((const char**)lesson_list_titles, star_sprites, num_lessons, &menu_opts, &lessons_scmo);
+  }
+  if (star_sprites)
+  {
+    free(star_sprites);
+    star_sprites = NULL;
+  }
+
+  if (chosen_lesson < 0)
+    return 0;
+  else
+    return 1;
+}
+
+
+/* Sets the user home directory in a tree of possible users     */
+/* -1 indicates that the user wants to quit without logging in, */
+/* 0 indicates that a choice has been made.                     */
+int run_login_menu(void)
+{
+  int n_login_questions = 0;
+  char **user_login_questions = NULL;
+  int n_users = 0;
+  char **user_names = NULL;
+  menu_options menu_opts;
+  int chosen_login = -1;
+  int level;
+  int i;
+  char *trailer_quit = "Quit";
+  char *trailer_back = "Back";
+  SDLMod mod;
+
+  // Check for & read user_login_questions file
+  n_login_questions = read_user_login_questions(&user_login_questions);
+
+  // Check for & read user_menu_entries file
+  n_users = read_user_menu_entries(&user_names);
+
+  if (n_users == 0)
+    return 0;   // a quick exit, there's only one user
+
+  // Check for a highscores file
+  if (high_scores_found_in_user_dir())
+    set_high_score_path();
+
+  level = 0;
+  set_default_menu_options(&menu_opts);
+  if (n_login_questions > 0)
+    menu_opts.title = user_login_questions[0];
+  menu_opts.trailer = trailer_quit;
+
+  while (n_users) {
+    // Get the user choice
+    chosen_login = choose_menu_item((const char**)user_names, NULL, n_users, &menu_opts, NULL);
+    // Determine whether there were any modifier (CTRL) keys pressed
+    mod = SDL_GetModState();
+    if (chosen_login == -1 || chosen_login == n_users) {
+      // 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;
+      }
+      else {
+        // Go back up one level of the directory tree
+        user_data_dirname_up();
+        level--;
+        menu_opts.starting_entry = -1;
+      }
+    }
+    else {
+      // User chose an entry, set it up
+      user_data_dirname_down(user_names[chosen_login]);
+      level++;
+      menu_opts.starting_entry = 0;
+    }
+    // Check for a highscores file
+    if (high_scores_found_in_user_dir())
+      set_high_score_path();
+    // Free the entries from the previous menu
+    for (i = 0; i < n_users; i++)
+      free(user_names[i]);
+    free(user_names);
+    user_names = NULL;
+    // If the CTRL key was pressed, choose this as the identity, even
+    // if there is a lower level to the hierarchy
+    if (mod & KMOD_CTRL)
+      break;
+    // Set the title appropriately for the next menu
+    if (level < n_login_questions)
+      menu_opts.title = user_login_questions[level];
+    else
+      menu_opts.title = NULL;
+    if (level == 0)
+      menu_opts.trailer = trailer_quit;
+    else
+      menu_opts.trailer = trailer_back;
+    // Check to see if there are more choices to be made
+    n_users = read_user_menu_entries(&user_names);
+  }
+
+  // The user home directory is set, clean up remaining memory
+  for (i = 0; i < n_login_questions; i++)
+    free(user_login_questions[i]);
+  free(user_login_questions);
+
+  // Signal success
+  return 0;
+}
+
+
+/****************************************************************/
+/* choose_menu_item: menu navigation utility function           */
+/* (the function returns the index for the selected menu item)  */
+/* -1 indicates that the user pressed escape                    */
+/****************************************************************/
+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;
+  SDL_Surface **menu_item_selected = NULL;
+  // Display region for menu choices
+  SDL_Rect *menu_text_rect = NULL;
+  // Translucent mouse "buttons" around menu text
+  SDL_Rect *menu_button_rect = NULL;
+  // Menu sprite locations
+  SDL_Rect *menu_sprite_rect = NULL;
+
+  // The section of the background that the menu rects actually cover
+  SDL_Rect *back_text_rect = NULL,
+           *back_button_rect = NULL,
+           *back_sprite_rect = NULL;
+  SDL_Rect left_arrow_rect, right_arrow_rect;
+  SDL_Rect temp_rect; //temporary copy of a dest rect that may be written to by SDL_BlitSurface
+
+  menu_options menu_opts;
+
+  Uint32 frame_counter = 0;
+  Uint32 frame_start = 0;       //For keeping frame rate constant
+  Uint32 frame_now = 0;
+  int stop = 0;
+  int loc = 0;                  //The currently selected menu item
+  int old_loc = 1;
+  int loc_screen_start = 0;     //The number of the top entry on current screen
+  int old_loc_screen_start = 0;
+  int redraw = 0;
+  int n_entries_per_screen = 0;
+  int buttonheight = 0;
+  int i = 0;
+  int imod = 0;                 // i % n_entries_per_screen
+  int tux_frame = 0;
+  int click_flag = 1;
+  int use_sprite = 0;
+  int warp_mouse = 0;
+  int title_offset = 0;
+  int have_trailer = 0;
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr, "Entering choose_menu_item():\n");
+#endif
+
+#ifdef TUXMATH_DEBUG
+  fprintf(stderr,"%d menu entries:\n",n_menu_entries);
+  for (i = 0; i < n_menu_entries; i++)
+    fprintf(stderr,"%s\n",menu_text[i]);
+#endif
+
+  if (custom_mo == NULL)
+    set_default_menu_options(&menu_opts);
+  else
+    menu_opts = *custom_mo;
+  if (set_custom_menu_opts != NULL)
+    set_custom_menu_opts(&menu_opts);
+
+  tmdprintf("Allocating memory\n");
+  /**** Memory allocation for menu text  ****/
+  title_offset = 0;
+  if (menu_opts.title != NULL)
+    title_offset = 1;
+  if (menu_opts.trailer != NULL)
+    have_trailer = 1;
+  menu_item_unselected = (SDL_Surface**)malloc((n_menu_entries+title_offset+have_trailer) * sizeof(SDL_Surface*));
+  menu_item_selected = (SDL_Surface**)malloc((n_menu_entries+title_offset+have_trailer) * sizeof(SDL_Surface*));
+  if (menu_item_unselected == NULL || menu_item_selected == NULL) {
+    free(menu_item_unselected);
+    free(menu_item_selected);
+    return -2;  // error
+  }
+
+  /**** Render the menu choices                               ****/
+  if (title_offset)
+  {
+    menu_item_unselected[0] = BlackOutline( _(menu_opts.title), DEFAULT_MENU_FONT_SIZE, &red);
+    // It will never be selected, so we don't have to do anything for selected.
+    menu_item_selected[0] = NULL;
+  }
+  for (i = 0; i < n_menu_entries; i++)
+  {
+    menu_item_unselected[i+title_offset] = BlackOutline( _(menu_text[i]), DEFAULT_MENU_FONT_SIZE, &white );
+    menu_item_selected[i+title_offset] = BlackOutline( _(menu_text[i]), DEFAULT_MENU_FONT_SIZE, &yellow);
+  }
+  if (have_trailer) {
+    menu_item_unselected[n_menu_entries+title_offset] = BlackOutline( _(menu_opts.trailer), DEFAULT_MENU_FONT_SIZE, &white );
+    menu_item_selected[n_menu_entries+title_offset] = BlackOutline( _(menu_opts.trailer), DEFAULT_MENU_FONT_SIZE, &yellow);
+  }
+  // We won't need the menu_text again, so now we can keep track of
+  // the total entries including the title & trailer
+  n_menu_entries += title_offset+have_trailer;
+
+//  recalcMenuPositions();
+
+  /**** Calculate the menu item heights and the number of     ****/
+  /**** entries per screen                                    ****/
+  if (menu_opts.buttonheight <= 0) {
+    buttonheight = 0;
+    for (i = 0; i < n_menu_entries; i++)
+      if (buttonheight < menu_item_unselected[i]->h)
+        buttonheight = menu_item_unselected[i]->h;
+    buttonheight += 10;
+  } else
+    buttonheight = menu_opts.buttonheight;
+
+  // First try using the whole screen; if we need more than one
+  // screen, then we have to save space for the arrows by respecting
+  // ybottom
+  n_entries_per_screen = (int) (screen->h - menu_opts.ytop+menu_opts.ygap)/(buttonheight + menu_opts.ygap);
+  if (n_entries_per_screen < n_menu_entries)
+    n_entries_per_screen = (int) (menu_opts.ybottom - menu_opts.ytop+menu_opts.ygap)/(buttonheight + menu_opts.ygap);
+
+  if (n_entries_per_screen > n_menu_entries)
+    n_entries_per_screen = n_menu_entries;
+
+  /**** Memory allocation for current screen rects  ****/
+  menu_text_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
+  menu_button_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
+  back_text_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
+  back_button_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
+  if (menu_text_rect == NULL || menu_button_rect == NULL ||
+      back_text_rect == NULL || back_button_rect == NULL) {
+    free(menu_text_rect);
+    free(menu_button_rect);
+    free(back_text_rect);
+    free(back_button_rect);
+    return -2;
+  }
+  if (menu_sprites != NULL) {
+    menu_sprite_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
+    back_sprite_rect = (SDL_Rect*) malloc(n_entries_per_screen * sizeof(SDL_Rect));
+    if (menu_sprite_rect == NULL || back_sprite_rect == NULL) {
+      free(menu_sprite_rect);
+      free(back_sprite_rect);
+      return -2;
+    }
+  }
+
+  /**** Define the locations of graphical elements on the screen ****/
+  /* Arrow buttons in right lower corner, inset by 20 pixels     */
+  /* with a 10 pixel space between:                              */
+  if (images[IMG_RIGHT])
+  {
+    right_arrow_rect.w = images[IMG_RIGHT]->w;
+    right_arrow_rect.h = images[IMG_RIGHT]->h;
+    right_arrow_rect.x = screen->w - images[IMG_RIGHT]->w - 20;
+    right_arrow_rect.y = screen->h - images[IMG_RIGHT]->h - 20;
+  }
+
+  if (images[IMG_LEFT])
+  {
+    left_arrow_rect.w = images[IMG_LEFT]->w;
+    left_arrow_rect.h = images[IMG_LEFT]->h;
+    left_arrow_rect.x = right_arrow_rect.x - 10 - images[IMG_LEFT]->w;
+    left_arrow_rect.y = screen->h - images[IMG_LEFT]->h - 20;
+  }
+  /* Red "Stop" circle in upper right corner to go back to main menu: */
+  if (images[IMG_STOP])
+  {
+    stopRect.w = images[IMG_STOP]->w;
+    stopRect.h = images[IMG_STOP]->h;
+    stopRect.x = screen->w - images[IMG_STOP]->w;
+    stopRect.y = 0;
+  }
+
+  /* Set initial menu rect sizes. The widths will change depending      */
+  /* on the size of the text displayed in each rect.  Set the widths    */
+  /* for the current screen of menu items.                              */
+  loc = menu_opts.starting_entry + title_offset;  // Initially selected item
+  loc_screen_start = loc - (loc % n_entries_per_screen);
+  if (loc_screen_start < 0 || loc_screen_start*n_entries_per_screen > n_menu_entries)
+    loc_screen_start = 0;  // in case starting_entry was -1 (or wasn't set)
+  imod = loc-loc_screen_start;
+  for (i = 0; i < n_entries_per_screen; i++)
+  {
+    menu_button_rect[i].x = menu_opts.xleft;
+    menu_text_rect[i].x = menu_opts.xleft + 15;  // 15 is left gap
+    if (menu_sprites != NULL)
+      menu_text_rect[i].x += 60;  // 40 is sprite width, 20 is gap
+    if (i > 0)
+      menu_text_rect[i].y = menu_text_rect[i - 1].y + buttonheight + menu_opts.ygap;
+    else
+      menu_text_rect[i].y = menu_opts.ytop;
+    menu_button_rect[i].y = menu_text_rect[i].y-5;
+    menu_text_rect[i].h = buttonheight-10;
+    menu_button_rect[i].h = buttonheight;
+    menu_button_rect[i].w = menu_text_rect[i].w = 0;
+    if (i + loc_screen_start < n_menu_entries) {
+      menu_text_rect[i].w = menu_item_unselected[i+loc_screen_start]->w;
+      menu_button_rect[i].w = menu_text_rect[i].w + 30;
+    }
+    if (menu_sprite_rect != NULL) {
+      menu_sprite_rect[i].x = menu_button_rect[i].x+3;
+      menu_sprite_rect[i].y = menu_button_rect[i].y+3;
+      menu_sprite_rect[i].w = 40;
+      menu_sprite_rect[i].h = 50;
+    }
+  }
+
+  if (menu_opts.button_same_width)
+    set_buttons_max_width(menu_button_rect,back_button_rect,n_entries_per_screen);
+
+  for (i = 0; i < n_entries_per_screen; ++i)
+  {
+    if (menu_button_rect)
+    {
+      back_button_rect[i] = menu_button_rect[i];
+      back_button_rect[i].x -= Backrect.x;
+      back_button_rect[i].y -= Backrect.y;
+    }
+    if (menu_text_rect)
+    {
+      back_text_rect[i] = menu_text_rect[i];
+      back_text_rect[i].x -= Backrect.x;
+      back_text_rect[i].y -= Backrect.y;
+    }
+    if (menu_sprite_rect)
+    {
+      back_sprite_rect[i] = menu_sprite_rect[i];
+      back_sprite_rect[i].x -= Backrect.x;
+      back_sprite_rect[i].y -= Backrect.y;
+    }
+  }
+
+  /**** Draw background, title, and Tux:                            ****/
+  if (current_bkg() )
+    SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect);
+  if (images[IMG_MENU_TITLE])
+    SDL_BlitSurface(images[IMG_MENU_TITLE], NULL, screen, &Titledest);
+  if (Tux && Tux->frame[0])
+    SDL_BlitSurface(Tux->frame[0], NULL, screen, &Tuxdest);
+  SDL_UpdateRect(screen, 0, 0, 0 ,0);
+
+  /* Move mouse to current button: */
+  cursor.x = menu_button_rect[imod].x + menu_button_rect[imod].w/2;
+  cursor.y = menu_button_rect[imod].y + menu_button_rect[imod].h/2;
+//  SDL_WarpMouse(cursor.x, cursor.y);
+  SDL_WM_GrabInput(SDL_GRAB_OFF);
+
+
+  /******** Main loop:                                *********/
+  redraw = 1;  // force a full redraw on first pass
+  old_loc_screen_start = loc_screen_start;
+  while (SDL_PollEvent(&event));  // clear pending events
+  while (!stop)
+  {
+    frame_start = SDL_GetTicks();         /* For keeping frame rate constant.*/
+
+    while (SDL_PollEvent(&event))
+    {
+      switch (event.type)
+      {
+        case SDL_QUIT:
+        {
+          cleanup();
+          //exit(0);
+          break;
+        }
+
+        case SDL_MOUSEMOTION:
+        {
+          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))
+            {
+              // Play sound if loc is being changed:
+              if (Opts_GetGlobalOpt(MENU_SOUND) && (old_loc != loc_screen_start + i))
+              {
+                playsound(SND_TOCK);
+              }
+              loc = loc_screen_start + i;
+              break;   /* from for loop */
+            }
+          }
+
+          /* "Left" button - make click if button active: */
+          if (inRect(left_arrow_rect, event.motion.x, event.motion.y))
+          {
+            if (loc_screen_start - n_entries_per_screen >= 0)
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND) && click_flag)
+              {
+                playsound(SND_TOCK);
+                click_flag = 0;
+              }
+            }
+            break;  /* from case switch */
+          }
+
+          /* "Right" button - go to next page: */
+          else if (inRect(right_arrow_rect, event.motion.x, event.motion.y ))
+          {
+            if (loc_screen_start + n_entries_per_screen < n_menu_entries)
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND) && click_flag)
+              {
+                playsound(SND_TOCK);
+                click_flag = 0;
+              }
+            }
+            break;  /* from case switch */
+          }
+
+          else  // Mouse outside of arrow rects - re-enable click sound:
+          {
+            click_flag = 1;
+            break;  /* from case switch */
+          }
+        }
+
+        case SDL_MOUSEBUTTONDOWN:
+        {
+          /* Choose a menu entry by mouse click */
+          for (i = 0; (i < n_entries_per_screen) && (loc_screen_start + i < n_menu_entries); i++)
+          {
+            if (inRect(menu_button_rect[i], event.button.x, event.button.y))
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+              {
+                playsound(SND_POP);
+              }
+
+              loc = loc_screen_start + i;
+              stop = 1;
+              break;
+            }
+          }
+
+          /* "Left" button - go to previous page: */
+          if (inRect(left_arrow_rect, event.button.x, event.button.y))
+          {
+            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
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+              {
+                playsound(SND_TOCK);
+              }
+              break;
+            }
+          }
+
+          /* "Right" button - go to next page: */
+          if (inRect( right_arrow_rect, event.button.x, event.button.y ))
+          {
+            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
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+              {
+                playsound(SND_TOCK);
+              }
+              break;
+            }
+          }
+
+          /* "Stop" button - go to main menu: */
+          if (inRect(stopRect, event.button.x, event.button.y ))
+          {
+            stop = 2;
+            playsound(SND_TOCK);
+            break;
+          }
+        } /* End of case SDL_MOUSEDOWN */
+
+
+        case SDL_KEYDOWN:
+        {
+          /* Proceed according to particular key pressed: */
+          switch (event.key.keysym.sym)
+          {
+            case SDLK_ESCAPE:
+            {
+              stop = 2;
+              break;
+            }
+
+            case SDLK_RETURN:
+            case SDLK_SPACE:
+            case SDLK_KP_ENTER:
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                playsound(SND_POP);
+              stop = 1;
+              break;
+            }
+
+
+            /* Go to previous page, if present: */
+            case SDLK_LEFT:
+            case SDLK_PAGEUP:
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                playsound(SND_TOCK);
+              if (loc_screen_start - n_entries_per_screen >= 0) {
+                loc_screen_start -= n_entries_per_screen;
+                loc = -1;
+              }
+              //  {loc = loc_screen_start - n_entries_per_screen;}
+              break;
+            }
+
+
+            /* Go to next page, if present: */
+            case SDLK_RIGHT:
+            case SDLK_PAGEDOWN:
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                playsound(SND_TOCK);
+              if (loc_screen_start + n_entries_per_screen < n_menu_entries) {
+                loc_screen_start += n_entries_per_screen;
+                loc = -1;
+              }
+              //  {loc = (loc_screen_start + n_entries_per_screen);}
+              break;
+            }
+
+            /* Go up one entry, if present: */
+            case SDLK_UP:
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                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;
+              break;
+            }
+
+
+            /* Go down one entry, if present: */
+            case SDLK_DOWN:
+            {
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                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;
+              break;
+           }
+
+
+            /* Toggle screen mode: */
+            case SDLK_F10:
+            {
+              SwitchScreenMode();
+              RecalcTitlePositions();
+              RecalcMenuPositions(&n_entries_per_screen,
+                                  n_menu_entries,
+                                  &menu_opts,
+                                  set_custom_menu_opts,
+                                  &menu_button_rect,
+                                  &menu_sprite_rect,
+                                  &menu_text_rect,
+                                  &back_button_rect,
+                                  &back_sprite_rect,
+                                  &back_text_rect,
+                                  &left_arrow_rect,
+                                  &right_arrow_rect);
+              //we're unsure how the entries might shuffle, so return to start
+              loc_screen_start = 0;
+              redraw = 1;
+              break;
+            }
+
+            /* Toggle menu music: */
+            case SDLK_F11:
+            {
+              if (Opts_GetGlobalOpt(MENU_MUSIC))
+              {
+                audioMusicUnload( );
+                Opts_SetGlobalOpt(MENU_MUSIC, 0);
+              }
+              else
+              {
+                Opts_SetGlobalOpt(MENU_MUSIC, 1);
+                audioMusicLoad("tuxi.ogg", -1);
+              }
+              break;
+            }
+#ifdef TESTING_CAMPAIGN
+            case SDLK_c:
+            {
+              start_campaign();
+              RecalcTitlePositions();
+              RecalcMenuPositions(&n_entries_per_screen,
+                                  n_menu_entries,
+                                  &menu_opts,
+                                  set_custom_menu_opts,
+                                  &menu_button_rect,
+                                  &menu_sprite_rect,
+                                  &menu_text_rect,
+                                  &back_button_rect,
+                                  &back_sprite_rect,
+                                  &back_text_rect,
+                                  &left_arrow_rect,
+                                  &right_arrow_rect);
+              redraw = 1;
+            }
+
+#endif
+            default:
+            {
+              /* Some other key - do nothing. */
+            }
+
+            break;  /* To get out of _outer_ switch/case statement */
+          }  /* End of key switch statement */
+        }  // End of case SDL_KEYDOWN in outer switch statement
+      }  // End event switch statement
+      if (handle_easter_egg(&event) )
+        redraw = 1;
+      else
+        ; //egg_active = 0;
+    }  // End SDL_PollEvent while loop
+
+
+
+    // Make sure the menu title is not selected
+    if (loc == 0 && title_offset)
+      loc = title_offset;
+
+    /* Redraw screen: */
+    if (loc >= 0)
+      loc_screen_start = loc - (loc % n_entries_per_screen);
+    if (old_loc_screen_start != loc_screen_start)
+      redraw = 1;
+    if (redraw)
+    {
+      tmdprintf("Updating entire screen\n");
+      /* This is a full-screen redraw */
+      /* Redraw background, title, stop button, and Tux: */
+      if (!current_bkg() || screen->flags & SDL_FULLSCREEN )
+        SDL_FillRect(screen, &screen->clip_rect, 0); //clear to black
+      if (current_bkg())
+        SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect);
+      if (images[IMG_MENU_TITLE])
+        SDL_BlitSurface(images[IMG_MENU_TITLE], NULL, screen, &Titledest);
+      if (images[IMG_STOP])
+        SDL_BlitSurface(images[IMG_STOP], NULL, screen, &stopRect);
+      if (Tux->frame[0])
+        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
+      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;
+        }
+      }
+
+      if (menu_opts.button_same_width)
+        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;
+      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]);
+      }
+
+      /* --- 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: */
+        {
+          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
+        {
+          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);
+    } else if (old_loc != loc) {
+      // 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);
+        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);
+      }
+      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);
+      }
+    } 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]);
+      }
+    }
+
+    redraw = 0;
+
+    /* Move the mouse pointer if there is only a single screen */
+    if (warp_mouse && n_menu_entries <= n_entries_per_screen) {
+      imod = loc - loc_screen_start;
+      cursor.x = menu_button_rect[imod].x + (menu_button_rect[imod].w / 2);
+      cursor.y = menu_button_rect[imod].y + (3 * menu_button_rect[imod].h / 4);
+//      SDL_WarpMouse(cursor.x, cursor.y);
+      warp_mouse = 0;
+    }
+
+    old_loc = loc;
+    old_loc_screen_start = loc_screen_start;
+
+
+
+    /* --- make Tux blink --- */
+    switch (frame_counter % TUX6)
+    {
+      case 0:    tux_frame = 1; break;
+      case TUX1: tux_frame = 2; break;
+      case TUX2: tux_frame = 3; break;
+      case TUX3: tux_frame = 4; break;
+      case TUX4: tux_frame = 3; break;
+      case TUX5: tux_frame = 2; break;
+      default: tux_frame = 0;
+    }
+
+    if (Tux && tux_frame)
+    {
+      /* Redraw background to keep edges anti-aliased properly: */
+      SDL_BlitSurface(current_bkg(),&Tuxdest, screen, &Tuxdest);
+      SDL_BlitSurface(Tux->frame[tux_frame - 1], NULL, screen, &Tuxdest);
+      SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
+      //SDL_UpdateRect(screen, 0, 0, 0, 0);
+    }
+
+    if (egg_active) { //if we need to, draw the egg cursor
+      //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);
+    }
+
+    /* Wait so we keep frame rate constant: */
+    frame_now = SDL_GetTicks();
+    if (frame_now < frame_start)
+      frame_start = frame_now;  // in case the timer wraps around
+    if (frame_now - frame_start < 33)
+      SDL_Delay(33-(frame_now-frame_start));
+
+    frame_counter++;
+  }  // End !stop while loop
+
+
+  /***** User made a choice, clean up and return the choice.   ******/
+
+  /* --- clear graphics before leaving function --- */
+  for (i = 0; i < n_menu_entries; i++)
+  {
+    SDL_FreeSurface(menu_item_unselected[i]);
+    SDL_FreeSurface(menu_item_selected[i]);
+  }
+  free(menu_item_unselected);
+  free(menu_item_selected);
+  free(menu_text_rect);
+  free(menu_button_rect);
+  free(back_text_rect);
+  free(back_button_rect);
+  free(menu_sprite_rect);
+  free(back_sprite_rect);
+
+  /* Return the value of the chosen item (-1 indicates escape) */
+  if (stop == 2)
+    return -1;
+  else
+    return loc - title_offset;
+}
+
+
+
+void set_buttons_max_width(SDL_Rect *menu_button_rect,
+                           SDL_Rect *back_button_rect, int n)
+{
+  int i,max;
+
+  max = 0;
+  for (i = 0; i < n; i++)
+    if (max < menu_button_rect[i].w)
+      max = menu_button_rect[i].w;
+
+  for (i = 0; i < n; i++)
+    menu_button_rect[i].w = back_button_rect[i].w = max;
+
+  tmdprintf("All buttons at width %d\n", max);
+}
+
+// Was in playgame.c in tuxtype:
+
+/*************************************************/
+/* TransWipe: Performs various wipes to new bkgs */
+/*************************************************/
+/*
+ * Given a wipe request type, and any variables
+ * that wipe requires, will perform a wipe from
+ * the current screen image to a new one.
+ */
+void TransWipe(SDL_Surface* newbkg, int type, int var1, int var2)
+{
+    int i, j, x1, x2, y1, y2;
+    int step1, step2, step3, step4;
+    int frame;
+    SDL_Rect src;
+    SDL_Rect dst;
+
+    if (!screen)
+    {
+#ifdef TUXMATH_DEBUG
+      fprintf(stderr, "TransWipe(): screen not valid!\n");
+#endif
+      return;
+    }
+
+    if (!newbkg)
+    {
+#ifdef TUXMATH_DEBUG
+      fprintf(stderr, "TransWipe(): newbkg not valid!\n");
+#endif
+      return;
+    }
+
+    numupdates = 0;
+    frame = 0;
+
+    if(newbkg->w == screen->w && newbkg->h == screen->h) {
+        if( type == RANDOM_WIPE )
+            type = (RANDOM_WIPE * ((float) rand()) / (RAND_MAX+1.0));
+
+        switch( type ) {
+            case WIPE_BLINDS_VERT: {
+ #ifdef TUXMATH_DEBUG
+                fprintf(stderr, "--+ Doing 'WIPE_BLINDS_VERT'\n");
+#endif
+                /* var1 is num of divisions
+                   var2 is how many frames animation should take */
+                if( var1 < 1 ) var1 = 1;
+                if( var2 < 1 ) var2 = 1;
+                step1 = screen->w / var1;
+                step2 = step1 / var2;
+
+                for(i = 0; i <= var2; i++)
+                {
+                    for(j = 0; j <= var1; j++)
+                    {
+                        x1 = step1 * (j - 0.5) - i * step2 + 1;
+                        x2 = step1 * (j - 0.5) + i * step2 + 1;
+                        src.x = x1;
+                        src.y = 0;
+                        src.w = step2;
+                        src.h = screen->h;
+                        dst.x = x2;
+                        dst.y = 0;
+                        dst.w = step2;
+                        dst.h = screen->h;
+
+                        SDL_BlitSurface(newbkg, &src, screen, &src);
+                        SDL_BlitSurface(newbkg, &dst, screen, &dst);
+
+                        AddRect(&src, &src);
+                        AddRect(&dst, &dst);
+                    }
+                    UpdateScreen(&frame);
+                }
+
+                src.x = 0;
+                src.y = 0;
+                src.w = screen->w;
+                src.h = screen->h;
+                SDL_BlitSurface(newbkg, NULL, screen, &src);
+                SDL_Flip(screen);
+
+                break;
+            } case WIPE_BLINDS_HORIZ: {
+#ifdef TUXMATH_DEBUG
+                fprintf(stderr, "--+ Doing 'WIPE_BLINDS_HORIZ'\n");
+#endif
+                /* var1 is num of divisions
+                   var2 is how many frames animation should take */
+                if( var1 < 1 ) var1 = 1;
+                if( var2 < 1 ) var2 = 1;
+                step1 = screen->h / var1;
+                step2 = step1 / var2;
+
+                for(i = 0; i <= var2; i++) {
+                    for(j = 0; j <= var1; j++) {
+                        y1 = step1 * (j - 0.5) - i * step2 + 1;
+                        y2 = step1 * (j - 0.5) + i * step2 + 1;
+                        src.x = 0;
+                        src.y = y1;
+                        src.w = screen->w;
+                        src.h = step2;
+                        dst.x = 0;
+                        dst.y = y2;
+                        dst.w = screen->w;
+                        dst.h = step2;
+
+                        SDL_BlitSurface(newbkg, &src, screen, &src);
+                        SDL_BlitSurface(newbkg, &dst, screen, &dst);
+
+                        AddRect(&src, &src);
+                        AddRect(&dst, &dst);
+                    }
+                    UpdateScreen(&frame);
+                }
+
+                src.x = 0;
+                src.y = 0;
+                src.w = screen->w;
+                src.h = screen->h;
+                SDL_BlitSurface(newbkg, NULL, screen, &src);
+                SDL_Flip(screen);
+
+                break;
+            } case WIPE_BLINDS_BOX: {
+#ifdef TUXMATH_DEBUG
+                fprintf(stderr, "--+ Doing 'WIPE_BLINDS_BOX'\n");
+#endif
+                /* var1 is num of divisions
+                   var2 is how many frames animation should take */
+                if( var1 < 1 ) var1 = 1;
+                if( var2 < 1 ) var2 = 1;
+                step1 = screen->w / var1;
+                step2 = step1 / var2;
+                step3 = screen->h / var1;
+                step4 = step1 / var2;
+
+                for(i = 0; i <= var2; i++) {
+                    for(j = 0; j <= var1; j++) {
+                        x1 = step1 * (j - 0.5) - i * step2 + 1;
+                        x2 = step1 * (j - 0.5) + i * step2 + 1;
+                        src.x = x1;
+                        src.y = 0;
+                        src.w = step2;
+                        src.h = screen->h;
+                        dst.x = x2;
+                        dst.y = 0;
+                        dst.w = step2;
+                        dst.h = screen->h;
+
+                        SDL_BlitSurface(newbkg, &src, screen, &src);
+                        SDL_BlitSurface(newbkg, &dst, screen, &dst);
+
+                        AddRect(&src, &src);
+                        AddRect(&dst, &dst);
+                        y1 = step3 * (j - 0.5) - i * step4 + 1;
+                        y2 = step3 * (j - 0.5) + i * step4 + 1;
+                        src.x = 0;
+                        src.y = y1;
+                        src.w = screen->w;
+                        src.h = step4;
+                        dst.x = 0;
+                        dst.y = y2;
+                        dst.w = screen->w;
+                        dst.h = step4;
+                        SDL_BlitSurface(newbkg, &src, screen, &src);
+                        SDL_BlitSurface(newbkg, &dst, screen, &dst);
+                        AddRect(&src, &src);
+                        AddRect(&dst, &dst);
+                    }
+                    UpdateScreen(&frame);
+                }
+
+                src.x = 0;
+                src.y = 0;
+                src.w = screen->w;
+                src.h = screen->h;
+                SDL_BlitSurface(newbkg, NULL, screen, &src);
+                SDL_Flip(screen);
+
+                break;
+            } default:
+                break;
+        }
+    }
+#ifdef TUXMATH_DEBUG
+      fprintf(stderr, "->TransWipe(): FINISH\n");
+#endif
+}
+
+
+
+/************************
+UpdateScreen : Update the screen and increment the frame num
+***************************/
+void UpdateScreen(int *frame) {
+  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();
+
+  /* -- 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);
+
+  numupdates = 0;
+  *frame = *frame + 1;
+}
+
+
+/******************************
+AddRect: Don't actually blit a surface,
+    but add a rect to be updated next
+    update
+*******************************/
+void AddRect(SDL_Rect* src, SDL_Rect* dst) {
+    /*borrowed from SL's alien (and modified)*/
+
+    struct blit    *update;
+
+    if (!src || !dst)
+    {
+#ifdef TUXMATH_DEBUG
+     fprintf(stderr, "AddRect(): src or dst invalid!\n");
+#endif
+      return;
+    }
+
+    update = &blits[numupdates++];
+
+    update->srcrect->x = src->x;
+    update->srcrect->y = src->y;
+    update->srcrect->w = src->w;
+    update->srcrect->h = src->h;
+    update->dstrect->x = dst->x;
+    update->dstrect->y = dst->y;
+    update->dstrect->w = dst->w;
+    update->dstrect->h = dst->h;
+    update->type = 'I';
+}
+
+/***********************
+ InitEngine
+ ***********************/
+void InitEngine(void) {
+    int i;
+
+    /* --- Set up the update rectangle pointers --- */
+
+    for (i = 0; i < MAX_UPDATES; ++i) {
+        blits[i].srcrect = &srcupdate[i];
+        blits[i].dstrect = &dstupdate[i];
+    }
+}
+
+
+void set_default_menu_options(menu_options *menu_opts)
+{
+  menu_opts->starting_entry = 0;
+  menu_opts->xleft = screen->w / 2 - screen->w * 3 / 32;
+  menu_opts->ytop = screen->h / 2 - 140;
+  // Leave room for arrows at the bottom:
+  menu_opts->ybottom = screen->h - images[IMG_LEFT]->h - 20;
+  menu_opts->buttonheight = -1;
+  menu_opts->ygap = 10;
+  menu_opts->button_same_width = 1;
+  menu_opts->title = NULL;
+  menu_opts->trailer = NULL;
+}
+
+/* Recalculate on-screen locations for title screen elements */
+void RecalcTitlePositions()
+{
+  Backrect = current_bkg()->clip_rect;
+  Backrect.x = (screen->w - Backrect.w) / 2;
+  Backrect.y = (screen->h - Backrect.h) / 2;
+
+  Titledest.x = 0;
+  Titledest.y = 0;
+
+  Tuxdest.x = 0;
+  Tuxdest.y = screen->h - Tuxdest.h;
+
+  beak.x = Tuxdest.x + 70;
+  beak.y = Tuxdest.y + 60;
+  beak.w = beak.h = 50;
+
+  stopRect.x = screen->w - stopRect.w;
+  stopRect.y = 0;
+}
+
+/* Recalculate on-screen locations for menus when screen dimensions change */
+/* Perhaps consider generalizing this for use in initial menu calculations? */
+void RecalcMenuPositions(int* numentries,
+                         int totalentries,
+                         menu_options* mo,
+                         void (*set_custom_menu_opts)(menu_options*),
+                         SDL_Rect** menu_button_rect,
+                         SDL_Rect** menu_sprite_rect,
+                         SDL_Rect** menu_text_rect,
+                         SDL_Rect** back_button_rect,
+                         SDL_Rect** back_sprite_rect,
+                         SDL_Rect** back_text_rect,
+                         SDL_Rect* left_arrow_rect,
+                         SDL_Rect* right_arrow_rect)
+{
+  int i;
+  SDL_Rect* old_mbr = *menu_button_rect;
+  SDL_Rect* old_msr = *menu_sprite_rect;
+  SDL_Rect* old_mtr = *menu_text_rect;
+  SDL_Rect* old_bbr = *back_button_rect;
+  SDL_Rect* old_bsr = *back_sprite_rect;
+  SDL_Rect* old_btr = *back_text_rect;
+
+  int old_ne = *numentries;
+  int buttonheight = old_mbr->h; //height shouldn't change
+  int textwidth = old_mtr->w; //neither should width =P
+
+  right_arrow_rect->x = screen->w - images[IMG_RIGHT]->w - 20;
+  right_arrow_rect->y = screen->h - images[IMG_RIGHT]->h - 20;
+  left_arrow_rect->x = right_arrow_rect->x - 10 - images[IMG_LEFT]->w;
+  left_arrow_rect->y = screen->h - images[IMG_LEFT]->h - 20;
+
+  set_default_menu_options(mo);
+  if (set_custom_menu_opts != NULL)
+    set_custom_menu_opts(mo);
+
+  *numentries     = (int)(screen->h - mo->ytop+mo->ygap)/(buttonheight + mo->ygap);
+  if (*numentries < totalentries)
+    *numentries = (int)(mo->ybottom - mo->ytop+mo->ygap)/(buttonheight + mo->ygap);
+  if (*numentries > totalentries)
+    *numentries = totalentries;
+
+
+
+
+  /**** Memory allocation for new screen rects  ****/
+  *menu_text_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *menu_button_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *menu_sprite_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *back_text_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *back_button_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  *back_sprite_rect = (SDL_Rect*) malloc(*numentries * sizeof(SDL_Rect));
+  if (*menu_text_rect == NULL ||
+      *back_text_rect == NULL ||
+      *menu_button_rect == NULL ||
+      *back_button_rect == NULL ||
+      *menu_sprite_rect == NULL ||
+      *back_sprite_rect == NULL) {
+    free(*menu_text_rect);
+    free(*menu_button_rect);
+    free(*menu_sprite_rect);
+    free(*back_text_rect);
+    free(*back_button_rect);
+    free(*back_sprite_rect);
+    *menu_text_rect = old_mtr;
+    *menu_button_rect = old_mbr;
+    *menu_sprite_rect = old_msr;
+    *numentries = old_ne;
+    return;
+  }
+  else {
+    free(old_mtr);
+    free(old_mbr);
+    free(old_msr);
+    free(old_btr);
+    free(old_bbr);
+    free(old_bsr);
+  }
+
+
+  //note: the [0] notation is merely to avoid typing out (*menu_xxx_rect)[i]
+  for (i = 0; i < *numentries; i++)
+  {
+    menu_button_rect[0][i].x = mo->xleft;
+    menu_text_rect[0][i].x = mo->xleft + 15;  // 15 is left gap
+    menu_text_rect[0][i].x += 60;  // for now, assume we have a sprite
+    if (i > 0)
+      menu_text_rect[0][i].y = menu_text_rect[0][i - 1].y + buttonheight + mo->ygap;
+    else
+      menu_text_rect[0][i].y = mo->ytop;
+
+    menu_button_rect[0][i].y = menu_text_rect[0][i].y - 5;
+    menu_text_rect[0][i].h = buttonheight - 10;
+    menu_button_rect[0][i].h = buttonheight;
+
+    menu_text_rect[0][i].w = textwidth;
+    menu_button_rect[0][i].w = menu_text_rect[0][i].w + 30;
+
+    if (menu_sprite_rect != NULL) {
+      menu_sprite_rect[0][i].x = menu_button_rect[0][i].x + 3;
+      menu_sprite_rect[0][i].y = menu_button_rect[0][i].y + 3;
+      menu_sprite_rect[0][i].w = 40;
+      menu_sprite_rect[0][i].h = 50;
+    }
+    tmdprintf("***Rects[%d]****\n", i);
+    tmdprintf("%3d %3d %3d %3d\n", menu_button_rect[0][i].x, menu_button_rect[0][i].y, menu_button_rect[0][i].w, menu_button_rect[0][i].h);
+    tmdprintf("%3d %3d %3d %3d\n", menu_text_rect[0][i].x, menu_text_rect[0][i].y, menu_text_rect[0][i].w, menu_text_rect[0][i].h);
+    tmdprintf("%3d %3d %3d %3d\n", menu_sprite_rect[0][i].x, menu_sprite_rect[0][i].y, menu_sprite_rect[0][i].w, menu_sprite_rect[0][i].h);
+    tmdprintf("***************\n");
+  }
+  for (i = 0; i < *numentries; ++i)
+  {
+    back_button_rect[0][i] = menu_button_rect[0][i];
+    back_button_rect[0][i].x -= Backrect.x;
+    back_button_rect[0][i].y -= Backrect.y;
+
+    back_text_rect[0][i] = menu_text_rect[0][i];
+    back_text_rect[0][i].x -= Backrect.x;
+    back_text_rect[0][i].y -= Backrect.y;
+
+    back_sprite_rect[0][i] = menu_sprite_rect[0][i];
+    back_sprite_rect[0][i].x -= Backrect.x;
+    back_sprite_rect[0][i].y -= Backrect.y;
+  }
+
+}
+
+int handle_easter_egg(const SDL_Event* evt)
+  {
+  static int eggtimer = 0;
+  int tuxframe;
+
+  // Avoid segfaults if needed images not available:
+  if (!Tux || !egg)
+  {
+    fprintf(stderr,
+      "handle_easter_egg() - needed images not avail, bailing out\n");
+    egg_active = 0;
+    return 1;
+  }
+
+  tuxframe = Tux->num_frames;
+
+
+  if (egg_active) //are we using the egg cursor?
+    {
+
+    if (eggtimer < SDL_GetTicks() ) //time's up
+      {
+      SDL_ShowCursor(SDL_ENABLE);
+      //SDL_FillRect(screen, &cursor, 0);
+      SDL_BlitSurface(current_bkg(), NULL, screen, &Backrect); //cover egg up once more
+      SDL_WarpMouse(cursor.x, cursor.y);
+      SDL_UpdateRect(screen, cursor.x, cursor.y, cursor.w, cursor.h); //egg->x, egg->y, egg->w, egg->h);
+      egg_active = 0;
+      }
+    return 1;
+    }
+  else //if not, see if the user clicked Tux's beak
+    {
+    eggtimer = 0;
+    if (evt->type == SDL_MOUSEBUTTONDOWN &&
+          inRect(beak, evt->button.x, evt->button.y) )
+      {
+      SDL_ShowCursor(SDL_DISABLE);
+
+      //animate
+      while (tuxframe != 0)
+        {
+        SDL_BlitSurface(Tux->frame[--tuxframe], NULL, screen, &Tuxdest);
+        SDL_UpdateRect(screen, Tuxdest.x, Tuxdest.y, Tuxdest.w, Tuxdest.h);
+        SDL_Delay(GOBBLE_ANIM_MS / Tux->num_frames);
+        }
+
+      eggtimer = SDL_GetTicks() + EASTER_EGG_MS;
+      egg_active = 1;
+      SDL_WarpMouse(Tuxdest.x + Tuxdest.w / 2, Tuxdest.y + Tuxdest.h - egg->h);
+
+      }
+
+    return 0;
+    }
+  }
+
+


Property changes on: tuxmath/branches/lan/src/titlescreen.c.old
___________________________________________________________________
Added: svn:mergeinfo
   + 

Modified: tuxmath/branches/lan/src/titlescreen.h
===================================================================
--- tuxmath/branches/lan/src/titlescreen.h	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/titlescreen.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -1,25 +1,26 @@
-/***************************************************************************
- -  file: titlescreen.h
- -  description: header for the tuxtype-derived files in tuxmath
-                            ------------------
+/*
+  titlescreen.h
 
-    David Bruce - 2006.
-    email                : <dbruce at tampabay.rr.com>
-                           <tuxmath-devel at lists.sourceforge.net>
-***************************************************************************/
+  Splash, background and title screen items.
+  (interface)
 
-/***************************************************************************
- *                                                                         *
- *   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.                                   *
- *                                                                         *
- ***************************************************************************/
+  begin                : Thur May 4 2000
+  copyright            : (C) 2000 by Sam Hart
+                       : (C) 2003 by Jesse Andrews
+  email                : tuxtype-dev at tux4kids.net
 
+  Modified for use in tuxmath by David Bruce - 2006-2007.
+  email                : <dbruce at tampabay.rr.com>
+                         <tuxmath-devel at lists.sourceforge.net>
 
+  Also significantly enhanced by Tim Holy - 2007
 
+  Part of "Tux4Kids" Project
+  http://www.tux4kids.com/
 
+  Copyright: See COPYING file that comes with this distribution.
+*/
+
 #ifndef TITLESCREEN_H
 #define TITLESCREEN_H
 
@@ -48,47 +49,27 @@
 #include "tuxmath.h"
 #include "loaders.h"
 
+#define MAX_LESSONS                     100
+#define MAX_NUM_WORDS                   500
+#define MAX_WORD_SIZE                   8
 
-// Options that affect how menus are presented
-typedef struct {
-  int starting_entry;
-  int xleft, ytop, ybottom;   // left, top, and bottom borders
-  int buttonheight; // size of menu item button  (-1 if calculated)
-  int ygap;  // vertical gap between entries
-  int button_same_width; // should all buttons have the same width?
-  char *title;
-  char *trailer;
-} menu_options;
-
-
-#define MAX_LESSONS 100
-#define MAX_NUM_WORDS   500
-#define MAX_WORD_SIZE   8
-
 //MAX_UPDATES needed for TransWipe() and friends:
-#define MAX_UPDATES 180
+#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
 
+/* trans_wipe() animation constants */
+#define ANIM_FRAMES                     30 /* frames to be displayed */
+#define ANIM_FPS                        25 /* max fps */
 
-/* Title sequence constants */
-#define PRE_ANIM_FRAMES                       10
-#define PRE_FRAME_MULT                        3
-#define MENU_SEP                              20
 
-/* paths */
-
-
-
-
-
 extern SDL_Event  event;
 
 
-#define MUSIC_FADE_OUT_MS        80
+#define MUSIC_FADE_OUT_MS               80
 
 enum {
     WIPE_BLINDS_VERT,
@@ -100,18 +81,6 @@
 };
 // End of code from tuxtype's globals.h
 
-
-/* --- SETUP MENU OPTIONS --- */
-
-#define TITLE_MENU_ITEMS                5
-#define TITLE_MENU_DEPTH                4
-
-#define OPTIONS_SUBMENU                 4
-#define GAME_OPTIONS_SUBMENU                       3
-#define ARCADE_SUBMENU                        2
-#define ROOTMENU                        1
-
-
 /* --- timings for tux blinking --- */
 #define TUX1                            115
 #define TUX2                            118
@@ -120,30 +89,27 @@
 #define TUX5                            127
 #define TUX6                            130
 
-#define EASTER_EGG_MS  5000 //length of time to replace cursor
-#define GOBBLE_ANIM_MS 1000 //duration of the gobbling animation
+#define EASTER_EGG_MS                   5000 //length of time to replace cursor
+#define GOBBLE_ANIM_MS                  1000 //duration of the gobbling animation
 
 /********************************/
 /* "Global" Function Prototypes */
 /********************************/
 
 /*In titlescreen.c */
-void TitleScreen(void);
-int ChooseMission(void);  //FIXME really should be in fileops.c
-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 *);
-SDL_Surface* current_bkg(); //appropriate background for current video mode
+void          TitleScreen(void);
+int           RenderTitleScreen(void);
+void          DrawTitleScreen(void);
+int           HandleTitleScreenEvents(const SDL_Event* evt);
+void          HandleTitleScreenAnimations();
+void          ShowMessage(const char* str1, const char* str2, const char* str3, const char* str4);
+SDL_Surface*  current_bkg(); //appropriate background for current video mode
 
 
-
 /* in audio.c  (from tuxtype): */
-void playsound(int snd);
-void audioMusicLoad(char* musicFilename, int repeatQty);
-void audioMusicUnload(void);
-void audioMusicPlay(Mix_Music* musicData, int repeatQty);
+void          playsound(int snd);
+void          audioMusicLoad(char* musicFilename, int repeatQty);
+void          audioMusicUnload(void);
+void          audioMusicPlay(Mix_Music* musicData, int repeatQty);
 
 #endif //TITLESCREEN_H

Modified: tuxmath/branches/lan/src/tuxmath.c
===================================================================
--- tuxmath/branches/lan/src/tuxmath.c	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/tuxmath.c	2009-09-03 22:06:06 UTC (rev 1477)
@@ -46,16 +46,14 @@
   s3 = bind_textdomain_codeset(PACKAGE, "UTF-8");
   s4 = textdomain(PACKAGE);
 
-#ifdef TUXMATH_DEBUG
-  fprintf(stderr, "PACKAGE = %s\n", PACKAGE);
-  fprintf(stderr, "TUXLOCALE = %s\n", TUXLOCALE);
-  fprintf(stderr, "setlocale(LC_ALL, \"\") returned: %s\n", s1);
-  fprintf(stderr, "bindtextdomain(PACKAGE, TUXLOCALE) returned: %s\n", s2);
-  fprintf(stderr, "bind_textdomain_codeset(PACKAGE, \"UTF-8\") returned: %s\n", s3);
-  fprintf(stderr, "textdomain(PACKAGE) returned: %s\n", s4);
-  fprintf(stderr, "gettext(\"Help\"): %s\n\n", gettext("Help"));
-  fprintf(stderr, "After gettext() call\n");
-#endif
+  DEBUGMSG(debug_setup, "PACKAGE = %s\n", PACKAGE);
+  DEBUGMSG(debug_setup, "TUXLOCALE = %s\n", TUXLOCALE);
+  DEBUGMSG(debug_setup, "setlocale(LC_ALL, \"\") returned: %s\n", s1);
+  DEBUGMSG(debug_setup, "bindtextdomain(PACKAGE, TUXLOCALE) returned: %s\n", s2);
+  DEBUGMSG(debug_setup, "bind_textdomain_codeset(PACKAGE, \"UTF-8\") returned: %s\n", s3);
+  DEBUGMSG(debug_setup, "textdomain(PACKAGE) returned: %s\n", s4);
+  DEBUGMSG(debug_setup, "gettext(\"Help\"): %s\n\n", gettext("Help"));
+  DEBUGMSG(debug_setup, "After gettext() call\n");
 
   setup(argc, argv);
   TitleScreen();  /* Run the game! */

Modified: tuxmath/branches/lan/src/tuxmath.h
===================================================================
--- tuxmath/branches/lan/src/tuxmath.h	2009-09-02 10:50:25 UTC (rev 1476)
+++ tuxmath/branches/lan/src/tuxmath.h	2009-09-03 22:06:06 UTC (rev 1477)
@@ -43,8 +43,23 @@
 //#define NOSOUND
 #include "globals.h"
 
+#define MAX_SPRITE_FRAMES   30
 
+typedef struct {
+  SDL_Surface *frame[MAX_SPRITE_FRAMES];
+  SDL_Surface *default_img;
+  int num_frames;
+  int cur;
+} sprite;
+
 /* Global data gets 'externed' here: */
+
+/* declared in setup.c */
+/* windowed mode screen  size */
+extern int win_res_x;
+extern int win_res_y;
+
+/* full screen size */
 extern int fs_res_x;
 extern int fs_res_y;
 
@@ -57,6 +72,7 @@
 
 extern SDL_Surface* screen; /* declared in setup.c; also used in game.c, options.c, fileops.c, credits.c, titlescreen.c */
 extern SDL_Surface* images[];    /* declared in setup.c, used in same files as screen */
+extern sprite* sprites[];
 extern SDL_Surface* flipped_images[];
 #define NUM_BLENDED_IGLOOS 15
 extern SDL_Surface* blended_igloos[];




More information about the Tux4kids-commits mailing list