X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=afa0f24f923f9cbcccfbe3ebcac1872545fe2b55;hb=db0cf963a41d958dc11ee1d3cfb2b1f88cba7f76;hp=62ed8bbbe66ce3c9c0642420afa724002cea924f;hpb=548bc4ec64319d780a7bc38a6d0141bf526c7e16;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 62ed8bbb..afa0f24f 100644 --- a/src/game.c +++ b/src/game.c @@ -59,6 +59,8 @@ #define USE_FIX_KILLED_BY_NON_WALKABLE (USE_NEW_STUFF * 1) #define USE_FIX_IMPACT_COLLISION (USE_NEW_STUFF * 1) +#define USE_GFX_RESET_WHEN_NOT_MOVING (USE_NEW_STUFF * 1) + /* for DigField() */ #define DF_NO_PUSH 0 @@ -85,9 +87,16 @@ #define EX_TYPE_DYNA (1 << 4) #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER) +#if 1 +#define PANEL_OFF() (local_player->LevelSolved_PanelOff) +#define PANEL_DEACTIVATED(p) ((p)->x < 0 || (p)->y < 0 || PANEL_OFF()) +#define PANEL_XPOS(p) (DX + ALIGNED_MENU_XPOS(p)) +#define PANEL_YPOS(p) (DY + ALIGNED_MENU_YPOS(p)) +#else #define PANEL_DEACTIVATED(p) ((p).x < 0 || (p).y < 0) #define PANEL_XPOS(p) (ALIGNED_XPOS((p).x, (p).width, (p).align)) #define PANEL_YPOS(p) ((p).y) +#endif /* special positions in the game control window (relative to control window) */ #define XX_LEVEL1 (PANEL_XPOS(game.panel.level)) @@ -913,6 +922,8 @@ static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, void GetPlayerConfig() { + GameFrameDelay = setup.game_frame_delay; + if (!audio.sound_available) setup.sound_simple = FALSE; @@ -931,57 +942,6 @@ void GetPlayerConfig() InitJoysticks(); } -static int getBeltNrFromBeltElement(int element) -{ - return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 : - element < EL_CONVEYOR_BELT_3_LEFT ? 1 : - element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3); -} - -static int getBeltNrFromBeltActiveElement(int element) -{ - return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 : - element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 : - element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3); -} - -static int getBeltNrFromBeltSwitchElement(int element) -{ - return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 : - element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 : - element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3); -} - -static int getBeltDirNrFromBeltSwitchElement(int element) -{ - static int belt_base_element[4] = - { - EL_CONVEYOR_BELT_1_SWITCH_LEFT, - EL_CONVEYOR_BELT_2_SWITCH_LEFT, - EL_CONVEYOR_BELT_3_SWITCH_LEFT, - EL_CONVEYOR_BELT_4_SWITCH_LEFT - }; - - int belt_nr = getBeltNrFromBeltSwitchElement(element); - int belt_dir_nr = element - belt_base_element[belt_nr]; - - return (belt_dir_nr % 3); -} - -static int getBeltDirFromBeltSwitchElement(int element) -{ - static int belt_move_dir[3] = - { - MV_LEFT, - MV_NONE, - MV_RIGHT - }; - - int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element); - - return belt_move_dir[belt_dir_nr]; -} - static int get_element_from_group_element(int element) { if (IS_GROUP_ELEMENT(element)) @@ -1325,148 +1285,151 @@ static inline void InitField_WithBug2(int x, int y, boolean init_game) #if 1 -inline void DrawGameValue_Emeralds(int value) +void DrawGameValue_Emeralds(int value) { + struct TextPosInfo *pos = &game.panel.gems; int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); - int xpos = (3 * 14 - 3 * font_width) / 2; + int digits = pos->chars; - if (PANEL_DEACTIVATED(game.panel.gems)) + if (PANEL_DEACTIVATED(pos)) return; - game.panel.gems.width = game.panel.gems.chars * font_width; - xpos = 0; + pos->width = digits * font_width; - DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), font_nr); + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); } -inline void DrawGameValue_Dynamite(int value) +void DrawGameValue_Dynamite(int value) { + struct TextPosInfo *pos = &game.panel.inventory; int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); - int xpos = (3 * 14 - 3 * font_width) / 2; - - if (PANEL_DEACTIVATED(game.panel.inventory)) - return; - - game.panel.inventory.width = game.panel.inventory.chars * font_width; - xpos = 0; - - DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), font_nr); -} - -inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) -{ - int base_key_graphic = EL_KEY_1; - int i; + int digits = pos->chars; - if (PANEL_DEACTIVATED(game.panel.keys)) + if (PANEL_DEACTIVATED(pos)) return; - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - base_key_graphic = EL_EM_KEY_1; - - /* currently only 4 of 8 possible keys are displayed */ - for (i = 0; i < STD_NUM_KEYS; i++) - { - int x = XX_KEYS + i * MINI_TILEX; - int y = YY_KEYS; + pos->width = digits * font_width; - if (key[i]) - DrawMiniGraphicExt(drawto, DX + x,DY + y, el2edimg(base_key_graphic + i)); - else - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, - DOOR_GFX_PAGEX5 + x, y, MINI_TILEX, MINI_TILEY, DX + x,DY + y); - } + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); } -inline void DrawGameValue_Score(int value) +void DrawGameValue_Score(int value) { + struct TextPosInfo *pos = &game.panel.score; int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); - int xpos = (5 * 14 - 5 * font_width) / 2; + int digits = pos->chars; - if (PANEL_DEACTIVATED(game.panel.score)) + if (PANEL_DEACTIVATED(pos)) return; - game.panel.score.width = game.panel.score.chars * font_width; - xpos = 0; + pos->width = digits * font_width; - DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), font_nr); + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); } -inline void DrawGameValue_Time(int value) +void DrawGameValue_Time(int value) { + struct TextPosInfo *pos = &game.panel.time; static int last_value = -1; - int num_digits1 = 3; - int num_digits2 = 4; - int num_digits = game.panel.time.chars; + int digits1 = 3; + int digits2 = 4; + int digits = pos->chars; int font1_nr = FONT_TEXT_2; int font2_nr = FONT_TEXT_1; int font_nr = font1_nr; - int font1_width = getFontWidth(font1_nr); - int font2_width = getFontWidth(font2_nr); - int xpos3 = (3 * 14 - 3 * font1_width) / 2; - int xpos4 = (4 * 10 - 4 * font2_width) / 2; + boolean use_dynamic_digits = (digits == -1 ? TRUE : FALSE); - if (PANEL_DEACTIVATED(game.panel.time)) + if (PANEL_DEACTIVATED(pos)) return; - if (num_digits == -1) /* use dynamic number of digits */ + if (use_dynamic_digits) /* use dynamic number of digits */ { - num_digits = (value < 1000 ? num_digits1 : num_digits2); - font_nr = (value < 1000 ? font1_nr : font2_nr); + digits = (value < 1000 ? digits1 : digits2); + font_nr = (value < 1000 ? font1_nr : font2_nr); } - xpos3 = 0; - xpos4 = 0; - /* clear background if value just changed its size (dynamic digits only) */ - if (game.panel.time.chars == -1 && (last_value < 1000) != (value < 1000)) + if (use_dynamic_digits && (last_value < 1000) != (value < 1000)) { - int width1 = num_digits1 * getFontWidth(font1_nr); - int width2 = num_digits2 * getFontWidth(font2_nr); + int width1 = digits1 * getFontWidth(font1_nr); + int width2 = digits2 * getFontWidth(font2_nr); int max_width = MAX(width1, width2); int max_height = MAX(getFontHeight(font1_nr), getFontHeight(font2_nr)); - game.panel.time.width = max_width; + pos->width = max_width; - ClearRectangleOnBackground(drawto, DX_TIME, DY_TIME, max_width, max_height); + ClearRectangleOnBackground(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), + max_width, max_height); } - game.panel.time.width = num_digits * getFontWidth(font_nr); + pos->width = digits * getFontWidth(font_nr); - DrawText(DX_TIME, DY_TIME, int2str(value, num_digits), font_nr); + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); last_value = value; } -inline void DrawGameValue_Level(int value) +void DrawGameValue_Level(int value) { - int num_digits1 = 2; - int num_digits2 = 3; - int num_digits = game.panel.level.chars; + struct TextPosInfo *pos = &game.panel.level; + int digits1 = 2; + int digits2 = 3; + int digits = pos->chars; int font1_nr = FONT_TEXT_2; int font2_nr = FONT_TEXT_1; int font_nr = font1_nr; + boolean use_dynamic_digits = (digits == -1 ? TRUE : FALSE); - if (PANEL_DEACTIVATED(game.panel.level)) + if (PANEL_DEACTIVATED(pos)) return; - if (num_digits == -1) /* use dynamic number of digits */ + if (use_dynamic_digits) /* use dynamic number of digits */ { - num_digits = (level_nr < 100 ? num_digits1 : num_digits2); - font_nr = (level_nr < 100 ? font1_nr : font2_nr); + digits = (level_nr < 100 ? digits1 : digits2); + font_nr = (level_nr < 100 ? font1_nr : font2_nr); } - game.panel.level.width = num_digits * getFontWidth(font_nr); + pos->width = digits * getFontWidth(font_nr); + + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); +} + +void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) +{ + struct TextPosInfo *pos = &game.panel.keys; + int base_key_graphic = EL_KEY_1; + int i; + + if (PANEL_DEACTIVATED(pos)) + return; + + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + base_key_graphic = EL_EM_KEY_1; + + pos->width = 4 * MINI_TILEX; + + /* currently only 4 of 8 possible keys are displayed */ + for (i = 0; i < STD_NUM_KEYS; i++) + { + int src_x = DOOR_GFX_PAGEX5 + 18; + int src_y = DOOR_GFX_PAGEY1 + 123; + int dst_x = PANEL_XPOS(pos) + i * MINI_TILEX; + int dst_y = PANEL_YPOS(pos); - DrawText(DX_LEVEL, DY_LEVEL, int2str(value, num_digits), font_nr); + if (key[i]) + DrawMiniGraphicExt(drawto, dst_x, dst_y, el2edimg(base_key_graphic + i)); + else + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, + MINI_TILEX, MINI_TILEY, dst_x, dst_y); + } } #else -inline void DrawGameValue_Emeralds(int value) +void DrawGameValue_Emeralds(int value) { int font_nr = FONT_TEXT_2; int xpos = (3 * 14 - 3 * getFontWidth(font_nr)) / 2; @@ -1477,7 +1440,7 @@ inline void DrawGameValue_Emeralds(int value) DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), font_nr); } -inline void DrawGameValue_Dynamite(int value) +void DrawGameValue_Dynamite(int value) { int font_nr = FONT_TEXT_2; int xpos = (3 * 14 - 3 * getFontWidth(font_nr)) / 2; @@ -1488,32 +1451,7 @@ inline void DrawGameValue_Dynamite(int value) DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), font_nr); } -inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) -{ - int base_key_graphic = EL_KEY_1; - int i; - - if (PANEL_DEACTIVATED(game.panel.keys)) - return; - - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - base_key_graphic = EL_EM_KEY_1; - - /* currently only 4 of 8 possible keys are displayed */ - for (i = 0; i < STD_NUM_KEYS; i++) - { - int x = XX_KEYS + i * MINI_TILEX; - int y = YY_KEYS; - - if (key[i]) - DrawMiniGraphicExt(drawto, DX + x,DY + y, el2edimg(base_key_graphic + i)); - else - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, - DOOR_GFX_PAGEX5 + x, y, MINI_TILEX, MINI_TILEY, DX + x,DY + y); - } -} - -inline void DrawGameValue_Score(int value) +void DrawGameValue_Score(int value) { int font_nr = FONT_TEXT_2; int xpos = (5 * 14 - 5 * getFontWidth(font_nr)) / 2; @@ -1524,7 +1462,7 @@ inline void DrawGameValue_Score(int value) DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), font_nr); } -inline void DrawGameValue_Time(int value) +void DrawGameValue_Time(int value) { int font1_nr = FONT_TEXT_2; #if 1 @@ -1548,7 +1486,7 @@ inline void DrawGameValue_Time(int value) DrawText(DX_TIME2 + xpos4, DY_TIME, int2str(value, 4), font2_nr); } -inline void DrawGameValue_Level(int value) +void DrawGameValue_Level(int value) { int font1_nr = FONT_TEXT_2; #if 1 @@ -1566,6 +1504,31 @@ inline void DrawGameValue_Level(int value) DrawText(DX_LEVEL2, DY_LEVEL, int2str(value, 3), font2_nr); } +void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) +{ + int base_key_graphic = EL_KEY_1; + int i; + + if (PANEL_DEACTIVATED(game.panel.keys)) + return; + + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + base_key_graphic = EL_EM_KEY_1; + + /* currently only 4 of 8 possible keys are displayed */ + for (i = 0; i < STD_NUM_KEYS; i++) + { + int x = XX_KEYS + i * MINI_TILEX; + int y = YY_KEYS; + + if (key[i]) + DrawMiniGraphicExt(drawto, DX + x,DY + y, el2edimg(base_key_graphic + i)); + else + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, + DOOR_GFX_PAGEX5 + x, y, MINI_TILEX, MINI_TILEY, DX + x,DY + y); + } +} + #endif void DrawAllGameValues(int emeralds, int dynamite, int score, int time, @@ -2231,7 +2194,9 @@ void InitGame() player->LevelSolved = FALSE; player->GameOver = FALSE; + player->LevelSolved_GameWon = FALSE; player->LevelSolved_GameEnd = FALSE; + player->LevelSolved_PanelOff = FALSE; player->LevelSolved_SaveTape = FALSE; player->LevelSolved_SaveScore = FALSE; } @@ -2963,10 +2928,12 @@ void GameWon() { static int time, time_final; static int score, score_final; - static int game_over_delay = 0; - int game_over_delay_value = 50; + static int game_over_delay_1 = 0; + static int game_over_delay_2 = 0; + int game_over_delay_value_1 = 50; + int game_over_delay_value_2 = 50; - if (!local_player->LevelSolved_GameEnd) + if (!local_player->LevelSolved_GameWon) { int i; @@ -2974,7 +2941,7 @@ void GameWon() if (local_player->MovPos) return; - local_player->LevelSolved_GameEnd = TRUE; + local_player->LevelSolved_GameWon = TRUE; local_player->LevelSolved_SaveTape = tape.recording; local_player->LevelSolved_SaveScore = !tape.playing; @@ -2985,7 +2952,8 @@ void GameWon() TapeStop(); #endif - game_over_delay = game_over_delay_value; + game_over_delay_1 = game_over_delay_value_1; + game_over_delay_2 = game_over_delay_value_2; time = time_final = (level.time == 0 ? TimePlayed : TimeLeft); score = score_final = local_player->score_final; @@ -3067,9 +3035,9 @@ void GameWon() PlaySound(SND_GAME_WINNING); } - if (game_over_delay > 0) + if (game_over_delay_1 > 0) { - game_over_delay--; + game_over_delay_1--; return; } @@ -3092,7 +3060,22 @@ void GameWon() PlaySoundLoop(SND_GAME_LEVELTIME_BONUS); else PlaySound(SND_GAME_LEVELTIME_BONUS); + + return; + } + + local_player->LevelSolved_PanelOff = TRUE; + + if (game_over_delay_2 > 0) + { + game_over_delay_2--; + + return; } + +#if 1 + GameEnd(); +#endif } void GameEnd() @@ -3100,6 +3083,8 @@ void GameEnd() int hi_pos; boolean raise_level = FALSE; + local_player->LevelSolved_GameEnd = TRUE; + CloseDoor(DOOR_CLOSE_1); if (local_player->LevelSolved_SaveTape) @@ -3326,7 +3311,12 @@ void InitMovingField(int x, int y, int direction) /* check if element was/is moving or being moved before/after mode change */ #if 1 +#if 1 + is_moving_before = (WasJustMoving[x][y] != 0); +#else + /* (!!! this does not work -- WasJustMoving is NOT a boolean value !!!) */ is_moving_before = WasJustMoving[x][y]; +#endif #else is_moving_before = (getElementMoveStepsizeExt(x, y, MovDir[x][y]) != 0); #endif @@ -6871,6 +6861,17 @@ void ContinueMoving(int x, int y) if (ABS(MovPos[x][y]) < TILEX) { +#if 0 + int ee = Feld[x][y]; + int gg = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + int ff = getGraphicAnimationFrame(gg, GfxFrame[x][y]); + + printf("::: %d.%d: moving %d ... [%d, %d, %d] [%d, %d, %d]\n", + x, y, ABS(MovPos[x][y]), + ee, gg, ff, + GfxAction[x][y], GfxDir[x][y], GfxFrame[x][y]); +#endif + DrawLevelField(x, y); return; /* element is still moving */ @@ -9063,8 +9064,18 @@ static void HandleElementChange(int x, int y, int page) if (change->can_change) { - ResetGfxAnimation(x, y); - ResetRandomAnimationValue(x, y); +#if 0 + /* !!! not clear why graphic animation should be reset at all here !!! */ +#if USE_GFX_RESET_WHEN_NOT_MOVING + /* when a custom element is about to change (for example by change delay), + do not reset graphic animation when the custom element is moving */ + if (IS_MOVING(x, y)) +#endif + { + ResetGfxAnimation(x, y); + ResetRandomAnimationValue(x, y); + } +#endif if (change->pre_change_function) change->pre_change_function(x, y); @@ -9859,7 +9870,7 @@ void GameActions() AllPlayersGone = TRUE; } - if (local_player->LevelSolved) + if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd) GameWon(); if (AllPlayersGone && !TAPE_IS_STOPPED(tape)) @@ -10556,25 +10567,79 @@ static boolean AllPlayersInVisibleScreen() void ScrollLevel(int dx, int dy) { +#if 1 + static Bitmap *bitmap_db_field2 = NULL; int softscroll_offset = (setup.soft_scrolling ? TILEX : 0); int x, y; +#else + int i, x, y; +#endif + + /* only horizontal XOR vertical scroll direction allowed */ + if ((dx == 0 && dy == 0) || (dx != 0 && dy != 0)) + return; + +#if 1 + if (bitmap_db_field2 == NULL) + bitmap_db_field2 = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH); + + BlitBitmap(drawto_field, bitmap_db_field2, + FX + TILEX * (dx == -1) - softscroll_offset, + FY + TILEY * (dy == -1) - softscroll_offset, + SXSIZE - TILEX * (dx != 0) + 2 * softscroll_offset, + SYSIZE - TILEY * (dy != 0) + 2 * softscroll_offset, + FX + TILEX * (dx == 1) - softscroll_offset, + FY + TILEY * (dy == 1) - softscroll_offset); + BlitBitmap(bitmap_db_field2, drawto_field, + FX + TILEX * (dx == 1) - softscroll_offset, + FY + TILEY * (dy == 1) - softscroll_offset, + SXSIZE - TILEX * (dx != 0) + 2 * softscroll_offset, + SYSIZE - TILEY * (dy != 0) + 2 * softscroll_offset, + FX + TILEX * (dx == 1) - softscroll_offset, + FY + TILEY * (dy == 1) - softscroll_offset); + +#else + +#if 1 + int xsize = (BX2 - BX1 + 1); + int ysize = (BY2 - BY1 + 1); + int start = (dx != 0 ? (dx == -1 ? BX1 : BX2) : (dy == -1 ? BY1 : BY2)); + int end = (dx != 0 ? (dx == -1 ? BX2 : BX1) : (dy == -1 ? BY2 : BY1)); + int step = (start < end ? +1 : -1); + + for (i = start; i != end; i += step) + { + BlitBitmap(drawto_field, drawto_field, + FX + TILEX * (dx != 0 ? i + step : 0), + FY + TILEY * (dy != 0 ? i + step : 0), + TILEX * (dx != 0 ? 1 : xsize), + TILEY * (dy != 0 ? 1 : ysize), + FX + TILEX * (dx != 0 ? i : 0), + FY + TILEY * (dy != 0 ? i : 0)); + } + +#else + + int softscroll_offset = (setup.soft_scrolling ? TILEX : 0); BlitBitmap(drawto_field, drawto_field, FX + TILEX * (dx == -1) - softscroll_offset, FY + TILEY * (dy == -1) - softscroll_offset, - SXSIZE - TILEX * (dx!=0) + 2 * softscroll_offset, - SYSIZE - TILEY * (dy!=0) + 2 * softscroll_offset, + SXSIZE - TILEX * (dx != 0) + 2 * softscroll_offset, + SYSIZE - TILEY * (dy != 0) + 2 * softscroll_offset, FX + TILEX * (dx == 1) - softscroll_offset, FY + TILEY * (dy == 1) - softscroll_offset); +#endif +#endif - if (dx) + if (dx != 0) { x = (dx == 1 ? BX1 : BX2); for (y = BY1; y <= BY2; y++) DrawScreenField(x, y); } - if (dy) + if (dy != 0) { y = (dy == 1 ? BY1 : BY2); for (x = BX1; x <= BX2; x++) @@ -13471,9 +13536,9 @@ static void LoadEngineSnapshotValues_RND() if (game.num_random_calls != num_random_calls) { - Error(ERR_RETURN, "number of random calls out of sync"); - Error(ERR_RETURN, "number of random calls should be %d", num_random_calls); - Error(ERR_RETURN, "number of random calls is %d", game.num_random_calls); + Error(ERR_INFO, "number of random calls out of sync"); + Error(ERR_INFO, "number of random calls should be %d", num_random_calls); + Error(ERR_INFO, "number of random calls is %d", game.num_random_calls); Error(ERR_EXIT, "this should not happen -- please debug"); } }