From 48dcdd627698354063fa1b551cfa1917dea1b25e Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 30 May 2005 16:15:34 +0000 Subject: [PATCH] First cut at a game timer. Yet another backend function which indicates whether a particular game state should have the timer going (for Mines the initial indeterminate state does not have this property, and neither does a dead or won state); a midend function that optionally (on request from the game) prepends a timer to the front of the status bar text; some complicated midend timing code. It's not great. It's ugly; it's probably slightly inaccurate; it's got no provision for anyone but the game author decreeing whether a game is timed or not. But Mines can't be taken seriously without a timer, so it's a start. git-svn-id: svn://svn.tartarus.org/sgt/puzzles@5866 cda61777-01e9-0310-a592-d414129be87e --- cube.c | 6 +++++ fifteen.c | 6 +++++ gtk.c | 6 ++++- midend.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- mines.c | 10 +++++++-- net.c | 6 +++++ netslide.c | 6 +++++ nullgame.c | 6 +++++ osx.m | 10 +++++---- pattern.c | 6 +++++ puzzles.h | 3 +++ rect.c | 6 +++++ sixteen.c | 6 +++++ solo.c | 6 +++++ twiddle.c | 6 +++++ windows.c | 12 +++++++++- 16 files changed, 158 insertions(+), 17 deletions(-) diff --git a/cube.c b/cube.c index 428569c..a65b918 100644 --- a/cube.c +++ b/cube.c @@ -1542,6 +1542,11 @@ static int game_wants_statusbar(void) return TRUE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame cube #endif @@ -1575,4 +1580,5 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; diff --git a/fifteen.c b/fifteen.c index 310e70a..bbdb939 100644 --- a/fifteen.c +++ b/fifteen.c @@ -802,6 +802,11 @@ static int game_wants_statusbar(void) return TRUE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame fifteen #endif @@ -835,4 +840,5 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; diff --git a/gtk.c b/gtk.c index 3fdfc87..84e5e72 100644 --- a/gtk.c +++ b/gtk.c @@ -98,10 +98,14 @@ void frontend_default_colour(frontend *fe, float *output) void status_bar(frontend *fe, char *text) { + char *rewritten; + assert(fe->statusbar); + rewritten = midend_rewrite_statusbar(fe->me, text); gtk_statusbar_pop(GTK_STATUSBAR(fe->statusbar), fe->statusctx); - gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, text); + gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, rewritten); + sfree(rewritten); } void start_draw(frontend *fe) diff --git a/midend.c b/midend.c index e31ce26..8adc1c3 100644 --- a/midend.c +++ b/midend.c @@ -43,6 +43,10 @@ struct midend_data { float flash_time, flash_pos; int dir; + int timing; + float elapsed; + char *laststatus; + int pressed_mouse_button; }; @@ -83,6 +87,9 @@ midend_data *midend_new(frontend *fe, const game *ourgame) me->dir = 0; me->ui = NULL; me->pressed_mouse_button = 0; + me->laststatus = NULL; + me->timing = FALSE; + me->elapsed = 0.0F; sfree(randseed); @@ -100,6 +107,7 @@ void midend_free(midend_data *me) me->ourgame->free_params(me->params); if (me->curparams) me->ourgame->free_params(me->curparams); + sfree(me->laststatus); sfree(me); } @@ -114,6 +122,16 @@ void midend_set_params(midend_data *me, game_params *params) me->params = me->ourgame->dup_params(params); } +static void midend_set_timer(midend_data *me) +{ + me->timing = (me->ourgame->is_timed && + me->ourgame->timing_state(me->states[me->statepos-1].state)); + if (me->timing || me->flash_time || me->anim_time) + activate_timer(me->frontend); + else + deactivate_timer(me->frontend); +} + void midend_new_game(midend_data *me) { while (me->nstates > 0) @@ -171,6 +189,8 @@ void midend_new_game(midend_data *me) me->nstates++; me->statepos = 1; me->drawstate = me->ourgame->new_drawstate(me->states[0].state); + me->elapsed = 0.0F; + midend_set_timer(me); if (me->ui) me->ourgame->free_ui(me->ui); me->ui = me->ourgame->new_ui(me->states[0].state); @@ -227,10 +247,7 @@ static void midend_finish_move(midend_data *me) me->anim_pos = me->anim_time = 0; me->dir = 0; - if (me->flash_time == 0 && me->anim_time == 0) - deactivate_timer(me->frontend); - else - activate_timer(me->frontend); + midend_set_timer(me); } static void midend_stop_anim(midend_data *me) @@ -266,7 +283,7 @@ void midend_restart_game(midend_data *me) me->anim_time = 0.0; midend_finish_move(me); midend_redraw(me); - activate_timer(me->frontend); + midend_set_timer(me); } static int midend_really_process_key(midend_data *me, int x, int y, int button) @@ -349,7 +366,7 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button) midend_redraw(me); - activate_timer(me->frontend); + midend_set_timer(me); return 1; } @@ -479,13 +496,22 @@ void midend_timer(midend_data *me, float tplus) if (me->anim_time > 0) midend_finish_move(me); } + me->flash_pos += tplus; if (me->flash_pos >= me->flash_time || me->flash_time == 0) { me->flash_pos = me->flash_time = 0; } - if (me->flash_time == 0 && me->anim_time == 0) - deactivate_timer(me->frontend); + midend_redraw(me); + + if (me->timing) { + float oldelapsed = me->elapsed; + me->elapsed += tplus; + if ((int)oldelapsed != (int)me->elapsed) + status_bar(me->frontend, me->laststatus ? me->laststatus : ""); + } + + midend_set_timer(me); } float *midend_colours(midend_data *me, int *ncolours) @@ -866,6 +892,36 @@ char *midend_solve(midend_data *me) me->anim_time = 0.0; midend_finish_move(me); midend_redraw(me); - activate_timer(me->frontend); + midend_set_timer(me); return NULL; } + +char *midend_rewrite_statusbar(midend_data *me, char *text) +{ + /* + * An important special case is that we are occasionally called + * with our own laststatus, to update the timer. + */ + if (me->laststatus != text) { + sfree(me->laststatus); + me->laststatus = dupstr(text); + } + + if (me->ourgame->is_timed) { + char timebuf[100], *ret; + int min, sec; + + sec = me->elapsed; + min = sec / 60; + sec %= 60; + sprintf(timebuf, "[%d:%02d] ", min, sec); + + ret = snewn(strlen(timebuf) + strlen(text) + 1, char); + strcpy(ret, timebuf); + strcat(ret, text); + return ret; + + } else { + return dupstr(text); + } +} diff --git a/mines.c b/mines.c index b2bc82c..881cad0 100644 --- a/mines.c +++ b/mines.c @@ -10,8 +10,6 @@ * That hook can talk to the game_ui and set the cheated flag, * and then make_move can avoid setting the `won' flag after that. * - * - timer - * * - question marks (arrgh, preferences?) * * - sensible parameter constraints @@ -2700,6 +2698,13 @@ static int game_wants_statusbar(void) return TRUE; } +static int game_timing_state(game_state *state) +{ + if (state->dead || state->won || !state->layout->mines) + return FALSE; + return TRUE; +} + #ifdef COMBINED #define thegame mines #endif @@ -2733,4 +2738,5 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + TRUE, game_timing_state, }; diff --git a/net.c b/net.c index 8793886..fa4c979 100644 --- a/net.c +++ b/net.c @@ -2568,6 +2568,11 @@ static int game_wants_statusbar(void) return TRUE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame net #endif @@ -2601,4 +2606,5 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; diff --git a/netslide.c b/netslide.c index 5209842..bf5fc75 100644 --- a/netslide.c +++ b/netslide.c @@ -1725,6 +1725,11 @@ static int game_wants_statusbar(void) return TRUE; } +static int game_timing_state(game_state *state) +{ + return FALSE; +} + #ifdef COMBINED #define thegame netslide #endif @@ -1758,4 +1763,5 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; diff --git a/nullgame.c b/nullgame.c index 7e27c4a..abb6cc5 100644 --- a/nullgame.c +++ b/nullgame.c @@ -215,6 +215,11 @@ static int game_wants_statusbar(void) return FALSE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame nullgame #endif @@ -248,4 +253,5 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; diff --git a/osx.m b/osx.m index ed33bf6..039f081 100644 --- a/osx.m +++ b/osx.m @@ -383,7 +383,7 @@ struct frontend { - (void)keyDown:(NSEvent *)ev; - (void)activateTimer; - (void)deactivateTimer; -- (void)setStatusLine:(NSString *)text; +- (void)setStatusLine:(char *)text; @end @implementation MyImageView @@ -1131,9 +1131,11 @@ struct frontend { [self sheetEndWithStatus:NO]; } -- (void)setStatusLine:(NSString *)text +- (void)setStatusLine:(char *)text { - [[status cell] setTitle:text]; + char *rewritten = midend_rewrite_statusbar(me, text); + [[status cell] setTitle:[NSString stringWithCString:rewritten]]; + sfree(rewritten); } @end @@ -1267,7 +1269,7 @@ void activate_timer(frontend *fe) void status_bar(frontend *fe, char *text) { - [fe->window setStatusLine:[NSString stringWithCString:text]]; + [fe->window setStatusLine:text]; } /* ---------------------------------------------------------------------- diff --git a/pattern.c b/pattern.c index df67c83..c5fd9dc 100644 --- a/pattern.c +++ b/pattern.c @@ -1105,6 +1105,11 @@ static int game_wants_statusbar(void) return FALSE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame pattern #endif @@ -1138,6 +1143,7 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; #ifdef STANDALONE_SOLVER diff --git a/puzzles.h b/puzzles.h index 9eb991a..f3db36f 100644 --- a/puzzles.h +++ b/puzzles.h @@ -145,6 +145,7 @@ char *midend_game_id(midend_data *me, char *id); char *midend_text_format(midend_data *me); char *midend_solve(midend_data *me); void midend_supersede_game_desc(midend_data *me, char *desc); +char *midend_rewrite_statusbar(midend_data *me, char *text); /* * malloc.c @@ -239,6 +240,8 @@ struct game { float (*flash_length)(game_state *oldstate, game_state *newstate, int dir, game_ui *ui); int (*wants_statusbar)(void); + int is_timed; + int (*timing_state)(game_state *state); }; /* diff --git a/rect.c b/rect.c index b0e0f9c..0ea0b8c 100644 --- a/rect.c +++ b/rect.c @@ -2515,6 +2515,11 @@ static int game_wants_statusbar(void) return FALSE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame rect #endif @@ -2548,4 +2553,5 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; diff --git a/sixteen.c b/sixteen.c index 8f43b7a..1871e5f 100644 --- a/sixteen.c +++ b/sixteen.c @@ -961,6 +961,11 @@ static int game_wants_statusbar(void) return TRUE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame sixteen #endif @@ -994,4 +999,5 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; diff --git a/solo.c b/solo.c index 9e350f6..addae60 100644 --- a/solo.c +++ b/solo.c @@ -2140,6 +2140,11 @@ static int game_wants_statusbar(void) return FALSE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame solo #endif @@ -2173,6 +2178,7 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; #ifdef STANDALONE_SOLVER diff --git a/twiddle.c b/twiddle.c index 6434c64..2523920 100644 --- a/twiddle.c +++ b/twiddle.c @@ -1111,6 +1111,11 @@ static int game_wants_statusbar(void) return TRUE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame twiddle #endif @@ -1144,4 +1149,5 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, }; diff --git a/windows.c b/windows.c index 383b742..0a61f3c 100644 --- a/windows.c +++ b/windows.c @@ -118,6 +118,7 @@ struct frontend { HFONT cfgfont; char *help_path; int help_has_contents; + char *laststatus; }; void fatal(char *fmt, ...) @@ -144,7 +145,14 @@ void get_random_seed(void **randseed, int *randseedsize) void status_bar(frontend *fe, char *text) { - SetWindowText(fe->statusbar, text); + char *rewritten = midend_rewrite_statusbar(fe->me, text); + if (!fe->laststatus || strcmp(rewritten, fe->laststatus)) { + SetWindowText(fe->statusbar, rewritten); + sfree(fe->laststatus); + fe->laststatus = rewritten; + } else { + sfree(rewritten); + } } void frontend_default_colour(frontend *fe, float *output) @@ -437,6 +445,8 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) fe->fonts = NULL; fe->nfonts = fe->fontsize = 0; + fe->laststatus = NULL; + { int i, ncolours; float *colours; -- 2.11.0