int save_board(struct board *cur_board, FILE *fp, int savegame, int version) { int num_robots, num_scrolls, num_sensors; int start_location = ftell(fp); int board_width = cur_board->board_width; int board_height = cur_board->board_height; int board_size = board_width * board_height; int i; // Board mode is now ignored, put 0 fputc(0, fp); // Put overlay mode if(cur_board->overlay_mode) { fputc(0, fp); fputc(cur_board->overlay_mode, fp); fputw(cur_board->board_width, fp); fputw(cur_board->board_height, fp); save_RLE2_plane(cur_board->overlay, fp, board_size); fputw(cur_board->board_width, fp); fputw(cur_board->board_height, fp); save_RLE2_plane(cur_board->overlay_color, fp, board_size); } fputw(board_width, fp); fputw(board_height, fp); save_RLE2_plane(cur_board->level_id, fp, board_size); fputw(board_width, fp); fputw(board_height, fp); save_RLE2_plane(cur_board->level_color, fp, board_size); fputw(board_width, fp); fputw(board_height, fp); save_RLE2_plane(cur_board->level_param, fp, board_size); fputw(board_width, fp); fputw(board_height, fp); save_RLE2_plane(cur_board->level_under_id, fp, board_size); fputw(board_width, fp); fputw(board_height, fp); save_RLE2_plane(cur_board->level_under_color, fp, board_size); fputw(board_width, fp); fputw(board_height, fp); save_RLE2_plane(cur_board->level_under_param, fp, board_size); // Save board parameters { size_t len = strlen(cur_board->mod_playing); fputw((int)len, fp); if(len) fwrite(cur_board->mod_playing, len, 1, fp); } fputc(cur_board->viewport_x, fp); fputc(cur_board->viewport_y, fp); fputc(cur_board->viewport_width, fp); fputc(cur_board->viewport_height, fp); fputc(cur_board->can_shoot, fp); fputc(cur_board->can_bomb, fp); fputc(cur_board->fire_burn_brown, fp); fputc(cur_board->fire_burn_space, fp); fputc(cur_board->fire_burn_fakes, fp); fputc(cur_board->fire_burn_trees, fp); fputc(cur_board->explosions_leave, fp); fputc(cur_board->save_mode, fp); fputc(cur_board->forest_becomes, fp); fputc(cur_board->collect_bombs, fp); fputc(cur_board->fire_burns, fp); for(i = 0; i < 4; i++) { fputc(cur_board->board_dir[i], fp); } fputc(cur_board->restart_if_zapped, fp); fputw(cur_board->time_limit, fp); if(savegame) { size_t len; fputc(cur_board->last_key, fp); fputw(cur_board->num_input, fp); fputw((int)cur_board->input_size, fp); len = strlen(cur_board->input_string); fputw((int)len, fp); if(len) fwrite(cur_board->input_string, len, 1, fp); fputc(cur_board->player_last_dir, fp); len = strlen(cur_board->bottom_mesg); fputw((int)len, fp); if(len) fwrite(cur_board->bottom_mesg, len, 1, fp); fputc(cur_board->b_mesg_timer, fp); fputc(cur_board->lazwall_start, fp); fputc(cur_board->b_mesg_row, fp); fputc(cur_board->b_mesg_col, fp); fputw(cur_board->scroll_x, fp); fputw(cur_board->scroll_y, fp); fputw(cur_board->locked_x, fp); fputw(cur_board->locked_y, fp); } fputc(cur_board->player_ns_locked, fp); fputc(cur_board->player_ew_locked, fp); fputc(cur_board->player_attack_locked, fp); if(savegame) { fputc(cur_board->volume, fp); fputc(cur_board->volume_inc, fp); fputc(cur_board->volume_target, fp); } // Save robots num_robots = cur_board->num_robots; fputc(num_robots, fp); if(num_robots) { struct robot *cur_robot; for(i = 1; i <= num_robots; i++) { cur_robot = cur_board->robot_list[i]; save_robot(cur_robot, fp, savegame, version); } } // Save scrolls num_scrolls = cur_board->num_scrolls; putc(num_scrolls, fp); if(num_scrolls) { struct scroll *cur_scroll; for(i = 1; i <= num_scrolls; i++) { cur_scroll = cur_board->scroll_list[i]; save_scroll(cur_scroll, fp, savegame); } } // Save sensors num_sensors = cur_board->num_sensors; fputc(num_sensors, fp); if(num_sensors) { struct sensor *cur_sensor; for(i = 1; i <= num_sensors; i++) { cur_sensor = cur_board->sensor_list[i]; save_sensor(cur_sensor, fp, savegame); } } return (ftell(fp) - start_location); }
static void save_mzm_common(struct world *mzx_world, int start_x, int start_y, int width, int height, int mode, int savegame, void *(*alloc)(size_t, void **), void **storage) { int storage_mode = 0; void *buffer; unsigned char *bufferPtr; size_t mzm_size; int num_robots_alloc = 0; if(mode) storage_mode = 1; if(savegame) savegame = 1; // Before saving the MZM, we first calculate its file size // Then we allocate the memory needed to store the MZM mzm_size = 20; // Add on the storage space required to store all tiles if (storage_mode == 0) { mzm_size += width * height * 6; } else { mzm_size += width * height * 2; } if (mode == 0) { // Allocate memory for robots struct board *src_board = mzx_world->current_board; struct robot **robot_list = src_board->robot_list_name_sorted; int num_robots_active = src_board->num_robots_active; int i; for (i = 0; i < num_robots_active; i++) { struct robot *cur_robot = robot_list[i]; if (cur_robot) { if (cur_robot->xpos >= start_x && cur_robot->ypos >= start_y && cur_robot->xpos < start_x + width && cur_robot->ypos < start_y + height) { mzm_size += save_robot_calculate_size(mzx_world, cur_robot, savegame, WORLD_VERSION); num_robots_alloc++; } } } } // Now, we need to add the total overhead of the zip file. // File names are all "r##", so the max name length is 3. mzm_size += zip_bound_total_header_usage(num_robots_alloc, 3); buffer = alloc(mzm_size, storage); bufferPtr = buffer; memcpy(bufferPtr, "MZM3", 4); bufferPtr += 4; mem_putw(width, &bufferPtr); mem_putw(height, &bufferPtr); // Come back here later if there's robot information mem_putd(0, &bufferPtr); mem_putc(0, &bufferPtr); mem_putc(storage_mode, &bufferPtr); mem_putc(0, &bufferPtr); mem_putw(WORLD_VERSION, &bufferPtr); bufferPtr += 3; switch(mode) { // Board, raw case 0: { struct zip_archive *zp; struct board *src_board = mzx_world->current_board; int board_width = src_board->board_width; char *level_id = src_board->level_id; char *level_param = src_board->level_param; char *level_color = src_board->level_color; char *level_under_id = src_board->level_under_id; char *level_under_param = src_board->level_under_param; char *level_under_color = src_board->level_under_color; int x, y; int offset = start_x + (start_y * board_width); int line_skip = board_width - width; int num_robots = 0; int robot_numbers[256]; int robot_table_position; enum thing current_id; int i; for(y = 0; y < height; y++) { for(x = 0; x < width; x++, offset++) { current_id = (enum thing)level_id[offset]; if(is_robot(current_id)) { // Robot robot_numbers[num_robots] = level_param[offset]; num_robots++; mem_putc(current_id, &bufferPtr); mem_putc(0, &bufferPtr); mem_putc(level_color[offset], &bufferPtr); mem_putc(level_under_id[offset], &bufferPtr); mem_putc(level_under_param[offset], &bufferPtr); mem_putc(level_under_color[offset], &bufferPtr); } else if((current_id == SENSOR) || is_signscroll(current_id) || (current_id == PLAYER)) { // Sensor, scroll, sign, or player // Put customblock fake mem_putc((int)CUSTOM_BLOCK, &bufferPtr); mem_putc(get_id_char(src_board, offset), &bufferPtr); mem_putc(get_id_color(src_board, offset), &bufferPtr); mem_putc(level_under_id[offset], &bufferPtr); mem_putc(level_under_param[offset], &bufferPtr); mem_putc(level_under_color[offset], &bufferPtr); } else { mem_putc(current_id, &bufferPtr); mem_putc(level_param[offset], &bufferPtr); mem_putc(level_color[offset], &bufferPtr); mem_putc(level_under_id[offset], &bufferPtr); mem_putc(level_under_param[offset], &bufferPtr); mem_putc(level_under_color[offset], &bufferPtr); } } offset += line_skip; } // Get the zip redy 2 go zp = zip_open_mem_write(buffer, mzm_size); robot_table_position = bufferPtr - (unsigned char *)buffer; // Get the zip in position. Won't alter the bufferPtr zseek(zp, robot_table_position, SEEK_SET); // Go back to header to put robot table information if(num_robots) { struct robot **robot_list = src_board->robot_list; char name[4]; bufferPtr = buffer; bufferPtr += 8; // Where the robots will be stored // (not actually necessary anymore) mem_putd(robot_table_position, &bufferPtr); // Number of robots mem_putc(num_robots, &bufferPtr); // Skip board storage mode bufferPtr += 1; // Savegame mode for robots mem_putc(savegame, &bufferPtr); // Write robots into the zip for(i = 0; i < num_robots; i++) { sprintf(name, "r%2.2X", i); // Save each robot save_robot(mzx_world, robot_list[robot_numbers[i]], zp, savegame, WORLD_VERSION, name, FPROP_ROBOT, 0, i); } } zip_close(zp, NULL); break; } // Overlay/Vlayer case 1: case 2: { struct board *src_board = mzx_world->current_board; int board_width; int x, y; int offset; int line_skip; char *chars; char *colors; if(mode == 1) { // Overlay if(!src_board->overlay_mode) setup_overlay(src_board, 3); chars = src_board->overlay; colors = src_board->overlay_color; board_width = src_board->board_width; } else { // Vlayer chars = mzx_world->vlayer_chars; colors = mzx_world->vlayer_colors; board_width = mzx_world->vlayer_width; } offset = start_x + (start_y * board_width); line_skip = board_width - width; for(y = 0; y < height; y++) { for(x = 0; x < width; x++, offset++) { mem_putc(chars[offset], &bufferPtr); mem_putc(colors[offset], &bufferPtr); } offset += line_skip; } break; } // Board, char based case 3: { struct board *src_board = mzx_world->current_board; int board_width = src_board->board_width; int x, y; int offset = start_x + (start_y * board_width); int line_skip = board_width - width; for(y = 0; y < height; y++) { for(x = 0; x < width; x++, offset++) { mem_putc(get_id_char(src_board, offset), &bufferPtr); mem_putc(get_id_color(src_board, offset), &bufferPtr); } offset += line_skip; } break; } } }