[Tux4kids-commits] r11 - in tuxmath/trunk: . data/images/comets
data/images/status data/images/tux docs src
dbruce at alioth.debian.org
dbruce at alioth.debian.org
Thu Mar 8 20:59:02 CET 2007
Author: dbruce
Date: 2006-06-12 20:14:08 +0000 (Mon, 12 Jun 2006)
New Revision: 11
Added:
tuxmath/trunk/data/images/comets/mini_comet1.png
tuxmath/trunk/data/images/comets/mini_comet2.png
tuxmath/trunk/data/images/comets/mini_comet3.png
tuxmath/trunk/data/images/status/gameover_won.png
tuxmath/trunk/data/images/status/nums.png
tuxmath/trunk/data/images/tux/console_led.png
tuxmath/trunk/data/images/tux/tux-egypt3.png
tuxmath/trunk/data/images/tux/tux-egypt4.png
Removed:
tuxmath/trunk/data/images/status/nums.png
Modified:
tuxmath/trunk/Makefile
tuxmath/trunk/docs/CHANGES.txt
tuxmath/trunk/docs/README.txt
tuxmath/trunk/src/game.c
tuxmath/trunk/src/images.h
tuxmath/trunk/src/mathcards.c
tuxmath/trunk/src/mathcards.h
tuxmath/trunk/src/setup.c
tuxmath/trunk/src/tuxmath.h
Log:
added question formats, question counter, victory screen
Modified: tuxmath/trunk/Makefile
===================================================================
--- tuxmath/trunk/Makefile 2006-05-16 17:05:20 UTC (rev 10)
+++ tuxmath/trunk/Makefile 2006-06-12 20:14:08 UTC (rev 11)
@@ -5,9 +5,12 @@
# bill at newbreedsoftware.com
# http://www.newbreedsoftware.com/tuxmath/
-# 2001.Aug.26 - 2005.Jan.03
+# Modified by David Bruce
+# dbruce at tampabay.rr.com
+# 2001.Aug.26 - 2006.Jun.12
+
CFLAGS=-Wall -g $(SDL_CFLAGS) -DDATA_PREFIX=\"$(DATA_PREFIX)\" -DDEBUG \
-DVERSION=\"$(VERSION)\" -D$(SOUND)SOUND
@@ -27,7 +30,7 @@
OWNER=$(shell if `groups root | grep root > /dev/null` ; then echo root:root ; else echo root:wheel ; fi)
-VERSION=2005.01.03
+VERSION=2006.06.12
all: tuxmath
Added: tuxmath/trunk/data/images/comets/mini_comet1.png
===================================================================
(Binary files differ)
Property changes on: tuxmath/trunk/data/images/comets/mini_comet1.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: tuxmath/trunk/data/images/comets/mini_comet2.png
===================================================================
(Binary files differ)
Property changes on: tuxmath/trunk/data/images/comets/mini_comet2.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: tuxmath/trunk/data/images/comets/mini_comet3.png
===================================================================
(Binary files differ)
Property changes on: tuxmath/trunk/data/images/comets/mini_comet3.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: tuxmath/trunk/data/images/status/gameover_won.png
===================================================================
(Binary files differ)
Property changes on: tuxmath/trunk/data/images/status/gameover_won.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Deleted: tuxmath/trunk/data/images/status/nums.png
===================================================================
(Binary files differ)
Added: tuxmath/trunk/data/images/status/nums.png
===================================================================
(Binary files differ)
Property changes on: tuxmath/trunk/data/images/status/nums.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: tuxmath/trunk/data/images/tux/console_led.png
===================================================================
(Binary files differ)
Property changes on: tuxmath/trunk/data/images/tux/console_led.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: tuxmath/trunk/data/images/tux/tux-egypt3.png
===================================================================
(Binary files differ)
Property changes on: tuxmath/trunk/data/images/tux/tux-egypt3.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: tuxmath/trunk/data/images/tux/tux-egypt4.png
===================================================================
(Binary files differ)
Property changes on: tuxmath/trunk/data/images/tux/tux-egypt4.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: tuxmath/trunk/docs/CHANGES.txt
===================================================================
--- tuxmath/trunk/docs/CHANGES.txt 2006-05-16 17:05:20 UTC (rev 10)
+++ tuxmath/trunk/docs/CHANGES.txt 2006-06-12 20:14:08 UTC (rev 11)
@@ -1,5 +1,24 @@
CHANGES.txt for "tuxmath"
+2006.Jun.12 (https://svn.tux4kids.net/tuxmath/ - revision 9)
+ Game:
+ * Command-line argument added to allow ending the game with
+ "victory" when all questions in the defined list have been
+ successfully answered.
+ * Counter of remaining questions added to upper center of screen
+ when operating in "defined list" mode.
+ * LED numbers now display in "monitor" added to Tux's console
+ when "defined list" mode selected".
+ * Drawing of math question formulas overhauled, with support
+ for display of negatives (e.g. 2 x -3 = ?). The program supports
+ negative numbers for limits of question ranges, but for now
+ this must be selected at compile time.
+ * Support for questions formatted like ? + 2 = 4 and 2 + ? = 4,
+ in addition to default format (2 + 2 = ?).
+ * Command-line options to select from the three question formats.
+
+ David Bruce <dbruce at tampabay.rr.com>
+
2006.May.16 (https://svn.tux4kids.net/tuxmath/ - revision 8)
Code:
* Major changes to internal workings of program. Everything
Modified: tuxmath/trunk/docs/README.txt
===================================================================
--- tuxmath/trunk/docs/README.txt 2006-05-16 17:05:20 UTC (rev 10)
+++ tuxmath/trunk/docs/README.txt 2006-06-12 20:14:08 UTC (rev 11)
@@ -2,7 +2,7 @@
An educational math tutorial game starring Tux, the Linux Penguin
-----------------------------------------------------------------
-February 21, 2003
+May 18, 2006
Objective
@@ -50,7 +50,21 @@
--------------------
The following command-line options can be sent to the program.
- --fullscreen - Run the game in full screen, instead of in a window,
+ --norepeats - Game consists of working through a list of questions
+ -r generated based on the selected options (or defaults).
+ If a comet strikes a city without being shot down by
+ the player, the question is reinserted into the list
+ in a random location. If the player answers all questions
+ correctly before the cities are destroyed, he/she wins.
+ If all cities get destroyed, the game ends in defeat.
+
+ --answersfirst - to ask questions in format: ? + num2 = num3 instead of
+ default format: num1 + num2 = ?.
+
+ --answersmiddle - to ask questions in format: num1 + ? = num3 instead of
+ default format: num1 + num2 = ?.
+
+ --fullscreen - Run the game in full screen, instead of in a window,
-f if possible.
--nosound - Do not play any sounds or music.
@@ -123,7 +137,7 @@
--------------
On this screen, you can select some of the gameplay options or return to
the Title Screen. Currently, the four math operations can be enabled
- or disenabled, as well as the speed setting and ranges of numbers to use.
+ or disabled, as well as the speed setting and ranges of numbers to use.
Use the [UP] and [DOWN] arrow keys to select what you wish to do,
and then press [ENTER / RETURN /SPACEBAR]. Or, use the mouse to click the
@@ -151,10 +165,13 @@
To destroy it:
--------------
First, figure out the answer to the equation.
- For example, "3 x 4" would be "12"
+ For example, "3 x 4 = ?" would be "12"
Second, type in the answer. As you type numbers on the keyboard, they
will appear in the "LED"-style display at the top center of the screen.
+ If negative answers are enabled, there will be a fourth place in the
+ LED display for the minus sign. The '-' and '+' keys will toggle the
+ minus sign on and off, respectively.
Finally, press [ENTER / RETURN].
@@ -199,9 +216,22 @@
destroyed. If the city is hit by another comet, it will be
completely destroyed.
- Once you lose all of your cities, the game will end.
+ Ending The Game
+ ---------------
+ By default, the game operates in an arcade-style manner, continuing
+ until you lose all of your cities. A GAME OVER screen is displayed.
+ By pressing any key or clicking the mouse, you return to the title
+ screen.
+ It is now possible to play through a defined list of questions. This
+ mode is selected via the "--norepeats" command line argument. By
+ default, the questions are asked in a random order. If answered
+ correctly, they are removed. A question that is not answered correctly
+ (allowing the comet to destroy its target) will reappear in random
+ order. If all questions are successfully answered before the cities
+ have been destroyed, the player wins and a "victory" screen is displayed.
+
Regaining Cities
----------------
[ Rules will go here ]
@@ -215,9 +245,32 @@
Setting Game Options
--------------------
[ UNDER CONSTRUCTION ]
+ This is still under construction, but many things can be set. For now,
+ there are three ways to set game options.
+ 1. Many command-line options are supported (see above).
+ 2. The "Options" screen allows several parameters to be set at run-time,
+ or reset between individual games while the program is still running.
+ Currently supported settings include the math operations to be used for
+ questions, the starting speed, the maximum value of answers (for division
+ questions, this is the maximum size of the dividend, not actually the
+ answer), and ranges of numbers to be used to generate questions.
+ 3. Editing the default values in tuxmath.h and mathcards.h and recompiling.
+ The default settings for general game options are contained in tuxmath.h, and
+ the defaults for math question settings are in mathcards.h. Very fine-grained
+ control over game behavior is offered, but this isn't exactly a user-friendly
+ method of controlling the program.
+
+ Two main improvements are planned. First, the program should read
+ and write the settings to disk in a human-readable fashion, where they
+ could be modified with a text editor. This also would allow creation of
+ a series of "lessons" that could be played in a planned order.
+ Second, the "Options" screen needs to be overhauled to give access to all
+ settings from within the program.
+
+
Setting Administrative Options
------------------------------
"Tux, of Math Command" allows parents/teachers to adjust which parts
@@ -231,7 +284,7 @@
On the other hand, you may wish to lock-in the other three kinds
of equations, so that the players cannot disable any of them.
All games will always have addition, subtraction and multiplication
- problems, but will never had division problems.
+ problems, but will never have division problems.
[ UNDER CONSTRUCTION ]
@@ -260,3 +313,6 @@
The GIMP
http://www.gimp.org/
+
+ KDevelop
+ http://www.kdevelop.org/
Modified: tuxmath/trunk/src/game.c
===================================================================
--- tuxmath/trunk/src/game.c 2006-05-16 17:05:20 UTC (rev 10)
+++ tuxmath/trunk/src/game.c 2006-06-12 20:14:08 UTC (rev 11)
@@ -60,13 +60,13 @@
#define ANSWER_LEN 5
-#define FORMULA_LEN 8
+#define FORMULA_LEN 14
+
typedef struct comet_type {
int alive;
int expl;
int city;
float x, y;
- int eq1, oper, eq2;
char formula[FORMULA_LEN];
int answer;
char answer_str[ANSWER_LEN];
@@ -75,9 +75,7 @@
/* Local (to game.c) 'globals': */
-static int quit;
-static int done;
-static int gameover;
+//static int gameover;
static int game_status;
static int SDL_quit_received;
static int escape_received;
@@ -86,6 +84,7 @@
static int score;
static int pre_wave_score;
static int num_attackers;
+static float speed;
static int demo_countdown;
static int tux_anim;
static int tux_anim_frame;
@@ -100,8 +99,6 @@
static int level_start_wait;
static int last_bkgd;
-static Uint32 last_time, now_time;
-
static int digits[3];
static comet_type comets[MAX_COMETS];
static city_type cities[NUM_CITIES];
@@ -119,38 +116,41 @@
static void game_handle_cities(void);
static void game_draw(void);
static int check_exit_conditions(void);
-static void print_exit_conditions(void);
+static void draw_numbers(char* str, int x, int y);
+static void draw_led_nums(void);
+static void draw_question_counter(void);
+static void draw_console_image(int i);
+static void draw_line(int x1, int y1, int x2, int y2, int r, int g, int b);
+static void putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel);
+
static void reset_level(void);
static int add_comet(void);
-static void draw_numbers(char* str, int x);
static int pause_game(void);
-static void draw_line(int x1, int y1, int x2, int y2, int r, int g, int b);
-static void putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel);
-static void draw_console_image(int i);
static void add_score(int inc);
-static int pick_operand(int min);
-static int in_range(int n);
static void reset_comets(void);
-static void draw_led_nums(void);
static void game_mouse_event(SDL_Event event);
static void game_key_event(SDLKey key);
+#ifdef TUXMATH_DEBUG
+static void print_exit_conditions(void);
+#endif
+
/* --- MAIN GAME FUNCTION!!! --- */
int game(void)
{
+ Uint32 last_time, now_time;
/* most code moved into smaller functions (game_*()): */
if (!game_initialize())
{
printf("\ngame_initialize() failed!");
fprintf(stderr, "\ngame_initialze() failed!");
- done = 1;
- return 0;
- /*exit(1);*/
+ /* return 1 so program exits: */
+ return 1;
}
/* --- MAIN GAME LOOP: --- */
@@ -162,46 +162,34 @@
old_tux_img = tux_img;
tux_pressing = 0;
- game_handle_user_events();
-
- if (doing_answer)
- {
- game_handle_answer();
- }
-
if (laser.alive > 0)
{
laser.alive--;
- }
+ }
- if (level_start_wait > 0)
- {
- game_countdown();
- }
-
+ /* Most code now in smaller functions: */
+ game_handle_user_events();
+ game_handle_answer();
+ game_countdown();
game_handle_tux();
game_handle_comets();
game_handle_cities();
+ game_handle_demo();
+ game_draw();
+ /* figure out if we should leave loop: */
+ game_status = check_exit_conditions();
-
- if (game_options->demo_mode)
- {
- game_handle_demo();
- }
- /* drawing code moved into own function: */
- game_draw();
-
/* If we're in "PAUSE" mode, pause! */
if (paused)
{
- /*quit = */pause_game();
+ pause_game();
paused = 0;
}
/* Keep playing music: */
-#ifndef NOSOUND
+ #ifndef NOSOUND
if (game_options->use_sound)
{
if (!Mix_PlayingMusic())
@@ -209,9 +197,7 @@
Mix_PlayMusic(musics[MUS_GAME + (rand() % 3)], 0);
}
}
-#endif
- /* figure out if we should leave loop: */
- game_status = check_exit_conditions();
+ #endif
/* Pause (keep frame-rate event) */
now_time = SDL_GetTicks();
@@ -223,18 +209,90 @@
while(GAME_IN_PROGRESS == game_status);
/* END OF MAIN GAME LOOP! */
- #ifdef TUXMATH_DEBUG
- print_exit_conditions();
+ #ifdef TUXMATH_DEBUG
+ print_exit_conditions();
#endif
- /* TODO: handle various end of game scenarios based on value of game_status */
+ /* TODO: need better "victory" screen with animation, special music, etc., */
+ /* as well as options to review missed questions, play again using missed */
+ /* questions as question list, etc. */
switch (game_status)
{
- SDL_Rect dest;
+ SDL_Rect dest_message;
+ SDL_Rect dest_tux;
SDL_Event event;
case GAME_OVER_WON:
{
+ int looping = 1;
+ int tux_offset = 0;
+ int tux_step = -3;
+
+ /* set up victory message: */
+ dest_message.x = (screen->w - images[IMG_GAMEOVER_WON]->w) / 2;
+ dest_message.y = (screen->h - images[IMG_GAMEOVER_WON]->h) / 2;
+ dest_message.w = images[IMG_GAMEOVER_WON]->w;
+ dest_message.h = images[IMG_GAMEOVER_WON]->h;
+
+ do
+ {
+ frame++;
+ last_time = SDL_GetTicks();
+
+ while (SDL_PollEvent(&event) > 0)
+ {
+ if (event.type == SDL_QUIT
+ || event.type == SDL_KEYDOWN
+ || event.type == SDL_MOUSEBUTTONDOWN)
+ {
+ looping = 0;
+ }
+ }
+ if (bkgd)
+ SDL_BlitSurface(bkgd, NULL, screen, NULL);
+
+
+
+ /* draw flashing victory message: */
+ if (((frame / 2) % 4))
+ {
+ SDL_BlitSurface(images[IMG_GAMEOVER_WON], NULL, screen, &dest_message);
+ }
+
+ /* draw dancing tux: */
+ draw_console_image(IMG_CONSOLE_LED);
+ /* walk tux back and forth */
+ tux_offset += tux_step;
+ /* select tux_egypt images according to which way tux is headed: */
+ if (tux_step < 0)
+ tux_img = IMG_TUX_EGYPT1 + ((frame / 3) % 2);
+ else
+ tux_img = IMG_TUX_EGYPT3 + ((frame / 3) % 2);
+
+ /* turn around if we go far enough: */
+ if (tux_offset >= (screen->w)/2
+ || tux_offset <= -(screen->w)/2)
+ {
+ tux_step = -tux_step;
+ }
+
+ dest_tux.x = ((screen->w - images[tux_img]->w) / 2) + tux_offset;
+ dest_tux.y = (screen->h - images[tux_img]->h);
+ dest_tux.w = images[tux_img]->w;
+ dest_tux.h = images[tux_img]->h;
+
+ SDL_BlitSurface(images[tux_img], NULL, screen, &dest_tux);
+
+/* draw_console_image(tux_img);*/
+
+ SDL_Flip(screen);
+
+ now_time = SDL_GetTicks();
+
+ if (now_time < last_time + FPS)
+ SDL_Delay(last_time + FPS - now_time);
+ }
+ while (looping);
break;
}
@@ -247,9 +305,18 @@
case GAME_OVER_LOST:
case GAME_OVER_OTHER:
{
- gameover = 1;
+ int looping = 1;
+
+ /* set up GAMEOVER message: */
+ dest_message.x = (screen->w - images[IMG_GAMEOVER]->w) / 2;
+ dest_message.y = (screen->h - images[IMG_GAMEOVER]->h) / 2;
+ dest_message.w = images[IMG_GAMEOVER]->w;
+ dest_message.h = images[IMG_GAMEOVER]->h;
+
do
{
+ frame++;
+ last_time = SDL_GetTicks();
while (SDL_PollEvent(&event) > 0)
{
@@ -257,16 +324,11 @@
|| event.type == SDL_KEYDOWN
|| event.type == SDL_MOUSEBUTTONDOWN)
{
- gameover = 0;
+ looping = 0;
}
}
- dest.x = (screen->w - images[IMG_GAMEOVER]->w) / 2;
- dest.y = (screen->h - images[IMG_GAMEOVER]->h) / 2;
- dest.w = images[IMG_GAMEOVER]->w;
- dest.h = images[IMG_GAMEOVER]->h;
-
- SDL_BlitSurface(images[IMG_GAMEOVER], NULL, screen, &dest);
+ SDL_BlitSurface(images[IMG_GAMEOVER], NULL, screen, &dest_message);
SDL_Flip(screen);
now_time = SDL_GetTicks();
@@ -274,7 +336,7 @@
if (now_time < last_time + FPS)
SDL_Delay(last_time + FPS - now_time);
}
- while (gameover);
+ while (looping);
break;
}
@@ -309,7 +371,16 @@
#endif
/* Return the chosen command: */
- return quit;
+ if (GAME_OVER_WINDOW_CLOSE == game_status)
+ {
+ /* program exits: */
+ return 1;
+ }
+ else
+ {
+ /* return to title() screen: */
+ return 0;
+ }
}
@@ -322,32 +393,28 @@
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
SDL_Flip(screen);
- /* FIXME done and quit will be superseded by game_status */
- done = 0;
- quit = 0;
-
game_status = GAME_IN_PROGRESS;
SDL_quit_received = 0;
escape_received = 0;
/* Start MathCards backend: */
/* FIXME may need to move this into tuxmath.c to accomodate option */
- /* to us MC_StartUsingWrongs() */
+ /* to use MC_StartUsingWrongs() */
if (!MC_StartGame())
{
+ #ifdef TUXMATH_DEBUG
printf("\nMC_StartGame() failed!");
+ #endif
fprintf(stderr, "\nMC_StartGame() failed!");
- done = 1;
return 0;
- /*exit(1);*/
}
/* Prepare to start the game: */
wave = 1;
num_attackers = 2;
+ speed = game_options->speed;
score = 0;
- gameover = 0;
demo_countdown = 1000;
level_start_wait = LEVEL_START_WAIT_START;
neg_answer_picked = 0;
@@ -355,32 +422,29 @@
/* (Create and position cities) */
for (i = 0; i < NUM_CITIES; i++)
+ {
+ cities[i].alive = 1;
+ cities[i].expl = 0;
+ cities[i].shields = 1;
+
+ /* Left vs. Right - makes room for Tux and the console */
+ if (i < NUM_CITIES / 2)
{
- cities[i].alive = 1;
- cities[i].expl = 0;
- cities[i].shields = 1;
-
-
- /* Left vs. Right - makes room for Tux and the console */
-
- if (i < NUM_CITIES / 2)
- {
- cities[i].x = (((screen->w / (NUM_CITIES + 1)) * i) +
- ((images[IMG_CITY_BLUE] -> w) / 2));
- }
- else
- {
- cities[i].x = (screen->w -
- ((((screen->w / (NUM_CITIES + 1)) *
- (i - (NUM_CITIES / 2)) +
- ((images[IMG_CITY_BLUE] -> w) / 2)))));
- }
+ cities[i].x = (((screen->w / (NUM_CITIES + 1)) * i) +
+ ((images[IMG_CITY_BLUE] -> w) / 2));
}
+ else
+ {
+ cities[i].x = (screen->w -
+ ((((screen->w / (NUM_CITIES + 1)) *
+ (i - (NUM_CITIES / 2)) +
+ ((images[IMG_CITY_BLUE] -> w) / 2)))));
+ }
+ }
num_cities_alive = NUM_CITIES;
num_comets_alive = 0;
-
/* (Clear laser) */
laser.alive = 0;
@@ -412,10 +476,6 @@
if (event.type == SDL_QUIT)
{
SDL_quit_received = 1;
- /* FIXME quit and done flags will be superseded */
- /* Window close event - quit! */
- quit = 1;
- done = 1;
}
else if (event.type == SDL_KEYDOWN)
{
@@ -431,6 +491,12 @@
void game_handle_demo(void)
{
+ /* If not in demo mode get out: */
+ if (!game_options->demo_mode)
+ {
+ return;
+ }
+
/* Demo mode! */
int demo_answer, answer_digit;
static int picked_comet;
@@ -497,15 +563,18 @@
/* Count down counter: */
demo_countdown--;
- if (demo_countdown <= 0 || num_cities_alive == 0)
- done = 1;
}
-/* FIXME need to end game if no more questions left */
+
void game_handle_answer(void)
{
int i, num, lowest, lowest_y;
+ if (!doing_answer)
+ {
+ return;
+ }
+
doing_answer = 0;
num = (digits[0] * 100 +
@@ -565,7 +634,7 @@
/* [ add = 25, sub = 50, mul = 75, div = 100 ] */
/* [ the higher the better ] */
- add_score(((25 * (comets[lowest].oper + 1)) *
+ add_score(((25 * (comets[lowest].flashcard.operation + 1)) *
(screen->h - comets[lowest].y + 1)) /
screen->h);
}
@@ -595,6 +664,9 @@
void game_countdown(void)
{
+ if (level_start_wait <= 0)
+ return;
+
level_start_wait--;
if (level_start_wait > LEVEL_START_WAIT_START / 4)
tux_img = IMG_TUX_RELAX1;
@@ -661,23 +733,20 @@
num_comets_alive++;
/* update comet position */
comets[i].x = comets[i].x + 0; /* no lateral motion for now! */
- comets[i].y = comets[i].y + (game_options->speed);
+ comets[i].y = comets[i].y + (speed);
if (comets[i].y >= (screen->h - images[IMG_CITY_BLUE]->h) &&
comets[i].expl < COMET_EXPL_END)
{
- printf("\nAbout to disable shields or destroy city!\n");
/* Disable shields or destroy city: */
MC_AnsweredIncorrectly(&(comets[i].flashcard));
if (cities[comets[i].city].shields)
{
- printf("\nDisabling shields!\n");
cities[comets[i].city].shields = 0;
playsound(SND_SHIELDSDOWN);
}
else
{
- printf("\nDestroying city!\n");
cities[comets[i].city].expl = CITY_EXPL_START;
playsound(SND_EXPLOSION);
}
@@ -701,8 +770,7 @@
/* add more comets if needed: */
if (level_start_wait == 0 &&
- (frame % 20) == 0 &&
- gameover == 0)
+ (frame % 20) == 0)
{
/* num_attackers is how many comets are left in wave */
if (num_attackers > 0)
@@ -720,29 +788,18 @@
if (num_comets_alive == 0)
{
/* Time for the next wave! */
-
- /* FIXME: End of level stuff goes here */
- /* FIXME this belongs in game_handle_cities(), I think */
- if (num_cities_alive > 0)
- {
- /* Go on to the next wave: */
wave++;
reset_level();
- }
- else
- {
- /* No more cities! Game over! */
- gameover = GAMEOVER_COUNTER_START;
- }
}
}
}
}
+
+
void game_handle_cities(void)
{
int i;
- /* FIXME does the following variable do anything? */
num_cities_alive = 0;
for (i = 0; i < NUM_CITIES; i++)
@@ -761,6 +818,8 @@
}
}
+
+/* FIXME consider splitting this into smaller functions e.g. draw_comets(), etc. */
void game_draw(void)
{
int i,j, img;
@@ -805,6 +864,13 @@
SDL_BlitSurface(images[IMG_DEMO], NULL, screen, &dest);
}
+ /* If we are playing through a defined list of questions */
+ /* without "recycling", display number of remaining questions: */
+ if (!MC_RecycleCorrects())
+ {
+ draw_question_counter();
+ }
+
/* Draw wave: */
dest.x = 0;
dest.y = 0;
@@ -814,7 +880,7 @@
SDL_BlitSurface(images[IMG_WAVE], NULL, screen, &dest);
sprintf(str, "%d", wave);
- draw_numbers(str, images[IMG_WAVE]->w + (images[IMG_NUMBERS]->w / 10));
+ draw_numbers(str, images[IMG_WAVE]->w + (images[IMG_NUMBERS]->w / 10), 0);
/* Draw score: */
dest.x = (screen->w - ((images[IMG_NUMBERS]->w / 10) * 7) -
@@ -826,7 +892,7 @@
SDL_BlitSurface(images[IMG_SCORE], NULL, screen, &dest);
sprintf(str, "%.6d", score);
- draw_numbers(str, screen->w - ((images[IMG_NUMBERS]->w / 10) * 6));
+ draw_numbers(str, screen->w - ((images[IMG_NUMBERS]->w / 10) * 6), 0);
/* Draw cities: */
for (i = 0; i < NUM_CITIES; i++)
@@ -920,8 +986,8 @@
if (laser.alive)
{
draw_line(laser.x1, laser.y1, laser.x2, laser.y2,
- 255 / (LASER_START - laser.alive),
- 192 / (LASER_START - laser.alive),
+ 255 / ((LASER_START + 1) - laser.alive),
+ 192 / ((LASER_START + 1) - laser.alive),
64);
}
@@ -950,28 +1016,11 @@
}
/* Draw console & tux: */
- /* FIXME add counter for remaining questions */
- draw_console_image(IMG_CONSOLE);
-
- if (gameover > 0)
- {
- tux_img = IMG_TUX_FIST1 + ((frame / 2) % 2);
- }
- draw_console_image(tux_img);
-
/* LED code moved into separate function by DSB */
+ /* this also draws the console */
draw_led_nums();
- /* Draw "Game Over" */
- if (gameover > 0)
- {
- dest.x = (screen->w - images[IMG_GAMEOVER]->w) / 2;
- dest.y = (screen->h - images[IMG_GAMEOVER]->h) / 2;
- dest.w = images[IMG_GAMEOVER]->w;
- dest.h = images[IMG_GAMEOVER]->h;
-
- SDL_BlitSurface(images[IMG_GAMEOVER], NULL, screen, &dest);
- }
+ draw_console_image(tux_img);
/* Swap buffers: */
SDL_Flip(screen);
@@ -990,24 +1039,11 @@
}
/* determine if game lost (i.e. all cities blown up): */
+ if (!num_cities_alive)
{
- int i;
- int surviving_cities = 0;
-
- for (i = 0; i < NUM_CITIES; i++)
- {
- if (cities[i].alive)
- {
- surviving_cities++;
- }
- }
-
- if (!surviving_cities)
- {
- return GAME_OVER_LOST;
- }
+ return GAME_OVER_LOST;
}
-
+
/* determine if game won (i.e. all questions in mission answered correctly): */
if (MC_MissionAccomplished())
{
@@ -1016,38 +1052,35 @@
/* Could have situation where mathcards doesn't have more questions */
/* even though not all questions answered correctly: */
- if (MC_GameOver())
+ if (!MC_TotalQuestionsLeft())
{
return GAME_OVER_OTHER;
}
- /* Need to get out if no comets alive and MathCards out of unanswered questions, */
+ /* 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)
{
-// int i;
-// int living_comets = 0;
-//
-// for (i = 0; i < MAX_COMETS; i++)
-// {
-// living_comets += comets[i].alive;
-// }
-
- if (MC_NoQuestionsLeft() && !num_comets_alive)
- {
- #ifdef TUXMATH_DEBUG
- printf("\nNoQuestionsLeft() = %d", MC_NoQuestionsLeft());
- printf("\nnum_comets_alive = %d", num_comets_alive);
- #endif
- return GAME_OVER_ERROR;
- }
+ #ifdef TUXMATH_DEBUG
+ printf("\nListQuestionsLeft() = %d", MC_ListQuestionsLeft());
+ printf("\nnum_comets_alive = %d", num_comets_alive);
+ #endif
+ return GAME_OVER_ERROR;
}
+
+ /* If using demo mode, see if counter has run out: */
+ if (game_options->demo_mode)
+ {
+ if (demo_countdown <= 0 )
+ return GAME_OVER_OTHER;
+ }
/* if we made it to here, the game goes on! */
return GAME_IN_PROGRESS;
}
+#ifdef TUXMATH_DEBUG
void print_exit_conditions(void)
{
printf("\ngame_status:\t");
@@ -1096,6 +1129,7 @@
}
}
}
+#endif
/* Reset stuff for the next level! */
void reset_level(void)
@@ -1164,11 +1198,11 @@
if (game_options->allow_speedup)
{
num_attackers = wave * game_options->extra_comets;
- game_options->speed = (game_options->speed) * game_options->speedup_factor;
+ speed = speed * game_options->speedup_factor;
- if (game_options->speed > game_options->max_speed)
+ if (speed > game_options->max_speed)
{
- game_options->speed = game_options->max_speed;
+ speed = game_options->max_speed;
}
}
else
@@ -1180,151 +1214,219 @@
/* Add a comet to the game (if there's room): */
-
int add_comet(void)
{
static int prev_city = -1;
int i, found;
-
+ float y_spacing;
- /* Look for a free comet slot: */
-
+ /* Look for a free comet slot and see if all live comets are far */
+ /* enough down to avoid overlap and keep formulas legible: */
found = -1;
-
+ y_spacing = (images[IMG_NUMS]->h) * 1.5;
+
for (i = 0; i < MAX_COMETS && found == -1; i++)
{
- if (comets[i].alive == 0)
+ if (comets[i].alive)
{
+ if (comets[i].y < y_spacing)
+ {
+ /* previous comet too high up to create another one yet: */
+ return 0;
+ }
+ }
+ else /* non-living comet so we found a free slot: */
+ {
found = i;
}
}
+ if (-1 == found)
+ {
+ /* free comet slot not found - no comet added: */
+ return 0;
+ }
+
- if (found != -1)
+ /* Get math question for new comet - the following function fills in */
+ /* the flashcard struct that is part of the comet struct: */
+ if (!MC_NextQuestion(&(comets[found].flashcard)))
{
- /* Get math question for new comet: */
- if (!MC_NextQuestion(&(comets[found].flashcard)))
- /* no more questions - cannot create comet. */
+ /* no more questions available - cannot create comet. */
+ return 0;
+ }
+
+ /* If we make it to here, create a new comet! */
+
+ /* The answer may be num1, num2, or num3, depending on format. */
+ /* Also, the formula string needs to be set accordingly: */
+ switch (comets[found].flashcard.format)
+ {
+ case MC_FORMAT_ANS_LAST: /* e.g. num1 + num2 = ? */
{
- return 0;
+ comets[found].answer = comets[found].flashcard.num3;
+
+ snprintf(comets[found].formula, FORMULA_LEN,"%d %c %d = ?",
+ comets[found].flashcard.num1,
+ operchars[comets[found].flashcard.operation],
+ comets[found].flashcard.num2);
+ break;
}
- /* FIXME streamline comet struct - for now assign to old variables */
- /* FIXME also need to handle question formats */
- comets[found].eq1 = comets[found].flashcard.num1;
- comets[found].oper = comets[found].flashcard.operation;
- comets[found].eq2 = comets[found].flashcard.num2;
- comets[found].answer = comets[found].flashcard.num3;
+ case MC_FORMAT_ANS_MIDDLE: /* e.g. num1 + ? = num3 */
+ {
+ comets[found].answer = comets[found].flashcard.num2;
- comets[found].alive = 1;
- num_comets_alive++;
+ snprintf(comets[found].formula, FORMULA_LEN,"%d %c ? = %d",
+ comets[found].flashcard.num1,
+ operchars[comets[found].flashcard.operation],
+ comets[found].flashcard.num3);
+ break;
+ }
- /* Pick a city to attack that was not attacked last time */
- /* (so formulas are less likely to overlap). */
- do
+ case MC_FORMAT_ANS_FIRST: /* e.g. ? + num2 = num3 */
{
- i = rand() % NUM_CITIES;
+ comets[found].answer = comets[found].flashcard.num1;
+
+ snprintf(comets[found].formula, FORMULA_LEN,"? %c %d = %d",
+ operchars[comets[found].flashcard.operation],
+ comets[found].flashcard.num2,
+ comets[found].flashcard.num3);
+ break;
}
- while (i == prev_city);
- prev_city = i;
+ default: /* should not get to here if MathCards behaves correctly */
+ {
+ #ifdef TUXMATH_DEBUG
+ printf("\nadd_comet() - invalid question format");
+ #endif
+ fprintf(stderr, "\nadd_comet() - invalid question format");
+ return 0;
+ }
+ }
+
+ /* set answer string: */
+ snprintf(comets[found].answer_str, ANSWER_LEN, "%d",
+ comets[found].answer);
+
+
+ comets[found].alive = 1;
+ num_comets_alive++;
+
+ /* Pick a city to attack that was not attacked last time */
+ /* (so formulas are less likely to overlap). */
+ do
+ {
+ i = rand() % NUM_CITIES;
+ }
+ while (i == prev_city);
+
+ prev_city = i;
- /* Set in to attack that city: */
- comets[found].city = i;
- /* Start at the top, above the city in question: */
- comets[found].x = cities[i].x;
- comets[found].y = 0;
+ /* Set in to attack that city: */
+ comets[found].city = i;
+ /* Start at the top, above the city in question: */
+ comets[found].x = cities[i].x;
+ comets[found].y = 0;
- snprintf(comets[found].formula, FORMULA_LEN,"%d%c%d",
- comets[found].eq1,
- operchars[comets[found].oper],
- comets[found].eq2);
- snprintf(comets[found].answer_str, ANSWER_LEN, "%d",
- comets[found].answer);
+ /* comet slot found and question found so return successfully: */
+ return 1;
+
- /* comet slot found and question found so return successfully: */
- return 1;
- }
- /* free comet slot not found - no comet added: */
- return 0;
}
-
/* Draw numbers/symbols over the attacker: */
-/* This draw the numbers related to the comets */
+/* This draws the numbers related to the comets */
void draw_nums(char * str, int x, int y)
{
int i, j, cur_x, c;
+ int str_length, char_width, image_length;
+
SDL_Rect src, dest;
-
+ /* avoid some recalculation and repeated function calls: */
+ str_length = strlen(str);
+ /* IMG_NUMS now consists of 10 digit graphics, NUM_OPERS (i.e. 4) */
+ /* operation symbols, and the '=' and '?' symbols, all side by side. */
+ /* char_width is the width of a single symbol. */
+ char_width = (images[IMG_NUMS]->w / (10 + NUM_OPERS + 2));
+ /* Calculate image_length, taking into account that the string will */
+ /* usually have four empty spaces that are only half as wide: */
+ image_length = str_length * char_width - (char_width * 0.5 * 4);
/* Center around the shape */
-
- cur_x = x - ((strlen(str) * (images[IMG_NUMS]->w / (10 + NUM_OPERS)))) / 2;
+ cur_x = x - (image_length) / 2;
- if (cur_x < 0)
- cur_x = 0;
+ /* the following code keeps the formula at least 8 pixels inside the window: */
+ if (cur_x < 8)
+ cur_x = 8;
+ if (cur_x + (image_length) >=
+ (screen->w - 8))
+ cur_x = ((screen->w - 8) -
+ (image_length));
- if (cur_x + (strlen(str) * (images[IMG_NUMS]->w / (10 + NUM_OPERS))) >=
- screen->w)
- cur_x = ((screen->w) -
- (strlen(str) * (images[IMG_NUMS]->w / (10 + NUM_OPERS))));
-
/* Draw each character: */
- for (i = 0; i < strlen(str); i++)
- {
- c = -1;
+ for (i = 0; i < str_length; i++)
+ {
+ c = -1;
- /* Determine which character to display: */
+ /* Determine which character to display: */
- if (str[i] >= '0' && str[i] <= '9')
- c = str[i] - '0';
- else
- {
- /* [ THIS COULD CAUSE SLOWNESS... ] */
-
- for (j = 0; j < NUM_OPERS; j++)
- {
- if (str[i] == operchars[j])
- {
- c = 10 + j;
- }
- }
+ if (str[i] >= '0' && str[i] <= '9')
+ {
+ c = str[i] - '0';
+ }
+ else if ('=' == str[i])
+ {
+ c = 14; /* determined by layout of nums.png image */
+ }
+ else if ('?' == str[i])
+ {
+ c = 15; /* determined by layout of nums.png image */
+ }
+ else /* [ THIS COULD CAUSE SLOWNESS... ] */
+ {
+ for (j = 0; j < NUM_OPERS; j++)
+ {
+ if (str[i] == operchars[j])
+ {
+ c = 10 + j;
}
+ }
+ }
-
- /* Display this character! */
-
- if (c != -1)
- {
- src.x = c * (images[IMG_NUMS]->w / (10 + NUM_OPERS));
- src.y = 0;
- src.w = (images[IMG_NUMS]->w / (10 + NUM_OPERS));
- src.h = images[IMG_NUMS]->h;
+ /* Display this character! */
+ if (c != -1)
+ {
+ src.x = c * char_width;
+ src.y = 0;
+ src.w = char_width;
+ src.h = images[IMG_NUMS]->h;
- dest.x = cur_x;
- dest.y = y - images[IMG_NUMS]->h;
- dest.w = src.w;
- dest.h = src.h;
+ dest.x = cur_x;
+ dest.y = y - images[IMG_NUMS]->h;
+ dest.w = src.w;
+ dest.h = src.h;
- SDL_BlitSurface(images[IMG_NUMS], &src,
+ SDL_BlitSurface(images[IMG_NUMS], &src,
screen, &dest);
-
-
- /* Move the 'cursor' one character width: */
-
- cur_x = cur_x + (images[IMG_NUMS]->w / (10 + NUM_OPERS));
- }
+ /* Move the 'cursor' one character width: */
+ cur_x = cur_x + char_width;
}
+ /* If char is a blank, no drawing to do but still move the cursor: */
+ /* NOTE: making spaces only half as wide seems to look better. */
+ if (' ' == str[i])
+ {
+ cur_x = cur_x + (char_width * 0.5);
+ }
+ }
}
/* Draw status numbers: */
-
-void draw_numbers(char * str, int x)
+void draw_numbers(char * str, int x, int y)
{
int i, cur_x, c;
SDL_Rect src, dest;
@@ -1356,7 +1458,7 @@
src.h = images[IMG_NUMBERS]->h;
dest.x = cur_x;
- dest.y = 0;
+ dest.y = y;
dest.w = src.w;
dest.h = src.h;
@@ -1409,7 +1511,6 @@
else if (event.type == SDL_QUIT)
{
SDL_quit_received = 1;
- /* FIXME quit is being superseded */
pause_quit = 1;
}
}
@@ -1548,7 +1649,6 @@
/* Draw image at lower center of screen: */
-
void draw_console_image(int i)
{
SDL_Rect dest;
@@ -1560,14 +1660,72 @@
SDL_BlitSurface(images[i], NULL, screen, &dest);
}
+
+
+void draw_question_counter(void)
+{
+ int questions_left;
+ int comet_img;
+ int nums_width;
+ int nums_x;
+ int comet_width;
+ int comet_x;
+
+ char str[64];
+ SDL_Rect dest;
+
+ /* Calculate placement based on image widths: */
+ nums_width = (images[IMG_NUMBERS]->w / 10) * 4; /* displaying 4 digits */
+ comet_width = images[IMG_MINI_COMET1]->w;
+ comet_x = (screen->w)/2 - (comet_width + nums_width)/2;
+ nums_x = comet_x + comet_width;
+
+ /* Draw mini comet symbol: */
+ /* Decide which image to display: */
+ comet_img = IMG_MINI_COMET1 + (frame % 3);
+ /* Draw it! */
+ dest.x = comet_x;
+ dest.y = 0;
+ dest.w = comet_width;
+ dest.h = images[comet_img]->h;
+
+ SDL_BlitSurface(images[comet_img], NULL, screen, &dest);
+
+ /* draw number of remaining questions: */
+ questions_left = MC_TotalQuestionsLeft();
+ sprintf(str, "%.4d", questions_left);
+ draw_numbers(str, nums_x, 0);
+}
+
+/* FIXME consider always using new image for simplicity */
+/* FIXME very confusing having this function draw console */
/* Draw LED digits at the top of the screen: */
/* Modified by DSB to display minus sign */
-
void draw_led_nums(void)
{
int i;
SDL_Rect src, dest;
+ int y;
+ /* draw either just above console or at top of screen: */
+ if (MC_RecycleCorrects())
+ {
+ /* draw traditional console: */
+ draw_console_image(IMG_CONSOLE);
+ /* LEDs go at top in traditional TuxMath: */
+ y = 4;
+
+ }
+ else
+ {
+ /* draw new console image with "monitor" for LED numbers: */
+ draw_console_image(IMG_CONSOLE_LED);
+ /* draw LED numbers into "monitor": */
+ y = (screen->h
+ - images[IMG_CONSOLE_LED]->h
+ + 4); /* "monitor" has 4 pixel margin */
+ }
+
/* begin drawing so as to center display depending on whether minus */
/* sign needed (4 digit slots) or not (3 digit slots) DSB */
if (MC_AllowNegAnswer())
@@ -1591,7 +1749,7 @@
src.w = (images[IMG_LED_NEG_SIGN]->w) / 2;
src.h = images[IMG_LED_NEG_SIGN]->h;
- dest.y = 4;
+ dest.y = y;
dest.w = src.w;
dest.h = src.h;
@@ -1608,7 +1766,7 @@
src.h = images[IMG_LEDNUMS]->h;
/* dest.x already set */
- dest.y = 4;
+ dest.y = y;
dest.w = src.w;
dest.h = src.h;
@@ -1658,13 +1816,13 @@
keypad_h = images[IMG_KEYPAD]->h;
}
}
-
if (!keypad_w || !keypad_h)
{
return;
}
+
/* only proceed if click falls within keypad: */
if (!((event.button.x >=
(screen->w / 2) - (keypad_w / 2) &&
@@ -1788,8 +1946,6 @@
{
/* Escape key - quit! */
escape_received = 1;
- /* FIXME done will be superseded */
- done = 1;
}
else if (key == SDLK_TAB
|| key == SDLK_p)
@@ -1863,42 +2019,7 @@
}
-/* Pick a suitable operand: */
-int pick_operand(int min)
-{
- int i;
-
- do
- {
- i = (rand() % 50) + min;
- }
- while (!in_range(i));
-
- return i;
-}
-
-
-/* Is the value with available operand ranges? */
-
-int in_range(int n)
-{
- int ok, i;
-
- ok = 0;
-
- for (i = 0; i < NUM_Q_RANGES && ok == 0; i++)
- {
- if (range_enabled[i])
- {
- if (n >= ranges[i].min && n <= ranges[i].max)
- ok = 1;
- }
- }
-
- return ok;
-}
-
void reset_comets(void)
{
int i =0;
@@ -1909,11 +2030,8 @@
comets[i].city = 0;
comets[i].x = 0;
comets[i].y = 0;
- comets[i].eq1 = 0;
- comets[i].oper = 0;
- comets[i].eq2 = 0;
- comets[i].formula[FORMULA_LEN] = "";
comets[i].answer = 0;
- comets[i].answer_str[ANSWER_LEN] = "";
+ strncpy(comets[i].formula, " ", FORMULA_LEN);
+ strncpy(comets[i].answer_str, " ", ANSWER_LEN);
}
}
Modified: tuxmath/trunk/src/images.h
===================================================================
--- tuxmath/trunk/src/images.h 2006-05-16 17:05:20 UTC (rev 10)
+++ tuxmath/trunk/src/images.h 2006-06-12 20:14:08 UTC (rev 11)
@@ -88,6 +88,9 @@
IMG_COMETEX2,
IMG_COMETEX1,
COMET_EXPL_START = IMG_COMETEX1,
+ IMG_MINI_COMET1,
+ IMG_MINI_COMET2,
+ IMG_MINI_COMET3,
IMG_NUMS,
IMG_LEDNUMS,
IMG_LED_NEG_SIGN,
@@ -97,12 +100,17 @@
IMG_KEYPAD,
IMG_KEYPAD_NO_NEG,
IMG_CONSOLE,
+ IMG_CONSOLE_LED,
IMG_TUX_CONSOLE1,
IMG_TUX_CONSOLE2,
IMG_TUX_CONSOLE3,
IMG_TUX_CONSOLE4,
IMG_TUX_RELAX1,
IMG_TUX_RELAX2,
+ IMG_TUX_EGYPT1,
+ IMG_TUX_EGYPT2,
+ IMG_TUX_EGYPT3,
+ IMG_TUX_EGYPT4,
IMG_TUX_DRAT,
IMG_TUX_YIPE,
IMG_TUX_YAY1,
@@ -116,6 +124,7 @@
IMG_SCORE,
IMG_NUMBERS,
IMG_GAMEOVER,
+ IMG_GAMEOVER_WON,
NUM_IMAGES
};
Modified: tuxmath/trunk/src/mathcards.c
===================================================================
--- tuxmath/trunk/src/mathcards.c 2006-05-16 17:05:20 UTC (rev 10)
+++ tuxmath/trunk/src/mathcards.c 2006-06-12 20:14:08 UTC (rev 11)
@@ -36,6 +36,7 @@
/* to give file scope rather than extern scope. */
static MC_MathQuestion* generate_list(void);
+static int validate_question(int n1, int n2, int n3);
static MC_MathQuestion* create_node(int n1, int n2, int op, int ans, int f);
static MC_MathQuestion* create_node_from_card(MC_FlashCard* card);
static MC_FlashCard* create_card_from_node(MC_MathQuestion* node);
@@ -317,7 +318,7 @@
/* to set up list based on math_opts */
{
#ifdef MC_DEBUG
- printf("\nNo wrong questions to review!\n");
+ printf("\nNo wrong questions to review - generate list from math_opts\n");
printf("\nLeaving MC_StartGameUsingWrongs()\n");
#endif
@@ -416,7 +417,7 @@
#endif
answered_correctly++;
-questions_pending--;
+ questions_pending--;
if (math_opts->recycle_corrects)
/* reinsert question into question list at random location */
@@ -558,18 +559,18 @@
}
}
-/* Returns 1 if no more questions left (either in list */
-/* or "in play" */
-int MC_GameOver(void)
+/* Returns number of questions left (either in list */
+/* or "in play") */
+int MC_TotalQuestionsLeft(void)
{
- return !unanswered;
+ return unanswered;
}
-/* Returns 1 if no more questions left in list, NOT */
+/* Returns number of questions left in list, NOT */
/* including questions currently "in play". */
-int MC_NoQuestionsLeft(void)
+int MC_ListQuestionsLeft(void)
{
- return !quest_list_length;
+ return quest_list_length;
}
@@ -1360,15 +1361,15 @@
/* using parameters from the mission struct, create linked list of "flashcards" */
/* FIXME should figure out how to proceed correctly if we run out of memory */
-/* FIXME implement question formats and question_copies flags */
-/* FIXME handle max_answer correctly, even if negative */
+/* FIXME very redundant code - figure out way to iterate through different */
+/* math operations and question formats */
MC_MathQuestion* generate_list(void)
{
MC_MathQuestion* top_of_list = 0;
MC_MathQuestion* end_of_list = 0;
MC_MathQuestion* tmp_ptr = 0;
- int i, j;
+ int i, j, k;
int length = 0;
#ifdef MC_DEBUG
@@ -1377,23 +1378,62 @@
#endif
/* add nodes for each math operation allowed */
+
+
if (math_opts->addition_allowed)
{
for (i = math_opts->min_augend; i <= math_opts->max_augend; i++)
{
for (j = math_opts->min_addend; j <= math_opts->max_addend; j++)
{
- /* prevent negative numbers if desired */
- if (math_opts->allow_neg_answer || ((i >= 0) && (j >=0)))
+ /* check if max_answer exceeded or if question */
+ /* contains undesired negative values: */
+ if (validate_question(i, j, i + j))
{
- /* make sure max_questions not exceeded */
- if (length < math_opts->max_questions)
+ /* put in the desired number of copies: */
+ for (k = 0; k < math_opts->question_copies; k++)
{
- tmp_ptr = create_node(i, j, MC_OPER_ADD, i + j, MC_FORMAT_ANS_LAST);
- top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
- end_of_list = tmp_ptr;
- length++;
- }
+ /* put in questions in each selected format: */
+
+ /* questions like num1 + num2 = ? */
+ if (math_opts->format_answer_last)
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i, j, MC_OPER_ADD, i + j, MC_FORMAT_ANS_LAST);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
+
+ /* questions like num1 + ? = num3 */
+ if (math_opts->format_answer_middle)
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i, j, MC_OPER_ADD, i + j, MC_FORMAT_ANS_MIDDLE);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
+
+ /* questions like ? + num2 = num3 */
+ if (math_opts->format_answer_first)
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i, j, MC_OPER_ADD, i + j, MC_FORMAT_ANS_FIRST);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
+ }
}
}
}
@@ -1405,17 +1445,54 @@
{
for (j = math_opts->min_subtrahend; j <= math_opts->max_subtrahend; j++)
{
- /* prevent negative numbers if desired */
- if (math_opts->allow_neg_answer || (i >= j))
- {
- /* make sure max_questions not exceeded */
- if (length < math_opts->max_questions)
+ /* check if max_answer exceeded or if question */
+ /* contains undesired negative values: */
+ if (validate_question(i, j, i - j))
+ {
+ /* put in the desired number of copies: */
+ for (k = 0; k < math_opts->question_copies; k++)
{
- tmp_ptr = create_node(i, j, MC_OPER_SUB, i - j, MC_FORMAT_ANS_LAST);
- top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
- end_of_list = tmp_ptr;
- length++;
- }
+ /* put in questions in each selected format: */
+
+ /* questions like num1 - num2 = ? */
+ if (math_opts->format_answer_last)
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i, j, MC_OPER_SUB, i - j, MC_FORMAT_ANS_LAST);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
+
+ /* questions like num1 - ? = num3 */
+ if (math_opts->format_answer_middle)
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i, j, MC_OPER_SUB, i - j, MC_FORMAT_ANS_MIDDLE);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
+
+ /* questions like ? - num2 = num3 */
+ if (math_opts->format_answer_first)
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i, j, MC_OPER_SUB, i - j, MC_FORMAT_ANS_FIRST);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
+ }
}
}
}
@@ -1426,17 +1503,58 @@
for (i = math_opts->min_multiplier; i <= math_opts->max_multiplier; i++)
{
for (j = math_opts->min_multiplicand; j <= math_opts->max_multiplicand; j++)
- {
- /* prevent negative numbers if desired */
- if (math_opts->allow_neg_answer || ((i >= 0) && (j >=0)))
- {
- /* make sure max_questions not exceeded */
- if (length < math_opts->max_questions)
+ {
+ /* check if max_answer exceeded or if question */
+ /* contains undesired negative values: */
+ if (validate_question(i, j, i * j))
+ {
+ /* put in the desired number of copies: */
+ for (k = 0; k < math_opts->question_copies; k++)
{
- tmp_ptr = create_node(i, j, MC_OPER_MULT, i * j, MC_FORMAT_ANS_LAST);
- top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
- end_of_list = tmp_ptr;
- length++;
+ /* put in questions in each selected format: */
+
+ /* questions like num1 x num2 = ? */
+ if (math_opts->format_answer_last)
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i, j, MC_OPER_MULT, i * j, MC_FORMAT_ANS_LAST);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
+
+ /* questions like num1 x ? = num3 */
+ /* (no questions like 0 x ? = 0) because answer indeterminate */
+ if ((math_opts->format_answer_middle)
+ && (i != 0))
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i, j, MC_OPER_MULT, i * j, MC_FORMAT_ANS_MIDDLE);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
+
+ /* questions like ? x num2 = num3 */
+ /* (no questions like ? X 0 = 0) because answer indeterminate */
+ if ((math_opts->format_answer_first)
+ && (j != 0))
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i, j, MC_OPER_MULT, i * j, MC_FORMAT_ANS_FIRST);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
}
}
}
@@ -1449,19 +1567,55 @@
{
for (j = math_opts->min_divisor; j <= math_opts->max_divisor; j++)
{
- /* prevent negative numbers if desired */
- if (math_opts->allow_neg_answer || ((i >= 0) && (j >=0)))
- {
- if (j) /* prevent division by zero */
+ /* check if max_answer exceeded or if question */
+ /* contains undesired negative values: */
+ if (j /* must avoid division by zero: */
+ &&
+ validate_question(i * j, j, i)) /* division problems are generated as multiplication */
+ {
+ /* put in the desired number of copies: */
+ for (k = 0; k < math_opts->question_copies; k++)
{
- /* make sure max_questions not exceeded */
- if (length < math_opts->max_questions)
+ /* put in questions in each selected format: */
+
+ /* questions like num1 / num2 = ? */
+ if (math_opts->format_answer_last)
{
- tmp_ptr = create_node(i * j, j, MC_OPER_DIV, i, MC_FORMAT_ANS_LAST);
- top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
- end_of_list = tmp_ptr;
- length++;
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i * j, j, MC_OPER_DIV, i, MC_FORMAT_ANS_LAST);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
}
+
+ /* questions like num1 / ? = num3 */
+ if (math_opts->format_answer_middle)
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i * j, j, MC_OPER_DIV, i, MC_FORMAT_ANS_MIDDLE);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
+
+ /* questions like ? / num2 = num3 */
+ if (math_opts->format_answer_first)
+ {
+ /* make sure max_questions not exceeded */
+ if (length < math_opts->max_questions)
+ {
+ tmp_ptr = create_node(i * j, j, MC_OPER_DIV, i, MC_FORMAT_ANS_FIRST);
+ top_of_list = insert_node(top_of_list, end_of_list, tmp_ptr);
+ end_of_list = tmp_ptr;
+ length++;
+ }
+ }
}
}
}
@@ -1489,8 +1643,29 @@
}
+/* this is used by generate_list to see if a possible question */
+/* meets criteria to be added to the list or not: */
+int validate_question(int n1, int n2, int n3)
+{
+ /* make sure none of values exceeds max_answer using absolute */
+ /* value comparison: */
+ if (abs_value(n1) > abs_value(math_opts->max_answer)
+ || abs_value(n2) > abs_value(math_opts->max_answer)
+ || abs_value(n3) > abs_value(math_opts->max_answer))
+ {
+ return 0;
+ }
+ /* make sure none of values are negative if negatives not allowed: */
+ if (!math_opts->allow_neg_answer)
+ {
+ if (n1 < 0 || n2 < 0 || n3 < 0)
+ {
+ return 0;
+ }
+ }
+ return 1;
+}
-
/* create a new node and return a pointer to it */
MC_MathQuestion* create_node(int n1, int n2, int op, int ans, int f)
{
@@ -1675,6 +1850,7 @@
+
/* prints struct to stdout for testing purposes */
void print_math_options(void)
{
@@ -1690,7 +1866,10 @@
printf("\nGeneral math options:\n");
printf("allow_neg_answer:\t%d\n", math_opts->allow_neg_answer);
printf("max_answer:\t%d\n", math_opts->max_answer);
- printf("max_questions:\t%d\n", math_opts->max_questions);
+ printf("max_questions:\t%d\n", math_opts->max_questions);
+ printf("recycle_corrects:\t%d\n", math_opts->recycle_corrects);
+ printf("recycle_wrongs:\t%d\n", math_opts->recycle_wrongs);
+ printf("copies_recycled_wrongs:\t%d\n", math_opts->copies_recycled_wrongs);
printf("format_answer_last:\t%d\n", math_opts->format_answer_last);
printf("format_answer_first:\t%d\n", math_opts->format_answer_first);
printf("format_answer_middle:\t%d\n", math_opts->format_answer_middle);
Modified: tuxmath/trunk/src/mathcards.h
===================================================================
--- tuxmath/trunk/src/mathcards.h 2006-05-16 17:05:20 UTC (rev 10)
+++ tuxmath/trunk/src/mathcards.h 2006-06-12 20:14:08 UTC (rev 11)
@@ -15,7 +15,7 @@
#ifndef MATHCARDS_H
#define MATHCARDS_H
-#undef MC_DEBUG
+#define MC_DEBUG
#include <stdio.h>
#include <stdlib.h>
@@ -195,15 +195,13 @@
/* 0 otherwise. */
int MC_MissionAccomplished(void);
-/* Returns 1 if no more questions left (either in list */
-/* or "in play" */
-/* FIXME would be better to return number of questions */
-/* left so it can be displayed in a counter. */
-int MC_GameOver(void);
+/* Returns number of questions left (either in list */
+/* or "in play") */
+int MC_TotalQuestionsLeft(void);
-/* Returns 1 if no more questions left in list, NOT */
-/* including questions currently "in play". */
-int MC_NoQuestionsLeft(void);
+/* Returns questions left in list, NOT */
+/* including questions currently "in play". */
+int MC_ListQuestionsLeft(void);
/* Tells MathCards to clean up - should be called when */
/* user interface program exits. */
Modified: tuxmath/trunk/src/setup.c
===================================================================
--- tuxmath/trunk/src/setup.c 2006-05-16 17:05:20 UTC (rev 10)
+++ tuxmath/trunk/src/setup.c 2006-06-12 20:14:08 UTC (rev 11)
@@ -107,6 +107,9 @@
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/status/nums.png",
DATA_PREFIX "/images/status/lednums.png",
DATA_PREFIX "/images/status/led_neg_sign.png",
@@ -116,12 +119,17 @@
DATA_PREFIX "/images/status/keypad.png",
DATA_PREFIX "/images/status/keypad_no_neg.png",
DATA_PREFIX "/images/tux/console.png",
+ DATA_PREFIX "/images/tux/console_led.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",
@@ -134,7 +142,8 @@
DATA_PREFIX "/images/status/wave.png",
DATA_PREFIX "/images/status/score.png",
DATA_PREFIX "/images/status/numbers.png",
- DATA_PREFIX "/images/status/gameover.png"
+ DATA_PREFIX "/images/status/gameover.png",
+ DATA_PREFIX "/images/status/gameover_won.png"
};
@@ -192,6 +201,7 @@
exit(1);
}
+
/* initialize game_options struct with defaults DSB */
game_options = malloc(sizeof(game_option_type));
if (!initialize_game_options(game_options))
@@ -201,13 +211,7 @@
exit(1);
}
-/* FIXME will not need this when MathCards used */
-/*
- for (i = 0; i < NUM_OPERS; i++)
- {
- opers[i] = 1;
- }
-*/
+
for (i = 0; i < NUM_Q_RANGES; i++)
{
range_enabled[i] = 1;
@@ -253,6 +257,12 @@
"When you lose all of your cities, the game ends.\n\n");
printf("Run the game with:\n"
+ "--norepeats - to ask each question only once, allowing player to\n"
+ " win game if all questions successfully answered\n"
+ "--answersfirst - to ask questions in format: ? + num2 = num3\n"
+ " instead of default format: num1 + num2 = ?\n"
+ "--answersmiddle - to ask questions in format: num1 + ? = num3\n"
+ " instead of default format: num1 + num2 = ?\n"
"--nosound - to disable sound/music\n"
"--nobackground - to disable background photos (for slower systems)\n"
"--fullscreen - to run in fullscreen, if possible (vs. windowed)\n"
@@ -339,6 +349,23 @@
{
MC_SetAllowNegAnswer(1);
}
+ else if (strcmp(argv[i], "--norepeats") == 0 ||
+ strcmp(argv[i], "-r") == 0)
+ {
+ MC_SetRecycleCorrects(0);
+ }
+ else if (strcmp(argv[i], "--answersfirst") == 0)
+ {
+ MC_SetFormatAnswerLast(0);
+ MC_SetFormatAnswerFirst(1);
+ MC_SetFormatAnswerMiddle(0);
+ }
+ else if (strcmp(argv[i], "--answersmiddle") == 0)
+ {
+ MC_SetFormatAnswerLast(0);
+ MC_SetFormatAnswerFirst(0);
+ MC_SetFormatAnswerMiddle(1);
+ }
else if (strcmp(argv[i], "--speed") == 0 ||
strcmp(argv[i], "-s") == 0)
{
@@ -403,6 +430,7 @@
game_options->use_keypad = 0;
}
+
/* Init SDL Video: */
@@ -414,7 +442,10 @@
"%s\n\n", SDL_GetError());
exit(1);
}
-
+
+ printf("before SDL Audio\n");
+
+
/* Init SDL Audio: */
#ifndef NOSOUND
@@ -430,11 +461,19 @@
game_options->use_sound = 0;
}
}
-
+
+ printf("middle of Audio\n");
+
if (game_options->use_sound)
- {
- if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 2048) < 0)
+ {
+ printf("using sound \n");
+ if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 2048) < 0)
{
+ printf( "\nWarning: I could not set up audio for 44100 Hz "
+ "16-bit stereo.\n"
+ "The Simple DirectMedia error that occured was:\n"
+ "%s\n\n", SDL_GetError());
+
fprintf(stderr,
"\nWarning: I could not set up audio for 44100 Hz "
"16-bit stereo.\n"
@@ -442,11 +481,13 @@
"%s\n\n", SDL_GetError());
game_options->use_sound = 0;
}
- }
+ }
#endif
-
+ printf("after SDL Audio\n");
+
+
if (game_options->fullscreen)
{
screen = SDL_SetVideoMode(640, 480, 16, SDL_FULLSCREEN | SDL_HWSURFACE);
@@ -479,13 +520,13 @@
SDL_WM_SetCaption("Tux, of Math Command", "TuxMath");
-
if (game_options->use_sound)
total_files = NUM_IMAGES + NUM_SOUNDS + NUM_MUSICS;
else
total_files = NUM_IMAGES;
+
+
-
/* Load images: */
for (i = 0; i < NUM_IMAGES; i++)
{
@@ -542,6 +583,8 @@
SDL_Flip(screen);
}
+ printf("all images loaded\n");
+
#ifndef NOSOUND
if (game_options->use_sound)
{
@@ -615,16 +658,12 @@
{
if (game_options)
free(game_options);
+ /* frees any heap used by MathCards: */
MC_EndGame();
}
-/* Set up math_options struct with defaults from tuxmath.h, */
-/* with simple sanity check for negatives */
-/* FIXME Should there be more error checking here? */
-/* FIXME move this to mathcards.c */
-
int initialize_game_options(game_option_type* opts)
{
/* bail out if no struct */
Modified: tuxmath/trunk/src/tuxmath.h
===================================================================
--- tuxmath/trunk/src/tuxmath.h 2006-05-16 17:05:20 UTC (rev 10)
+++ tuxmath/trunk/src/tuxmath.h 2006-06-12 20:14:08 UTC (rev 11)
@@ -20,7 +20,8 @@
#ifndef TUXMATH_H
#define TUXMATH_H
-#undef TUXMATH_DEBUG /* for conditional compilation of debugging output */
+//#define NOSOUND
+#define TUXMATH_DEBUG /* for conditional compilation of debugging output */
/* this struct contains all options regarding general */
/* gameplay but not having to do with math questions per se */
@@ -60,7 +61,7 @@
#define DEFAULT_REUSE_QUESTIONS 0
#define DEFAULT_SPEED 1
#define DEFAULT_ALLOW_SPEEDUP 1
-#define DEFAULT_SPEEDUP_FACTOR 1
+#define DEFAULT_SPEEDUP_FACTOR 1.2
#define DEFAULT_MAX_SPEED 10
#define DEFAULT_SLOW_AFTER_WRONG 0
#define DEFAULT_EXTRA_COMETS 2
More information about the Tux4kids-commits
mailing list