replaced glib function calls to g_string_*()
[rocksndiamonds.git] / src / game_bd / bd_gameplay.c
1 /*
2  * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <glib.h>
18 #include <glib/gi18n.h>
19
20 #include "main_bd.h"
21
22
23 /* universal settings */
24 static boolean gd_no_invisible_outbox = FALSE;
25
26
27 void gd_game_free(GdGame *game)
28 {
29   /* stop sounds */
30   gd_sound_off();
31
32   if (game->element_buffer)
33     gd_cave_map_free(game->element_buffer);
34   if (game->last_element_buffer)
35     gd_cave_map_free(game->last_element_buffer);
36   if (game->dir_buffer)
37     gd_cave_map_free(game->dir_buffer);
38   if (game->gfx_buffer)
39     gd_cave_map_free(game->gfx_buffer);
40
41   game->player_lives = 0;
42
43   if (game->cave)
44     gd_cave_free(game->cave);
45
46   /* if we recorded some replays during this run, we check them.
47      we remove those which are too short */
48   if (game->replays_recorded)
49   {
50     GList *citer;
51
52     /* check all caves */
53     for (citer = gd_caveset; citer != NULL; citer = citer->next)
54     {
55       GdCave *cave = (GdCave *)citer->data;
56       GList *riter;
57
58       /* check replays of all caves */
59       for (riter = cave->replays; riter != NULL; )
60       {
61         GdReplay *replay = (GdReplay *)riter->data;
62
63         /* remember next iter, as we may delete the current */
64         GList *nextrep = riter->next;
65
66         /* if we recorded this replay now, and it is too short, we delete it */
67         /* but do not delete successful ones! */
68         if (g_list_find(game->replays_recorded, replay) &&
69             (replay->movements->len < 16) &&
70             (!replay->success))
71         {
72           /* delete from list */
73           cave->replays = g_list_delete_link(cave->replays, riter);
74
75           /* also free replay */
76           gd_replay_free(replay);
77         }
78
79         riter = nextrep;
80       }
81     }
82
83     /* free the list of newly recorded replays, as we checked them */
84     g_list_free(game->replays_recorded);
85     game->replays_recorded = NULL;
86   }
87
88   free(game);
89 }
90
91 /* add bonus life. if sound enabled, play sound, too. */
92 static void add_bonus_life(GdGame *game, boolean inform_user)
93 {
94   /* only inform about bonus life when playing a game */
95   /* or when testing the cave (so the user can see that a bonus life can be earned in that cave */
96   if (game->type == GD_GAMETYPE_NORMAL ||
97       game->type == GD_GAMETYPE_TEST)
98   {
99     if (inform_user)
100     {
101       gd_sound_play_bonus_life();
102       game->bonus_life_flash = 100;
103     }
104   }
105
106   /* really increment number of lifes? only in a real game, nowhere else. */
107   if (game->player_lives &&
108       game->player_lives < gd_caveset_data->maximum_lives)
109   {
110     /* only add a life, if lives is > 0.
111        lives == 0 is a test run or a snapshot, no bonus life then. */
112     /* also, obey max number of bonus lives. */
113     game->player_lives++;
114   }
115 }
116
117 /* increment score of player.
118    flash screen if bonus life
119 */
120 static void increment_score(GdGame *game, int increment)
121 {
122   int i;
123
124   i = game->player_score / gd_caveset_data->bonus_life_score;
125   game->player_score += increment;
126   game->cave_score += increment;
127
128   /* also record to replay */
129   if (game->replay_record)
130     game->replay_record->score += increment;
131
132   /* if score crossed bonus_life_score point boundary, player won a bonus life */
133   if (game->player_score / gd_caveset_data->bonus_life_score > i)
134     add_bonus_life(game, TRUE);
135 }
136
137 /* do the things associated with loading a new cave. function creates gfx buffer and the like. */
138 static void load_cave(GdGame *game)
139 {
140   int x, y;
141
142   /* delete element buffer */
143   if (game->element_buffer)
144     gd_cave_map_free(game->element_buffer);
145   game->element_buffer = NULL;
146
147   /* delete last element buffer */
148   if (game->last_element_buffer)
149     gd_cave_map_free(game->last_element_buffer);
150   game->last_element_buffer = NULL;
151
152   /* delete direction buffer */
153   if (game->dir_buffer)
154     gd_cave_map_free(game->dir_buffer);
155   game->dir_buffer = NULL;
156
157   /* delete gfx buffer */
158   if (game->gfx_buffer)
159     gd_cave_map_free(game->gfx_buffer);
160   game->gfx_buffer = NULL;
161
162   /* load the cave */
163   game->cave_score = 0;
164
165   /* delete previous cave */
166   gd_cave_free(game->cave);
167
168   if (native_bd_level.loaded_from_caveset)
169     game->original_cave = gd_get_original_cave_from_caveset(game->cave_num);
170   else
171     game->original_cave = native_bd_level.cave;
172
173   game->cave = gd_get_prepared_cave(game->original_cave, game->level_num);
174
175   if (game->cave->intermission && game->cave->intermission_instantlife)
176     add_bonus_life(game, FALSE);
177
178   game->milliseconds_anim = 0;
179   game->milliseconds_game = 0;        /* set game timer to zero, too */
180
181   /* create new element buffer */
182   game->element_buffer = gd_cave_map_new(game->cave, int);
183
184   for (y = 0; y < game->cave->h; y++)
185     for (x = 0; x < game->cave->w; x++)
186       game->element_buffer[y][x] = O_NONE;
187
188   /* create new last element buffer */
189   game->last_element_buffer = gd_cave_map_new(game->cave, int);
190
191   for (y = 0; y < game->cave->h; y++)
192     for (x = 0; x < game->cave->w; x++)
193       game->last_element_buffer[y][x] = O_NONE;
194
195   /* create new direction buffer */
196   game->dir_buffer = gd_cave_map_new(game->cave, int);
197
198   for (y = 0; y < game->cave->h; y++)
199     for (x = 0; x < game->cave->w; x++)
200       game->dir_buffer[y][x] = GD_MV_STILL;
201
202   /* create new gfx buffer */
203   game->gfx_buffer = gd_cave_map_new(game->cave, int);
204
205   for (y = 0; y < game->cave->h; y++)
206     for (x = 0; x < game->cave->w; x++)
207       game->gfx_buffer[y][x] = -1;    /* fill with "invalid" */
208 }
209
210 GdCave *gd_create_snapshot(GdGame *game)
211 {
212   GdCave *snapshot;
213   g_return_val_if_fail (game->cave != NULL, NULL);
214
215   /* make an exact copy */
216   snapshot = gd_cave_new_from_cave(game->cave);
217
218   return snapshot;
219 }
220
221 /* this starts a new game */
222 GdGame *gd_game_new(const int cave, const int level)
223 {
224   GdGame *game;
225
226   game = checked_calloc(sizeof(GdGame));
227
228   game->cave_num = cave;
229   game->level_num = level;
230
231   game->player_lives = gd_caveset_data->initial_lives;
232   game->player_score = 0;
233
234   game->player_move = GD_MV_STILL;
235   game->player_move_stick = FALSE;
236   game->player_fire = FALSE;
237
238   game->type = GD_GAMETYPE_NORMAL;
239   game->state_counter = GAME_INT_LOAD_CAVE;
240
241   game->show_story = TRUE;
242
243   return game;
244 }
245
246 /* starts a new snapshot playing */
247 GdGame *gd_game_new_replay(GdCave *cave, GdReplay *replay)
248 {
249   GdGame *game;
250
251   game = checked_calloc(sizeof(GdGame));
252
253   gd_strcpy(game->player_name, "");
254
255   game->player_lives = 0;
256   game->player_score = 0;
257
258   game->player_move = GD_MV_STILL;
259   game->player_move_stick = FALSE;
260   game->player_fire = FALSE;
261
262   game->original_cave = cave;
263   game->replay_from = replay;
264
265   game->type = GD_GAMETYPE_REPLAY;
266   game->state_counter = GAME_INT_LOAD_CAVE;
267
268   return game;
269 }
270
271 static void iterate_cave(GdGame *game, GdDirection player_move, boolean fire)
272 {
273   boolean suicide = FALSE;
274
275   /* if we are playing a replay, but the user intervents, continue as a snapshot. */
276   /* do not trigger this for fire, as it would not be too intuitive. */
277   if (game->type == GD_GAMETYPE_REPLAY)
278   {
279     if (player_move != GD_MV_STILL)
280     {
281       game->type = GD_GAMETYPE_CONTINUE_REPLAY;
282       game->replay_from = NULL;
283     }
284   }
285
286   /* ANYTHING EXCEPT A TIMEOUT, WE ITERATE THE CAVE */
287   if (game->cave->player_state != GD_PL_TIMEOUT)
288   {
289     /* IF PLAYING FROM REPLAY, OVERWRITE KEYPRESS VARIABLES FROM REPLAY */
290     if (game->type == GD_GAMETYPE_REPLAY)
291     {
292       boolean result;
293
294       /* if the user does touch the keyboard, we immediately exit replay,
295          and he can continue playing */
296       result = gd_replay_get_next_movement(game->replay_from, &player_move, &fire, &suicide);
297       /* if could not get move from snapshot, continue from keyboard input. */
298       if (!result)
299         game->replay_no_more_movements++;
300
301       /* if no more available movements, and the user does not do anything,
302          we cover cave and stop game. */
303       if (game->replay_no_more_movements > 15)
304         game->state_counter = GAME_INT_COVER_START;
305     }
306
307     if (TapeIsPlaying_ReplayBD())
308     {
309       byte *action_rnd = TapePlayAction_BD();
310
311       if (action_rnd != NULL)
312       {
313         int action_bd = map_action_RND_to_BD(action_rnd[0]);
314
315         player_move = (action_bd & GD_REPLAY_MOVE_MASK);
316         fire        = (action_bd & GD_REPLAY_FIRE_MASK) != 0;
317       }
318     }
319
320     /* iterate cave */
321     gd_cave_iterate(game->cave, player_move, fire, suicide);
322
323     if (game->replay_record)
324       gd_replay_store_movement(game->replay_record, player_move, fire, suicide);
325
326     if (game->cave->score)
327       increment_score(game, game->cave->score);
328
329     gd_sound_play_cave(game->cave);
330   }
331
332   if (game->cave->player_state == GD_PL_EXITED)
333   {
334     if (game->cave->intermission &&
335         game->cave->intermission_rewardlife &&
336         game->player_lives != 0)
337     {
338       /* one life extra for completing intermission */
339       add_bonus_life(game, FALSE);
340     }
341
342     if (game->replay_record)
343       game->replay_record->success = TRUE;
344
345     /* start adding points for remaining time */
346     game->state_counter = GAME_INT_CHECK_BONUS_TIME;
347     gd_cave_clear_sounds(game->cave);
348
349     /* play cave finished sound */
350     gd_sound_play(game->cave, GD_S_FINISHED, O_NONE, -1, -1);
351     gd_sound_play_cave(game->cave);
352   }
353
354   if (game->cave->player_state == GD_PL_DIED ||
355       game->cave->player_state == GD_PL_TIMEOUT)
356   {
357     game_bd.game_over = TRUE;
358     game_bd.cover_screen = TRUE;
359   }
360 }
361
362 static GdGameState gd_game_main_int(GdGame *game, boolean allow_iterate, boolean fast_forward)
363 {
364   int millisecs_elapsed = 20;
365   boolean frame;    /* set to true, if this will be an animation frame */
366   GdGameState return_state;
367   int counter_next;
368   int x, y;
369
370   counter_next = GAME_INT_INVALID;
371   return_state = GD_GAME_INVALID_STATE;
372   game->milliseconds_anim += millisecs_elapsed;    /* keep track of time */
373   frame = FALSE;    /* set to true, if this will be an animation frame */
374
375   if (game->milliseconds_anim >= 40)
376   {
377     frame = TRUE;
378     game->milliseconds_anim -= 40;
379   }
380
381   /* cannot be less than uncover start. */
382   if (game->state_counter < GAME_INT_LOAD_CAVE)
383   {
384     ;
385   }
386   else if (game->state_counter == GAME_INT_LOAD_CAVE)
387   {
388     /* do the things associated with loading a new cave. function creates gfx buffer and the like. */
389     load_cave(game);
390
391     return_state = GD_GAME_NOTHING;
392     counter_next = GAME_INT_SHOW_STORY;
393   }
394   else if (game->state_counter == GAME_INT_SHOW_STORY)
395   {
396     /* for normal game, every cave can have a long string of description/story. show that. */
397
398     /* if we have a story... */
399 #if 0
400     if (game->show_story && game->original_cave && game->original_cave->story != NULL)
401       Info("Cave Story: %s", game->original_cave->story);
402 #endif
403
404     counter_next = GAME_INT_START_UNCOVER;
405     return_state = GD_GAME_NOTHING;
406   }
407   else if (game->state_counter == GAME_INT_START_UNCOVER)
408   {
409     /* the very beginning. */
410
411     /* cover all cells of cave */
412     for (y = 0; y < game->cave->h; y++)
413       for (x = 0; x < game->cave->w; x++)
414         game->cave->map[y][x] |= COVERED;
415
416     counter_next = game->state_counter + 1;
417
418     /* very important: tell the caller that we loaded a new cave. */
419     /* size of the cave might be new, colors might be new, and so on. */
420     return_state = GD_GAME_CAVE_LOADED;
421   }
422   else if (game->state_counter < GAME_INT_UNCOVER_ALL)
423   {
424     /* uncover animation */
425
426     /* to play cover sound */
427     gd_sound_play(game->cave, GD_S_COVERING, O_COVERED, -1, -1);
428     gd_sound_play_cave(game->cave);
429
430     counter_next = game->state_counter;
431
432     if (frame)
433     {
434       int j;
435
436       /* original game uncovered one cell per line each frame.
437        * we have different cave sizes, so uncover width * height / 40 random
438        * cells each frame. (original was width = 40).
439        * this way the uncovering is the same speed also for intermissions. */
440       for (j = 0; j < game->cave->w * game->cave->h / 40; j++)
441       {
442         y = g_random_int_range(0, game->cave->h);
443         x = g_random_int_range(0, game->cave->w);
444
445         game->cave->map[y][x] &= ~COVERED;
446       }
447
448       counter_next++;    /* as we did something, advance the counter. */
449     }
450
451     return_state = GD_GAME_NOTHING;
452   }
453   else if (game->state_counter == GAME_INT_UNCOVER_ALL)
454   {
455     /* time to uncover the whole cave. */
456     for (y = 0; y < game->cave->h; y++)
457       for (x = 0; x < game->cave->w; x++)
458         game->cave->map[y][x] &= ~COVERED;
459
460     /* to stop uncover sound. */
461     gd_cave_clear_sounds(game->cave);
462     gd_sound_play_cave(game->cave);
463
464     counter_next = GAME_INT_CAVE_RUNNING;
465     return_state = GD_GAME_NOTHING;
466   }
467   else if (game->state_counter == GAME_INT_CAVE_RUNNING)
468   {
469     /* normal. */
470     int cavespeed;
471
472     if (!fast_forward)
473       cavespeed = game->cave->speed;   /* cave speed in ms, like 175ms/frame */
474     else
475       cavespeed = 40;    /* if fast forward, ignore cave speed, and go as 25 iterations/sec */
476
477     /* ITERATION - cave is running. */
478
479     /* normally nothing happes. but if we iterate, this might change. */
480     return_state = GD_GAME_NOTHING;
481
482     /* if allowing cave movements, add elapsed time to timer. and then we can check what to do. */
483     if (allow_iterate)
484       game->milliseconds_game += millisecs_elapsed;
485
486     /* increment cycle (frame) counter for the current cave iteration */
487     game->itercycle++;
488
489     if (game->milliseconds_game >= cavespeed)
490     {
491       GdPlayerState pl;
492
493       game->milliseconds_game -= cavespeed;
494       pl = game->cave->player_state;
495
496       /* initialize buffers for last cave element and direction for next iteration */
497       for (y = 0; y < game->cave->h; y++)
498       {
499         for (x = 0; x < game->cave->w; x++)
500         {
501           game->last_element_buffer[y][x] = game->element_buffer[y][x];
502           game->dir_buffer[y][x] = GD_MV_STILL;
503         }
504       }
505
506       /* store last maximum number of cycles (to force redraw if changed) */
507       game->itermax_last = game->itermax;
508
509       /* update maximum number of cycles (frame) per cave iteration */
510       game->itermax = game->itercycle;
511
512       /* reset cycle (frame) counter for the next cave iteration */
513       game->itercycle = 0;
514
515       iterate_cave(game, game->player_move, game->player_fire);
516
517       if (game->player_move == GD_MV_STILL)
518       {
519         game->player_move_stick = FALSE;
520       }
521       else
522       {
523         game->player_move_stick = TRUE;
524         game->player_move = GD_MV_STILL;
525       }
526
527       /* as we iterated, the score and the like could have been changed. */
528       return_state = GD_GAME_LABELS_CHANGED;
529
530       /* and if the cave timeouted at this moment, that is a special case. */
531       if (pl != GD_PL_TIMEOUT && game->cave->player_state == GD_PL_TIMEOUT)
532         return_state = GD_GAME_TIMEOUT_NOW;
533     }
534
535     /* do not change counter state, as it is set by iterate_cave() */
536     counter_next = game->state_counter;
537   }
538   else if (game->state_counter == GAME_INT_CHECK_BONUS_TIME)
539   {
540     /* before covering, we check for time bonus score */
541     if (frame)
542     {
543       /* if time remaining, bonus points are added. do not start animation yet. */
544       if (game->cave->time > 0)
545       {
546         /* subtract number of "milliseconds" - nothing to do with gameplay->millisecs! */
547         game->cave->time -= game->cave->timing_factor;
548
549         /* higher levels get more bonus points per second remained */
550         increment_score(game, game->cave->timevalue);
551
552         /* if much time (> 60s) remained, fast counter :) */
553         if (game->cave->time > 60 * game->cave->timing_factor)
554         {
555           /* decrement by nine each frame, so it also looks like a fast counter. 9 is 8 + 1! */
556           game->cave->time -= 8 * game->cave->timing_factor;
557           increment_score(game, game->cave->timevalue * 8);
558         }
559
560         /* just to be neat */
561         if (game->cave->time < 0)
562           game->cave->time = 0;
563
564         counter_next = game->state_counter;    /* do not change yet */
565       }
566       else
567       {
568         game_bd.level_solved = TRUE;
569         game_bd.cover_screen = TRUE;
570
571         /* if no more points, start waiting a bit, and later start covering. */
572         counter_next = GAME_INT_WAIT_BEFORE_COVER;
573       }
574
575       if (game->cave->time / game->cave->timing_factor > 8)
576         gd_sound_play(game->cave, GD_S_FINISHED, O_NONE, -1, -1); /* play cave finished sound */
577
578       /* play bonus sound */
579       gd_cave_set_seconds_sound(game->cave);
580       gd_sound_play_cave(game->cave);
581
582       return_state = GD_GAME_LABELS_CHANGED;
583     }
584     else
585     {
586       return_state = GD_GAME_NOTHING;
587
588       /* do not change counter state, as it is set by iterate_cave() */
589       counter_next = game->state_counter;
590     }
591   }
592   else if (game->state_counter == GAME_INT_WAIT_BEFORE_COVER)
593   {
594     /* after adding bonus points, we wait some time before starting to cover.
595        this is the FIRST frame... so we check for game over and maybe jump there */
596     /* if no more lives, game is over. */
597     counter_next = game->state_counter;
598
599     if (game->type == GD_GAMETYPE_NORMAL && game->player_lives == 0)
600       return_state = GD_GAME_NO_MORE_LIVES;
601     else
602       return_state = GD_GAME_NOTHING;
603   }
604   else if (game->state_counter > GAME_INT_WAIT_BEFORE_COVER &&
605            game->state_counter < GAME_INT_COVER_START)
606   {
607     /* after adding bonus points, we wait some time before starting to cover.
608        ... and the other frames. */
609     counter_next = game->state_counter;
610     if (frame)
611       counter_next++;    /* 40 ms elapsed, advance counter */
612
613     return_state = GD_GAME_NOTHING;
614   }
615   else if (game->state_counter == GAME_INT_COVER_START)
616   {
617     /* starting to cover. start cover sound. */
618
619     gd_cave_clear_sounds(game->cave);
620     gd_sound_play(game->cave, GD_S_COVERING, O_COVERED, -1, -1);
621
622     /* to play cover sound */
623     gd_sound_play_cave(game->cave);
624
625     counter_next = game->state_counter + 1;
626     return_state = GD_GAME_NOTHING;
627   }
628   else if (game->state_counter > GAME_INT_COVER_START &&
629            game->state_counter < GAME_INT_COVER_ALL)
630   {
631     /* covering. */
632     gd_sound_play(game->cave, GD_S_COVERING, O_COVERED, -1, -1);
633
634     counter_next = game->state_counter;
635
636     if (frame)
637     {
638       int j;
639
640       counter_next++;    /* 40 ms elapsed, doing cover: advance counter */
641
642       /* covering eight times faster than uncovering. */
643       for (j = 0; j < game->cave->w * game->cave->h * 8 / 40; j++)
644         game->cave->map[g_random_int_range(0, game->cave->h)][g_random_int_range (0, game->cave->w)] |= COVERED;
645     }
646
647     return_state = GD_GAME_NOTHING;
648   }
649   else if (game->state_counter == GAME_INT_COVER_ALL)
650   {
651     /* cover all */
652     for (y = 0; y < game->cave->h; y++)
653       for (x = 0; x < game->cave->w; x++)
654         game->cave->map[y][x] |= COVERED;
655
656     counter_next = game->state_counter + 1;
657     return_state = GD_GAME_NOTHING;
658
659     /* to stop uncover sound. */
660     gd_cave_clear_sounds(game->cave);
661     gd_sound_play_cave(game->cave);
662   }
663   else
664   {
665     /* cover all + 1 */
666
667     /* if this is a normal game: */
668     if (game->type == GD_GAMETYPE_NORMAL)
669     {
670       if (game->player_lives != 0)
671         return_state = GD_GAME_NOTHING;    /* and go to next level */
672       else
673         return_state = GD_GAME_GAME_OVER;
674     }
675     else
676     {
677       /* for snapshots and replays and the like, this is the end. */
678       return_state = GD_GAME_STOP;
679     }
680   }
681
682   /* draw the cave */
683   if (frame)
684   {
685     if (game->bonus_life_flash)    /* bonus life - frames */
686       game->bonus_life_flash--;
687
688     game->animcycle = (game->animcycle + 1) % 8;
689   }
690
691   /* always render the cave to the gfx buffer;
692      however it may do nothing if animcycle was not changed. */
693   if (game->element_buffer && game->gfx_buffer)
694     gd_drawcave_game(game->cave, game->element_buffer, game->gfx_buffer,
695                      game->bonus_life_flash != 0, game->animcycle, gd_no_invisible_outbox);
696
697   game->state_counter = counter_next;
698
699   return return_state;
700 }
701
702 void play_game_func(GdGame *game, int action)
703 {
704   GdGameState state;
705   boolean move_up    = ((action & JOY_UP)    != 0);
706   boolean move_down  = ((action & JOY_DOWN)  != 0);
707   boolean move_left  = ((action & JOY_LEFT)  != 0);
708   boolean move_right = ((action & JOY_RIGHT) != 0);
709   boolean fire  = ((action & (JOY_BUTTON_1 | JOY_BUTTON_2)) != 0);
710
711   if (game->player_move_stick || move_up || move_down || move_left || move_right) // no "fire"!
712   {
713     /* get movement */
714     game->player_move = gd_direction_from_keypress(move_up, move_down, move_left, move_right);
715
716     /* when storing last action, only update fire action with direction */
717     /* (prevents clearing direction if snapping stopped before action is performed) */
718     game->player_fire = fire;
719   }
720
721   /* if no direction was stored before, allow setting fire to current state */
722   if (game->player_move == GD_MV_STILL)
723     game->player_fire = fire;
724
725   /* tell the interrupt "20ms has passed" */
726   state = gd_game_main_int(game, !game->out_of_window, gd_keystate[SDL_SCANCODE_F]);
727
728   /* state of game, returned by gd_game_main_int */
729   switch (state)
730   {
731     case GD_GAME_CAVE_LOADED:
732       /* select colors, prepare drawing etc. */
733       gd_scroll_to_origin();
734
735       /* fill whole screen with black - cave might be smaller than previous! */
736       FillRectangle(gd_screen_bitmap, 0, 0, SXSIZE, SYSIZE, BLACK_PIXEL);
737       break;
738
739     default:
740       break;
741   }
742
743   /* for the sdl version, it seems nicer if we first scroll, and then draw. */
744   /* scrolling for the sdl version will merely invalidate the whole gfx buffer. */
745   /* if drawcave was before scrolling, it would draw, scroll would invalidate,
746      and then it should be drawn again */
747   /* only do the drawing if the cave already exists. */
748   if (game->cave && game->element_buffer && game->gfx_buffer)
749   {
750     /* if fine scrolling, scroll at 50hz. if not, only scroll at every second call, so 25hz. */
751     /* do the scrolling. scroll exactly, if player is not yet alive */
752     game->out_of_window = gd_scroll(game, game->cave->player_state == GD_PL_NOT_YET, FALSE);
753   }
754 }