Subversion Repositories Games.Prince of Persia

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2. SDLPoP, a port/conversion of the DOS game Prince of Persia.
  3. Copyright (C) 2013-2018  Dávid Nagy
  4.  
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  
  18. The authors of this program may be contacted at http://forum.princed.org
  19. */
  20.  
  21. #include "common.h"
  22.  
  23. #ifdef USE_SCREENSHOT
  24.  
  25. // TODO: Use incrementing numbers and a separate folder, like DOSBox? Or allow custom filenames.
  26. const char screenshot_filename[] = "screenshot.png";
  27.  
  28. #define EVENT_OFFSET 0 // Add this number to displayed event numbers. Use 1 for Apoplexy compatibility.
  29.  
  30. #define NUMBER_OF_ROOMS 24
  31.  
  32. // Save a screenshot.
  33. void save_screenshot() {
  34.         IMG_SavePNG(onscreen_surface_, screenshot_filename);
  35.         printf("Saved screenshot to \"%s\".\n", screenshot_filename);
  36. }
  37.  
  38. // Switch to the given room and draw it.
  39. void switch_to_room(int room) {
  40.         drawn_room = room;
  41.         load_room_links();
  42.  
  43.         if (tbl_level_type[current_level]) {
  44.                 gen_palace_wall_colors();
  45.         }
  46.  
  47.         // for guards
  48.         Guard.direction = dir_56_none;
  49.         guardhp_curr = 0; // otherwise guard HPs stay on screen
  50.         draw_guard_hp(0, 10); // otherwise guard HPs still stay on screen if some guards have extra HP
  51.         enter_guard(); // otherwise the guard won't show up
  52.         check_shadow(); // otherwise the shadow won't appear on level 6
  53.  
  54.         // for potion bubbles
  55.         for (int tilepos=0;tilepos<30;tilepos++) {
  56.                 int tile_type = curr_room_tiles[tilepos] & 0x1F;
  57.                 if (tile_type == tiles_10_potion) {
  58.                         int modifier = curr_room_modif[tilepos];
  59.                         if ((modifier & 7) == 0) curr_room_modif[tilepos]++;
  60.                 }
  61.         }
  62.  
  63.         redraw_screen(1);
  64. }
  65.  
  66. bool event_used[256] = {false};
  67. bool has_trigger_potion = false;
  68.  
  69. // delta vectors for room links
  70. const int dx[4] = {-1, +1,  0,  0};
  71. const int dy[4] = { 0,  0, -1, +1};
  72.  
  73. int xpos[NUMBER_OF_ROOMS+1] = {0};
  74. int ypos[NUMBER_OF_ROOMS+1] = {0};
  75.  
  76. // Show annotations for non-visible things, like: room bounds, room numbers, door events, loose floors, potion types, special events, ...
  77. // (this will make the function even more like a cheat)
  78. // TODO: guard HPs, skill? fake tiles?
  79. void draw_extras() {
  80.         // ambiguous tiles
  81.         // The editor branch has something similar...
  82.         for (int tilepos=0;tilepos<30;tilepos++) {
  83.                 int tile_type = curr_room_tiles[tilepos] & 0x1F;
  84.                 int modifier = curr_room_modif[tilepos];
  85.                 int row = tilepos/10;
  86.                 int col = tilepos%10;
  87.                 int y = row * 63 + 3;
  88.                 int x = col * 32;
  89.  
  90.                 // special floors
  91.                 rect_type floor_rect = {y+60-3, x, y+63-3, x+32};
  92.  
  93.                 // loose floors
  94.                 if (tile_type == tiles_11_loose) {
  95.                         int color = color_15_brightwhite;
  96.                         if (curr_room_tiles[tilepos] & 0x20) color = color_13_brightmagenta; // stable loose floor
  97.                         show_text_with_color(&floor_rect, 0, -1, "~~~~", color);
  98.                 }
  99.  
  100.                 // buttons
  101.                 if (tile_type == tiles_15_opener) {
  102.                         show_text_with_color(&floor_rect, 0, -1, "^^^^", color_10_brightgreen);
  103.                 }
  104.                 if (tile_type == tiles_6_closer) {
  105.                         //show_text_with_color(&floor_rect, 0, -1, "XXXX", color_12_brightred);
  106.                         floor_rect.top -= 2;
  107.                         show_text_with_color(&floor_rect, 0, -1, "xxxx", color_12_brightred); // Only the top half is visible, looks like an inverted "^" or a tiny "v".
  108.                 }
  109.  
  110.                 bool is_trob_here = false;
  111.                 for (int index = 0; index < trobs_count; ++index) {
  112.                         trob = trobs[index];
  113.                         if (trob.room == drawn_room && trob.tilepos == tilepos) {
  114.                                 is_trob_here = true;
  115.                                 break;
  116.                         }
  117.                 }
  118.  
  119.                 if (!is_trob_here) { // It's not stuck if it's currently animated.
  120.                         // harmless spikes
  121.                         if (tile_type == tiles_2_spike) {
  122.                                 if (modifier >= 5) { // harmless
  123.                                         rect_type spike_rect = {y+50, x, y+60, x+32};
  124.                                         show_text_with_color(&spike_rect, 0, -1, "safe", color_10_brightgreen);
  125.                                 }
  126.                         }
  127.  
  128.                         // stuck chompers
  129.                         if (tile_type == tiles_18_chomper) {
  130.                                 int frame = (modifier & 0x7F);
  131.                                 if (frame != 0) {
  132.                                         rect_type chomper_rect = {y, x-10, y+60, x+32+10};
  133.                                         int color = color_10_brightgreen;
  134.                                         if (frame == 2) color = color_12_brightred;
  135.                                         show_text_with_color(&chomper_rect, 0, 0, "stuck", color);
  136.                                 }
  137.                         }
  138.                 }
  139.  
  140.                 // potion types
  141.                 if (tile_type == tiles_10_potion) {
  142.                         struct pot_type {
  143.                                 int color;
  144.                                 const char* text;
  145.                         } pot_types[7] = {
  146.                                 {color_7_lightgray, "x"}, // empty
  147.                                 {color_12_brightred, "+1"}, // heal
  148.                                 {color_12_brightred, "+++"}, // life
  149.                                 {color_10_brightgreen, "slow\nfall"}, // slow fall
  150.                                 {color_10_brightgreen, "flip"}, // upside down
  151.                                 {color_9_brightblue, "-1"}, // hurt
  152.                                 {color_9_brightblue, "trig"}, // open
  153.                         };
  154.                         int potion_type = modifier >> 3;
  155.                         int color;
  156.                         const char* text;
  157.                         char temp_text[4];
  158.                         if (potion_type >= 0 && potion_type < 7) {
  159.                                 color = pot_types[potion_type].color;
  160.                                 text = pot_types[potion_type].text;
  161.                         } else {
  162.                                 color = color_15_brightwhite;
  163.                                 snprintf(temp_text, sizeof(temp_text), "%d", potion_type);
  164.                                 text = temp_text;
  165.                         }
  166.                         rect_type pot_rect = {y+40, x, y+60, x+32};
  167.                         show_text_with_color(&pot_rect, 0, -1, text, color);
  168.                 }
  169.  
  170.                 // triggered door events
  171.                 if (tile_type == tiles_6_closer || tile_type == tiles_15_opener
  172.                         // These tiles are triggered even if they are not buttons!
  173.                         /*
  174.                         || (current_level == 1 && drawn_room == 5 && tilepos == 2) // triggered at start
  175.                         || (current_level == 13 && drawn_room == 24 && tilepos == 0) // triggered when player enters any room from the right after Jaffar died
  176.                         */
  177.                         || (has_trigger_potion && drawn_room == 8 && tilepos == 0) // triggered when player drinks an open potion
  178.                 ) {
  179.                         int first_event = modifier;
  180.                         int last_event = modifier;
  181.                         while (last_event<256 && get_doorlink_next(last_event)) last_event++;
  182.                         /*
  183.                         char events[10];
  184.                         if (modifier==last_event) {
  185.                                 snprintf(events, sizeof(events), "%d", first_event+EVENT_OFFSET);
  186.                         } else { // from-to
  187.                                 snprintf(events, sizeof(events), "%d:%d", first_event+EVENT_OFFSET, last_event+EVENT_OFFSET);
  188.                         }
  189.                         */
  190.                         char events[256*4] = ""; // More than enough space to list all the numbers from 0 to 255.
  191.                         int events_pos = 0;
  192.                         for (int event=first_event; event<=last_event && events_pos<sizeof(events); event++) {
  193.                                 int len = snprintf(events+events_pos, sizeof(events)-events_pos, "%d ", event+EVENT_OFFSET);
  194.                                 if (len < 0) break; // snprintf might return -1 if the buffer is too small.
  195.                                 events_pos += len;
  196.                         }
  197.                         --events_pos;
  198.                         if (events_pos>0 && events_pos<sizeof(events)) events[events_pos]='\0'; // trim trailing space
  199.                         rect_type buttonmod_rect = {y/*+50-3*/, x, y+60-3, x+32};
  200.                         show_text_with_color(&buttonmod_rect, 0, 1, events, color_14_brightyellow);
  201.                 }
  202.  
  203.                 // TODO: Add an option to merge events pointing to the same tile?
  204.  
  205.                 // door events that point here
  206.                 char events[256*4] = "";
  207.                 int events_pos = 0;
  208.                 for (int event=0; event<256 && events_pos<sizeof(events); event++) {
  209.                         if (event_used[event] && get_doorlink_room(event) == drawn_room && get_doorlink_tile(event) == tilepos) {
  210.                                 int len = snprintf(events+events_pos, sizeof(events)-events_pos, "%d ", event+EVENT_OFFSET);
  211.                                 if (len < 0) break;
  212.                                 events_pos += len;
  213.                         }
  214.                 }
  215.                 --events_pos;
  216.                 if (events_pos>0 && events_pos<sizeof(events)) events[events_pos]='\0'; // trim trailing space
  217.                 if (*events) {
  218.                         //printf("room %d, tile %d, events: %s\n", drawn_room, tilepos, events); // debug
  219.                         rect_type events_rect = {y,x,y+63-3,x+32-7};
  220.                         show_text_with_color(&events_rect, 0, 1, events, color_14_brightyellow);
  221.                 }
  222.  
  223.                 // special events
  224.                 char* special_event = NULL;
  225.                 if (current_level == 0 && drawn_room == 24) {
  226.                         special_event = "exit"; // exit by entering this room
  227.                 }
  228.                 // not marked: level 1 falling entry
  229.                 if (current_level == 1 && drawn_room == 5 && tilepos == 2) {
  230.                         special_event = "start\ntrig"; // triggered at start
  231.                 }
  232.                 if (current_level == 3 && drawn_room == 7 && col == 0) {
  233.                         special_event = "<-\nchk point"; // checkpoint activation
  234.                 }
  235.                 if (current_level == 3 && drawn_room == 7 && tilepos == 4) {
  236.                         special_event = "removed"; // loose floor is removed
  237.                 }
  238.                 if (current_level == 3 && drawn_room == 2 && tile_type == tiles_4_gate) {
  239.                         special_event = "loud"; // closing can be heard everywhere
  240.                 }
  241.                 if (current_level == 3 && drawn_room == 2 && tilepos == 6) {
  242.                         special_event = "check point"; // restart at checkpoint
  243.                         // TODO: Show this room even if it is unreachable from the start via room links?
  244.                 }
  245.                 if (current_level == 3 && drawn_room == 1 && tilepos == 15 && tile_type == tiles_21_skeleton) {
  246.                         special_event = "skel wake"; // skeleton wakes
  247.                 }
  248.                 if (current_level == 3 && drawn_room == 3 && tilepos == 14) {
  249.                         special_event = "skel cont"; // skeleton continue
  250.                 }
  251.                 if (current_level == 4 && drawn_room == 4 && tilepos == 4) {
  252.                         special_event = "mirror"; // mirror appears
  253.                 }
  254.                 // not marked: level 4 mirror clip
  255.                 // not marked: level 5 shadow, required opening gate
  256.                 if (current_level == 5 && drawn_room == 24 && tilepos == 3 && tile_type == tiles_10_potion) {
  257.                         special_event = "stolen"; // stolen potion
  258.                 }
  259.                 // not marked: level 6 shadow (it's already visible)
  260.                 if (current_level == 6 && drawn_room == 1 && row == 2) {
  261.                         special_event = "exit\ndown"; // exit by falling
  262.                 }
  263.                 // not marked: level 7 falling entry
  264.                 if (current_level == 8 && drawn_room == 16 && tilepos == 9) {
  265.                         special_event = "mouse"; // mouse comes
  266.                 }
  267.                 if (current_level == 12 && drawn_room == 15 && tilepos == 1 && tile_type == tiles_22_sword) {
  268.                         special_event = "disapp"; // sword disappears
  269.                 }
  270.                 if (current_level == 12 && drawn_room == 18 && col == 9) {
  271.                         special_event = "disapp\n->"; // sword disappears
  272.                 }
  273.                 // not marked: level 12 shadow
  274.                 if (current_level == 12 && row == 0 && (drawn_room == 2 || (drawn_room == 13 && col >= 6))) {
  275.                         special_event = "floor"; // floors appear
  276.                 }
  277.                 if (current_level == 12 && drawn_room == 23) {
  278.                         special_event = "exit"; // exit by entering this room
  279.                 }
  280.                 if (current_level == 13 && (drawn_room == level.roomlinks[23-1].up || drawn_room == level.roomlinks[16-1].up) && (tilepos >= 22 && tilepos <= 27)) {
  281.                         special_event = "fall"; // falling loose floors
  282.                 }
  283.                 if (current_level == 13 && drawn_room == 3 && col == 9) {
  284.                         special_event = "meet\n->"; // meet Jaffar
  285.                 }
  286.                 // not marked: flash
  287.                 if (current_level == 13 && drawn_room == 24 && tilepos == 0) {
  288.                         special_event = "Jffr\ntrig"; // triggered when player enters any room from the right after Jaffar died
  289.                 }
  290.                 if (current_level == 14 && drawn_room == 5) {
  291.                         special_event = "end"; // end of game
  292.                 }
  293.                 if (has_trigger_potion && drawn_room == 8 && tilepos == 0) {
  294.                         special_event = "blue\ntrig"; // triggered when player drinks an open potion
  295.                 }
  296.                 if (special_event) {
  297.                         rect_type event_rect = {y,x-10,y+63,x+32+10};
  298.                         show_text_with_color(&event_rect, 0, 0, special_event, color_14_brightyellow);
  299.                 }
  300.  
  301.                 // Attempt to show broken room links:
  302.                 byte* roomlinks = (byte*)(&level.roomlinks[drawn_room-1]);
  303.                 for (int direction = 0; direction < 4; direction++) {
  304.                         int other_room = roomlinks[direction];
  305.                         if (other_room >= 1 && other_room <= NUMBER_OF_ROOMS) {
  306.                                 int other_x = xpos[drawn_room] + dx[direction];
  307.                                 int other_y = ypos[drawn_room] + dy[direction];
  308.                                 // If the linked room was placed elsewhere: Write the number of the linked room to the corresponding edge of the room.
  309.                                 if (xpos[other_room] != other_x || ypos[other_room] != other_y) {
  310.                                         int center_x = 160+dx[direction]*150;
  311.                                         int center_y = 96+dy[direction]*85;
  312.                                         rect_type text_rect = {center_y-6, center_x-10, center_y+6, center_x+10};
  313.                                         char room_num[4];
  314.                                         snprintf(room_num, sizeof(room_num), "%d", other_room);
  315.                                         method_5_rect(&text_rect, 0, color_4_red);
  316.                                         show_text_with_color(&text_rect, 0, 0, room_num, color_15_brightwhite);
  317.                                 }
  318.                         }
  319.                 }
  320.  
  321.                 // start pos
  322.                 if (level.start_room == drawn_room && level.start_pos == tilepos) {
  323.                         byte start_dir = level.start_dir;
  324.                         if (current_level == 1 || current_level == 13) start_dir ^= 0xFF; // falling/running entry
  325.                         char* start_text = (start_dir == dir_0_right) ? "start\n->" : "start\n<-";
  326.                         rect_type start_rect = {y,x-10,y+63,x+32+10};
  327.                         show_text_with_color(&start_rect, 0, 0, start_text, color_14_brightyellow);
  328.                 }
  329.  
  330.         }
  331.  
  332.         // room number
  333.         char room_num[4];
  334.         snprintf(room_num, sizeof(room_num), "%d", drawn_room);
  335.         rect_type text_rect = {10, 10, 21, 30};
  336.         method_5_rect(&text_rect, 0, color_8_darkgray);
  337.         show_text_with_color(&text_rect, 0, 0, room_num, color_15_brightwhite);
  338.  
  339.         // grid lines
  340.         rect_type vline = {0,0,192,1};
  341.         method_5_rect(&vline, 0, color_12_brightred);
  342.         rect_type hline = {3,0,4,320};
  343.         method_5_rect(&hline, 0, color_12_brightred);
  344. }
  345.  
  346. // Save a "screenshot" of the whole level.
  347. void save_level_screenshot(bool want_extras) {
  348.         // TODO: Disable in the intro or if a cutscene is active?
  349.  
  350.         // Restrict this to cheat mode. After all, it's like using H/J/U/N or opening the level in an editor.
  351.         if (!cheats_enabled) return;
  352.  
  353.         upside_down = 0;
  354.  
  355.         //printf("random_seed = 0x%08X\n", random_seed);
  356.  
  357.         // First, figure out where to put each room.
  358.         // We don't stop on broken room links, because the resulting map might still be usable.
  359.  
  360.         bool processed[NUMBER_OF_ROOMS+1] = {false};
  361.         for (int room=1;room<=NUMBER_OF_ROOMS;room++) {
  362.                 xpos[drawn_room] = -999;
  363.                 ypos[drawn_room] = -999;
  364.         }
  365.         xpos[drawn_room] = 0;
  366.         ypos[drawn_room] = 0;
  367.         int queue[NUMBER_OF_ROOMS] = {drawn_room}; // We start mapping from the current room.
  368.         int queue_start = 0;
  369.         int queue_end = 1;
  370.  
  371.         while (queue_start < queue_end) {
  372.                 int room = queue[queue_start++];
  373.                 byte* roomlinks = (byte*)(&level.roomlinks[room-1]);
  374.                 for (int direction = 0; direction < 4; direction++) {
  375.                         int other_room = roomlinks[direction];
  376.                         if (other_room >= 1 && other_room <= NUMBER_OF_ROOMS && !processed[other_room]) {
  377.                                 int other_x = xpos[room] + dx[direction];
  378.                                 int other_y = ypos[room] + dy[direction];
  379.                                 xpos[other_room] = other_x;
  380.                                 ypos[other_room] = other_y;
  381.                                 processed[other_room] = true;
  382.                                 queue[queue_end++] = other_room;
  383.                         }
  384.                 }
  385.         }
  386.  
  387.         int min_x=0, max_x=0, min_y=0, max_y=0;
  388.         for (int room=1;room<=NUMBER_OF_ROOMS;room++) {
  389.                 if (xpos[room] < min_x) min_x = xpos[room];
  390.                 if (xpos[room] > max_x) max_x = xpos[room];
  391.                 if (ypos[room] < min_y) min_y = ypos[room];
  392.                 if (ypos[room] > max_y) max_y = ypos[room];
  393.         }
  394.  
  395.         int map_width = max_x-min_x+1;
  396.         int map_height = max_y-min_y+1;
  397.  
  398.         #define MAX_MAP_SIZE NUMBER_OF_ROOMS
  399.         int map[MAX_MAP_SIZE][MAX_MAP_SIZE] = {{0}};
  400.         for (int room=1;room<=NUMBER_OF_ROOMS;room++) {
  401.                 if (processed[room]) {
  402.                         int y = ypos[room] - min_y;
  403.                         int x = xpos[room] - min_x;
  404.                         if (x>=0 && y>=0 && x<MAX_MAP_SIZE && y<MAX_MAP_SIZE) {
  405.                                 if (map[y][x]) {
  406.                                         printf("Warning: room %d was mapped to the same place as room %d!\n", room, map[y][x]);
  407.                                         // Force broken link display for room links pointing into this room:
  408.                                         // TODO: Try to find some other place for this room?
  409.                                         xpos[room] = -999;
  410.                                         ypos[room] = -999;
  411.                                 } else {
  412.                                         map[y][x] = room;
  413.                                 }
  414.                         }
  415.                 }
  416.         }
  417.  
  418.         // Debug printout of arrangement.
  419.         /*
  420.         printf("LEVEL %d\n", current_level);
  421.         for (int y=0;y<map_height;y++) {
  422.                 for (int x=0;x<map_width;x++) {
  423.                         int room = map[y][x];
  424.                         if (room) {
  425.                                 printf(" %2d", room);
  426.                         } else {
  427.                                 printf("   ");
  428.                         }
  429.                 }
  430.                 printf("\n");
  431.         }
  432.         printf("\n");
  433.         */
  434.  
  435.         // Now we have the arrangement, let's make the picture!
  436.  
  437.         int image_width = map_width*320;
  438.         int image_height = map_height*189+3+8;
  439.  
  440.         SDL_Surface* map_surface = SDL_CreateRGBSurface(0, image_width, image_height, 32, 0xFF, 0xFF<<8, 0xFF<<16, 0xFF<<24);
  441.         if (map_surface == NULL) {
  442.                 sdlperror("SDL_CreateRGBSurface (map_surface)");
  443.                 //exit(1);
  444.                 return;
  445.         }
  446.  
  447.         // TODO: Background color for places where there is no room?
  448.  
  449.         // TODO: Add an option for displaying all unreachable rooms?
  450.  
  451.         has_trigger_potion = false;
  452.  
  453.         // Is there a trigger potion on the level?
  454.         for (int room=1;room<=NUMBER_OF_ROOMS;room++) {
  455.                 if (processed[room]) {
  456.                         get_room_address(room);
  457.                         for (int tilepos=0;tilepos<30;tilepos++) {
  458.                                 int tile_type = curr_room_tiles[tilepos] & 0x1F;
  459.                                 if (tile_type == tiles_10_potion && curr_room_modif[tilepos] >> 3 == 6) {
  460.                                         has_trigger_potion = true;
  461.                                 }
  462.                         }
  463.                 }
  464.         }
  465.  
  466.         memset(event_used, 0, sizeof(event_used));
  467.  
  468.         // Find out which door events are used:
  469.         for (int room=1;room<=NUMBER_OF_ROOMS;room++) {
  470.                 if (processed[room]) {
  471.                         get_room_address(room);
  472.                         for (int tilepos=0;tilepos<30;tilepos++) {
  473.                                 int tile_type = curr_room_tiles[tilepos] & 0x1F;
  474.                                 if (tile_type == tiles_6_closer || tile_type == tiles_15_opener
  475.                                         // These tiles are triggered even if they are not buttons!
  476.                                         // TODO: Force displaying of special trigger rooms even if they are unreachable via room links?
  477.                                         /*
  478.                                         || (current_level == 1 && room == 5 && tilepos == 2) // triggered at start
  479.                                         || (current_level == 13 && room == 24 && tilepos == 0) // triggered when player enters any room from the right after Jaffar died
  480.                                         */
  481.                                         || (has_trigger_potion && room == 8 && tilepos == 0) // triggered when player drinks an open potion
  482.                                 ) {
  483.                                         int modifier = curr_room_modif[tilepos];
  484.                                         for (int index = modifier; index < 256; index++) {
  485.                                                 event_used[index] = true;
  486.                                                 if (!get_doorlink_next(index)) break;
  487.                                         }
  488.                                 }
  489.                         }
  490.                 }
  491.         }
  492.  
  493.         // debug
  494.         /*
  495.         printf("Used events:");
  496.         for (int event=0;event<256;event++) {
  497.                 if (event_used[event]) {
  498.                         printf(" %d", event+EVENT_OFFSET);
  499.                 }
  500.         }
  501.         printf("\n");
  502.         */
  503.         /*
  504.         for (int event=0;event<256;event++) {
  505.                 if (event_used[event]) {
  506.                         printf("event %d: room %d tile %d %s\n",
  507.                                 event+EVENT_OFFSET, get_doorlink_room(event), get_doorlink_tile(event),
  508.                                 get_doorlink_next(event) ? "+next" : "");
  509.                 }
  510.         }
  511.         */
  512.  
  513.         screen_updates_suspended = true;
  514.         int old_room = drawn_room;
  515.         for (int y=0;y<map_height;y++) {
  516.                 for (int x=0;x<map_width;x++) {
  517.                         int room = map[y][x];
  518.                         if (room) {
  519.                                 SDL_Rect dest_rect;
  520.                                 dest_rect.x = x*320;
  521.                                 dest_rect.y = y*189;
  522.                                 switch_to_room(room);
  523.  
  524.                                 if (want_extras) draw_extras();
  525.  
  526.                                 // TODO: Hide the status bar, or maybe show some custom text on it?
  527.  
  528.                                 SDL_BlitSurface(onscreen_surface_, NULL, map_surface, &dest_rect);
  529.                         }
  530.                 }
  531.         }
  532.         switch_to_room(old_room);
  533.         screen_updates_suspended = false;
  534.  
  535.         IMG_SavePNG(map_surface, screenshot_filename);
  536.         printf("Saved level screenshot to \"%s\".\n", screenshot_filename);
  537.  
  538.         SDL_FreeSurface(map_surface);
  539.  
  540.         //printf("random_seed = 0x%08X\n", random_seed);
  541. }
  542.  
  543. bool want_auto = false;
  544. bool want_auto_whole_level = false;
  545. bool want_auto_extras = false;
  546.  
  547. void init_screenshot() {
  548.         // Command-line options to automatically save a screenshot at startup.
  549.         const char* screenshot_param = check_param("--screenshot");
  550.         if (screenshot_param != NULL) {
  551.                 // We require megahit+levelnumber.
  552.                 if (start_level < 0) {
  553.                         printf("You must supply a level number if you want to make an automatic screenshot!\n");
  554.                         exit(1);
  555.                 } else {
  556.                         want_auto = true;
  557.                         want_auto_whole_level = (check_param("--screenshot-level") != NULL);
  558.                         want_auto_extras = (check_param("--screenshot-level-extras") != NULL);
  559.                 }
  560.         }
  561. }
  562.  
  563. // TODO: Don't open a window if the user wants an auto screenshot.
  564.  
  565. // To skip cutscenes, etc.
  566. bool want_auto_screenshot() {
  567.         return want_auto;
  568. }
  569.  
  570. // Called when the level is drawn for the first time.
  571. void auto_screenshot() {
  572.         if (!want_auto) return;
  573.  
  574.         if (want_auto_whole_level) {
  575.                 save_level_screenshot(want_auto_extras);
  576.         } else {
  577.                 save_screenshot();
  578.         }
  579.  
  580.         quit(1);
  581. }
  582.  
  583. #endif
  584.  
  585.