[Tux4kids-commits] [SCM] tuxhistory - Educational history game branch, master, updated. f0b0d00e71233d5597746899321ab1e525418e74
julio (none)
julio at julio-desktop.
Wed May 26 01:30:01 UTC 2010
The following commit has been merged in the master branch:
commit f0b0d00e71233d5597746899321ab1e525418e74
Author: julio <julio at julio-desktop.(none)>
Date: Tue May 25 20:28:13 2010 -0500
Cleaning TuxMath sources, deleting TuxMath sepsific code... v1
diff --git a/data/menus/main_menu.xml b/data/menus/main_menu.xml
index 2188d84..9170b90 100644
--- a/data/menus/main_menu.xml
+++ b/data/menus/main_menu.xml
@@ -1,4 +1,4 @@
-<menu title="Main Menu" entries="7">
+<menu title="Main Menu" entries="6">
<menu title="Play Alone" sprite="alone" entries="5">
<item title="Math Command Training Academy" sprite="lesson" run="RUN_ACADEMY">
<item title="Math Command Fleet Missions" sprite="fleet" run="RUN_CAMPAIGN">
@@ -14,11 +14,6 @@
<item title="Play Custom Game" sprite="tux_config_brown" run="RUN_CUSTOM">
<item title="Main Menu" sprite="main" run="RUN_MAIN_MENU">
</menu>
- <menu title="Network Game" sprite="lan" entries="3">
- <item title="Run Server" sprite="lan" run="RUN_LAN_HOST">
- <item title="Join Game" sprite="lan" run="RUN_LAN_JOIN">
- <item title="Main Menu" sprite="main" run="RUN_MAIN_MENU">
- </menu>
<menu title="Play With Friends" sprite="friends" entries="3">
<menu title="Score Sweep" sprite="nums" entries="6">
<item title="Space Cadet" sprite="tux_helmet_yellow" run="RUN_SCORE_SWEEP" param="0">
diff --git a/src/Makefile.am b/src/Makefile.am
index 276ae91..5216419 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,7 +30,6 @@ tuxhistory_SOURCES = tuxhistory.c \
titlescreen.c \
menu.c \
game.c \
- factoroids.c \
fileops_media.c \
options.c \
credits.c \
@@ -38,15 +37,10 @@ tuxhistory_SOURCES = tuxhistory.c \
linewrap.c \
loaders.c \
audio.c \
- network.c \
- mathcards.c \
- campaign.c \
- multiplayer.c \
fileops.c \
convert_utf.c \
SDL_extras.c \
SDL_rotozoom.c \
- lessons.c \
scandir.c \
pixels.c \
server.c \
@@ -58,7 +52,6 @@ TuxHistory_SOURCES = $(tuxhistory_SOURCES) tuxmathrc.rc
EXTRA_DIST = credits.h \
- factoroids.h \
fileops.h \
game.h \
menu.h \
@@ -66,25 +59,18 @@ EXTRA_DIST = credits.h \
highscore.h \
linewrap.h \
loaders.h \
- network.h \
titlescreen.h \
menu.h \
options.h \
setup.h \
- mathcards.h \
- campaign.h \
- multiplayer.h \
tuxhistory.h \
convert_utf.h \
SDL_extras.h \
SDL_rotozoom.h \
- lessons.h \
gettext.h \
scandir.h \
pixels.h \
compiler.h \
- server.h \
- testclient.h \
transtruct.h \
throttle.h
diff --git a/src/fileops.c b/src/fileops.c
index b62428c..343da91 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -34,10 +34,8 @@
#include "globals.h"
#include "fileops.h"
#include "setup.h"
-#include "mathcards.h"
#include "options.h"
#include "highscore.h"
-#include "lessons.h"
#include "scandir.h"
/* OS includes - NOTE: these may not be very portable */
@@ -194,7 +192,7 @@ char *GetDefaultSaveDir(const char *suffix)
#else
# define get_home getenv("HOME")
-#define OPTIONS_SUBDIR "/.tuxmath"
+#define OPTIONS_SUBDIR "/.tuxhistory"
#define OPTIONS_FILENAME "options"
#define HIGHSCORE_FILENAME "highscores"
#define GOLDSTAR_FILENAME "goldstars"
@@ -1331,22 +1329,7 @@ int read_config_file(FILE *fp, int file_type)
free(parameter);
}
//handle min > max by disallowing operation
- if (MC_GetOpt(MIN_AUGEND) > MC_GetOpt(MAX_AUGEND) ||
- MC_GetOpt(MIN_ADDEND) > MC_GetOpt(MAX_ADDEND) )
- MC_SetOpt(ADDITION_ALLOWED, 0);
- if (MC_GetOpt(MIN_MINUEND) > MC_GetOpt(MAX_MINUEND) ||
- MC_GetOpt(MIN_SUBTRAHEND) > MC_GetOpt(MAX_SUBTRAHEND) )
- MC_SetOpt(SUBTRACTION_ALLOWED, 0);
- if (MC_GetOpt(MIN_MULTIPLICAND) > MC_GetOpt(MAX_MULTIPLICAND) ||
- MC_GetOpt(MIN_MULTIPLIER) > MC_GetOpt(MAX_MULTIPLIER) )
- MC_SetOpt(MULTIPLICATION_ALLOWED, 0);
- if (MC_GetOpt(MIN_DIVISOR) > MC_GetOpt(MAX_DIVISOR) ||
- MC_GetOpt(MIN_QUOTIENT) > MC_GetOpt(MAX_QUOTIENT) )
- MC_SetOpt(DIVISION_ALLOWED, 0);
- if (MC_GetOpt(MIN_TYPING_NUM) > MC_GetOpt(MAX_TYPING_NUM) )
- MC_SetOpt(TYPING_PRACTICE_ALLOWED, 0);
-
- DEBUGMSG(debug_fileops, "After file read in:\n");
+ DEBUGMSG(debug_fileops, "After file read in:\n");
DEBUGCODE(debug_fileops)
write_config_file(stdout, 0);
DEBUGMSG(debug_fileops, "Leaving read_config_file()\n");
@@ -1360,11 +1343,8 @@ static int parse_option(const char* name, int val, int file_type)
{
int index = -1;
- if ((index = MC_MapTextToIndex(name)) != -1) //is it a math opt?
- {
- MC_SetOpt(index, val);
- }
- else if ((index = Opts_MapTextToIndex(name)) != -1) //is it a global opt?
+
+ if ((index = Opts_MapTextToIndex(name)) != -1) //is it a global opt?
{
if (file_type == GLOBAL_CONFIG_FILE)
Opts_SetGlobalOpt(index, val);
@@ -1415,670 +1395,11 @@ int write_user_config_file(void)
int write_config_file(FILE *fp, int verbose)
{
int i, vcommentsprimed = 0;
- static char* vcomments[NOPTS]; //comments when writing out verbose
- if (!vcommentsprimed) //we only want to initialize these once
- {
- vcommentsprimed = 1;
- for (i = 0; i < NOPTS; ++i)
- vcomments[i] = NULL;
- vcomments[PLAY_THROUGH_LIST] =
- "############################################################\n"
- "# #\n"
- "# Tuxmath Configuration File #\n"
- "# #\n"
- "# The behavior of Tuxmath can be controlled to a great #\n"
- "# extent by editing this file with any and saving it in #\n"
- "# the default options location ($HOME/.tuxmath/options). #\n"
- "# The file consists of 'NAME = VALUE' pairs, one pair per #\n"
- "# line. Each option is one of the following types: #\n"
- "# #\n"
- "# boolean: 1 (synonyms 'true', 'T', 'yes', 'Y', 'on') #\n"
- "# or #\n"
- "# 0 (synonyms 'false, 'F', 'no', 'N', 'off') #\n"
- "# integer (i.e. non-fractional numbers) #\n"
- "# float (i.e decimal fractions) #\n"
- "# #\n"
- "# Lines beginning with '#' or ';' are ignored as comments. #\n"
- "# The synonyms for boolean '0' and '1' are accepted as #\n"
- "# input, but always written as '0' or '1' when Tuxmath #\n"
- "# writes a config file to disk. #\n"
- "# The file is organized with the more important options #\n"
- "# first. #\n"
- "############################################################\n"
- "\n"
- "############################################################\n"
- "# #\n"
- "# Game Mode #\n"
- "# #\n"
- "# Parameter: play_through_list (Boolean) #\n"
- "# Default: 1 #\n"
- "# #\n"
- "# Tuxmath generates a list of math questions based on #\n"
- "# parameters set below. By default, (play_through_list = #\n"
- "# 1) the questions are asked in a random order. #\n"
- "# Correctly answered questions are removed from the list. #\n"
- "# If the player fails to correctly answer a question #\n"
- "# before it hits a city, the question will be reinserted #\n"
- "# into the list in a random location. #\n"
- "# The player wins if all questions are answered correctly #\n"
- "# before the cities are destroyed. #\n"
- "# #\n"
- "# Alternatively, Tuxmath can be played in 'Arcade Mode' #\n"
- "# by setting play_through_list = 0 (i.e. 'false'). If this #\n"
- "# is done, all questions will be randomly reinserted into #\n"
- "# the list whether or not they are answered correctly, and #\n"
- "# the game continues as long as there is a surviving city. #\n"
- "############################################################\n"
- "\n";
-
- vcomments[ADDITION_ALLOWED] =
- "\n############################################################\n"
- "# #\n"
- "# Selecting Math Operations #\n"
- "# #\n"
- "# Parameter: addition_allowed (boolean) #\n"
- "# Default: 1 #\n"
- "# Parameter: subtraction_allowed (boolean) #\n"
- "# Default: 1 #\n"
- "# Parameter: multiplication_allowed (boolean) #\n"
- "# Default: 1 #\n"
- "# Parameter: division_allowed (boolean) #\n"
- "# Default: 1 #\n"
- "# #\n"
- "# These options enable questions for each of the four math #\n"
- "# operations. All are 1 (yes) by default. #\n"
- "############################################################\n\n";
- vcomments[TYPING_PRACTICE_ALLOWED] =
- "\n############################################################\n"
- "# #\n"
- "# Typing Practice #\n"
- "# #\n"
- "# Parameter: typing_practice_allowed (boolean) #\n"
- "# Default: 0 #\n"
- "# #\n"
- "# This option simply displays numbers for the youngest #\n"
- "# players to type in to learn the keyboard. #\n"
- "############################################################\n\n";
- vcomments[ALLOW_NEGATIVES] =
- "\n############################################################\n"
- "# #\n"
- "# Negative Number Support #\n"
- "# #\n"
- "# Parameter: allow_negatives (boolean) #\n"
- "# Default: 0 #\n"
- "# #\n"
- "# 'allow_negatives' allows or disallows use of negative #\n"
- "# numbers as both operands and answers. Default is 0 #\n"
- "# (no), which disallows questions like: #\n"
- "# 2 - 4 = ? #\n"
- "# Note: this option must be enabled in order to set the #\n"
- "# operand ranges to include negatives. If it is changed #\n"
- "# from 1 (yes) to 0 (no), any negative operand limits will #\n"
- "# be reset to 0. #\n"
- "############################################################\n\n";
- vcomments[MIN_AUGEND] =
- "\n############################################################\n"
- "# #\n"
- "# Minimum and Maximum Values for Operand Ranges #\n"
- "# #\n"
- "# Parameters: (multiple - all integer type) #\n"
- "# #\n"
- "# Operand limits can be set to any integer up to the #\n"
- "# value of 'max_answer'. Tuxmath will generate questions #\n"
- "# for every value in the specified range. The maximum must #\n"
- "# be greater than or equal to the corresponding minimum #\n"
- "# for any questions to be generated for that operation. #\n"
- "# Defaults are 0 for minima and 12 for maxima. #\n"
- "# #\n"
- "# Note: 'allow_negatives' must be set to 1 for negative #\n"
- "# values to be accepted (see 'Advanced Options'). #\n"
- "############################################################\n"
- "\n# Addition operands:\n"
- "# augend + addend = sum\n\n";
- vcomments[MIN_MINUEND] =
- "\n# Subtraction operands:\n"
- "# minuend - subtrahend = difference\n\n";
- vcomments[MIN_MULTIPLIER] =
- "\n# Multiplication operands:\n"
- "# multiplier * multiplicand = product\n\n";
- vcomments[MIN_DIVISOR] =
- "\n# Division operands:\n"
- "# dividend / divisor = quotiend\n\n";
- vcomments[MIN_TYPING_NUM] =
- "\n# Typing practice:\n";
- vcomments[QUESTION_COPIES] =
- "\n\n\n############################################################\n"
- "# #\n"
- "# Advanced Options #\n"
- "# #\n"
- "# The remaining settings further customize Tuxmath's #\n"
- "# behavior. Most users will probably not change them. #\n"
- "############################################################\n\n"
-
- "\n############################################################\n"
- "# #\n"
- "# Advanced Math Question List Options #\n"
- "# #\n"
- "# Parameter: question_copies (integer) #\n"
- "# Default: 1 #\n"
- "# Parameter: repeat_wrongs (boolean) #\n"
- "# Default: 1 #\n"
- "# Parameter: copies_repeated_wrongs (integer) #\n"
- "# Default: 1 #\n"
- "# Parameter: fraction_to_keep (float) #\n"
- "# Default: 1 #\n"
- "# #\n"
- "# These settings offer further control over the question #\n"
- "# list and are generally only useful if 'play_through_list'#\n"
- "# is enabled (as it is by default). #\n"
- "# #\n"
- "# 'question_copies' is the number of times each question #\n"
- "# is put into the initial list. It can be 1 to 10. #\n"
- "# #\n"
- "# 'repeat_wrongs' determines whether questions the player #\n"
- "# failed to answer correctly will be asked again. #\n"
- "# #\n"
- "# 'copies_repeated_wrongs' gives the number of times a #\n"
- "# missed question will reappear. This can be set anywhere #\n"
- "# from 1 to 10. #\n"
- "# #\n"
- "# The defaults for these values result in a 'mission' #\n"
- "# for Tux that is accomplished by answering all #\n"
- "# questions correctly with at least one surviving city. #\n"
- "############################################################\n\n";
- vcomments[FORMAT_ADD_ANSWER_LAST] =
- "\n############################################################\n"
- "# #\n"
- "# Math Question Formats #\n"
- "# #\n"
- "# The 'format_<op>_answer_<place> options control #\n"
- "# generation of questions with the answer in different #\n"
- "# places in the equation. i.e.: #\n"
- "# #\n"
- "# format_add_answer_last: 2 + 2 = ? #\n"
- "# format_add_answer_first: ? + 2 = 4 #\n"
- "# format_add_answer_middle: 2 + ? = 4 #\n"
- "# #\n"
- "# By default, 'format_answer_first' is enabled and the #\n"
- "# other two formats are disabled. Note that the options #\n"
- "# are not mutually exclusive - the question list may #\n"
- "# contain questions with different formats. #\n"
- "# #\n"
- "# The formats are set independently for each of the four #\n"
- "# math operations. All parameters are type 'boolean'. #\n"
- "############################################################\n\n";
- vcomments[MAX_ANSWER] =
- "\n############################################################\n"
- "# #\n"
- "# Parameter: max_answer (integer) #\n"
- "# Default: 999 #\n"
- "# #\n"
- "# 'max_answer' is the largest absolute value allowed in #\n"
- "# any value in a question (not only the answer). Default #\n"
- "# is 999, which is as high as it can be set. It can be set #\n"
- "# lower to fine-tune the list for certain 'lessons'. #\n"
- "############################################################\n\n";
- vcomments[MAX_QUESTIONS] =
- "\n############################################################\n"
- "# #\n"
- "# Parameter: max_questions (integer) #\n"
- "# Default: 5000 #\n"
- "# #\n"
- "# 'max_questions' is limit of the length of the question #\n"
- "# list. Default is 5000 - only severe taskmasters will #\n"
- "# need to raise it! #\n"
- "############################################################\n\n";
- vcomments[RANDOMIZE] =
- "\n############################################################\n"
- "# #\n"
- "# Parameter: randomize (boolean) #\n"
- "# Default: 1 #\n"
- "# #\n"
- "# If 'randomize' selected, the list will be shuffled #\n"
- "# at the start of the game. Otherwise, the questions #\n"
- "# appear in the order the program generates them. #\n"
- "############################################################\n\n";
-
- }
- 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");
- DEBUGMSG(debug_fileops, "Leaving write_config_file()\n");
- return 0;
- }
-
- for (i = 0; i < NOPTS; ++i) //for each option
- {
- if (verbose && vcomments[i]) //comment goes before
- fprintf(fp, "%s", vcomments[i]);
- fprintf(fp, "%s = %d\n", MC_OPTION_TEXT[i], MC_GetOpt(i) );
- }
-
- if (verbose)
- {
- //allow_speedup comment
- }
- fprintf(fp, "allow_speedup = %d\n", Opts_AllowSpeedup() );
-
- if (verbose)
- {
- //use_sound comment
- }
- fprintf(fp, "use_sound = %d\n", Opts_GetGlobalOpt(USE_SOUND) );
-
- if (verbose)
- {
- fprintf (fp, "\n############################################################\n"
- "# #\n"
- "# Advanced Comet Speed Options #\n"
- "# #\n"
- "# Parameter: starting_comets (integer) #\n"
- "# Default: 2 #\n"
- "# Parameter: extra_comets_per_wave (integer) #\n"
- "# Default: 2 #\n"
- "# Parameter: max_comets (integer) #\n"
- "# Default: 10 #\n"
- "# Parameter: speed (float) #\n"
- "# Default: 1.00 #\n"
- "# Parameter: max_speed (float) #\n"
- "# Default: 10.00 #\n"
- "# Parameter: speedup_factor (float) #\n"
- "# Default: 1.20 #\n"
- "# Parameter: bonus_comet_interval (integer) #\n"
- "# Default: 10 #\n"
- "# Parameter: bonus_speed_ratio (float) #\n"
- "# Default: 1.50 #\n"
- "# Parameter: slow_after_wrong (bool) #\n"
- "# Default: 0 #\n"
- "# #\n"
- "# (for 'feedback' speed control system): #\n"
- "# Parameter: danger_level (float) #\n"
- "# Default: 0.35 #\n"
- "# Parameter: danger_level_speedup (float) #\n"
- "# Default: 1.1 #\n"
- "# Parameter: danger_level_max (float) #\n"
- "# Default: 0.9 #\n"
- "# Parameter: city_explode_handicap (float) #\n"
- "# Default: 0 #\n"
- "# #\n"
- "# The comet number parameters and initial/max speed apply #\n"
- "# whether or not the feedback system is activated. #\n"
- "# #\n"
- "# 'speedup_factor' and 'slow_after_wrong' only apply if #\n"
- "# feedback is not activated. #\n"
- "# #\n"
- "# The 'danger_level_*' and 'city_explode_handicap' #\n"
- "# parameters are only used if feedback is activated. #\n"
- "############################################################\n\n");
- }
-
- if(verbose)
- {
- fprintf (fp, "\n# Number of comets for first wave. Default is 2.\n");
- }
- fprintf(fp, "starting_comets = %d\n", Opts_StartingComets());
-
- if(verbose)
- {
- fprintf (fp, "\n# Comets to add for each successive wave. Default is 2.\n");
- }
- fprintf(fp, "extra_comets_per_wave = %d\n", Opts_ExtraCometsPerWave());
-
- if(verbose)
- {
- fprintf (fp, "\n# Maximum number of comets. Default is 10.\n");
- }
- fprintf(fp, "max_comets = %d\n", Opts_MaxComets());
-
- if(verbose)
- {
- fprintf (fp, "\n# Starting comet speed. Default is 1.\n");
- }
- fprintf(fp, "speed = %.2f\n", Opts_Speed());
-
- if(verbose)
- {
- fprintf (fp, "\n# Maximum speed. Default is 10.\n");
- }
- fprintf(fp, "max_speed = %.2f\n", Opts_MaxSpeed());
-
- if(verbose)
- {
- fprintf (fp, "\n# 'speedup_factor': If feedback is not used but \n"
- "# 'allow_speedup' is enabled, the comet speed will be\n"
- "# multiplied by this factor with each new wave.\n"
- "# Values from 0.5 to 2 are accepted (note that a \n"
- "# value less than 1 causes the comets to be \n"
- "# slower with each wave!).\n"
- "# Default is 1.2 (i.e. 20 percent increase per wave)\n\n");
- }
- fprintf(fp, "speedup_factor = %.2f\n", Opts_SpeedupFactor());
-
-
- if(verbose)
- {
- fprintf (fp, "\n# 'bonus_comet_interval' controls how frequently\n"
- "# special comets appear that cause a igloo to be \n"
- "# rebuilt if answered correctly. The bonus comet \n"
- "# appears after this number of regular comets (a \n"
- "# value of 0 disables bonus comets). Default is 10. \n");
- }
- fprintf(fp, "bonus_comet_interval = %d\n", Opts_BonusCometInterval());
-
-
- if(verbose)
- {
- fprintf (fp, "\n# 'bonus_speed_ratio' determines how fast the\n"
- "# bonus comets fall relative to the regular comets.\n"
- "# Range 1.0 - 3.0, default 1.5:\n");
- }
- fprintf(fp, "bonus_speed_ratio = %.2f\n", Opts_BonusSpeedRatio());
-
-
- if(verbose)
- {
- fprintf (fp, "\n# 'slow_after_wrong' tells Tuxmath to go back to \n"
- "# starting speed and number of comets if the player misses \n"
- "# a question. Useful for smaller kids. Default is 0.\n\n");
- }
-
- fprintf(fp, "slow_after_wrong = %d\n", Opts_SlowAfterWrong());
-
-
- if(verbose)
- {
- fprintf (fp, "\n# (Feedback) Set the desired danger level.\n"
- "# 0 = too safe, comets typically exploded at the very top\n"
- "# 1 = too dangerous, comets typically exploded as they\n"
- "# hit cities. Set it somewhere between these extremes. As\n"
- "# a guideline, early elementary kids might prefer\n"
- "# 0.2-0.3, older kids at around 0.4-0.6. Default 0.35.\n\n");
- }
- fprintf(fp, "danger_level = %.2f\n", Opts_DangerLevel());
-
- if(verbose)
- {
- fprintf (fp, "\n# (Feedback) Set danger level speedup.\n"
- "# The margin of safety will decrease by this factor each\n"
- "# wave. Default 1.1. Note 1 = no increase in danger level.\n\n");
- }
- fprintf(fp, "danger_level_speedup = %.2f\n", Opts_DangerLevelSpeedup());
-
- if(verbose)
- {
- fprintf (fp, "\n# (Feedback) Set the maximum danger level.\n"
- "# Default 0.9.\n");
- }
- fprintf(fp, "danger_level_max = %.2f\n", Opts_DangerLevelMax());
-
- if (verbose)
- {
- fprintf (fp, "\n# (Feedback) Set the handicap for hitting cities.\n"
- "# When bigger than 0, this causes the game to slow down\n"
- "# by an extra amount after a wave in which one or more\n"
- "# cities get hit. Note that this is similar to\n"
- "# 'slow_after_wrong', but allows for more gradual\n"
- "# changes. Default 0 (no extra handicap).\n\n");
- }
- fprintf(fp, "city_explode_handicap = %.2f\n", Opts_CityExplHandicap());
-
- if(verbose)
- {
- fprintf (fp, "\n\n############################################################\n"
- "# #\n"
- "# Managing User Settings #\n"
- "# #\n"
- "# Parameter: per_user_config (boolean) #\n"
- "# Default: 1 #\n"
- "# Parameter: homedir (string) #\n"
- "# Default: <none supplied> #\n"
- "# #\n"
- "# 'per_user_config' determines whether Tuxmath will look #\n"
- "# in the user's home directory for settings. Default is 1 #\n"
- "# (yes). If set to 0, the program will ignore the user's #\n"
- "# .tuxmath file and use the the global settings in the #\n"
- "# installation-wide config file. #\n"
- "# #\n"
- "# 'homedir' allows you to specify the location to look for #\n"
- "# user home directories. You probably do not want to #\n"
- "# specify this unless all users share the same login #\n"
- "# account. See the README for details on configuration. #\n"
- "# To enable this feature, remove the '#' comment mark and #\n"
- "# set the path as desired. #\n"
- "# #\n"
- "# These settings cannot be changed by an ordinary user, as #\n"
- "# they are ignored unless the config file is Tuxmath's #\n"
- "# global config file. Thus, users cannot 'lock themselves #\n"
- "# out' by accidentally setting per_user_config to 0. #\n"
- "############################################################\n\n");
- }
- fprintf(fp, "per_user_config = %d\n", Opts_GetGlobalOpt(PER_USER_CONFIG));
- fprintf(fp, "# homedir = /servervolume/tuxmath_users\n");
-
-
- /* print general game options (passing '1' as second arg causes */
- /* "help" info for each option to be written to file as comments) */
-// print_game_options(fp, 1);
- /* print options pertaining to math questions from MathCards: */
-// MC_PrintMathOptions(fp, 1);
-
DEBUGMSG(debug_fileops, "Leaving write_config_file()\n");
return 1;
}
-
-/* write_pregame_summary() and write_postgame_summary() are used to */
-/* record data about the player's game to file for review (perhaps by */
-/* teacher). write_pregame_summary() is called at the start of each */
-/* game and records the question list along with identifying data. It */
-/* also rotates old game summaries to successive filenames, keeping */
-/* the last ten summaries for review. write_postgame_summary() */
-/* the list of questions that were not answered correctly and */
-/* calculates the percent correct. */
-int write_pregame_summary(void)
-{
- int i;
- FILE* fp;
- 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())
- {
- fprintf(stderr, "\nCould not find or create tuxmath dir\n");
- return 0;
- }
-
-
-
- /* Rotate filenames of old summaries, oldest summary if present */
- /* and leaving summary1 available for current game: */
-
- /* find $HOME and tack on file name: */
- get_user_data_dir_with_subdir(filepath1);
- strcat(filepath1, summary_filenames[NUM_SUMMARIES - 1]);
-
- fp = fopen(filepath1, "r");
- if (fp)
- {
- DEBUGMSG(debug_fileops,"\nIn write_pregame_summary() - removing oldest summary file\n")
-
- fclose(fp);
- remove(filepath1);
- }
-
- /* Now shift each old file back by one: */
- /* 'filepath1' is the old name for each file, */
- /* 'filepath2' is the new name (i.e. we go from i - 1 to i). */
- for (i = NUM_SUMMARIES - 1; i > 0; i--)
- {
- /* old filename: */
- get_user_data_dir_with_subdir(filepath1);
- strcpy(filepath2,filepath1);
- strcat(filepath1, summary_filenames[i - 1]);
- /* new filename: */
- strcat(filepath2, summary_filenames[i]);
- /* now change the name: */
- rename(filepath1, filepath2);
- }
-
- /* summary_filenames[0] (i.e. 'summary1') should now be vacant: */
- get_user_data_dir_with_subdir(filepath1);
- strcat(filepath1, summary_filenames[0]);
-
- fp = fopen(filepath1, "w"); /* "w" means start writing with empty file */
- if (fp)
- {
- /* Write header and identifying data for summary file: */
- fprintf(fp, "************************\n"
- "* Tuxmath Game Summary *\n"
- "************************\n");
- if (add_subdir)
- {
- /* Identify user by login if we're not in a multiuser configuration */
- fprintf(fp, "\nPlayer: %s\n", getenv("USER"));
- }
- else {
- /* Identify user by the directory name.*/
- fprintf(fp, "\nPlayer: %s\n", get_user_name());
- }
-
- fprintf(fp, "\nMission: %s\n", last_config_file_name);
-
- /* Write question list: */
- fprintf(fp, "\nStarting Question List:");
- MC_PrintQuestionList(fp);
- 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;
- }
-}
-
-int write_postgame_summary(void)
-{
- FILE *fp;
- char filepath1[PATH_MAX];
- int total_answered;
- float median_time;
- int success = 1;
- int write_column_names = 0;
- time_t filetime;
- struct stat filestat;
- struct tm datetime;
- char *mission_name;
-
- get_user_data_dir_with_subdir(filepath1);
- strcat(filepath1, summary_filenames[0]);
-
- total_answered = MC_NumAnsweredCorrectly() + MC_NumNotAnsweredCorrectly();
- median_time = MC_MedianTimePerQuestion();
-
- fp = fopen(filepath1, "a"); /* "a" means append to end of file */
- if (fp)
- {
- /* Write list of questions missed: */
- fprintf(fp, "\n\n\nList Of Questions Not Answered Correctly:");
- MC_PrintWrongList(fp);
- fprintf(fp, "\n\nNumber Of Distinct Questions Not Answered Correctly: %d",
- MC_WrongListLength());
-
- /* Write post-game statistics: */
-
- fprintf(fp, "\n\nSummary:\n");
- fprintf(fp, "Questions Answered:\t%d\n", total_answered);
- fprintf(fp, "Questions Correct:\t%d\n",
- MC_NumAnsweredCorrectly());
- fprintf(fp, "Questions Missed:\t%d\n",
- MC_NumNotAnsweredCorrectly());
- /* Avoid divide-by-zero errror: */
- if (total_answered)
- {
- fprintf(fp, "Percent Correct:\t%d %%\n",
- ((MC_NumAnsweredCorrectly() * 100)/ total_answered) );
- }
- else
- fprintf(fp, "Percent Correct: (not applicable)\n");
-
- fprintf(fp,"Median Time/Question:\t%g\n",median_time);
-
- fprintf(fp, "Mission Accomplished:\t");
- if (MC_MissionAccomplished())
- {
- fprintf(fp, "Yes!\n\n8^)\n");
- }
- else
- {
- fprintf(fp, "No.\n\n:^(\n");
- }
-
- fclose(fp);
- }
- else /* Couldn't write file for some reason: */
- {
- fprintf(stderr,"Summary not written.\n");
- success = 0;
- }
-
- /* Append brief summary to log */
- if (total_answered > 0) {
- /* We're going to want to write the date. Use the filetime */
- /* rather than calling "time" directly, because "time" */
- /* returns the time according to whatever computer is */
- /* running tuxmath, and in a server/client mode it's likely */
- /* that some of the clients' clocks may be wrong. Use */
- /* instead the time according to the server on which the */
- /* accounts are stored, which can be extracted from the */
- /* modification time of the summary we just wrote. */
- if (stat(filepath1,&filestat) == 0) {
- filetime = filestat.st_mtime;
- } else {
- filetime = time(NULL);
- }
- localtime_r(&filetime,&datetime); /* generate broken-down time */
-
- get_user_data_dir_with_subdir(filepath1);
- strcat(filepath1, "log.csv");
- /* See whether the log file already exists; if not, write */
- /* the column names */
- fp = fopen(filepath1, "r");
- if (fp == NULL)
- write_column_names = 1;
- else
- fclose(fp);
-
- fp = fopen(filepath1, "a"); /* "a" means append to end of file */
- if (fp) {
- if (write_column_names) {
- fprintf(fp,"\"User\",\"Mission\",\"Date\",\"Completed?\",\"Number answered\",\"Percent correct\",\"Time per question\"\n");
- }
- if (last_config_file_name)
- mission_name = strdup(last_config_file_name);
- else
- mission_name = strdup("[NONE]");
- fprintf(fp,"\"%s\",\"%s\",%d/%d/%d,%d,%d,%d,%g\n", get_user_name(), get_file_name(mission_name), datetime.tm_year+1900, datetime.tm_mon+1, datetime.tm_mday, MC_MissionAccomplished(), total_answered, ((MC_NumAnsweredCorrectly() * 100)/ total_answered), median_time);
- fclose(fp);
- free(mission_name);
- } else
- success = 0;
- }
- return success;
-}
-
-
-
/* Checks to see if user's .tuxmath directory exists and, if not, tries */
/* to create it. Returns 1 if .tuxmath dir found or successfully created */
static int find_tuxmath_dir(void)
diff --git a/src/game.c b/src/game.c
index 287a851..05afa35 100644
--- a/src/game.c
+++ b/src/game.c
@@ -32,204 +32,28 @@
#include "SDL_mixer.h"
#endif
-/* Make sure we don't try to call network code if we built without */
-/* network support: */
-#ifdef HAVE_LIBSDL_NET
-#include "network.h"
-#endif
-
#include "transtruct.h"
#include "game.h"
#include "fileops.h"
#include "setup.h"
#include "loaders.h"
-#include "mathcards.h"
-#include "multiplayer.h"
#include "titlescreen.h"
#include "options.h"
#include "SDL_extras.h"
#include "pixels.h"
-#include "throttle.h"
#define FPS 15 /* 15 frames per second */
#define MS_PER_FRAME (1000 / FPS)
-#define CITY_EXPL_START (3 * 5) /* Must be mult. of 5 (number of expl frames) */
-#define ANIM_FRAME_START (4 * 2) /* Must be mult. of 2 (number of tux frames) */
-#define GAMEOVER_COUNTER_START 40
-#define LEVEL_START_WAIT_START 20
-#define LASER_START 5
-#define FLAPPING_START 12
-#define FLAPPING_INTERVAL 500
-#define STEAM_START 15
-#define IGLOO_SWITCH_START 8
-#define STANDING_COUNTER_START 8
-#define EVAPORATING_COUNTER_START 100
-
-#define PENGUIN_WALK_SPEED 3
-#define SNOWFLAKE_SPEED 6
-#define SNOWFLAKE_SEPARATION 3
-
-const int SND_IGLOO_SIZZLE = SND_SIZZLE;
-const int IMG_CITY_NONE = 0;
-
-typedef struct comet_type {
- int alive;
- int expl;
- int city;
- float x, y;
- int answer;
- int bonus;
- int zapped;
- MC_FlashCard flashcard;
- Uint32 time_started;
-} comet_type;
-
-/* Local (to game.c) 'globals': */
-
-static int gameover_counter;
-static int game_status;
-static int user_quit_received;
-static int total_questions_left;
-static int paused;
-static int wave;
-static int score;
-static int pre_wave_score;
-static int prev_wave_comets;
-static int slowdown;
-static int num_attackers;
-static float speed;
-static int demo_countdown;
-static int tux_anim;
-static int tux_anim_frame;
-static int num_cities_alive;
-static int tux_img;
-static int old_tux_img;
-static int frame;
-static int neg_answer_picked;
-static int tux_pressing;
-static int doing_answer;
-static int level_start_wait;
-static int last_bkgd;
-static int igloo_vertical_offset;
-//static int extra_life_counter;
-static int bonus_comet_counter;
-static int extra_life_earned;
-static int key_pressed;
-static int game_over_other;
-static int game_over_won;
-
-/* Feedback-related variables */
-static int city_expl_height;
-static int comet_feedback_number;
-static float comet_feedback_height;
-static float danger_level;
-
-static int digits[MC_MAX_DIGITS];
-
-static comet_type* comets = NULL;
-static city_type* cities = NULL;
-static penguin_type* penguins = NULL;
-static steam_type* steam = NULL;
-
-static cloud_type cloud;
-static laser_type laser;
static SDL_Surface* bkgd = NULL; //640x480 background (windowed)
static SDL_Surface* scaled_bkgd = NULL; //native resolution (fullscreen)
-static SDL_Surface* current_bkgd()
- { return screen->flags & SDL_FULLSCREEN ? scaled_bkgd : bkgd; }
-
-static game_message s1, s2, s3, s4, s5;
-static int start_message_chosen = 0;
-
-/*****************************************************************/
-MC_FlashCard quest_queue[QUEST_QUEUE_SIZE]; //current questions
-int remaining_quests = 0;
-static int comet_counter = 0;
-static int lan_players = 0;
-char lan_pnames[MAX_CLIENTS][NAME_SIZE];
-int lan_pscores[MAX_CLIENTS];
-/****************************************************************/
-
-typedef struct {
- int x_is_blinking;
- int extra_life_is_blinking;
- int laser_enabled;
-} help_controls_type;
-static help_controls_type help_controls;
-
-/* Local function prototypes: */
-static int game_initialize(void);
-static void game_cleanup(void);
-static void game_handle_help(void);
-static void game_handle_user_events(void);
-static void game_handle_demo(void);
-static void game_handle_answer(void);
-static void game_countdown(void);
-static void game_handle_tux(void);
-static void game_handle_comets(void);
-static void game_handle_cities(void);
-static void game_handle_penguins(void);
-static void game_handle_steam(void);
-static void game_handle_extra_life(void);
-static void game_draw(void);
-static void game_draw_background(void);
-static void game_draw_comets(void);
-static void game_draw_cities(void);
-static void game_draw_misc(void);
-
-static int check_extra_life(void);
-static int check_exit_conditions(void);
-
-static void game_set_message(game_message*, const char* ,int x, int y);
-static void game_clear_message(game_message*);
-static void game_clear_messages(void);
-void game_write_message(const game_message* msg);
-static void game_write_messages(void);
-static void draw_led_console(void);
-static void draw_question_counter(void);
-static void draw_console_image(int i);
-
-static void reset_level(void);
-static int add_comet(void);
-static void add_score(int inc);
-static void reset_comets(void);
-static int num_comets_alive(void);
-
-static void game_mouse_event(SDL_Event event);
-static void game_key_event(SDLKey key, SDLMod mod);
-static void free_on_exit(void);
-
-static void help_add_comet(const char* formula_str, const char* ans_str);
-static int help_renderframe_exit(void);
-static void game_recalc_positions(void);
-
-void putpixel(SDL_Surface* surface, int x, int y, Uint32 pixel);
-
-/*****************************************************/
-#ifdef HAVE_LIBSDL_NET
-void game_handle_net_messages(void);
-void game_handle_net_msg(char* buf);
-int add_quest_recvd(char* buf);
-int remove_quest_recvd(char* buf);
-int connected_players_recvd(char* buf);
-int update_score_recvd(char* buf);
-int erase_comet_on_screen(comet_type* comet_ques);
-MC_FlashCard* search_queue_by_id(int id);
-comet_type* search_comets_by_id(int id);
-/******************************************************/
-#endif
-
-void print_current_quests(void);
-
-static void print_exit_conditions(void);
-static void print_status(void);
-
-
-/* --- MAIN GAME FUNCTION!!! --- */
+static SDL_Surface* current_bkgd()
+ {
+ return screen->flags & SDL_FULLSCREEN ? scaled_bkgd : bkgd;
+ }
int game(void)
{
@@ -243,3714 +67,4 @@ int game(void)
;//SwitchScreenMode(); //Huh??
}
-
- /* most code moved into smaller functions (game_*()): */
- if (!game_initialize())
- {
- fprintf(stderr, "\ngame_initialize() failed!");
- return 0;
- }
-
-
- if (Opts_HelpMode()) {
- game_handle_help();
- game_cleanup();
- return GAME_OVER_OTHER;
- }
-
-
-
- /* --- MAIN GAME LOOP: --- */
- do
- {
- /* reset or increment various things with each loop: */
- frame++;
- old_tux_img = tux_img;
- tux_pressing = 0;
-
- if (laser.alive > 0)
- {
- laser.alive--;
- }
-
- /* Check for server messages if we are playing a LAN game: */
-#ifdef HAVE_LIBSDL_NET
- if(Opts_LanMode())
- {
- game_handle_net_messages();
- }
-#endif
- /* Most code now in smaller functions: */
-
- // 1. Check for user input
- game_handle_user_events();
- // 2. Update state of various game elements
- game_handle_demo();
- game_handle_answer();
- game_countdown();
- game_handle_tux();
- game_handle_comets();
- game_handle_cities();
- game_handle_penguins();
- game_handle_steam();
- game_handle_extra_life();
- // 3. Redraw:
- game_draw();
- // 4. Figure out if we should leave loop:
- game_status = check_exit_conditions();
-
- /* If we're in "PAUSE" mode, pause! */
- if (paused)
- {
- pause_game();
- paused = 0;
- }
-
- /* Keep playing music: */
-
-#ifndef NOSOUND
- if (Opts_UsingSound())
- {
- if (!Mix_PlayingMusic())
- {
- Mix_PlayMusic(musics[MUS_GAME + (rand() % 3)], 0);
- }
- }
-#endif
-
-
- /* Pause (keep frame-rate event) */
- Throttle(MS_PER_FRAME, &timer);
-
- }
- while(GAME_IN_PROGRESS == game_status);
- /* END OF MAIN GAME LOOP! */
-
-
- DEBUGCODE(debug_game) print_exit_conditions();
-
- /* TODO: need better "victory" screen with animation, special music, etc., */
- /* as well as options to review missed questions, play again using missed */
- /* questions as question list, etc. */
- switch (game_status)
- {
- 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++;
-
- while (SDL_PollEvent(&event) > 0)
- {
- if (event.type == SDL_QUIT
- || event.type == SDL_KEYDOWN
- || event.type == SDL_MOUSEBUTTONDOWN)
- {
- looping = 0;
- }
- }
-
- if (current_bkgd() )
- SDL_BlitSurface(current_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_BASH);
- /* 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);
- Throttle(MS_PER_FRAME, &timer);
- }
- while (looping);
- break;
- }
-
- case GAME_OVER_ERROR:
- DEBUGMSG(debug_game, "game() exiting with error:\n");
- case GAME_OVER_LOST:
- case GAME_OVER_OTHER:
- {
- 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++;
-
- while (SDL_PollEvent(&event) > 0)
- {
- if (event.type == SDL_QUIT
- || event.type == SDL_KEYDOWN
- || event.type == SDL_MOUSEBUTTONDOWN)
- {
- looping = 0;
- }
- }
-
- SDL_BlitSurface(images[IMG_GAMEOVER], NULL, screen, &dest_message);
- SDL_Flip(screen);
-
- Throttle(MS_PER_FRAME, &timer);
- }
- while (looping);
-
- break;
- }
-
- case GAME_OVER_ESCAPE:
- {
- break;
- }
-
- case GAME_OVER_WINDOW_CLOSE:
- {
- break;
- }
-
- }
-
- game_cleanup();
-
- /* Write post-game info to game summary file: */
- if (Opts_SaveSummary())
- {
- write_postgame_summary();
- }
-
- /* Save score in case needed for high score table: */
- Opts_SetLastScore(score);
-
- /* Return the chosen command: */
- if (GAME_OVER_WINDOW_CLOSE == game_status)
- {
- /* program exits: */
- cleanup();
- DEBUGMSG(debug_game, "Leaving game() from window close\n");
- return 1;
- }
- else
- {
- /* return to title() screen: */
- DEBUGMSG(debug_game, "Leaving game() normally\n");
- return game_status;
- }
-}
-
-
-
-
-
-
-#ifdef HAVE_LIBSDL_NET
-/***************** Functions for LAN support *****************/
-
-/*Examines the network messages from the buffer and calls
- appropriate function accordingly*/
-
-void game_handle_net_messages(void)
-{
- char buf[NET_BUF_LEN];
- int done = 0;
- while(!done)
- {
- switch(LAN_NextMsg(buf))
- {
- case 1: //Message received (e.g. a new question):
- game_handle_net_msg(buf);
- break;
- case 0: //No more messages:
- done = 1;
- break;
- case -1: //Error in networking or server:
- game_cleanup();
- game_status = GAME_OVER_ERROR;
- default:
- {}
- }
- }
-}
-
-
-void game_handle_net_msg(char* buf)
-{
- DEBUGMSG(debug_lan, "Received server message: %s\n", buf);
-
- if(strncmp(buf, "PLAYER_MSG", strlen("PLAYER_MSG")) == 0)
- {
- DEBUGMSG(debug_lan, "buf is %s\n", buf);
- }
-
- else if(strncmp(buf, "ADD_QUESTION", strlen("ADD_QUESTION")) == 0)
- {
- if(!add_quest_recvd(buf))
- printf("ADD_QUESTION received but could not add question\n");
- else
- DEBUGCODE(debug_game) print_current_quests();
- }
-
- else if(strncmp(buf, "REMOVE_QUESTION", strlen("REMOVE_QUESTION")) == 0)
- {
- if(!remove_quest_recvd(buf)) //remove the question with id in buf
- printf("REMOVE_QUESTION received but could not remove question\n");
- else
- DEBUGCODE(debug_game) print_current_quests();
- }
-
- else if(strncmp(buf, "TOTAL_QUESTIONS", strlen("TOTAL_QUESTIONS")) == 0)
- {
- sscanf(buf,"%*s %d", &total_questions_left);
- if(!total_questions_left)
- game_over_other = 1;
- }
-
- else if(strncmp(buf, "CONNECTED_PLAYERS", strlen("CONNECTED_PLAYERS")) == 0)
- {
- connected_players_recvd(buf);
- }
-
- else if(strncmp(buf, "UPDATE_SCORE", strlen("UPDATE_SCORE")) == 0)
- {
- update_score_recvd(buf);
- }
-
- else if(strncmp(buf, "MISSION_ACCOMPLISHED", strlen("MISSION_ACCOMPLISHED")) == 0)
- {
- game_over_won = 1;
- }
- else
- {
- DEBUGMSG(debug_game, "Unrecognized message from server: %s\n", buf);
- }
-}
-
-
-int add_quest_recvd(char* buf)
-{
- /* Empty slots indicated by question_id == -1 */
- MC_FlashCard* fc = search_queue_by_id(-1);
-
- DEBUGMSG(debug_game, "Enter add_quest_recvd(), buf is: %s\n", buf);
-
- // if fc = NULL means no empty slot for question
- if(!buf)
- {
- printf("NULL buf\n");
- return 0;
- }
-
- if(!fc)
- {
- printf("NULL fc - no empty slot for question\n");
- return 0;
- }
-
- /* function call to parse buffer and receive question */
- if(!Make_Flashcard(buf, fc))
- {
- printf("Unable to parse buffer into FlashCard\n");
- return 0;
- }
-
- DEBUGCODE(debug_game) print_current_quests();
-
- /* If we have an open comet slot, put question in: */
-
- if(num_attackers > 0)
- if(add_comet())
- num_attackers--;
-
- return 1;
-}
-
-
-int remove_quest_recvd(char* buf)
-{
- int id = 0;
- char* p = NULL;
- MC_FlashCard* fc = NULL;
- comet_type* comet_screen;
-
- if(!buf)
- return 0;
-
- p = strchr(buf, '\t');
- if(!p)
- return 0;
-
- p++;
- id = atoi(p);
-
- DEBUGMSG(debug_game, "remove_quest_recvd() for id = %d\n", id);
-
- if(id < 1) // The question_id can never be negative or zero
- return 0;
-
- comet_screen = search_comets_by_id(id);
- fc = search_queue_by_id(id);
- if(!comet_screen && !fc)
- return 0;
-
- if(comet_screen)
- {
- DEBUGMSG(debug_game, "comet on screen found with question_id = %d\n", id);
- erase_comet_on_screen(comet_screen);
- }
-
- //NOTE: normally the question should no longer be in the queue,
- //so the next statement should not get executed:
- if(fc)
- {
- DEBUGMSG(debug_game,
- "Note - request to erase question still in queue: %s\n",
- fc->formula_string);
- MC_ResetFlashCard(fc);
- }
-
- return 1;
-}
-
-
-/* Here we have been told how many LAN players are still */
-/* in the game. This should always be followed by a series */
-/* of UPDATE_SCORE messages, each with the name and score */
-/* of a player. We clear out the array to get rid of anyone */
-/* who has disconnected. */
-int connected_players_recvd(char* buf)
-{
- int n = 0;
- int i = 0;
- char* p = NULL;
-
- if(!buf)
- return 0;
-
- p = strchr(buf, '\t');
- if(!p)
- return 0;
- p++;
- n = atoi(p);
-
- DEBUGMSG(debug_game, "connected_players_recvd() for n = %d\n", n);
-
- if(n < 0 || n > MAX_CLIENTS)
- {
- fprintf(stderr, "connected_players_recvd() - illegal value: %d\n", n);
- return -1;
- }
- lan_players = n;
-
- /* Reset array - we should be getting new values in immediately */
- /* following messages. */
- for(i = 0; i < MAX_CLIENTS; i++)
- {
- lan_pnames[i][0] = '\0';
- lan_pscores[i] = -1;
- }
- return n;
-}
-
-/* Receive the name and current score of a currently-connected */
-/* LAN player. */
-int update_score_recvd(char* buf)
-{
- int i = 0;
- char* p = NULL;
-
- if(buf == NULL)
- return 0;
- // get i:
- p = strchr(buf, '\t');
- if(!p)
- return 0;
- p++;
- i = atoi(p);
-
- //get name:
- p = strchr(p, '\t');
- if(!p)
- return 0;
- p++;
- strncpy(lan_pnames[i], p, NAME_SIZE);
- //This has most likely copied the score field as well, so replace the
- //tab delimiter with a null to terminate the string:
- {
- char* p2 = strchr(lan_pnames[i], '\t');
- if (p2)
- *p2 = '\0';
- }
-
- //Now get score:
- p = strchr(p, '\t');
- if(p)
- lan_pscores[i] = atoi(p);
-
- DEBUGMSG(debug_lan, "update_score_recvd() - buf is: %s\n", buf);
- DEBUGMSG(debug_lan, "i is: %d\tname is: %s\tscore is: %d\n",
- i, lan_pnames[i], lan_pscores[i]);
-
- return 1;
-}
-
-/* Return a pointer to an empty comet slot, */
-/* returning NULL if no vacancy found: */
-
-MC_FlashCard* search_queue_by_id(int id)
-{
- int i = 0;
- for(i = 0; i < QUEST_QUEUE_SIZE; i++)
- {
- if(quest_queue[i].question_id == id)
- return &quest_queue[i];
- }
- //if we don't find a match:
- return NULL;
-}
-
-
-comet_type* search_comets_by_id(int id)
-{
- int i;
- for (i = 0; i < Opts_MaxComets(); i++)
- {
- if (comets[i].flashcard.question_id == id)
- {
- DEBUGMSG(debug_lan, "the question id is in slot %d\n", i);
- return &comets[i];
- }
- }
- // Didn't find it:
- return NULL;
-}
-
-
-
-int erase_comet_on_screen(comet_type* comet)
-{
- if(!comet)
- return 0;
- //setting expl to 0 starts comet explosion animation
- comet->expl = 0;
-
- //TODO consider more elaborate sound or animation
- playsound(SND_SIZZLE);
-
- return 1;
-}
-
-#endif
-
-/* Print the current questions and the number of remaining questions: */
-void print_current_quests(void)
-{
- int i;
- printf("\n------------ Current Questions: -----------\n");
- for(i = 0; i < Opts_MaxComets(); i++)
- {
- if(comets[i].alive == 1)
- printf("Comet %d - question %d:\t%s\n", i, comets[i].flashcard.question_id, comets[i].flashcard.formula_string);
-
- }
- printf("--------------Question Queue-----------------\n");
- for(i = 0; i < QUEST_QUEUE_SIZE; i++)
- {
- if(quest_queue[i].question_id != -1)
- printf("quest_queue %d - question %d:\t%s\n", i, quest_queue[i].question_id, quest_queue[i].formula_string);
- else
- printf("quest_queue %d:\tEmpty\n", i);
- }
- printf("------------------------------------------\n");
-}
-
-
-
-
-/*
-Set one to four lines of text to display at the game's start. Eventually
-this should stylishly fade out over the first few moments of the game.
-*/
-void game_set_start_message(const char* m1, const char* m2,
- const char* m3, const char* m4)
-{
- 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;
-}
-
-
-
-int game_initialize(void)
-{
- int i,img;
-
- DEBUGMSG(debug_game,"Entering game_initialize()\n");
-
- /* Clear window: */
- SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
- SDL_Flip(screen);
-
- game_status = GAME_IN_PROGRESS;
- gameover_counter = -1;
- user_quit_received = 0;
-
- /* Make sure we don't try to call network code if we built without */
- /* network support: */
- /* NOTE with this check it should be safe to assume we have SDL_net */
- /* for the rest of this file if Opts_LanMode() == 1 */
-#ifndef HAVE_LIBSDL_NET
- Opts_SetLanMode(0);
-#endif
-
- /* Start MathCards backend, unless we are getting questions from network: */
- /* FIXME may need to move this into tuxmath.c to accomodate option */
- /* to use MC_StartUsingWrongs() */
- /* NOTE MC_StartGame() will return 0 if the list length is zero due */
- /* (for example) to all math operations being deselected */
- /* NOTE if we are playing a network game, MC_StartGame() has already */
- /* been called on the server by the time we get to here: */
-
- if(!Opts_LanMode())
- {
- if (!MC_StartGame())
- {
- fprintf(stderr, "\nMC_StartGame() failed!");
- return 0;
- }
- DEBUGMSG(debug_mathcards | debug_game,"MC_StartGame() finished.\n")
- }
- else
- {
- /* Reset question queue and player name/score lists: */
- int i;
-
- for(i = 0; i < QUEST_QUEUE_SIZE; i ++)
- MC_ResetFlashCard(&(quest_queue[i]));
-
- for(i = 0; i < MAX_CLIENTS; i++)
- {
- lan_pnames[i][0] = '\0';
- lan_pscores[i] = -1;
- }
- }
-
- /* Allocate memory */
- comets = NULL; // set in case allocation fails partway through
- cities = NULL;
- penguins = NULL;
- steam = NULL;
- comets = (comet_type *) malloc(MAX_MAX_COMETS * sizeof(comet_type));
- if (comets == NULL)
- {
- printf("Allocation of comets failed");
- return 0;
- }
-
- cities = (city_type *) malloc(NUM_CITIES * sizeof(city_type));
- if (cities == NULL)
- {
- printf("Allocation of cities failed");
- return 0;
- }
-
- penguins = (penguin_type *) malloc(NUM_CITIES * sizeof(penguin_type));
- if (penguins == NULL)
- {
- printf("Allocation of penguins failed");
- return 0;
- }
-
- steam = (steam_type *) malloc(NUM_CITIES * sizeof(steam_type));
- if (steam == NULL)
- {
- printf("Allocation of steam failed");
- return 0;
- }
-
-
- /* Write pre-game info to game summary file: */
- if (Opts_SaveSummary())
- {
- write_pregame_summary();
- }
-
- /* Prepare to start the game: */
- city_expl_height = screen->h - images[IMG_CITY_BLUE]->h;
-
- /* Initialize feedback parameters */
- comet_feedback_number = 0;
- comet_feedback_height = 0;
- danger_level = Opts_DangerLevel();
-
- wave = 1;
- num_attackers = 2;
- prev_wave_comets = Opts_StartingComets();
- speed = Opts_Speed();
- slowdown = 0;
- score = 0;
- demo_countdown = 2000;
- total_questions_left = 0;
- level_start_wait = LEVEL_START_WAIT_START;
- neg_answer_picked = 0;
-
- /* (Create and position cities) */
-
- if (Opts_GetGlobalOpt(USE_IGLOOS))
- img = IMG_IGLOO_INTACT;
- else
- img = IMG_CITY_BLUE;
- for (i = 0; i < NUM_CITIES; i++)
- {
- cities[i].hits_left = 2;
- cities[i].status = CITY_PRESENT;
- cities[i].counter = 0;
- cities[i].threatened = 0;
- cities[i].layer = 0;
-
- /* 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] -> w) / 2));
- }
- else
- {
- cities[i].x = (screen->w -
- ((((screen->w / (NUM_CITIES + 1)) *
- (i - (NUM_CITIES / 2)) +
- ((images[img] -> w) / 2)))));
- }
- }
-
- num_cities_alive = NUM_CITIES;
-
- igloo_vertical_offset = images[IMG_CITY_BLUE]->h - images[IMG_IGLOO_INTACT]->h;
-
- /* Create and position the penguins and steam */
- for (i = 0; i < NUM_CITIES; i++)
- {
- penguins[i].status = PENGUIN_HAPPY;
- penguins[i].counter = 0;
- penguins[i].x = cities[i].x;
- penguins[i].layer = 0;
- steam[i].status = STEAM_OFF;
- steam[i].layer = 0;
- steam[i].counter = 0;
- }
-
- if (Opts_BonusCometInterval())
- {
- bonus_comet_counter = Opts_BonusCometInterval() + 1;
- DEBUGMSG(debug_game,"\nInitializing with bonus_comet_counter = %d\n",bonus_comet_counter);
- }
-
- extra_life_earned = 0;
- cloud.status = EXTRA_LIFE_OFF;
-
- /* (Clear laser) */
- laser.alive = 0;
-
- /* Reset remaining stuff: */
-
- bkgd = scaled_bkgd = NULL;
- last_bkgd = -1;
- reset_level();
- reset_comets();
-
- frame = 0;
- paused = 0;
- doing_answer = 0;
- tux_pressing = 0;
- tux_img = IMG_TUX_RELAX1;
- tux_anim = -1;
- tux_anim_frame = 0;
-
- // Initialize the messages
- game_clear_message(&s5);
- if (!start_message_chosen)
- {
- game_clear_message(&s1);
- game_clear_message(&s2);
- game_clear_message(&s3);
- game_clear_message(&s4);
- }
-
- help_controls.x_is_blinking = 0;
- help_controls.extra_life_is_blinking = 0;
- help_controls.laser_enabled = 1;
-
- DEBUGMSG(debug_game,"Exiting game_initialize()\n");
-
- return 1;
-}
-
-
-void game_cleanup(void)
-{
-#ifdef HAVE_LIBSDL_NET
- LAN_Cleanup();
-#endif
-
- /* Free background: */
- if (bkgd != NULL)
- {
- SDL_FreeSurface(bkgd);
- bkgd = NULL;
- }
- if (scaled_bkgd != NULL)
- {
- SDL_FreeSurface(scaled_bkgd);
- scaled_bkgd = NULL;
- }
-
- /* clear start message */
- start_message_chosen = 0;
-
- /* Free dynamically-allocated items */
- free_on_exit();
-
- /* Stop music: */
-#ifndef NOSOUND
- if (Opts_UsingSound())
- {
- if (Mix_PlayingMusic())
- {
- Mix_HaltMusic();
- }
- }
-#endif
-
- DEBUGMSG(debug_game, "Leaving game_cleanup():\n");
}
-
-
-void game_handle_help(void)
-{
- const int left_edge = 140;
- int frame_start;
- int quit_help = 0;
-
- help_controls.laser_enabled = 0;
- help_controls.x_is_blinking = 0;
- help_controls.extra_life_is_blinking = 0;
-
- // Here are some things that have to happen before we can safely
- // draw the screen
- tux_img = IMG_TUX_CONSOLE1;
- old_tux_img = tux_img;
- tux_pressing = 0;
- frame = 0;
-
- // Write the introductory text
- game_set_message(&s1,_("Welcome to TuxMath!"),-1,50);
-
-#ifndef NOSOUND
- if (Opts_UsingSound())
- {
- if (!Mix_PlayingMusic())
- {
- Mix_PlayMusic(musics[MUS_GAME], 0);
- }
- }
-#endif
-
- // Wait 2 seconds while rendering frames
- while (frame < 2*FPS && !(quit_help = help_renderframe_exit()));
- if (quit_help)
- return;
-
- game_set_message(&s2,_("Your mission is to save your"), left_edge, 100);
- game_set_message(&s3,_("penguins' igloos from the"), left_edge, 135);
- game_set_message(&s4,_("falling comets."), left_edge, 170);
-
- frame_start = frame;
- while (frame-frame_start < 5*FPS && !(quit_help = help_renderframe_exit())); // wait 5 more secs
- if (quit_help)
- return;
-
- // Bring in a comet
- speed = 2;
- help_add_comet("2 + 1 = ?", "3");
- help_controls.laser_enabled = 1;
- level_start_wait = 0;
-
- frame_start = frame;
- while (comets[0].alive && frame-frame_start < 100 && !(quit_help = help_renderframe_exit())); // advance comet
- if (quit_help)
- return;
-
- if (comets[0].alive == 1) {
- game_set_message(&s1,_("Stop a comet by typing"),left_edge,100);
- game_set_message(&s2,_("the answer to the math problem"),left_edge,135);
- game_set_message(&s3,_("and hitting 'space' or 'enter'."),left_edge,170);
- game_set_message(&s4,_("Try it now!"),left_edge,225);
-
- speed = 0;
- while (comets[0].alive && !(quit_help = help_renderframe_exit()));
- if (quit_help)
- return;
- }
-
- game_set_message(&s1,_("Good shot!"),left_edge,100);
- game_clear_message(&s2);
- game_clear_message(&s3);
- game_clear_message(&s4);
-
- help_controls.laser_enabled = 0;
- frame_start = frame;
- while (frame-frame_start < 3*FPS && !(quit_help = help_renderframe_exit())); // wait 3 secs
-
- speed = 2;
- game_set_message(&s1,_("If an igloo gets hit by a comet,"),left_edge,100);
- game_set_message(&s2,_("it melts. But don't worry: the"),left_edge,135);
- game_set_message(&s3,_("penguin is OK!"),left_edge,170);
- game_set_message(&s4,_("Just watch what happens:"),left_edge,225);
- game_set_message(&s5,_("(Press a key to start)"),left_edge,260);
-
- key_pressed = 0;
- while (!key_pressed && !(quit_help = help_renderframe_exit()));
- if (quit_help)
- return;
- game_clear_message(&s5);
-
- help_add_comet("3 * 3 = ?", "9");
- comets[0].y = 2*(screen->h)/3; // start it low down
- 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);
- help_renderframe_exit();
- SDL_Delay(4000);
- game_clear_message(&s4);
-
- frame_start = frame;
- while (frame-frame_start < 5*FPS && !(quit_help = help_renderframe_exit())); // wait 5 secs
- if (quit_help)
- return;
-
- game_set_message(&s1,_("If it gets hit again, the"),left_edge,100);
- game_set_message(&s2,_("penguin leaves."),left_edge,135);
- game_set_message(&s3,_("(Press a key when ready)"),left_edge,200);
-
- key_pressed = 0;
- while (!key_pressed && !(quit_help = help_renderframe_exit()));
- if (quit_help)
- return;
- game_clear_message(&s3);
-
- help_add_comet("56 / 8 = ?", "7");
- comets[0].y = 2*(screen->h)/3; // start it low down
-
- while (comets[0].alive && !(quit_help = help_renderframe_exit()));
-
- if (quit_help)
- return;
- frame_start = frame;
-
- while ((frame-frame_start < 3*FPS) && !(quit_help = help_renderframe_exit()));
-
- if (quit_help)
- return;
-
- help_controls.laser_enabled = 1;
- game_set_message(&s1,_("You can fix the igloos"), left_edge,100);
- game_set_message(&s2,_("by stopping bonus comets."), left_edge,135);
- help_add_comet("2 + 2 = ?", "4");
- comets[0].bonus = 1;
- frame_start = frame;
-
- while (comets[0].alive && (frame-frame_start < 50) && !(quit_help = help_renderframe_exit()));
-
- if (quit_help)
- return;
- if (comets[0].alive)
- speed = 0;
- game_set_message(&s3,_("Zap it now!"),left_edge,225);
-
- while (comets[0].alive && !(quit_help = help_renderframe_exit()));
-
- if (quit_help)
- return;
- game_set_message(&s1,_("Great job!"),left_edge,100);
- game_clear_message(&s2);
- game_clear_message(&s3);
- frame_start = frame;
-
- while ((frame-frame_start < 2*FPS) && !(quit_help = help_renderframe_exit()));
-
- if (quit_help)
- return;
- check_extra_life();
- frame_start = frame;
-
- while ((frame-frame_start < 10*FPS) && !(quit_help = help_renderframe_exit()));
-
- if (quit_help)
- return;
-
-
- game_set_message(&s1,_("Quit at any time by pressing"),left_edge,100);
- game_set_message(&s2,_("'Esc' or clicking the 'X'"),left_edge,135);
- game_set_message(&s3,_("in the upper right corner."),left_edge,170);
- game_set_message(&s4,_("Do it now, and then play!"),left_edge,225);
-
- help_controls.x_is_blinking = 1;
-
- while (!help_renderframe_exit());
-}
-
-// This function handles all the interactions expected during help
-// screens and renders a single frame. This function normally returns
-// 0, but returns 1 if the user chooses to exit help.
-int help_renderframe_exit(void)
-{
- static Uint32 last_time = 0;
- static Uint32 now_time;
-
- if (last_time == 0)
- last_time = SDL_GetTicks(); // Initialize...
-
- tux_pressing = 0;
- if (laser.alive > 0)
- laser.alive--;
- game_handle_user_events();
- game_handle_answer();
- game_handle_tux();
- game_handle_comets();
- game_handle_cities();
- game_handle_penguins();
- game_handle_steam();
- game_handle_extra_life();
- game_draw();
- game_status = check_exit_conditions();
-
- // Delay to keep frame rate constant. Do this in a way
- // that won't cause a freeze if the timer wraps around.
- now_time = SDL_GetTicks();
- if (now_time >= last_time && now_time < last_time + MS_PER_FRAME)
- SDL_Delay((last_time+MS_PER_FRAME) - now_time);
- last_time = now_time;
-
- frame++;
-
- return (game_status != GAME_IN_PROGRESS);
-}
-
-/* explicitly create a comet with a hardcoded problem */
-void help_add_comet(const char* formula_str, const char* ans_str)
-{
-// char probstr[MC_FORMULA_LEN];
-// char ansstr[MC_ANSWER_LEN];
-
- comets[0].alive = 1;
- comets[0].expl = -1;
- comets[0].answer = atoi(ans_str);
-// num_comets_alive = 1;
- comets[0].city = 0;
- comets[0].x = cities[0].x;
- comets[0].y = 0;
- comets[0].zapped = 0;
- comets[0].bonus = 0;
-
- strncpy(comets[0].flashcard.formula_string,formula_str,MC_MaxFormulaSize() );
- strncpy(comets[0].flashcard.answer_string,ans_str,MC_MaxAnswerSize() );
-}
-
-void game_set_message(game_message *msg,const char *txt,int x,int y)
-{
- if (msg && txt)
- {
- msg->x = x;
- msg->y = y;
- msg->alpha = SDL_ALPHA_OPAQUE;
- strncpy(msg->message,txt,GAME_MESSAGE_LENGTH);
- }
-}
-
-void game_clear_message(game_message *msg)
-{
- game_set_message(msg,"",0,0);
-}
-
-void game_clear_messages()
-{
- game_clear_message(&s1);
- game_clear_message(&s2);
- game_clear_message(&s3);
- game_clear_message(&s4);
- game_clear_message(&s5);
-}
-
-void game_write_message(const game_message *msg)
-{
- SDL_Surface* surf;
- SDL_Rect rect;
-
- if (strlen(msg->message) > 0)
- {
- surf = BlackOutline( _(msg->message), DEFAULT_HELP_FONT_SIZE, &white);
- rect.w = surf->w;
- rect.h = surf->h;
- if (msg->x < 0)
- rect.x = (screen->w/2) - (rect.w/2); // centered
- else
- rect.x = msg->x; // left justified
- rect.y = msg->y;
- //FIXME alpha blending doesn't seem to work properly
- SDL_SetAlpha(surf, SDL_SRCALPHA, msg->alpha);
- SDL_BlitSurface(surf, NULL, screen, &rect);
- SDL_FreeSurface(surf);
- //SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
- }
-}
-
-void game_write_messages(void)
-{
- game_write_message(&s1);
- game_write_message(&s2);
- game_write_message(&s3);
- game_write_message(&s4);
- game_write_message(&s5);
-}
-
-void game_handle_user_events(void)
-{
- SDL_Event event;
- SDLKey key;
- SDLMod mod;
-
- while (SDL_PollEvent(&event) > 0)
- {
- if (event.type == SDL_QUIT)
- {
- user_quit_received = GAME_OVER_WINDOW_CLOSE;
- }
- else if (event.type == SDL_KEYDOWN)
- {
- key = event.key.keysym.sym;
- mod = event.key.keysym.mod;
- game_key_event(key, mod);
- }
- else if (event.type == SDL_MOUSEBUTTONDOWN)
- {
- game_mouse_event(event);
- }
- }
-}
-
-void game_handle_demo(void)
-{
- /* If not in demo mode get out: */
- if (!Opts_DemoMode())
- {
- return;
- }
-
- /* Demo mode! */
- {
- static int demo_answer = 0;
- static int answer_digit = 0;
- static int picked_comet=-1;
-
- if (picked_comet == -1 && (rand() % 10) < 3)
- {
- /* Demo mode! Randomly pick a comet to destroy: */
- picked_comet = (rand() % Opts_MaxComets());
-
- if (!(comets[picked_comet].alive &&
- comets[picked_comet].expl == -1)
- || comets[picked_comet].y < 80)
- {
- picked_comet = -1;
- }
- else
- {
- /* found a comet to blow up! */
- demo_answer = comets[picked_comet].answer;
- if ((rand() % 3) < 1)
- demo_answer--; // sometimes get it wrong on purpose
-
- DEBUGMSG(debug_game, "Demo mode, comet %d attacked with answer %d\n", picked_comet,demo_answer);
-
- /* handle negative answer: */
- if (demo_answer < 0)
- {
- demo_answer = -demo_answer;
- neg_answer_picked = 1;
- }
- if (demo_answer >= 100)
- answer_digit = 0;
- else if (demo_answer >= 10)
- answer_digit = 1;
- else
- answer_digit = 2;
- }
- }
-
- /* Add a digit: */
- if (picked_comet != -1 && (frame % 5) == 0 && (rand() % 10) < 8)
- {
- tux_pressing = 1;
-
- if (answer_digit < 3)
- {
- digits[0] = digits[1];
- digits[1] = digits[2];
-
- if (answer_digit == 0)
- {
- digits[2] = demo_answer / 100;
- }
- else if (answer_digit == 1)
- {
- digits[2] = (demo_answer % 100) / 10;
- }
- else if (answer_digit == 2)
- {
- digits[2] = (demo_answer % 10);
- }
-
- answer_digit++;
- }
- else
- {
- /* "Press Return" */
- DEBUGMSG(debug_game, "Demo mode firing with these digits: %d%d%d\n",
- digits[0], digits[1], digits[2]);
- doing_answer = 1;
- picked_comet = -1;
- }
- }
-
- /* Count down counter: */
- demo_countdown--;
- }
-}
-
-void game_handle_answer(void)
-{
- int i, j, lowest, lowest_y;
- char ans[MC_MAX_DIGITS + 2]; //extra space for negative, and for final '\0'
- Uint32 ctime;
-
- if (!doing_answer)
- {
- return;
- }
-
- doing_answer = 0;
-
- /* negative answer support DSB */
-
- ans[0] = '-'; //for math questions only, this is just replaced.
- for (i = 0; i < MC_MAX_DIGITS - 1 && !digits[i]; ++i); //skip leading 0s
- for (j = neg_answer_picked ? 1 : 0; i < MC_MAX_DIGITS; ++i, ++j)
- ans[j] = digits[i] + '0';
- ans[j] = '\0';
-
-
-
- /* Pick the lowest comet which has the right answer: */
- /* FIXME: do we want it to prefer bonus comets to regular comets? */
- lowest_y = 0;
- lowest = -1;
-
- for (i = 0; i < Opts_MaxComets(); i++)
- {
- if (comets[i].alive &&
- 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)
- {
- lowest = i;
- lowest_y = comets[i].y;
- }
- }
-
- /* If there was a comet with this answer, destroy it! */
- if (lowest != -1) /* -1 means no comet had this answer */
- {
- float t;
- /* Store the time the question was present on screen (do this */
- /* in a way that avoids storing it if the time wrapped around */
- ctime = SDL_GetTicks();
- if (ctime > comets[lowest].time_started)
- t = ((float)(ctime - comets[lowest].time_started)/1000);
- else
- t = -1; //Mathcards will ignore t == -1
- /* Tell Mathcards or the server that we answered correctly: */
- if(Opts_LanMode())
-#ifdef HAVE_LIBSDL_NET
- LAN_AnsweredCorrectly(comets[lowest].flashcard.question_id, t);
-#else
- {} // Needed for compiler, even though this path can't occur
-#endif
- else
- MC_AnsweredCorrectly(comets[lowest].flashcard.question_id, t);
-
-
- /* Destroy comet: */
- comets[lowest].expl = 0;
- comets[lowest].zapped = 1;
- /* Fire laser: */
- laser.alive = LASER_START;
- laser.x1 = screen->w / 2;
- laser.y1 = screen->h;
- laser.x2 = comets[lowest].x;
- laser.y2 = comets[lowest].y;
- playsound(SND_LASER);
- playsound(SND_SIZZLE);
-
- /* Record data for feedback */
- if (Opts_UseFeedback())
- {
- comet_feedback_number++;
- comet_feedback_height += comets[lowest].y/city_expl_height;
-
-#ifdef FEEDBACK_DEBUG
- printf("Added comet feedback with height %g\n",comets[lowest].y/city_expl_height);
-#endif
- }
-
- /* Pick Tux animation: */
- /* 50% of the time.. */
- if ((rand() % 10) < 5)
- {
- /* ... pick an animation to play: */
- if ((rand() % 10) < 5)
- tux_anim = IMG_TUX_YES1;
- else
- tux_anim = IMG_TUX_YAY1;
- tux_anim_frame = ANIM_FRAME_START;
- }
-
- /* Increment score: */
-
- /* [ add = 25, sub = 50, mul = 75, div = 100 ] */
- /* [ the higher the better ] */
- /* FIXME looks like it might score a bit differently based on screen mode? */
- add_score(25 * comets[lowest].flashcard.difficulty *
- (screen->h - comets[lowest].y + 1) /
- screen->h);
- }
- else
- {
- /* Didn't hit anything! */
- laser.alive = LASER_START;
- laser.x1 = screen->w / 2;
- laser.y1 = screen->h;
- laser.x2 = laser.x1;
- laser.y2 = 0;
- playsound(SND_LASER);
- playsound(SND_BUZZ);
-
- if ((rand() % 10) < 5)
- tux_img = IMG_TUX_DRAT;
- else
- tux_img = IMG_TUX_YIPE;
- }
-
- /* Clear digits: */
- for (i = 0; i < MC_MAX_DIGITS; ++i)
- digits[i] = 0;
- neg_answer_picked = 0;
-}
-
-void game_countdown(void)
-{
- if (level_start_wait <= 0)
- {
- game_clear_messages();
- return;
- }
-
- //dim start messages
- s1.alpha -= SDL_ALPHA_OPAQUE / LEVEL_START_WAIT_START;
- s2.alpha -= SDL_ALPHA_OPAQUE / LEVEL_START_WAIT_START;
- s3.alpha -= SDL_ALPHA_OPAQUE / LEVEL_START_WAIT_START;
- s4.alpha -= SDL_ALPHA_OPAQUE / LEVEL_START_WAIT_START;
- DEBUGMSG(debug_game, "alpha = %d\n", s1.alpha);
-
- level_start_wait--;
- if (level_start_wait > LEVEL_START_WAIT_START / 4)
- tux_img = IMG_TUX_RELAX1;
- else if (level_start_wait > 0)
- tux_img = IMG_TUX_RELAX2;
- else
- tux_img = IMG_TUX_SIT;
-
- if (level_start_wait == LEVEL_START_WAIT_START / 4)
- {
- playsound(SND_ALARM);
- }
-}
-
-void game_handle_tux(void)
-{
- static int tux_same_counter;
- /* If Tux pressed a button, pick a new (different!) stance: */
- if (tux_pressing)
- {
- do { tux_img = IMG_TUX_CONSOLE1 + (rand() % 4); }
- while (tux_img == old_tux_img);
- playsound(SND_TOCK);
- }
-
- /* If Tux is being animated, show the animation: */
- if (tux_anim != -1)
- {
- tux_anim_frame--;
- if (tux_anim_frame < 0)
- tux_anim = -1;
- else
- tux_img = tux_anim + 1 - (tux_anim_frame / (ANIM_FRAME_START / 2));
- }
-
- /* Reset Tux to sitting if he's been doing nothing for a while: */
- if (old_tux_img == tux_img)
- {
- tux_same_counter++;
- if (tux_same_counter >= 20)
- {
- tux_img = IMG_TUX_SIT;
- }
- }
- else
- tux_same_counter = 0;
-}
-
-//FIXME might be simpler to store vertical position (and speed) in terms of time
-//rather than absolute position, and determine the latter in game_draw_comets()
-void game_handle_comets(void)
-{
- /* Handle comets. Since the comets also are the things that trigger
- changes in the cities, we set some flags in them, too. */
- int i, this_city;
- Uint32 ctime;
-
-// num_comets_alive = 0;
-
- /* Clear the threatened flag on each city */
- for (i = 0; i < NUM_CITIES; i++)
- cities[i].threatened = 0;
-
- for (i = 0; i < Opts_MaxComets(); i++)
- {
- if (comets[i].alive)
- {
-// num_comets_alive++;
- this_city = comets[i].city;
-
- /* Update comet position */
- comets[i].x = comets[i].x + 0; /* no lateral motion for now! */
- /* Make bonus comet move faster at chosen ratio: */
- /* NOTE y increment scaled to make game play similar at any resolution */
- if (comets[i].bonus)
- {
- comets[i].y += speed * Opts_BonusSpeedRatio() *
- city_expl_height / (screen->h - images[IMG_CITY_BLUE]->h);
- }
- else /* Regular comet: */
- {
- comets[i].y += speed *
- city_expl_height / (screen->h - images[IMG_CITY_BLUE]->h);
- }
-
- /* Does it threaten a city? */
- if (comets[i].y > 3 * screen->h / 4)
- cities[this_city].threatened = 1;
-
- /* Did it hit a city? */
- if (comets[i].y >= city_expl_height &&
- comets[i].expl == -1)
- {
- /* Tell MathCards about it - question not answered correctly: */
- if(Opts_LanMode())
-#ifdef HAVE_LIBSDL_NET
- LAN_NotAnsweredCorrectly(comets[i].flashcard.question_id);
-#else
- {}
-#endif
- else
- MC_NotAnsweredCorrectly(comets[i].flashcard.question_id);
-
- /* Store the time the question was present on screen (do this */
- /* in a way that avoids storing it if the time wrapped around */
- ctime = SDL_GetTicks();
- if (ctime > comets[i].time_started) {
- MC_AddTimeToList((float)(ctime - comets[i].time_started)/1000);
- }
-
- /* Record data for speed feedback */
- /* Do this only for cities that are alive; dead cities */
- /* might not get much protection from the player */
- if (Opts_UseFeedback() && cities[this_city].hits_left) {
- comet_feedback_number++;
- comet_feedback_height += 1.0 + Opts_CityExplHandicap();
-
-#ifdef FEEDBACK_DEBUG
- printf("Added comet feedback with height %g\n",
- 1.0 + Opts_CityExplHandicap());
-#endif
- }
-
- /* Disable shields/destroy city/create steam cloud: */
- if (cities[this_city].hits_left)
- {
- cities[this_city].status = CITY_EXPLODING;
- if (Opts_GetGlobalOpt(USE_IGLOOS)) {
- playsound(SND_IGLOO_SIZZLE);
- cities[this_city].counter = IGLOO_SWITCH_START;
- steam[this_city].status = STEAM_ON;
- steam[this_city].counter = STEAM_START;
- }
- else {
- if (cities[comets[i].city].hits_left == 2) {
- playsound(SND_SHIELDSDOWN);
- cities[this_city].counter = 1; /* Will act immediately */
- }
- else {
- playsound(SND_EXPLOSION);
- cities[this_city].counter = CITY_EXPL_START;
- }
- }
- cities[this_city].hits_left--;
- }
-
- /* If this was a bonus comet, restart the counter */
- if (comets[i].bonus)
- bonus_comet_counter = Opts_BonusCometInterval()+1;
-
- /* If slow_after_wrong selected, set flag to go back to starting speed and */
- /* number of attacking comets: */
- if (Opts_SlowAfterWrong())
- {
- speed = Opts_Speed();
- slowdown = 1;
- }
-
- tux_anim = IMG_TUX_FIST1;
- tux_anim_frame = ANIM_FRAME_START;
-
- /* Destroy comet: */
- comets[i].expl = 0;
- }
-
- /* Handle comet explosion animation: */
- if (comets[i].expl >= 0)
- {
- 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--;
- 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;
- DEBUGMSG(debug_game, "Extra life earned!");
- }
- }
- }
- }
- }
-
- /* FIXME for the LAN game, the adding of comets needs to take place in */
- /* check_messages() when new questions come in from the server. For */
- /* ease of understanding, we should do it at the same place in the game */
- /* loop for the non-LAN (i.e. local MC_*() functions) game - DSB */
- /* add more comets if needed: */
- if (!Opts_HelpMode() && level_start_wait == 0) //&&
- // (frame % 20) == 0)
- {
- /* num_attackers is how many comets are left in wave */
- if (num_attackers > 0)
- {
-// if ((rand() % 2) == 0 || num_comets_alive() == 0) NOTE also caused timing issue
- {
- if (add_comet())
- {
- num_attackers--;
- }
- }
- }
- else
- {
- if (num_comets_alive() == 0)
- {
- if (!check_extra_life())
- {
- /* Time for the next wave! */
- wave++;
- reset_level();
- }
- }
- }
- }
-}
-
-
-
-void game_handle_cities(void)
-{
- /* Update the status of the cities. These also determine the changes
- in the penguins. */
- int i;
- num_cities_alive = 0;
-
- for (i = 0; i < NUM_CITIES; i++)
- {
- /* Note: when status is CITY_REBUILDING, status and image
- selection is handled by the extra_life code */
- if (cities[i].status == CITY_REBUILDING)
- continue;
- if (cities[i].hits_left)
- num_cities_alive++;
- /* Handle counter for animated explosion: */
- if (cities[i].status == CITY_EXPLODING)
- {
- cities[i].counter--;
- if (cities[i].counter == 0) {
- if (cities[i].hits_left)
- cities[i].status = CITY_PRESENT;
- else {
- if (Opts_GetGlobalOpt(USE_IGLOOS)) {
- cities[i].status = CITY_EVAPORATING;
- cities[i].counter = EVAPORATING_COUNTER_START;
- cities[i].img = IMG_IGLOO_MELTED1;
- } else {
- cities[i].status = CITY_GONE;
- cities[i].img = IMG_CITY_NONE;
- }
- }
- }
- }
- /* Choose the correct city/igloo image */
- if (Opts_GetGlobalOpt(USE_IGLOOS)) {
- if (cities[i].status == CITY_EVAPORATING) {
- /* Handle the evaporation animation */
- cities[i].layer = 0; /* these have to be drawn below the penguin */
- cities[i].counter--;
- if (cities[i].counter == 0) {
- cities[i].img--;
- if (cities[i].img < IMG_IGLOO_MELTED3) {
- cities[i].img = IMG_CITY_NONE;
- cities[i].status = CITY_GONE;
- }
- else
- cities[i].counter = EVAPORATING_COUNTER_START;
- }
- } else {
- if (cities[i].status != CITY_GONE) {
- cities[i].layer = 1; /* these have to be drawn above the penguin */
- cities[i].img = IMG_IGLOO_MELTED1 + cities[i].hits_left;
- /* If we're in the middle of an "explosion," don't switch to the
- new igloo. Note the steam may have a different counter than
- the igloo on this matter; the switch is designed to occur
- halfway through the steam cloud. */
- if (cities[i].status == CITY_EXPLODING)
- cities[i].img++;
- }
- }
- }
- else {
- /* We're using the original "city" graphics */
- cities[i].layer = 0; /* No layering needed */
- if (cities[i].hits_left)
- cities[i].img = IMG_CITY_BLUE;
- else if (cities[i].status == CITY_EXPLODING)
- cities[i].img = (IMG_CITY_BLUE_EXPL5 - (cities[i].counter / (CITY_EXPL_START / 5)));
- else
- cities[i].img = IMG_CITY_BLUE_DEAD;
-
- /* Change image to appropriate color: */
- cities[i].img = cities[i].img + ((wave % MAX_CITY_COLORS) *
- (IMG_CITY_GREEN - IMG_CITY_BLUE));
-
- }
- }
-}
-
-
-void game_handle_penguins(void)
-{
- int i,direction,walk_counter;
-
- if (!Opts_GetGlobalOpt(USE_IGLOOS))
- return;
- for (i = 0; i < NUM_CITIES; i++) {
- penguins[i].layer = 0;
- if (cities[i].status == CITY_EVAPORATING)
- penguins[i].layer = 1; /* will go higher in certain cases */
- /* Handle interaction with comets & city status (ducking) */
- if (cities[i].threatened && penguins[i].status < PENGUIN_WALKING_OFF
- && penguins[i].status != PENGUIN_OFFSCREEN)
- penguins[i].status = PENGUIN_DUCKING;
- else if (!cities[i].threatened && penguins[i].status == PENGUIN_DUCKING) {
- if (cities[i].hits_left == 2)
- penguins[i].status = PENGUIN_HAPPY;
- else
- penguins[i].status = PENGUIN_GRUMPY;
- }
- switch (penguins[i].status) {
- case PENGUIN_HAPPY:
- penguins[i].img = IMG_PENGUIN_FLAPDOWN;
- if (rand() % FLAPPING_INTERVAL == 0) {
- penguins[i].status = PENGUIN_FLAPPING;
- penguins[i].counter = FLAPPING_START;
- }
- break;
- case PENGUIN_FLAPPING:
- if (penguins[i].counter % 4 >= 2)
- penguins[i].img = IMG_PENGUIN_FLAPUP;
- else
- penguins[i].img = IMG_PENGUIN_FLAPDOWN;
- penguins[i].counter--;
- if (penguins[i].counter == 0)
- penguins[i].status = PENGUIN_HAPPY;
- break;
- case PENGUIN_DUCKING:
- penguins[i].img = IMG_PENGUIN_INCOMING;
- break;
- case PENGUIN_GRUMPY:
- penguins[i].img = IMG_PENGUIN_GRUMPY;
- if (rand() % FLAPPING_INTERVAL == 0) {
- penguins[i].status = PENGUIN_WORRIED;
- penguins[i].counter = FLAPPING_START;
- }
- break;
- case PENGUIN_WORRIED:
- penguins[i].img = IMG_PENGUIN_WORRIED;
- penguins[i].counter--;
- if (penguins[i].counter == 0)
- penguins[i].status = PENGUIN_GRUMPY;
- break;
- case PENGUIN_STANDING_UP:
- penguins[i].img = IMG_PENGUIN_STANDING_UP;
- penguins[i].counter--;
- if (penguins[i].counter == 0)
- penguins[i].status = PENGUIN_WALKING_OFF;
- break;
- case PENGUIN_SITTING_DOWN:
- penguins[i].img = IMG_PENGUIN_SITTING_DOWN;
- penguins[i].counter--;
- if (penguins[i].counter == 0) {
- penguins[i].status = PENGUIN_FLAPPING;
- penguins[i].counter = FLAPPING_START;
- }
- break;
- case PENGUIN_WALKING_ON:
- walk_counter = (penguins[i].counter % 8)/2;
- if (walk_counter == 3)
- walk_counter = 1;
- penguins[i].img = IMG_PENGUIN_WALK_ON1 + walk_counter;
- penguins[i].counter++;
- direction = 2*(i < NUM_CITIES/2)-1; /* +1 for walk right, -1 for left */
- penguins[i].x += direction*PENGUIN_WALK_SPEED;
- if (direction*penguins[i].x >= direction*cities[i].x) {
- penguins[i].status = PENGUIN_SITTING_DOWN;
- penguins[i].counter = STANDING_COUNTER_START;
- penguins[i].x = cities[i].x;
- }
- penguins[i].layer = 3; /* Stand in front of steam */
- break;
- case PENGUIN_WALKING_OFF:
- walk_counter = (penguins[i].counter % 8)/2;
- if (walk_counter == 3)
- walk_counter = 1;
- penguins[i].img = IMG_PENGUIN_WALK_OFF1 + walk_counter;
- penguins[i].counter++;
- direction = 1-2*(i < NUM_CITIES/2);
- penguins[i].x += direction*PENGUIN_WALK_SPEED;
- if (direction < 0) {
- if (penguins[i].x + images[IMG_PENGUIN_WALK_OFF1]->w/2 < 0)
- penguins[i].status = PENGUIN_OFFSCREEN;
- } else {
- if (penguins[i].x - images[IMG_PENGUIN_WALK_OFF1]->w/2 > screen->w)
- penguins[i].status = PENGUIN_OFFSCREEN;
- }
- penguins[i].layer = 3;
- break;
- case PENGUIN_OFFSCREEN:
- penguins[i].img = -1;
- break;
- }
- }
-}
-
-void game_handle_steam(void)
-{
- int i;
-
- if (!Opts_GetGlobalOpt(USE_IGLOOS))
- return;
- for (i = 0; i < NUM_CITIES; i++) {
- if (steam[i].counter) {
- steam[i].counter--;
- if (!steam[i].counter) {
- steam[i].status = STEAM_OFF;
- if (cloud.status != EXTRA_LIFE_ON || cloud.city != i) {
- /* The penguin was ducking, now we can stop */
- if (cities[i].hits_left)
- penguins[i].status = PENGUIN_GRUMPY;
- else {
- penguins[i].status = PENGUIN_STANDING_UP;
- penguins[i].counter = STANDING_COUNTER_START;
- }
- }
- }
- }
- if (steam[i].status == STEAM_OFF)
- steam[i].img = -1;
- else {
- steam[i].img = IMG_STEAM5 - steam[i].counter/3;
- steam[i].layer = 2;
- }
- }
-}
-
-int check_extra_life(void)
-{
- /* This is called at the end of a wave. Returns 1 if we're in the
- middle of handling an extra life, otherwise 0 */
- int i,fewest_hits_left,fewest_index,snow_width;
-
- if (cloud.status == EXTRA_LIFE_ON)
- return 1;
- DEBUGCODE(debug_game)
- print_status();
-
- if (extra_life_earned) {
- /* Check to see if any ingloo has been hit */
- fewest_hits_left = 2;
- fewest_index = -1;
- for (i = 0; i < NUM_CITIES; i++) {
- if (cities[i].hits_left < fewest_hits_left) {
- fewest_hits_left = cities[i].hits_left;
- fewest_index = i;
- }
- }
- if (fewest_hits_left == 2)
- return 0; /* Don't need an extra life, there's no damage */
- /* Begin the extra life sequence */
- extra_life_earned = 0;
- cloud.status = EXTRA_LIFE_ON;
- cloud.y = screen->h/3;
- cloud.city = fewest_index;
- bonus_comet_counter = Opts_BonusCometInterval()+1;
-
- DEBUGMSG(debug_game, "Bonus comet counter restored to %d\n",bonus_comet_counter);
-
- if (cloud.city < NUM_CITIES/2)
- cloud.x = -images[IMG_CLOUD]->w/2; /* come in from the left */
- else
- cloud.x = screen->w + images[IMG_CLOUD]->w/2; /* come from the right */
- penguins[cloud.city].status = PENGUIN_WALKING_ON;
- /* initialize the snowflakes */
- snow_width = images[IMG_CLOUD]->w - images[IMG_SNOW1]->w;
- for (i = 0; i < NUM_SNOWFLAKES; i++) {
- cloud.snowflake_y[i] = cloud.y - i*SNOWFLAKE_SEPARATION;
- cloud.snowflake_x[i] = - snow_width/2 + (rand() % snow_width);
- cloud.snowflake_size[i] = rand() % 3;
- }
- DEBUGCODE(debug_game)
- print_status();
- return 1;
- }
- 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;
-
- if (cloud.status == EXTRA_LIFE_ON) {
-
- 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;
- if (direction*cloud.x < direction*cities[cloud.city].x) {
- cloud.x += direction*PENGUIN_WALK_SPEED;
- }
- else {
- // Cloud is "parked," handle the snowfall and igloo rebuilding
- cities[cloud.city].status = CITY_REBUILDING;
- igloo_top = screen->h - igloo_vertical_offset
- - images[IMG_IGLOO_INTACT]->h;
- for (i = 0, num_below_igloo = 0; i < NUM_SNOWFLAKES; i++) {
- cloud.snowflake_y[i] += SNOWFLAKE_SPEED;
- if (cloud.snowflake_y[i] > igloo_top)
- num_below_igloo++;
- }
- if (cloud.snowflake_y[NUM_SNOWFLAKES-1] > igloo_top) {
- cities[cloud.city].hits_left = 2;
- cities[cloud.city].img = IMG_IGLOO_INTACT; // completely rebuilt
- } else if (cities[cloud.city].hits_left == 0) {
- // We're going to draw one of the blended igloos
- // FIXME: It's a hack to encode a blended igloo with a negative number!
- penguins[cloud.city].layer = 0;
- cities[cloud.city].layer = 1;
- if (num_below_igloo < 3)
- num_below_igloo = 0; // Don't show progress until a few have fallen
- cities[cloud.city].img = -((float) (num_below_igloo)/NUM_SNOWFLAKES) * NUM_BLENDED_IGLOOS;
- }
- if (cloud.snowflake_y[NUM_SNOWFLAKES-1] > screen->h - igloo_vertical_offset) {
- /* exit rebuilding when last snowflake at igloo bottom */
- cloud.status = EXTRA_LIFE_OFF;
- cities[cloud.city].status = CITY_PRESENT;
- }
- }
- }
-}
-
-void game_draw(void)
-{
- SDL_Rect dest;
-
- /* Clear screen: */
- game_draw_background();
-
- /* Draw miscellaneous informational items */
- game_draw_misc();
-
- /* Draw cities/igloos and (if applicable) penguins: */
- game_draw_cities();
-
- /* Draw normal comets first, then bonus comets */
- game_draw_comets();
-
-
- /* Draw laser: */
- if (laser.alive)
- {
- draw_line(laser.x1, laser.y1, laser.x2, laser.y2,
- 255 / ((LASER_START + 1) - laser.alive),
- 192 / ((LASER_START + 1) - laser.alive),
- 64);
- }
-
- /* Draw numeric keypad: */
- if (Opts_GetGlobalOpt(USE_KEYPAD))
- {
- /* pick image to draw: */
- int keypad_image;
- if (MC_GetOpt(ALLOW_NEGATIVES) )
- {
- /* draw regular keypad */
- keypad_image = IMG_KEYPAD;
- }
- else
- {
- /* draw keypad with with grayed-out '+' and '-' */
- keypad_image = IMG_KEYPAD_NO_NEG;
- }
-
- /* now draw it: */
- dest.x = (screen->w - images[keypad_image]->w) / 2;
- dest.y = (screen->h - images[keypad_image]->h) / 2;
- dest.w = images[keypad_image]->w;
- dest.h = images[keypad_image]->h;
- SDL_BlitSurface(images[keypad_image], NULL, screen, &dest);
- }
-
- /* Draw console, LED numbers, & tux: */
- draw_led_console();
- draw_console_image(tux_img);
-
- /* Draw any messages on the screen (used for the help mode) */
- game_write_messages();
-
- /* Swap buffers: */
- SDL_Flip(screen);
-}
-
-void game_draw_background(void)
-{
- static int old_wave = 0; //update wave immediately
- static Uint32 bgcolor, fgcolor = 0;
- SDL_Rect dest;
-
- if (fgcolor == 0)
- fgcolor = SDL_MapRGB(screen->format, 64, 96, 64);
- if (old_wave != 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) );
- DEBUGMSG(debug_game,"Filling screen with color %d\n", bgcolor);
- }
-
- if (current_bkgd() == NULL || (current_bkgd()->w != screen->w &&
- current_bkgd()->h != screen->h) )
- {
- dest.x = 0;
- dest.y = 0;
- dest.w = screen->w;
- dest.h = ((screen->h) / 4) * 3;
-
- SDL_FillRect(screen, &dest, bgcolor);
-
-
- dest.y = ((screen->h) / 4) * 3;
- dest.h = (screen->h) / 4;
-
- SDL_FillRect(screen, &dest, fgcolor);
- }
-
- if (current_bkgd())
- {
- dest.x = (screen->w - current_bkgd()->w) / 2;
- dest.y = (screen->h - current_bkgd()->h) / 2;
- SDL_BlitSurface(current_bkgd(), NULL, screen, &dest);
- }
-}
-
-/* Draw comets: */
-/* NOTE bonus comets split into separate pass to make them */
-/* draw last (i.e. in front), as they can overlap */
-void game_draw_comets(void)
-{
-
- int i;
- SDL_Surface* img = NULL;
- SDL_Rect dest;
- char* comet_str;
-
- /* First draw regular comets: */
- for (i = 0; i < Opts_MaxComets(); i++)
- {
- if (comets[i].alive && !comets[i].bonus)
- {
- if (comets[i].expl == -1)
- {
- /* Decide which image to display: */
- 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)
- {
- comet_str = comets[i].flashcard.formula_string;
- }
- else
- {
- comet_str = NULL;
- }
- }
- else
- {
- /* 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 - (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);
- }
- }
- }
-
- /* Now draw any bonus comets: */
- for (i = 0; i < Opts_MaxComets(); i++)
- {
- if (comets[i].alive && comets[i].bonus)
- {
- if (comets[i].expl == -1)
- {
- /* Decide which image to display: */
- 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)
- {
- comet_str = comets[i].flashcard.formula_string;
- }
- else
- {
- comet_str = NULL;
- }
- }
- else
- {
- img = sprites[IMG_BONUS_COMET_EXPL]->frame[comets[i].expl / 2];
- comet_str = comets[i].flashcard.answer_string;
- }
-
- /* Draw it! */
- dest.x = comets[i].x - (img->w / 2);
- dest.y = comets[i].y - img->h;
- dest.w = img->w;
- dest.h = img->h;
- SDL_BlitSurface(img, NULL, 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;
- SDL_Rect src, dest;
- SDL_Surface* this_image;
-
- if (Opts_GetGlobalOpt(USE_IGLOOS)) {
- /* We have to draw respecting layering */
- current_layer = 0;
- max_layer = 0;
- do {
- for (i = 0; i < NUM_CITIES; i++) {
- if (cities[i].status != CITY_GONE && cities[i].layer > max_layer)
- max_layer = cities[i].layer;
- if (penguins[i].status != PENGUIN_OFFSCREEN && penguins[i].layer > max_layer)
- max_layer = penguins[i].layer;
- if (steam[i].status == STEAM_ON && steam[i].layer > max_layer)
- max_layer = steam[i].layer;
- if (cities[i].layer == current_layer &&
- cities[i].img != IMG_CITY_NONE) {
- // Handle the blended igloo images, which are encoded
- // (FIXME) with a negative image number
- if (cities[i].img <= 0)
- this_image = blended_igloos[-cities[i].img];
- else
- this_image = images[cities[i].img];
- //this_image = blended_igloos[frame % NUM_BLENDED_IGLOOS];
- dest.x = cities[i].x - (this_image->w / 2);
- dest.y = (screen->h) - (this_image->h) - igloo_vertical_offset;
- if (cities[i].img == IMG_IGLOO_MELTED3 ||
- cities[i].img == IMG_IGLOO_MELTED2)
- dest.y -= (images[IMG_IGLOO_MELTED1]->h - this_image->h)/2;
- dest.w = (this_image->w);
- dest.h = (this_image->h);
- SDL_BlitSurface(this_image, NULL, screen, &dest);
- }
- if (penguins[i].layer == current_layer &&
- penguins[i].status != PENGUIN_OFFSCREEN) {
- this_image = images[penguins[i].img];
- if (penguins[i].status == PENGUIN_WALKING_OFF ||
- penguins[i].status == PENGUIN_WALKING_ON) {
- /* With walking penguins, we have to use flipped images
- when it's walking left. The other issue is that the
- images are of different widths, so aligning on the
- center produces weird forward-backward walking. The
- reliable way is the align them all on the tip of the
- beak (the right border of the unflipped image) */
- dest.x = penguins[i].x - (this_image->w / 2);
- dest.y = (screen->h) - (this_image->h);
- if ((i<NUM_CITIES/2 && penguins[i].status==PENGUIN_WALKING_OFF) ||
- (i>=NUM_CITIES/2 && penguins[i].status==PENGUIN_WALKING_ON)) {
- /* walking left */
- this_image = flipped_images[flipped_img_lookup[penguins[i].img]];
- dest.x = penguins[i].x - images[IMG_PENGUIN_WALK_OFF2]->w/2;
- } else
- dest.x = penguins[i].x - this_image->w
- + images[IMG_PENGUIN_WALK_OFF2]->w/2; /* walking right */
- }
- else {
- dest.x = penguins[i].x - (this_image->w / 2);
- dest.y = (screen->h) - (5*(this_image->h))/4 - igloo_vertical_offset;
- }
- dest.w = (this_image->w);
- dest.h = (this_image->h);
- SDL_BlitSurface(this_image, NULL, screen, &dest);
- }
- if (steam[i].layer == current_layer &&
- steam[i].status == STEAM_ON) {
- this_image = images[steam[i].img];
- dest.x = cities[i].x - (this_image->w / 2);
- dest.y = (screen->h) - this_image->h - ((4 * images[IMG_IGLOO_INTACT]->h) / 7);
- dest.w = (this_image->w);
- dest.h = (this_image->h);
- SDL_BlitSurface(this_image, NULL, screen, &dest);
- }
- }
- current_layer++;
- } while (current_layer <= max_layer);
- if (cloud.status == EXTRA_LIFE_ON) {
- /* Render cloud & snowflakes */
- for (i = 0; i < NUM_SNOWFLAKES; i++) {
- if (cloud.snowflake_y[i] > cloud.y &&
- cloud.snowflake_y[i] < screen->h - igloo_vertical_offset) {
- this_image = images[IMG_SNOW1+cloud.snowflake_size[i]];
- dest.x = cloud.snowflake_x[i] - this_image->w/2 + cloud.x;
- dest.y = cloud.snowflake_y[i] - this_image->h/2;
- dest.w = this_image->w;
- dest.h = this_image->h;
- SDL_BlitSurface(this_image, NULL, screen, &dest);
- }
- }
- this_image = images[IMG_CLOUD];
- dest.x = cloud.x - this_image->w/2;
- dest.y = cloud.y - this_image->h/2;
- dest.w = this_image->w;
- dest.h = this_image->h;
- SDL_BlitSurface(this_image, NULL, screen, &dest);
- }
- }
- else {
- /* We're drawing original city graphics, for which there are no
- layering issues, but has special handling for the shields */
- for (i = 0; i < NUM_CITIES; i++) {
- this_image = images[cities[i].img];
- dest.x = cities[i].x - (this_image->w / 2);
- dest.y = (screen->h) - (this_image->h);
- dest.w = (this_image->w);
- dest.h = (this_image->h);
- SDL_BlitSurface(this_image, NULL, screen, &dest);
-
- /* Draw sheilds: */
- if (cities[i].hits_left > 1) {
- for (j = (frame % 3); j < images[IMG_SHIELDS]->h; j = j + 3) {
- src.x = 0;
- src.y = j;
- src.w = images[IMG_SHIELDS]->w;
- src.h = 1;
-
- dest.x = cities[i].x - (images[IMG_SHIELDS]->w / 2);
- dest.y = (screen->h) - (images[IMG_SHIELDS]->h) + j;
- dest.w = src.w;
- dest.h = src.h;
-
- SDL_BlitSurface(images[IMG_SHIELDS], &src, screen, &dest);
- }
- }
- }
- }
-
-
-}
-void game_draw_misc(void)
-{
- int i;
- int offset;
- SDL_Rect dest;
- char str[64];
-
- /* Draw "Demo" */
- if (Opts_DemoMode())
- {
- dest.x = (screen->w - images[IMG_DEMO]->w) / 2;
- dest.y = (screen->h - images[IMG_DEMO]->h) / 2;
- dest.w = images[IMG_DEMO]->w;
- dest.h = images[IMG_DEMO]->h;
-
- 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_GetOpt(PLAY_THROUGH_LIST) )
- {
- draw_question_counter();
- }
-
- if (extra_life_earned) {
- /* Draw extra life earned icon */
- dest.x = 0;
- dest.y = 0;
- dest.w = images[IMG_EXTRA_LIFE]->w;
- dest.h = images[IMG_EXTRA_LIFE]->h;
- SDL_BlitSurface(images[IMG_EXTRA_LIFE], NULL, screen, &dest);
- } else if (bonus_comet_counter) {
- /* Draw extra life progress bar */
- dest.x = 0;
- dest.y = images[IMG_EXTRA_LIFE]->h/4;
- dest.h = images[IMG_EXTRA_LIFE]->h/2;
- dest.w = ((Opts_BonusCometInterval() + 1 - bonus_comet_counter)
- * images[IMG_EXTRA_LIFE]->w) / Opts_BonusCometInterval();
- SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 255, 0));
- }
-
- /* Draw wave: */
- if (Opts_BonusCometInterval())
- offset = images[IMG_EXTRA_LIFE]->w + 5;
- else
- offset = 0;
-
- dest.x = offset;
- dest.y = glyph_offset;
- dest.w = images[IMG_WAVE]->w;
- dest.h = images[IMG_WAVE]->h;
-
- SDL_BlitSurface(images[IMG_WAVE], NULL, screen, &dest);
-
- sprintf(str, "%d", wave);
- draw_numbers(str, offset+images[IMG_WAVE]->w + (images[IMG_NUMBERS]->w / 10), 0);
-
- /* In LAN mode, we show the server-generated score: */
- if (Opts_KeepScore() && !Opts_LanMode())
- {
- /* Draw "score" label: */
- dest.x = (screen->w - ((images[IMG_NUMBERS]->w / 10) * 7) -
- images[IMG_SCORE]->w -
- images[IMG_STOP]->w - 5);
- dest.y = glyph_offset;
- dest.w = images[IMG_SCORE]->w;
- dest.h = images[IMG_SCORE]->h;
- SDL_BlitSurface(images[IMG_SCORE], NULL, screen, &dest);
-
- /* Draw score numbers: */
- sprintf(str, "%.6d", score);
- draw_numbers(str,
- screen->w - ((images[IMG_NUMBERS]->w / 10) * 6) - images[IMG_STOP]->w - 5,
- 0);
- }
-
- /* Draw other players' scores (turn-based single machine multiplayer) */
- if (mp_get_parameter(PLAYERS) && mp_get_parameter(MODE) == SCORE_SWEEP )
- {
- int i;
- for (i = 0; i < mp_get_parameter(PLAYERS); ++i)
- {
- SDL_Surface* score;
- snprintf(str, 64, "%s: %d", mp_get_player_name(i),mp_get_player_score(i));
- 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);
- }
- }
- }
-
- /* Draw other players' scores (LAN game) */
- if (Opts_LanMode())
- {
- int entries = 0;
- for (i = 0; i < MAX_CLIENTS; i++)
- {
- if(lan_pscores[i] >= 0)
- {
- SDL_Surface* score;
- snprintf(str, 64, "%s: %d", lan_pnames[i], lan_pscores[i]);
- score = BlackOutline(str, DEFAULT_MENU_FONT_SIZE, &white);
- if(score)
- {
- SDL_Rect loc;
- loc.w = score->w;
- loc.h = score->h;
- loc.x = 0;
- loc.y = score->h * (entries + 2);
- SDL_BlitSurface(score, NULL, screen, &loc);
- entries++;
- }
- }
- }
- }
-
- /* Draw stop button: */
- if (!help_controls.x_is_blinking || (frame % 10 < 5)) {
- dest.x = (screen->w - images[IMG_STOP]->w);
- dest.y = 0;
- dest.w = images[IMG_STOP]->w;
- dest.h = images[IMG_STOP]->h;
-
- SDL_BlitSurface(images[IMG_STOP], NULL, screen, &dest);
- }
-}
-
-int check_exit_conditions(void)
-{
-// int x;
-
- if (user_quit_received)
- {
- if (user_quit_received != GAME_OVER_WINDOW_CLOSE &&
- user_quit_received != GAME_OVER_ESCAPE &&
- user_quit_received != GAME_OVER_CHEATER)
- {
- fprintf(stderr, "Unexpected value %d for user_quit_received\n", user_quit_received);
- return GAME_OVER_OTHER;
- }
- return user_quit_received;
- }
-
- /* determine if game lost (i.e. all igloos melted): */
- if (!num_cities_alive)
- {
- if (gameover_counter < 0)
- gameover_counter = GAMEOVER_COUNTER_START;
- gameover_counter--;
- if (gameover_counter == 0)
- return GAME_OVER_LOST;
- }
-
- /* determine if game won (i.e. all questions in mission answered correctly): */
- if(Opts_LanMode())
- {
- if(game_over_won)
- return GAME_OVER_WON;
- }
- else
- {
- if (MC_MissionAccomplished())
- {
- DEBUGMSG(debug_game,"Mission accomplished!\n");
- return GAME_OVER_WON;
- }
- }
-
-
- /* Could have situation where mathcards doesn't have more questions */
- /* even though not all questions answered correctly: */
- if(Opts_LanMode())
- {
- if(game_over_other)
- return GAME_OVER_OTHER;
- }
- else
- {
- if(!MC_TotalQuestionsLeft())
- return GAME_OVER_OTHER;
- }
-
-
- //NOTE can't use this check in LAN mode because we don't know if the server has
- //questions left
-
- /* Need to get out if no comets alive and MathCards has no questions left in list, */
- /* even though MathCards thinks there are still questions "in play". */
- /* This SHOULD NOT HAPPEN and means we have a bug somewhere. */
- if (!Opts_LanMode())
- {
- 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 (Opts_DemoMode())
- {
- if (demo_countdown <= 0 )
- return GAME_OVER_OTHER;
- }
-
- /* if we made it to here, the game goes on! */
- return GAME_IN_PROGRESS;
-}
-
-
-void print_exit_conditions(void)
-{
- printf("\ngame_status:\t");
- switch (game_status)
- {
- case GAME_IN_PROGRESS:
- {
- printf("GAME_IN_PROGRESS\n");
- break;
- }
-
- case GAME_OVER_WON:
- {
- printf("GAME_OVER_WON\n");
- break;
- }
- case GAME_OVER_LOST:
- {
- printf("GAME_OVER_LOST\n");
- break;
- }
- case GAME_OVER_OTHER:
- {
- printf("GAME_OVER_OTHER\n");
- break;
- }
- case GAME_OVER_ESCAPE:
- {
- printf("GAME_OVER_ESCAPE\n");
- print_status();
- break;
- }
- case GAME_OVER_WINDOW_CLOSE:
- {
- printf("GAME_OVER_WINDOW_CLOSE\n");
- break;
- }
- case GAME_OVER_ERROR:
- {
- printf("GAME_OVER_ERROR\n");
- break;
- }
- default:
- {
- printf("Unrecognized value\n");
- break;
- }
- }
-}
-
-
-/* Reset stuff for the next level! */
-void reset_level(void)
-{
- char fname[1024];
- int i;
- int next_wave_comets;
- int use_feedback;
- float comet_avg_height, height_differential;
-
-
- /* Clear all comets: */
-
- for (i = 0; i < Opts_MaxComets(); i++)
- {
- DEBUGCODE(debug_game)
- {
- if(comets[i].alive)
- printf("Warning - resetting comets but comet[%d| still alive\n", i);
- }
- comets[i].alive = 0;
- }
-
- /* Clear LED F: */
-
- for (i = 0; i < MC_MAX_DIGITS; ++i)
- digits[i] = 0;
- neg_answer_picked = 0;
-
- /* Load random background image, but ensure it's different from this one: */
- for (i = last_bkgd; i == last_bkgd; i = rand() % NUM_BKGDS);
-
- last_bkgd = i;
-
- sprintf(fname, "backgrounds/%d.jpg", i);
-
- if (bkgd != NULL)
- {
- SDL_FreeSurface(bkgd);
- bkgd = NULL;
- }
- if (scaled_bkgd != NULL)
- {
- SDL_FreeSurface(scaled_bkgd);
- scaled_bkgd = NULL;
- }
-
- if (Opts_UseBkgd())
- {
- LoadBothBkgds(fname, &scaled_bkgd, &bkgd);
- if (bkgd == NULL || scaled_bkgd == NULL)
- {
- fprintf(stderr,
- "\nWarning: Could not load background image:\n"
- "%s\n"
- "The Simple DirectMedia error that ocurred was: %s\n",
- fname, SDL_GetError());
- Opts_SetUseBkgd(0);
- }
- }
-
-
-
- /* Record score before this wave: */
-
- pre_wave_score = score;
-
- /* Set number of attackers for this wave: */
-
- /* On first wave or if slowdown flagged due to wrong answer: */
- if (wave == 1 || slowdown)
- {
- next_wave_comets = Opts_StartingComets();
- speed = Opts_Speed();
- slowdown = 0;
- }
-
- else /* Otherwise increase comets and speed if selected, not to */
- /* exceed maximum: */
- {
- next_wave_comets = prev_wave_comets;
- if (Opts_AllowSpeedup())
- {
- next_wave_comets += Opts_ExtraCometsPerWave();
- if (next_wave_comets > Opts_MaxComets())
- {
- next_wave_comets = Opts_MaxComets();
- }
-
- use_feedback = Opts_UseFeedback();
-
- if (use_feedback)
- {
- #ifdef FEEDBACK_DEBUG
- printf("Evaluating feedback...\n old danger level = %g,",danger_level);
- #endif
-
- /* Update our danger level, i.e., the target height */
- danger_level = 1 - (1-danger_level) /
- Opts_DangerLevelSpeedup();
- if (danger_level > Opts_DangerLevelMax())
- danger_level = Opts_DangerLevelMax();
-
- #ifdef FEEDBACK_DEBUG
- printf(" new danger level = %g.\n",danger_level);
- #endif
-
- /* Check to see whether we have any feedback data. If not, skip it. */
- if (comet_feedback_number == 0)
- {
- use_feedback = 0; /* No comets above living cities, skip feedback */
-
- #ifdef FEEDBACK_DEBUG
- printf("No feedback data available, aborting.\n\n");
- #endif
- }
- else
- {
- /* Compute the average height of comet destruction. */
- comet_avg_height = comet_feedback_height/comet_feedback_number;
-
- /* Determine how this average height compares with target. */
- height_differential = comet_avg_height - danger_level;
-
- /* Set the speed so that we move halfway towards the target */
- /* height. That makes the changes a bit more conservative. */
-
- #ifdef FEEDBACK_DEBUG
- printf(" comet average height = %g, height differential = %g.\n",
- comet_avg_height, height_differential);
- printf(" old speed = %g,",speed);
- #endif
-
- speed *= (1 - height_differential/danger_level/2);
-
- /* Enforce bounds on speed */
- if (speed < MINIMUM_SPEED)
- speed = MINIMUM_SPEED;
- if (speed > Opts_MaxSpeed())
- speed = Opts_MaxSpeed();
-
- #ifdef FEEDBACK_DEBUG
- printf(" new speed = %g.\n",speed);
- printf("Feedback evaluation complete.\n\n");
- #endif
- }
- }
-
- if (!use_feedback)
- {
- /* This is not an "else" because we might skip feedback */
- /* when comet_feedback_number == 0 */
- speed = speed * Opts_SpeedupFactor();
- if (speed > Opts_MaxSpeed())
- {
- speed = Opts_MaxSpeed();
- }
- }
- }
- }
-
- comet_feedback_number = 0;
- comet_feedback_height = 0;
-
- prev_wave_comets = next_wave_comets;
- num_attackers = prev_wave_comets;
-}
-
-
-
-/* Add a comet to the game (if there's room): */
-int add_comet(void)
-{
- static int prev_city = -1;
- int i;
- float y_spacing;
-
- int com_found = -1;
- int q_found = -1;
-
- y_spacing = (images[IMG_NUMS]->h) * 1.5;
-
- /* Return if any previous comet too high up to create another one yet: */
- for (i = 0; i < Opts_MaxComets(); i++)
- {
- if (comets[i].alive)
- if (comets[i].y < y_spacing)
- {
- DEBUGMSG(debug_game,
- "add_comet() - returning because comet[%d] not"
- " far enough down: %f\n", i, comets[i].y);
- return 0;
- }
- }
-
- /* Now look for a free comet slot: */
- for (i = 0; i < Opts_MaxComets(); i++)
- {
- if (!comets[i].alive)
- {
- com_found = i;
- break;
- }
- }
-
- if (-1 == com_found)
- {
- /* free comet slot not found - no comet added: */
- DEBUGMSG(debug_game, "add_comet() called but no free comet slot\n");
- DEBUGCODE(debug_game) print_current_quests();
- return 0;
- }
-
-
- /* If playing in LAN mode, see if we have a question ready in */
- /* our local queue: */
-
- if(Opts_LanMode())
- {
- DEBUGCODE(debug_game) print_current_quests();
- for (i = 0; i < QUEST_QUEUE_SIZE; i++)
- {
- if(quest_queue[i].question_id != -1)
- {
- DEBUGMSG(debug_game, "Found question_id %d, %s\n",
- quest_queue[i].question_id,
- quest_queue[i].formula_string);
- q_found = i;
- break;
- }
- }
-
- if(q_found == -1)
- {
- DEBUGMSG(debug_game, "add_comet() called but no question available in queue\n");
- DEBUGCODE(debug_game) print_current_quests();
- return 0;
- }
- }
-
- /* Now we have a vacant comet slot at com_found and (if in LAN mode) */
- /* a question for it at q_found. Now just copy: */
-
- if(Opts_LanMode())
- {
- MC_CopyCard(&(quest_queue[q_found]), &(comets[com_found].flashcard));
- MC_ResetFlashCard(&(quest_queue[q_found]));
- }
- else // Not LAN mode - just get question with direct call:
- {
- if (!MC_NextQuestion(&(comets[com_found].flashcard)))
- {
- /* no more questions available - cannot create comet. */
- return 0;
- }
- }
-
- DEBUGCODE(debug_game)
- {
- printf("In add_comet(), card is\n");
- print_card(comets[com_found].flashcard);
- }
-
- /* Make sure question is "sane" before we add it: */
- if( (comets[com_found].flashcard.answer > 999)
- ||(comets[com_found].flashcard.answer < -999))
- {
- printf("Warning, card with invalid answer encountered: %d\n",
- comets[com_found].flashcard.answer);
- MC_ResetFlashCard(&(comets[com_found].flashcard));
- return 0;
- }
-
- /* If we make it to here, create a new comet!*/
- comets[com_found].answer = comets[com_found].flashcard.answer;
- comets[com_found].alive = 1;
-// num_comets_alive++;
-
- /* Pick a city to attack that was not attacked last time */
- /* (so formulas are less likely to overlap). */
- do
- {
- i = rand() % NUM_CITIES;
- }
- while (i == prev_city);
-
- prev_city = i;
-
- /* Set in to attack that city: */
- comets[com_found].city = i;
- /* Start at the top, above the city in question: */
- comets[com_found].x = cities[i].x;
- comets[com_found].y = 0;
- comets[com_found].zapped = 0;
- /* Should it be a bonus comet? */
- comets[com_found].bonus = 0;
-
- DEBUGMSG(debug_game, "bonus_comet_counter is %d\n",bonus_comet_counter);
-
- if (bonus_comet_counter == 1)
- {
- bonus_comet_counter = 0;
- comets[com_found].bonus = 1;
- playsound(SND_BONUS_COMET);
- DEBUGMSG(debug_game, "Created bonus comet");
- }
-
- DEBUGMSG(debug_game, "add_comet(): formula string is: %s\n", comets[com_found].flashcard.formula_string);
-
- /* Record the time at which this comet was created */
- comets[com_found].time_started = SDL_GetTicks();
-
- /* comet slot found and question found so return successfully: */
- return 1;
-}
-
-
-
-/* Draw numbers/symbols over the attacker: */
-/* This draws the numbers related to the comets */
-void draw_nums(const char* str, int x, int y)
-{
- 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 / (16));
- /* 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 - (image_length) / 2;
-
- /* 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));
-
- /* Draw each character: */
- for (i = 0; i < str_length; i++)
- {
- c = -1;
-
- /* Determine which character to display: */
-
- 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 < 4; j++)
- {
- if (str[i] == operchars[j])
- {
- c = 10 + j;
- }
- }
- }
-
- /* 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;
-
- SDL_BlitSurface(images[IMG_NUMS], &src,
- screen, &dest);
- /* 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(const char* str, int x, int y)
-{
- int i, cur_x, c;
- SDL_Rect src, dest;
-
- cur_x = x;
-
- /* Draw each character: */
-
- for (i = 0; i < strlen(str); i++)
- {
- c = -1;
-
- /* Determine which character to display: */
- if (str[i] >= '0' && str[i] <= '9')
- c = str[i] - '0';
-
- /* Display this character! */
- if (c != -1)
- {
- src.x = c * (images[IMG_NUMBERS]->w / 10);
- src.y = 0;
- src.w = (images[IMG_NUMBERS]->w / 10);
- src.h = images[IMG_NUMBERS]->h;
-
- dest.x = cur_x;
- dest.y = y;
- dest.w = src.w;
- dest.h = src.h;
-
- SDL_BlitSurface(images[IMG_NUMBERS], &src,
- screen, &dest);
-
- /* Move the 'cursor' one character width: */
- cur_x = cur_x + (images[IMG_NUMBERS]->w / 10);
- }
- }
-}
-
-
-/* Pause loop: */
-
-int pause_game(void)
-{
- /* NOTE - done and quit changed to pause_done and pause_quit */
- /* due to potentially confusing name collision */
- int pause_done, pause_quit;
- SDL_Event event;
- SDL_Rect dest;
-
- /* Only pause if pause allowed: */
- if (!Opts_AllowPause())
- {
- fprintf(stderr, "Pause requested but not allowed by Opts!\n");
- return 0;
- }
-
- pause_done = 0;
- pause_quit = 0;
-
- dest.x = (screen->w - images[IMG_PAUSED]->w) / 2;
- dest.y = (screen->h - images[IMG_PAUSED]->h) / 2;
- dest.w = images[IMG_PAUSED]->w;
- dest.h = images[IMG_PAUSED]->h;
-
- DarkenScreen(1); // cut all channels by half
- SDL_BlitSurface(images[IMG_PAUSED], NULL, screen, &dest);
- SDL_UpdateRect(screen, 0, 0, 0, 0);
-
-#ifndef NOSOUND
- if (Opts_UsingSound())
- Mix_PauseMusic();
-#endif
-
- do
- {
- while (SDL_PollEvent(&event))
- {
- if (event.type == SDL_KEYDOWN)
- pause_done = 1;
- else if (event.type == SDL_QUIT)
- {
- user_quit_received = GAME_OVER_WINDOW_CLOSE;
- pause_quit = 1;
- }
- }
-
- SDL_Delay(100);
- }
- while (!pause_done && !pause_quit);
-
-#ifndef NOSOUND
- if (Opts_UsingSound())
- Mix_ResumeMusic();
-#endif
-
- return (pause_quit);
-}
-
-
-
-/* FIXME these ought to be in SDL_extras - DSB */
-
-/* Draw a line: */
-void draw_line(int x1, int y1, int x2, int y2, int red, int grn, int blu)
-{
- int dx, dy, tmp;
- float m, b;
- Uint32 pixel;
- SDL_Rect dest;
-
- pixel = SDL_MapRGB(screen->format, red, grn, blu);
-
- dx = x2 - x1;
- dy = y2 - y1;
-
- putpixel(screen, x1, y1, pixel);
-
- if (dx != 0)
- {
- m = ((float) dy) / ((float) dx);
- b = y1 - m * x1;
-
- if (x2 > x1)
- dx = 1;
- else
- dx = -1;
-
- while (x1 != x2)
- {
- x1 = x1 + dx;
- y1 = m * x1 + b;
-
- putpixel(screen, x1, y1, pixel);
- }
- }
- else
- {
- if (y1 > y2)
- {
- tmp = y1;
- y1 = y2;
- y2 = tmp;
- }
-
- dest.x = x1;
- dest.y = y1;
- dest.w = 3;
- dest.h = y2 - y1;
-
- SDL_FillRect(screen, &dest, pixel);
- }
-}
-
-
-/* Draw a single pixel into the surface: */
-
-void putpixel(SDL_Surface* surface, int x, int y, Uint32 pixel)
-{
-#ifdef PUTPIXEL_RAW
- int bpp;
- Uint8* p;
-
- /* Determine bytes-per-pixel for the surface in question: */
-
- bpp = surface->format->BytesPerPixel;
-
-
- /* Set a pointer to the exact location in memory of the pixel
- in question: */
-
- p = (Uint8 *) (surface->pixels + /* Start at beginning of RAM */
- (y * surface->pitch) + /* Go down Y lines */
- (x * bpp)); /* Go in X pixels */
-
-
- /* Assuming the X/Y values are within the bounds of this surface... */
-
- if (x >= 0 && y >= 0 && x < surface->w && y < surface->h)
- {
- /* Set the (correctly-sized) piece of data in the surface's RAM
- to the pixel value sent in: */
-
- if (bpp == 1)
- *p = pixel;
- else if (bpp == 2)
- *(Uint16 *)p = pixel;
- else if (bpp == 3)
- {
- if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
- {
- p[0] = (pixel >> 16) & 0xff;
- p[1] = (pixel >> 8) & 0xff;
- p[2] = pixel & 0xff;
- }
- else
- {
- p[0] = pixel & 0xff;
- p[1] = (pixel >> 8) & 0xff;
- p[2] = (pixel >> 16) & 0xff;
- }
- }
- else if (bpp == 4)
- {
- *(Uint32 *)p = pixel;
- }
- }
-#else
- SDL_Rect dest;
-
- dest.x = x;
- dest.y = y;
- dest.w = 3;
- dest.h = 4;
-
- SDL_FillRect(surface, &dest, pixel);
-#endif
-}
-
-
-/* Draw image at lower center of screen: */
-void draw_console_image(int i)
-{
- SDL_Rect dest;
-
- dest.x = (screen->w - images[i]->w) / 2;
- dest.y = (screen->h - images[i]->h);
- dest.w = images[i]->w;
- dest.h = images[i]->h;
-
- 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: */
- if(Opts_LanMode())
- questions_left = total_questions_left;
- else
- questions_left = MC_TotalQuestionsLeft();
-
- sprintf(str, "%.4d", questions_left);
- draw_numbers(str, nums_x, 0);
-}
-
-/* FIXME very confusing having this function draw console */
-void draw_led_console(void)
-{
- int i;
- SDL_Rect src, dest;
- int y;
-
- /* draw new console image with "monitor" for LED numbers: */
- draw_console_image(IMG_CONSOLE_LED);
- /* set y to draw LED numbers into Tux's "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_GetOpt(ALLOW_NEGATIVES) )
- dest.x = ((screen->w - ((images[IMG_LEDNUMS]->w) / 10) * 4) / 2);
- else
- dest.x = ((screen->w - ((images[IMG_LEDNUMS]->w) / 10) * 3) / 2);
-
- for (i = -1; i < MC_MAX_DIGITS; i++) /* -1 is special case to allow minus sign */
- /* with minimal modification of existing code DSB */
- {
- if (-1 == i)
- {
- if (MC_GetOpt(ALLOW_NEGATIVES))
- {
- if (neg_answer_picked)
- src.x = (images[IMG_LED_NEG_SIGN]->w) / 2;
- else
- src.x = 0;
-
- src.y = 0;
- src.w = (images[IMG_LED_NEG_SIGN]->w) / 2;
- src.h = images[IMG_LED_NEG_SIGN]->h;
-
- dest.y = y;
- dest.w = src.w;
- dest.h = src.h;
-
- SDL_BlitSurface(images[IMG_LED_NEG_SIGN], &src, screen, &dest);
- /* move "cursor" */
- dest.x += src.w;
- }
- }
- else
- {
- src.x = digits[i] * ((images[IMG_LEDNUMS]->w) / 10);
- src.y = 0;
- src.w = (images[IMG_LEDNUMS]->w) / 10;
- src.h = images[IMG_LEDNUMS]->h;
-
- /* dest.x already set */
- dest.y = y;
- dest.w = src.w;
- dest.h = src.h;
-
- SDL_BlitSurface(images[IMG_LEDNUMS], &src, screen, &dest);
- /* move "cursor" */
- dest.x += src.w;
- }
- }
-}
-
-/* Translates mouse events into keyboard events when on-screen keypad used */
-/* or when exit button clicked. */
-void game_mouse_event(SDL_Event event)
-{
- int keypad_w, keypad_h, x, y, row, column;
- SDLKey key = SDLK_UNKNOWN;
- SDLMod mod = event.key.keysym.mod;
- keypad_w = 0;
- keypad_h = 0;
-
- /* Check to see if user clicked exit button: */
- /* The exit button is in the upper right corner of the screen: */
- if ((event.button.x >= (screen->w - images[IMG_STOP]->w))
- &&(event.button.y <= images[IMG_STOP]->h))
- {
- key = SDLK_ESCAPE;
- game_key_event(key, mod);
- return;
- }
-
- /* get out unless we really are using keypad */
- if ( level_start_wait
- || Opts_DemoMode()
- || !Opts_GetGlobalOpt(USE_KEYPAD))
- {
- return;
- }
-
-
- /* make sure keypad image is valid and has non-zero dimensions: */
- /* FIXME maybe this checking should be done once at the start */
- /* of game() rather than with every mouse click */
- if (MC_GetOpt(ALLOW_NEGATIVES))
- {
- if (!images[IMG_KEYPAD])
- return;
- else
- {
- keypad_w = images[IMG_KEYPAD]->w;
- keypad_h = images[IMG_KEYPAD]->h;
- }
- }
- else
- {
- if (!images[IMG_KEYPAD_NO_NEG])
- return;
- else
- {
- keypad_w = images[IMG_KEYPAD]->w;
- 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) &&
- event.button.x <=
- (screen->w / 2) + (keypad_w / 2) &&
- event.button.y >=
- (screen->h / 2) - (keypad_h / 2) &&
- event.button.y <=
- (screen->h / 2) + (keypad_h / 2))))
- /* click outside of keypad - do nothing */
- {
- return;
- }
-
- else /* click was within keypad */
- {
- x = (event.button.x - ((screen->w / 2) - (keypad_w / 2)));
- y = (event.button.y - ((screen->h / 2) - (keypad_h / 2)));
-
- /* Now determine what onscreen key was pressed */
- /* */
- /* The on-screen keypad has a 4 x 4 layout: */
- /* */
- /* ********************************* */
- /* * * * * * */
- /* * 7 * 8 * 9 * - * */
- /* * * * * * */
- /* ********************************* */
- /* * * * * * */
- /* * 4 * 5 * 6 * * */
- /* * * * * * */
- /* ************************* + * */
- /* * * * * * */
- /* * 1 * 2 * 3 * * */
- /* * * * * * */
- /* ********************************* */
- /* * * * */
- /* * 0 * Enter * */
- /* * * * */
- /* ********************************* */
- /* */
- /* The following code simply figures out the */
- /* row and column based on x and y and looks */
- /* up the SDlKey accordingly. */
-
- column = x/((keypad_w)/4);
- row = y/((keypad_h)/4);
-
- /* make sure row and column are sane */
- if (column < 0
- || column > 3
- || row < 0
- || row > 3)
- {
- printf("\nIllegal row or column value!\n");
- return;
- }
-
- /* simple but tedious - I am sure this could be done more elegantly */
-
- if (0 == row)
- {
- if (0 == column)
- key = SDLK_7;
- if (1 == column)
- key = SDLK_8;
- if (2 == column)
- key = SDLK_9;
- if (3 == column)
- key = SDLK_MINUS;
- }
- if (1 == row)
- {
- if (0 == column)
- key = SDLK_4;
- if (1 == column)
- key = SDLK_5;
- if (2 == column)
- key = SDLK_6;
- if (3 == column)
- key = SDLK_PLUS;
- }
- if (2 == row)
- {
- if (0 == column)
- key = SDLK_1;
- if (1 == column)
- key = SDLK_2;
- if (2 == column)
- key = SDLK_3;
- if (3 == column)
- key = SDLK_PLUS;
- }
- if (3 == row)
- {
- if (0 == column)
- key = SDLK_0;
- if (1 == column)
- key = SDLK_RETURN;
- if (2 == column)
- key = SDLK_RETURN;
- if (3 == column)
- key = SDLK_RETURN;
- }
-
- if (key == SDLK_UNKNOWN)
- {
- return;
- }
-
- /* now can proceed as if keyboard was used */
- game_key_event(key, mod);
- }
-}
-
-/* called by either key presses or mouse clicks on */
-/* on-screen keypad */
-void game_key_event(SDLKey key, SDLMod mod)
-{
- int i;
- key_pressed = 1; // Signal back in cases where waiting on any key
-
- if (key == SDLK_ESCAPE)
- {
- /* Escape key - quit! */
- user_quit_received = GAME_OVER_ESCAPE;
- }
- DEBUGCODE(debug_game)
- {
- if (key == SDLK_LEFTBRACKET) //a nice nonobvious/unused key
- {
- user_quit_received = GAME_OVER_CHEATER;
- }
- }
- else if (key == SDLK_TAB
- || key == SDLK_p)
- {
- /* [TAB] or [P]: Pause! (if settings allow) */
- if (Opts_AllowPause())
- {
- paused = 1;
- }
- }
-
- /* Adjust speed if settings allow: */
- else if (key == SDLK_UP)
- {
- if (Opts_AllowPause())
- {
- speed *= 1.2;
- }
- }
-
- else if (key == SDLK_DOWN)
- {
- if (Opts_AllowPause())
- {
- speed /= 1.2;
- }
- }
-
-
- /* Toggle screen mode: */
- else if (key == SDLK_F10)
- {
- Opts_SetGlobalOpt(FULLSCREEN, !Opts_GetGlobalOpt(FULLSCREEN) );
- SwitchScreenMode();
- game_recalc_positions();
- }
-
- /* Toggle music: */
-#ifndef NOSOUND
- else if (key == SDLK_F11)
- {
- if (Opts_UsingSound())
- {
- if (Mix_PlayingMusic())
- {
- Mix_HaltMusic();
- }
- else
- {
- Mix_PlayMusic(musics[MUS_GAME + (rand() % 3)], 0);
- }
- }
- }
-#endif
-
-
- if (level_start_wait > 0 || Opts_DemoMode() || !help_controls.laser_enabled)
- {
- /* Eat other keys until level start wait has passed,
- or if game is in demo mode: */
- key = SDLK_UNKNOWN;
- }
-
-
- /* The rest of the keys control the numeric answer console: */
-
- if (key >= SDLK_0 && key <= SDLK_9)
- {
- /* [0]-[9]: Add a new digit: */
- for (i = 0; i < MC_MAX_DIGITS-1; ++i)
- digits[i] = digits[i+1];
- digits[MC_MAX_DIGITS-1] = key - SDLK_0;
-
-// digits[0] = digits[1];
-// digits[1] = digits[2];
-// digits[2] = key - SDLK_0;
- tux_pressing = 1;
- }
- else if (key >= SDLK_KP0 && key <= SDLK_KP9)
- {
- /* Keypad [0]-[9]: Add a new digit: */
- for (i = 0; i < MC_MAX_DIGITS-1; ++i)
- digits[i] = digits[i+1];
- digits[MC_MAX_DIGITS-1] = key - SDLK_KP0;
-
-// digits[0] = digits[1];
-// digits[1] = digits[2];
-// digits[2] = key - SDLK_KP0;
- tux_pressing = 1;
- }
- /* support for negative answer input DSB */
- else if ((key == SDLK_MINUS || key == SDLK_KP_MINUS)
- && MC_GetOpt(ALLOW_NEGATIVES) ) /* do nothing unless neg answers allowed */
- {
- /* allow player to make answer negative: */
- neg_answer_picked = 1;
- tux_pressing = 1;
- }
- else if ( /* Effort to make logical operators clear: */
- (
- ( /* HACK this hard-codes the plus sign to the US layout: */
- (key == SDLK_EQUALS) && (mod & KMOD_SHIFT)
- )
- ||
- (
- key == SDLK_KP_PLUS
- )
- )
- &&
- MC_GetOpt(ALLOW_NEGATIVES)
- ) /* do nothing unless neg answers allowed */
- {
- /* allow player to make answer positive: */
- printf("SDKL_PLUS received\n");
- neg_answer_picked = 0;
- tux_pressing = 1;
- }
- else if (key == SDLK_BACKSPACE ||
- key == SDLK_CLEAR ||
- key == SDLK_DELETE)
- {
- /* [BKSP]: Clear digits! */
- for (i = 0; i < MC_MAX_DIGITS; ++i)
- digits[i] = 0;
- tux_pressing = 1;
- }
- else if (key == SDLK_RETURN ||
- key == SDLK_KP_ENTER ||
- key == SDLK_SPACE)
- {
- /* [ENTER]: Accept digits! */
- doing_answer = 1;
- }
-}
-
-/* Increment score: */
-
-void add_score(int inc)
-{
- score += inc;
- DEBUGMSG(debug_game,"Score is now: %d\n", score);
-}
-
-
-
-void reset_comets(void)
-{
- int i = 0;
- comet_counter = 0;
-
- for (i = 0; i < Opts_MaxComets(); i++)
- {
- comets[i].alive = 0;
- comets[i].expl = -1;
- comets[i].city = 0;
- comets[i].x = 0;
- comets[i].y = 0;
- comets[i].answer = 0;
- MC_ResetFlashCard(&(comets[i].flashcard) );
- comets[i].bonus = 0;
- }
-}
-
-
-void print_status(void)
-{
- int i;
-
- printf("\nCities:");
- printf("\nHits left: ");
- for (i = 0; i < NUM_CITIES; i++)
- printf("%02d ",cities[i].hits_left);
- printf("\nStatus: ");
- for (i = 0; i < NUM_CITIES; i++)
- printf("%02d ",cities[i].status);
-
- printf("\nPenguins:");
- printf("\nStatus: ");
- for (i = 0; i < NUM_CITIES; i++)
- printf("%02d ",penguins[i].status);
-
- printf("\nCloud:");
- printf("\nStatus: %d",cloud.status);
- printf("\nCity: %d",cloud.city);
- printf("\n");
-}
-
-
-void free_on_exit(void)
-{
- int i;
- for (i = 0; i < MAX_MAX_COMETS; ++i)
- MC_FreeFlashcard(&(comets[i].flashcard));
- free(comets);
- free(cities);
- free(penguins);
- free(steam);
-}
-
-/* Recalculate on-screen city & comet locations when screen dimensions change */
-void game_recalc_positions(void)
-{
- int i, img;
- int old_city_expl_height = city_expl_height;
-
- DEBUGMSG(debug_game,"Recalculating positions\n");
-
- if (Opts_GetGlobalOpt(USE_IGLOOS))
- img = IMG_IGLOO_INTACT;
- else
- img = IMG_CITY_BLUE;
-
- for (i = 0; i < NUM_CITIES; ++i)
- {
- /* 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] -> w) / 2));
- DEBUGMSG(debug_game,"%d,", cities[i].x);
- }
- else
- {
- cities[i].x = screen->w -
- (screen->w / (NUM_CITIES + 1) *
- (i - NUM_CITIES / 2) +
- images[img]->w / 2);
- DEBUGMSG(debug_game,"%d,", cities[i].x);
- }
-
- penguins[i].x = cities[i].x;
- }
-
- city_expl_height = screen->h - images[IMG_CITY_BLUE]->h;
- //move comets to a location 'equivalent' to where they were
- //i.e. with the same amount of time left before impact
- for (i = 0; i < Opts_MaxComets(); ++i)
- {
- if (!comets[i].alive)
- continue;
-
- comets[i].x = cities[comets[i].city].x;
- //if (Opts_GetGlobalOpt(FULLSCREEN) )
- comets[i].y = comets[i].y * city_expl_height / old_city_expl_height;
- //else
- // comets[i].y = comets[i].y * RES_Y / screen->h;
- }
-}
-
-static int num_comets_alive()
-{
- int i = 0;
- int living = 0;
- for(i = 0; i < Opts_MaxComets(); i++)
- if(comets[i].alive)
- living++;
- return living;
-}
-
diff --git a/src/highscore.c b/src/highscore.c
index 94e7e27..f844544 100644
--- a/src/highscore.c
+++ b/src/highscore.c
@@ -21,7 +21,6 @@
#include "SDL_extras.h"
#include "convert_utf.h"
#include "transtruct.h"
-#include "network.h"
#include "throttle.h"
diff --git a/src/lessons.c b/src/lessons.c
deleted file mode 100644
index 12359ae..0000000
--- a/src/lessons.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
-* C Implementation: lessons
-*
-* Description:
-*
-*
-* Author: David Bruce <davidstuartbruce at gmail.com>, (C) 2007
-*
-* Copyright: See COPYING file that comes with this distribution
-*
-*/
-#include <stdio.h>
-//for strtok()
-#include <string.h>
-#include "lessons.h"
-//for basename(), if available
-#ifdef HAVE_LIBGEN_H
-#include <libgen.h>
-#endif
-
-// extern unsigned char **lesson_list_titles;
-// extern unsigned char **lesson_list_filenames;
-int* lesson_list_goldstars = NULL;
-// extern int num_lessons;
-
-/* local function prototypes: */
-static int filename_comp(const char* s1, const char* s2);
-
-/* Reads the file pointed to by the arg and sets */
-/* lesson_list_goldstars* accordingly: */
-int read_goldstars_fp(FILE* fp)
-{
- char buf[PATH_MAX];
- char* token;
- const char delimiters[] = "\t\n\r"; /* this will keep newline chars out of string */
- int i;
-
- DEBUGMSG(debug_lessons, "Entering read_goldstars_fp()\n");
-
- /* get out if file pointer invalid: */
- if(!fp)
- {
- fprintf(stderr, "In read_goldstars_fp(), file pointer invalid!\n");
- return 0;
- }
-
- if (num_lessons <= 0)
- {
- perror("no lessons - returning");
- num_lessons = 0;
- 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 - */
- /* for now, each line just contains a lesson file name, */
- /* but eventually there may be more fields (e.g date, % correct) */
- token = strtok(buf, delimiters);
- if (!token)
- continue;
-
- /* Now set "goldstar" to 1 if we find a matching lesson: */
- for (i = 0; i < num_lessons; i++)
- {
- /* compare basenames only, not entire path (see below): */
- if (0 == filename_comp(token, lesson_list_filenames[i]))
- {
- lesson_list_goldstars[i] = 1;
- break; //should not have to worry about duplicates
- }
- }
- }
- return 1;
-}
-
-
-/* Write lessons gold star list to the provided FILE* in format */
-/* compatible with read_goldstars_fp () above. */
-
-void write_goldstars_fp(FILE* fp)
-{
- int i = 0;
-
- DEBUGMSG(debug_lessons, "Entering write_goldstars_fp()\n");
-
- /* get out if file pointer invalid: */
- if(!fp)
- {
- fprintf(stderr, "In write_goldstars_fp(), file pointer invalid!\n");
- return;
- }
-
- /* make sure we start at beginning: */
- rewind(fp);
-
- for (i = 0; i < num_lessons; i++)
- {
- 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)
- {
- fprintf(fp, "%s\n", lesson_list_filenames[i]);
- }
- }
- return;
-}
-
-
-/* Perform a strcasecmp() on two path strings, stripping away all the */
-/* dirs in the path and just comparing the filenames themselves: */
-/* FIXME: basename() may not be available on all platforms. */
-/* If not available, just compare the full paths. Consider including */
-/* our own implementation at some point. Note that the docs say */
-/* basename() takes a const char*, but the actual header is char*, */
-/* hence the casts to reassure the compiler. */
-static int filename_comp(const char* s1, const char* s2)
-{
-#ifdef HAVE_BASENAME
- return strcasecmp(basename((char*)s1), basename((char*)s2));
-#else
- return strcasecmp(s1, s2);
-#endif
-}
-
diff --git a/src/lessons.h b/src/lessons.h
deleted file mode 100644
index dc9473b..0000000
--- a/src/lessons.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// C Interface: lessons
-//
-// Description: Code for reading and parsing the lessons directory,
-// as well as keeping track of the player's progress
-//
-//
-// Author: David Bruce <davidstuartbruce at gmail.com>, (C) 2007
-//
-// Copyright: See COPYING file that comes with this distribution
-// (Briefly, GNU GPL version 2 or greater).
-//
-#ifndef LESSONS_H
-#define LESSONS_H
-
-#include "globals.h"
-
-int read_goldstars_fp(FILE* fp);
-void write_goldstars_fp(FILE* fp);
-
-#endif
diff --git a/src/menu.c b/src/menu.c
index 5771e4b..173586f 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -18,27 +18,17 @@
#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"
-#ifdef HAVE_LIBSDL_NET
-#include "network.h"
-#include "server.h"
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-
/* create string array of activities' names */
#define X(name) #name
char* activities[] = { ACTIVITIES };
@@ -215,13 +205,15 @@ MenuNode* load_menu_from_file(FILE* xml_file, MenuNode* parent)
read_attributes(xml_file, new_node);
if(new_node->title == NULL)
{
- DEBUGMSG(debug_menu_parser, "load_menu_from_file(): no title attribute, exiting\n");
+
+ 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;
}
@@ -302,66 +294,20 @@ int handle_activity(int act, int param)
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();
+ 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;
-
+ game();
+
case RUN_INFO:
ShowMessage(DEFAULT_MENU_FONT_SIZE,
_("TuxMath is free and open-source!"),
@@ -383,186 +329,7 @@ int handle_activity(int act, int param)
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(DEFAULT_MENU_FONT_SIZE, 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.
diff --git a/src/menu.h b/src/menu.h
index 9dd2732..52d4a54 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -32,25 +32,14 @@
#define ACTIVITIES \
X( RUN_QUIT ),\
- X( RUN_ACADEMY ),\
- X( RUN_CAMPAIGN ),\
X( RUN_ARCADE ),\
- X( RUN_CUSTOM ),\
X( RUN_MAIN_MENU ),\
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 */
diff --git a/src/options.c b/src/options.c
index 880c813..56ab43c 100644
--- a/src/options.c
+++ b/src/options.c
@@ -24,8 +24,6 @@
//#include "SDL.h"
-#include "mathcards.h"
-
#include "options.h"
#include "fileops.h"
#include "setup.h"
@@ -965,22 +963,6 @@ int int_to_bool(int i)
else
return 0;
}
-
-///* determine which option class a name belongs to, and set it */
-///* accordingly. Returns 1 on success, 0 on failure */
-//static int find_and_set_option(const char* name, int val)
-//{
-// int index = -1;
-//
-// if ((index = MC_MapTextToIndex(name)) != -1) //is it a math opt?
-// MC_SetOpt(index, val);
-// else if ((index = Opts_MapTextToIndex(name)) != -1) //is it a global opt?
-// Opts_SetGlobalOpt(index, val);
-// else //no? oh well.
-// return 0;
-//
-// return 1;
-//}
/* prints struct to stream: */
void print_game_options(FILE* fp, int verbose)
diff --git a/src/setup.c b/src/setup.c
index 1cfea86..341f9f8 100644
--- a/src/setup.c
+++ b/src/setup.c
@@ -40,7 +40,6 @@
#include "options.h"
#include "tuxhistory.h"
-#include "mathcards.h"
#include "setup.h"
#include "fileops.h"
#include "loaders.h"
@@ -141,13 +140,6 @@ void setup(int argc, char * argv[])
/* then read in global config file */
void initialize_options(void)
{
- /* Initialize MathCards backend for math questions: */
- if (!MC_Initialize())
- {
- printf("\nUnable to initialize MathCards\n");
- fprintf(stderr, "\nUnable to initialize MathCards\n");
- exit(1);
- }
/* initialize game_options struct with defaults DSB */
if (!Opts_Initialize())
@@ -249,13 +241,6 @@ void handle_command_args(int argc, char* argv[])
" current working directory, the absolute path of the\n"
" filename, tuxmath's missions directory, the user's\n"
" tuxmath directory, and the user's home.\n"
- "--playthroughlist - 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"
@@ -352,7 +337,7 @@ void handle_command_args(int argc, char* argv[])
else if (strcmp(argv[i], "--version") == 0 ||
strcmp(argv[i], "-v") == 0)
{
- printf("Tux, of Math Command (\"tuxmath\")\n"
+ printf("Tux History (\"tuxhistory\")\n"
"Version " VERSION "\n");
cleanup_on_error();
exit(0);
@@ -372,28 +357,6 @@ void handle_command_args(int argc, char* argv[])
{
Opts_SetGlobalOpt(USE_KEYPAD, 1);
}
- else if (strcmp(argv[i], "--allownegatives") == 0 ||
- strcmp(argv[i], "-n") == 0)
- {
- MC_SetOpt(ALLOW_NEGATIVES, 1);
- }
- else if (strcmp(argv[i], "--playthroughlist") == 0 ||
- strcmp(argv[i], "-l") == 0)
- {
- MC_SetOpt(PLAY_THROUGH_LIST, 1);
- }
- else if (strcmp(argv[i], "--answersfirst") == 0)
- {
- MC_SetOpt(FORMAT_ANSWER_LAST, 0);
- MC_SetOpt(FORMAT_ANSWER_FIRST, 1);
- MC_SetOpt(FORMAT_ANSWER_MIDDLE, 0);
- }
- else if (strcmp(argv[i], "--answersmiddle") == 0)
- {
- MC_SetOpt(FORMAT_ANSWER_LAST, 0);
- MC_SetOpt(FORMAT_ANSWER_FIRST, 0);
- MC_SetOpt(FORMAT_ANSWER_MIDDLE, 1);
- }
else if (strcmp(argv[i], "--speed") == 0 ||
strcmp(argv[i], "-s") == 0)
{
@@ -787,9 +750,7 @@ void cleanup_memory(void)
/* frees the game_options struct: */
Opts_Cleanup();
- /* frees any heap used by MathCards: */
- MC_EndGame();
-}
+ }
diff --git a/src/throttle.c b/src/throttle.c
new file mode 100644
index 0000000..5052fc8
--- /dev/null
+++ b/src/throttle.c
@@ -0,0 +1,45 @@
+/*
+* C Implementation: network.c
+*
+* Description: A simple function that uses SDL_Delay() to keep
+* loops from eating all available CPU.
+
+*
+* Author: David Bruce, and the TuxMath team, (C) 2009
+* Developers list: <tuxmath-devel at lists.sourceforge.net>
+*
+* Copyright: See COPYING file that comes with this distribution. (Briefly, GNU GPL).
+*/
+
+
+#include "SDL.h"
+
+/* NOTE now store the time elsewhere to make function thread-safe */
+
+void Throttle(int loop_msec, Uint32* last_t)
+{
+ Uint32 now_t, wait_t;
+
+ if(!last_t)
+ return;
+
+ //Target loop time must be between 0 and 1000 msec:
+ if(loop_msec < 0)
+ loop_msec = 0;
+ if(loop_msec > 1000)
+ loop_msec = 1000;
+
+ //See if we need to wait:
+ now_t = SDL_GetTicks();
+ if (now_t < (*last_t + loop_msec))
+ {
+ wait_t = (*last_t + loop_msec) - now_t;
+ //Avoid problem if we somehow wrap past uint32 size (at 49.7 days!)
+ if(wait_t < 0)
+ wait_t = 0;
+ if(wait_t > loop_msec)
+ wait_t = loop_msec;
+ SDL_Delay(wait_t);
+ }
+ *last_t = SDL_GetTicks();
+}
diff --git a/src/throttle.h b/src/throttle.h
new file mode 100644
index 0000000..6d55501
--- /dev/null
+++ b/src/throttle.h
@@ -0,0 +1,24 @@
+/*
+
+ throttle.h
+
+ Description: A simple function that uses SDL_Delay() to keep loops from eating all available
+ CPU
+ Author: David Bruce and the TuxMath team, (C) 2009
+
+ Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
+
+*/
+
+#ifndef THROTTLE_H
+#define THROTTLE_H
+
+#include "SDL.h"
+
+// This simple function uses SDL_Delay() to wait to return until 'loop_msec'
+// milliseconds after it returned the last time. Per SDL docs, the granularity
+// is likely no better than 10 msec
+// NOTE Uint32* last_t arg added to make function thread-safe
+void Throttle(int loop_msec, Uint32* last_t);
+
+#endif
diff --git a/src/tuxhistory.h b/src/tuxhistory.h
index e59f28b..4dfca5c 100644
--- a/src/tuxhistory.h
+++ b/src/tuxhistory.h
@@ -75,7 +75,4 @@ extern Mix_Chunk* sounds[]; /* declared in setup.c; also used in fileops.c, p
extern Mix_Music* musics[]; /* declared in setup.c; also used in fileops.c, game.c */
#endif
-
-/* NOTE: default values for math options are now in mathcards.h */
-
#endif
--
tuxhistory - Educational history game
More information about the Tux4kids-commits
mailing list