void clear_board(struct board *cur_board) { int i; int num_robots_active = cur_board->num_robots_active; int num_scrolls = cur_board->num_scrolls; int num_sensors = cur_board->num_sensors; struct robot **robot_list = cur_board->robot_list; struct robot **robot_name_list = cur_board->robot_list_name_sorted; struct robot *cur_robot; struct scroll **scroll_list = cur_board->scroll_list; struct sensor **sensor_list = cur_board->sensor_list; free(cur_board->level_id); free(cur_board->level_param); free(cur_board->level_color); free(cur_board->level_under_id); free(cur_board->level_under_param); free(cur_board->level_under_color); if(cur_board->overlay_mode) { free(cur_board->overlay); free(cur_board->overlay_color); } for(i = 0; i < num_robots_active; i++) { cur_robot = robot_name_list[i]; clear_robot(cur_robot); } free(robot_name_list); free(robot_list); for(i = 1; i <= num_scrolls; i++) if(scroll_list[i]) clear_scroll(scroll_list[i]); free(scroll_list); for(i = 1; i <= num_sensors; i++) if(sensor_list[i]) clear_sensor(sensor_list[i]); free(sensor_list); free(cur_board); }
__editor_maybe_static int load_board_direct(struct board *cur_board, FILE *fp, int data_size, int savegame, int version) { int num_robots, num_scrolls, num_sensors, num_robots_active; int overlay_mode, size, board_width, board_height, i; int viewport_x, viewport_y, viewport_width, viewport_height; int truncated = 0; struct robot *cur_robot; struct scroll *cur_scroll; struct sensor *cur_sensor; char *test_buffer; int board_location = ftell(fp); cur_board->num_robots = 0; cur_board->num_robots_allocated = 0; cur_board->num_robots_active = 0; cur_board->num_scrolls = 0; cur_board->num_scrolls_allocated = 0; cur_board->num_sensors = 0; cur_board->num_sensors_allocated = 0; cur_board->robot_list = NULL; cur_board->robot_list_name_sorted = NULL; cur_board->sensor_list = NULL; cur_board->scroll_list = NULL; // Initialize some fields that may no longer be loaded // from the board file itself.. cur_board->last_key = '?'; cur_board->num_input = 0; cur_board->input_size = 0; cur_board->input_string[0] = 0; cur_board->player_last_dir = 0x10; cur_board->bottom_mesg[0] = 0; cur_board->b_mesg_timer = 0; cur_board->lazwall_start = 7; cur_board->b_mesg_row = 24; cur_board->b_mesg_col = -1; cur_board->scroll_x = 0; cur_board->scroll_y = 0; cur_board->locked_x = -1; cur_board->locked_y = -1; cur_board->volume = 255; cur_board->volume_inc = 0; cur_board->volume_target = 255; // board_mode, unused if(fgetc(fp) == EOF) { val_error(WORLD_BOARD_MISSING, board_location); return VAL_MISSING; } overlay_mode = fgetc(fp); if(!overlay_mode) { int overlay_width; int overlay_height; overlay_mode = fgetc(fp); overlay_width = fgetw(fp); overlay_height = fgetw(fp); size = overlay_width * overlay_height; if((size < 1) || (size > MAX_BOARD_SIZE)) goto err_invalid; cur_board->overlay = cmalloc(size); cur_board->overlay_color = cmalloc(size); if(load_RLE2_plane(cur_board->overlay, fp, size)) goto err_freeoverlay; test_buffer = cmalloc(1024); free(test_buffer); // Skip sizes if(fseek(fp, 4, SEEK_CUR) || load_RLE2_plane(cur_board->overlay_color, fp, size)) goto err_freeoverlay; test_buffer = cmalloc(1024); free(test_buffer); } else { overlay_mode = 0; // Undo that last get fseek(fp, -1, SEEK_CUR); } cur_board->overlay_mode = overlay_mode; board_width = fgetw(fp); board_height = fgetw(fp); cur_board->board_width = board_width; cur_board->board_height = board_height; size = board_width * board_height; if((size < 1) || (size > MAX_BOARD_SIZE)) goto err_freeoverlay; cur_board->level_id = cmalloc(size); cur_board->level_color = cmalloc(size); cur_board->level_param = cmalloc(size); cur_board->level_under_id = cmalloc(size); cur_board->level_under_color = cmalloc(size); cur_board->level_under_param = cmalloc(size); if(load_RLE2_plane(cur_board->level_id, fp, size)) goto err_freeboard; if(fseek(fp, 4, SEEK_CUR) || load_RLE2_plane(cur_board->level_color, fp, size)) goto err_freeboard; if(fseek(fp, 4, SEEK_CUR) || load_RLE2_plane(cur_board->level_param, fp, size)) goto err_freeboard; if(fseek(fp, 4, SEEK_CUR) || load_RLE2_plane(cur_board->level_under_id, fp, size)) goto err_freeboard; if(fseek(fp, 4, SEEK_CUR) || load_RLE2_plane(cur_board->level_under_color, fp, size)) goto err_freeboard; if(fseek(fp, 4, SEEK_CUR) || load_RLE2_plane(cur_board->level_under_param, fp, size)) goto err_freeboard; // Load board parameters if(version < 0x0253) { fread(cur_board->mod_playing, LEGACY_MOD_FILENAME_MAX, 1, fp); cur_board->mod_playing[LEGACY_MOD_FILENAME_MAX] = 0; } else { size_t len = fgetw(fp); if(len >= MAX_PATH) len = MAX_PATH - 1; fread(cur_board->mod_playing, len, 1, fp); cur_board->mod_playing[len] = 0; } viewport_x = fgetc(fp); viewport_y = fgetc(fp); viewport_width = fgetc(fp); viewport_height = fgetc(fp); if( (viewport_x < 0) || (viewport_x > 79) || (viewport_y < 0) || (viewport_y > 24) || (viewport_width < 1) || (viewport_width > 80) || (viewport_height < 1) || (viewport_height > 25)) goto err_invalid; cur_board->viewport_x = viewport_x; cur_board->viewport_y = viewport_y; cur_board->viewport_width = viewport_width; cur_board->viewport_height = viewport_height; cur_board->can_shoot = fgetc(fp); cur_board->can_bomb = fgetc(fp); cur_board->fire_burn_brown = fgetc(fp); cur_board->fire_burn_space = fgetc(fp); cur_board->fire_burn_fakes = fgetc(fp); cur_board->fire_burn_trees = fgetc(fp); cur_board->explosions_leave = fgetc(fp); cur_board->save_mode = fgetc(fp); cur_board->forest_becomes = fgetc(fp); cur_board->collect_bombs = fgetc(fp); cur_board->fire_burns = fgetc(fp); for(i = 0; i < 4; i++) { cur_board->board_dir[i] = fgetc(fp); } cur_board->restart_if_zapped = fgetc(fp); cur_board->time_limit = fgetw(fp); if(version < 0x0253) { cur_board->last_key = fgetc(fp); cur_board->num_input = fgetw(fp); cur_board->input_size = fgetc(fp); fread(cur_board->input_string, LEGACY_INPUT_STRING_MAX + 1, 1, fp); cur_board->input_string[LEGACY_INPUT_STRING_MAX] = 0; cur_board->player_last_dir = fgetc(fp); fread(cur_board->bottom_mesg, LEGACY_BOTTOM_MESG_MAX + 1, 1, fp); cur_board->bottom_mesg[LEGACY_BOTTOM_MESG_MAX] = 0; cur_board->b_mesg_timer = fgetc(fp); cur_board->lazwall_start = fgetc(fp); cur_board->b_mesg_row = fgetc(fp); cur_board->b_mesg_col = (signed char)fgetc(fp); cur_board->scroll_x = (signed short)fgetw(fp); cur_board->scroll_y = (signed short)fgetw(fp); cur_board->locked_x = (signed short)fgetw(fp); cur_board->locked_y = (signed short)fgetw(fp); } else if(savegame) { size_t len; cur_board->last_key = fgetc(fp); cur_board->num_input = fgetw(fp); cur_board->input_size = fgetw(fp); len = fgetw(fp); if(len >= ROBOT_MAX_TR) len = ROBOT_MAX_TR - 1; fread(cur_board->input_string, len, 1, fp); cur_board->input_string[len] = 0; cur_board->player_last_dir = fgetc(fp); len = fgetw(fp); if(len >= ROBOT_MAX_TR) len = ROBOT_MAX_TR - 1; fread(cur_board->bottom_mesg, len, 1, fp); cur_board->bottom_mesg[len] = 0; cur_board->b_mesg_timer = fgetc(fp); cur_board->lazwall_start = fgetc(fp); cur_board->b_mesg_row = fgetc(fp); cur_board->b_mesg_col = (signed char)fgetc(fp); cur_board->scroll_x = (signed short)fgetw(fp); cur_board->scroll_y = (signed short)fgetw(fp); cur_board->locked_x = (signed short)fgetw(fp); cur_board->locked_y = (signed short)fgetw(fp); } cur_board->player_ns_locked = fgetc(fp); cur_board->player_ew_locked = fgetc(fp); cur_board->player_attack_locked = fgetc(fp); if(version < 0x0253 || savegame) { cur_board->volume = fgetc(fp); cur_board->volume_inc = fgetc(fp); cur_board->volume_target = fgetc(fp); } /***************/ /* Load robots */ /***************/ num_robots = fgetc(fp); num_robots_active = 0; if(num_robots == EOF) truncated = 1; // EOF/crazy value check if((num_robots < 0) || (num_robots > 255) || (num_robots > size)) goto board_scan; cur_board->robot_list = ccalloc(num_robots + 1, sizeof(struct robot *)); // Also allocate for name sorted list cur_board->robot_list_name_sorted = ccalloc(num_robots, sizeof(struct robot *)); // Any null objects being placed will later be optimized out if(num_robots) { for(i = 1; i <= num_robots; i++) { // Make sure there's robots to load here int length_check = fgetw(fp); fseek(fp, -2, SEEK_CUR); if(length_check < 0) { // Send off the error and then tell validation to shut up for now val_error(WORLD_ROBOT_MISSING, ftell(fp)); set_validation_suppression(1); truncated = 1; } cur_robot = load_robot_allocate(fp, savegame, version); if(cur_robot->used) { cur_board->robot_list[i] = cur_robot; cur_board->robot_list_name_sorted[num_robots_active] = cur_robot; num_robots_active++; } else { // We don't need no null robot clear_robot(cur_robot); cur_board->robot_list[i] = NULL; } } } set_validation_suppression(-1); if(num_robots_active > 0) { if(num_robots_active != num_robots) { cur_board->robot_list_name_sorted = crealloc(cur_board->robot_list_name_sorted, sizeof(struct robot *) * num_robots_active); } qsort(cur_board->robot_list_name_sorted, num_robots_active, sizeof(struct robot *), cmp_robots); } else { free(cur_board->robot_list_name_sorted); cur_board->robot_list_name_sorted = NULL; } cur_board->num_robots = num_robots; cur_board->num_robots_allocated = num_robots; cur_board->num_robots_active = num_robots_active; /****************/ /* Load scrolls */ /****************/ num_scrolls = fgetc(fp); if(num_scrolls == EOF) truncated = 1; if((num_scrolls < 0) || (num_scrolls > 255) || (num_robots + num_scrolls > size)) goto board_scan; cur_board->scroll_list = ccalloc(num_scrolls + 1, sizeof(struct scroll *)); if(num_scrolls) { for(i = 1; i <= num_scrolls; i++) { cur_scroll = load_scroll_allocate(fp); if(cur_scroll->used) cur_board->scroll_list[i] = cur_scroll; else clear_scroll(cur_scroll); } } cur_board->num_scrolls = num_scrolls; cur_board->num_scrolls_allocated = num_scrolls; /****************/ /* Load sensors */ /****************/ num_sensors = fgetc(fp); if(num_sensors == EOF) truncated = 1; if((num_sensors < 0) || (num_sensors > 255) || (num_scrolls + num_sensors + num_robots > size)) goto board_scan; cur_board->sensor_list = ccalloc(num_sensors + 1, sizeof(struct sensor *)); if(num_sensors) { for(i = 1; i <= num_sensors; i++) { cur_sensor = load_sensor_allocate(fp); if(cur_sensor->used) cur_board->sensor_list[i] = cur_sensor; else clear_sensor(cur_sensor); } } cur_board->num_sensors = num_sensors; cur_board->num_sensors_allocated = num_sensors; board_scan: // Now do a board scan to make sure there aren't more than the data told us. { int robot_count = 0, scroll_count = 0, sensor_count = 0; char err_mesg[80] = { 0 }; for(i = 0; i < (board_width * board_height); i++) { if(cur_board->level_id[i] > 127) cur_board->level_id[i] = CUSTOM_BLOCK; if(cur_board->level_under_id[i] > 127) cur_board->level_under_id[i] = CUSTOM_FLOOR; switch(cur_board->level_id[i]) { case ROBOT: case ROBOT_PUSHABLE: { robot_count++; if(robot_count > cur_board->num_robots) { cur_board->level_id[i] = CUSTOM_BLOCK; cur_board->level_param[i] = 'R'; cur_board->level_color[i] = 0xCF; } break; } case SIGN: case SCROLL: { scroll_count++; if(scroll_count > cur_board->num_scrolls) { cur_board->level_id[i] = CUSTOM_BLOCK; cur_board->level_param[i] = 'S'; cur_board->level_color[i] = 0xCF; } } case SENSOR: { // Wait, I forgot. Nobody cares about sensors. //sensor_count++; if(sensor_count > cur_board->num_sensors) { cur_board->level_id[i] = CUSTOM_FLOOR; cur_board->level_param[i] = 'S'; cur_board->level_color[i] = 0xDF; } } } } if(robot_count > cur_board->num_robots) { snprintf(err_mesg, 80, "Board @ %Xh: found %i robots; expected %i", board_location, robot_count, cur_board->num_robots); error(err_mesg, 1, 8, 0); } if(scroll_count > cur_board->num_scrolls) { snprintf(err_mesg, 80, "Board @ %Xh: found %i scrolls/signs; expected %i", board_location, scroll_count, cur_board->num_scrolls); error(err_mesg, 1, 8, 0); } // This won't be reached but I'll leave it anyway. if(sensor_count > cur_board->num_sensors) { snprintf(err_mesg, 80, "Board @ %Xh: found %i sensors; expected %i", board_location, sensor_count, cur_board->num_sensors); error(err_mesg, 1, 8, 0); } if(err_mesg[0]) error("Any extra robots/scrolls/signs were replaced", 1, 8, 0); } if(truncated == 1) val_error(WORLD_BOARD_TRUNCATED_SAFE, board_location); return VAL_SUCCESS; err_freeboard: free(cur_board->level_id); free(cur_board->level_color); free(cur_board->level_param); free(cur_board->level_under_id); free(cur_board->level_under_color); free(cur_board->level_under_param); err_freeoverlay: if(overlay_mode) { free(cur_board->overlay); free(cur_board->overlay_color); } err_invalid: val_error(WORLD_BOARD_CORRUPT, board_location); return VAL_INVALID; }
static int load_mzm_common(struct world *mzx_world, const void *buffer, int file_length, int start_x, int start_y, int mode, int savegame, char *name) { const unsigned char *bufferPtr = buffer; char magic_string[5]; int storage_mode; int width, height; int savegame_mode; int num_robots; int robots_location; int data_start; int expected_data_size; // MegaZeux 2.83 is the last version that won't save the ver, // so if we don't have a ver, just act like it's 2.83 int mzm_world_version = 0x0253; if (file_length < 4) goto err_invalid; memcpy(magic_string, bufferPtr, 4); bufferPtr += 4; magic_string[4] = 0; if(!strncmp(magic_string, "MZMX", 4)) { // An MZM1 file is always storage mode 0 storage_mode = 0; savegame_mode = 0; num_robots = 0; robots_location = 0; if (file_length < 16) goto err_invalid; width = mem_getc(&bufferPtr); height = mem_getc(&bufferPtr); bufferPtr += 10; } else if(!strncmp(magic_string, "MZM2", 4)) { if (file_length < 16) goto err_invalid; width = mem_getw(&bufferPtr); height = mem_getw(&bufferPtr); robots_location = mem_getd(&bufferPtr); num_robots = mem_getc(&bufferPtr); storage_mode = mem_getc(&bufferPtr); savegame_mode = mem_getc(&bufferPtr); bufferPtr += 1; } else if(!strncmp(magic_string, "MZM3", 4)) { if (file_length < 20) goto err_invalid; // MZM3 is like MZM2, except the robots are stored as source code if // savegame_mode is 0 and version >= VERSION_PROGRAM_SOURCE. width = mem_getw(&bufferPtr); height = mem_getw(&bufferPtr); robots_location = mem_getd(&bufferPtr); num_robots = mem_getc(&bufferPtr); storage_mode = mem_getc(&bufferPtr); savegame_mode = mem_getc(&bufferPtr); mzm_world_version = mem_getw(&bufferPtr); bufferPtr += 3; } else goto err_invalid; data_start = bufferPtr - (const unsigned char *)buffer; expected_data_size = (width * height) * (storage_mode ? 2 : 6); // Validate if( (savegame_mode > 1) || (savegame_mode < 0) // Invalid save mode || (storage_mode > 1) || (storage_mode < 0) // Invalid storage mode || (file_length - data_start < expected_data_size) // not enough space to store data || (file_length < robots_location) // The end of file is before the robot offset || (robots_location && (expected_data_size + data_start > robots_location)) // robots offset before data end ) goto err_invalid; // If the mzm version is newer than the MZX version, show a message and continue. if(mzm_world_version > WORLD_VERSION) { error_message(E_MZM_FILE_VERSION_TOO_RECENT, mzm_world_version, name); } // If the MZM is a save MZM but we're not loading at runtime, show a message and continue. if(savegame_mode > savegame) { error_message(E_MZM_FILE_FROM_SAVEGAME, 0, name); } switch(mode) { // Write to board case 0: { struct board *src_board = mzx_world->current_board; int board_width = src_board->board_width; int board_height = src_board->board_height; int effective_width = width; int effective_height = height; int file_line_skip; int line_skip; int x, y; int offset = start_x + (start_y * 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; enum thing src_id; // Clip if((effective_width + start_x) >= board_width) effective_width = board_width - start_x; if((effective_height + start_y) >= board_height) effective_height = board_height - start_y; line_skip = board_width - effective_width; switch(storage_mode) { case 0: { // Board style, write as is enum thing current_id; int current_robot_loaded = 0; int robot_x_locations[256]; int robot_y_locations[256]; int width_difference; int i; width_difference = width - effective_width; for(y = 0; y < effective_height; y++) { for(x = 0; x < effective_width; x++, offset++) { current_id = (enum thing)mem_getc(&bufferPtr); if(current_id >= SENSOR) { if(is_robot(current_id)) { robot_x_locations[current_robot_loaded] = x + start_x; robot_y_locations[current_robot_loaded] = y + start_y; current_robot_loaded++; } // Wipe a bunch of crap we don't want in MZMs with spaces else current_id = 0; } src_id = (enum thing)level_id[offset]; if(src_id >= SENSOR) { if(src_id == SENSOR) clear_sensor_id(src_board, level_param[offset]); else if(is_signscroll(src_id)) clear_scroll_id(src_board, level_param[offset]); else if(is_robot(src_id)) clear_robot_id(src_board, level_param[offset]); } // Don't allow the player to be overwritten if(src_id != PLAYER) { level_id[offset] = current_id; level_param[offset] = mem_getc(&bufferPtr); level_color[offset] = mem_getc(&bufferPtr); level_under_id[offset] = mem_getc(&bufferPtr); level_under_param[offset] = mem_getc(&bufferPtr); level_under_color[offset] = mem_getc(&bufferPtr); // We don't want this on the under layer, thanks if(level_under_id[offset] >= SENSOR) { level_under_id[offset] = 0; level_under_param[offset] = 0; level_under_color[offset] = 7; } } else { bufferPtr += 5; } } offset += line_skip; // Gotta run through and mark the next robots to be skipped for(i = 0; i < width_difference; i++) { current_id = (enum thing)mem_getc(&bufferPtr); bufferPtr += 5; if(is_robot(current_id)) { robot_x_locations[current_robot_loaded] = -1; current_robot_loaded++; } } } for(i = current_robot_loaded; i < num_robots; i++) { robot_x_locations[i] = -1; } if(num_robots) { struct zip_archive *zp; unsigned int file_id; unsigned int robot_id; int result; struct robot *cur_robot; int current_x, current_y; int offset; int new_param; int robot_calculated_size = 0; int robot_partial_size = 0; int current_position; int dummy = 0; // We suppress the errors that will generally occur here and barely // error check the zip functions. Why? This needs to run all the way // through, regardless of whether it finds errors. Otherwise, we'll // get invalid robots with ID=0 littered around the board. set_error_suppression(E_WORLD_ROBOT_MISSING, 1); set_error_suppression(E_BOARD_ROBOT_CORRUPT, 1); // Reset the error count. get_and_reset_error_count(); if(mzm_world_version <= WORLD_LEGACY_FORMAT_VERSION) { robot_partial_size = legacy_calculate_partial_robot_size(savegame_mode, mzm_world_version); bufferPtr = buffer; bufferPtr += robots_location; zp = NULL; } else { zp = zip_open_mem_read(buffer, file_length); zip_read_directory(zp); assign_fprops(zp, 1); } // If we're loading a "runtime MZM" then it means that we're loading // bytecode. And to do this we must both be in-game and must be // running the same version this was made in. But since loading // dynamically created MZMs in the editor is still useful, we'll just // dummy out the robots. if((savegame_mode > savegame) || (WORLD_VERSION < mzm_world_version)) { dummy = 1; } for(i = 0; i < num_robots; i++) { cur_robot = cmalloc(sizeof(struct robot)); current_x = robot_x_locations[i]; current_y = robot_y_locations[i]; // TODO: Skipped legacy robots aren't checked for, so the loaded // chars for dummy robots on clipped MZMs might be off. This // shouldn't matter too often though. if(mzm_world_version <= WORLD_LEGACY_FORMAT_VERSION) { create_blank_robot(cur_robot); current_position = bufferPtr - (const unsigned char *)buffer; // If we fail, we have to continue, or robots won't be dummied // correctly. In this case, seek to the end. if(current_position + robot_partial_size <= file_length) { robot_calculated_size = legacy_load_robot_calculate_size(bufferPtr, savegame_mode, mzm_world_version); if(current_position + robot_calculated_size <= file_length) { legacy_load_robot_from_memory(mzx_world, cur_robot, bufferPtr, savegame_mode, mzm_world_version, (int)current_position); } else { bufferPtr = (const unsigned char*)buffer + file_length; dummy = 1; } } else { bufferPtr = (const unsigned char*)buffer + file_length; dummy = 1; } bufferPtr += robot_calculated_size; } // Search the zip until a robot is found. else do { result = zip_get_next_prop(zp, &file_id, NULL, &robot_id); if(result != ZIP_SUCCESS) { // We have to continue, or we'll get screwed up robots. create_blank_robot(cur_robot); create_blank_robot_program(cur_robot); dummy = 1; break; } else if(file_id != FPROP_ROBOT || (int)robot_id < i) { // Not a robot or is a skipped robot zip_skip_file(zp); } else if((int)robot_id > i) { // There's a robot missing. create_blank_robot(cur_robot); create_blank_robot_program(cur_robot); break; } else { load_robot(mzx_world, cur_robot, zp, savegame_mode, mzm_world_version); break; } } while(1); if(dummy) { // Unfortunately, getting the actual character for the robot is // kind of a lot of work right now. We have to load it then // throw it away. // If this is from a futer version and the format changed, we'll // just end up with an 'R' char, but this shouldn't happen again if(current_x != -1) { offset = current_x + (current_y * board_width); level_id[offset] = CUSTOM_BLOCK; level_param[offset] = cur_robot->robot_char; } clear_robot(cur_robot); } else { cur_robot->world_version = mzx_world->version; cur_robot->xpos = current_x; cur_robot->ypos = current_y; #ifdef CONFIG_DEBYTECODE // If we're loading source code at runtime, we need to compile it if(savegame_mode < savegame) prepare_robot_bytecode(mzx_world, cur_robot); #endif if(current_x != -1) { new_param = find_free_robot(src_board); offset = current_x + (current_y * board_width); if(new_param != -1) { if((enum thing)level_id[offset] != PLAYER) { add_robot_name_entry(src_board, cur_robot, cur_robot->robot_name); src_board->robot_list[new_param] = cur_robot; cur_robot->xpos = current_x; cur_robot->ypos = current_y; level_param[offset] = new_param; } else { clear_robot(cur_robot); } } else { clear_robot(cur_robot); level_id[offset] = 0; level_param[offset] = 0; level_color[offset] = 7; } } else { clear_robot(cur_robot); } } } if(mzm_world_version > WORLD_LEGACY_FORMAT_VERSION) { zip_close(zp, NULL); } // If any errors were encountered, report if(get_and_reset_error_count()) goto err_robots; } break; } case 1: { // Compact style; expand to customblocks // Board style, write as is file_line_skip = (width - effective_width) * 2; for(y = 0; y < effective_height; y++) { for(x = 0; x < effective_width; x++, offset++) { src_id = (enum thing)level_id[offset]; if(src_id == SENSOR) clear_sensor_id(src_board, level_param[offset]); else if(is_signscroll(src_id)) clear_scroll_id(src_board, level_param[offset]); else if(is_robot(src_id)) clear_robot_id(src_board, level_param[offset]); // Don't allow the player to be overwritten if(src_id != PLAYER) { level_id[offset] = CUSTOM_BLOCK; level_param[offset] = mem_getc(&bufferPtr); level_color[offset] = mem_getc(&bufferPtr); level_under_id[offset] = 0; level_under_param[offset] = 0; level_under_color[offset] = 0; } else { bufferPtr += 2; } } offset += line_skip; bufferPtr += file_line_skip; } break; } } break; } // Overlay/vlayer case 1: case 2: { struct board *src_board = mzx_world->current_board; int dest_width = src_board->board_width; int dest_height = src_board->board_height; char *dest_chars; char *dest_colors; int effective_width = width; int effective_height = height; int file_line_skip; int line_skip; int x, y; int offset; if(mode == 1) { // Overlay if(!src_board->overlay_mode) setup_overlay(src_board, 3); dest_chars = src_board->overlay; dest_colors = src_board->overlay_color; dest_width = src_board->board_width; dest_height = src_board->board_height; } else { // Vlayer dest_chars = mzx_world->vlayer_chars; dest_colors = mzx_world->vlayer_colors; dest_width = mzx_world->vlayer_width; dest_height = mzx_world->vlayer_height; } offset = start_x + (start_y * dest_width); // Clip if((effective_width + start_x) >= dest_width) effective_width = dest_width - start_x; if((effective_height + start_y) >= dest_height) effective_height = dest_height - start_y; line_skip = dest_width - effective_width; switch(storage_mode) { case 0: { // Coming from board storage; for now use param as char file_line_skip = (width - effective_width) * 6; for(y = 0; y < effective_height; y++) { for(x = 0; x < effective_width; x++, offset++) { // Skip ID bufferPtr += 1; dest_chars[offset] = mem_getc(&bufferPtr); dest_colors[offset] = mem_getc(&bufferPtr); // Skip under parts bufferPtr += 3; } offset += line_skip; bufferPtr += file_line_skip; } break; } case 1: { // Coming from layer storage; transfer directly file_line_skip = (width - effective_width) * 2; for(y = 0; y < effective_height; y++) { for(x = 0; x < effective_width; x++, offset++) { dest_chars[offset] = mem_getc(&bufferPtr); dest_colors[offset] = mem_getc(&bufferPtr); } offset += line_skip; bufferPtr += file_line_skip; } break; } } break; } } // Clear none of the validation error suppressions: // 1) in combination with poor practice, they could lock MZX, // 2) they'll get reset after reloading the world. return 0; err_robots: // The main file loaded fine, but there was a problem handling robots error_message(E_MZM_ROBOT_CORRUPT, 0, name); return 0; err_invalid: error_message(E_MZM_FILE_INVALID, 0, name); return -1; }
__editor_maybe_static void load_board_direct(struct board *cur_board, FILE *fp, int savegame, int version) { int num_robots, num_scrolls, num_sensors, num_robots_active; int overlay_mode, size, board_width, board_height, i; struct robot *cur_robot; struct scroll *cur_scroll; struct sensor *cur_sensor; char *test_buffer; // Initialize some fields that may no longer be loaded // from the board file itself.. cur_board->last_key = '?'; cur_board->num_input = 0; cur_board->input_size = 0; cur_board->input_string[0] = 0; cur_board->player_last_dir = 0x10; cur_board->bottom_mesg[0] = 0; cur_board->b_mesg_timer = 0; cur_board->lazwall_start = 7; cur_board->b_mesg_row = 24; cur_board->b_mesg_col = -1; cur_board->scroll_x = 0; cur_board->scroll_y = 0; cur_board->locked_x = -1; cur_board->locked_y = -1; cur_board->volume = 255; cur_board->volume_inc = 0; cur_board->volume_target = 255; // board_mode, unused fgetc(fp); overlay_mode = fgetc(fp); if(!overlay_mode) { int overlay_width; int overlay_height; overlay_mode = fgetc(fp); overlay_width = fgetw(fp); overlay_height = fgetw(fp); size = overlay_width * overlay_height; cur_board->overlay = cmalloc(size); cur_board->overlay_color = cmalloc(size); load_RLE2_plane(cur_board->overlay, fp, size); test_buffer = cmalloc(1024); free(test_buffer); // Skip sizes fseek(fp, 4, SEEK_CUR); load_RLE2_plane(cur_board->overlay_color, fp, size); test_buffer = cmalloc(1024); free(test_buffer); } else { overlay_mode = 0; // Undo that last get fseek(fp, -1, SEEK_CUR); } cur_board->overlay_mode = overlay_mode; board_width = fgetw(fp); board_height = fgetw(fp); cur_board->board_width = board_width; cur_board->board_height = board_height; size = board_width * board_height; cur_board->level_id = cmalloc(size); cur_board->level_color = cmalloc(size); cur_board->level_param = cmalloc(size); cur_board->level_under_id = cmalloc(size); cur_board->level_under_color = cmalloc(size); cur_board->level_under_param = cmalloc(size); load_RLE2_plane(cur_board->level_id, fp, size); fseek(fp, 4, SEEK_CUR); load_RLE2_plane(cur_board->level_color, fp, size); fseek(fp, 4, SEEK_CUR); load_RLE2_plane(cur_board->level_param, fp, size); fseek(fp, 4, SEEK_CUR); load_RLE2_plane(cur_board->level_under_id, fp, size); fseek(fp, 4, SEEK_CUR); load_RLE2_plane(cur_board->level_under_color, fp, size); fseek(fp, 4, SEEK_CUR); load_RLE2_plane(cur_board->level_under_param, fp, size); // Load board parameters if(version < 0x0253) { fread(cur_board->mod_playing, LEGACY_MOD_FILENAME_MAX, 1, fp); cur_board->mod_playing[LEGACY_MOD_FILENAME_MAX] = 0; } else { size_t len = fgetw(fp); if(len >= MAX_PATH) len = MAX_PATH - 1; fread(cur_board->mod_playing, len, 1, fp); cur_board->mod_playing[len] = 0; } cur_board->viewport_x = fgetc(fp); cur_board->viewport_y = fgetc(fp); cur_board->viewport_width = fgetc(fp); cur_board->viewport_height = fgetc(fp); cur_board->can_shoot = fgetc(fp); cur_board->can_bomb = fgetc(fp); cur_board->fire_burn_brown = fgetc(fp); cur_board->fire_burn_space = fgetc(fp); cur_board->fire_burn_fakes = fgetc(fp); cur_board->fire_burn_trees = fgetc(fp); cur_board->explosions_leave = fgetc(fp); cur_board->save_mode = fgetc(fp); cur_board->forest_becomes = fgetc(fp); cur_board->collect_bombs = fgetc(fp); cur_board->fire_burns = fgetc(fp); for(i = 0; i < 4; i++) { cur_board->board_dir[i] = fgetc(fp); } cur_board->restart_if_zapped = fgetc(fp); cur_board->time_limit = fgetw(fp); if(version < 0x0253) { cur_board->last_key = fgetc(fp); cur_board->num_input = fgetw(fp); cur_board->input_size = fgetc(fp); fread(cur_board->input_string, LEGACY_INPUT_STRING_MAX + 1, 1, fp); cur_board->input_string[LEGACY_INPUT_STRING_MAX] = 0; cur_board->player_last_dir = fgetc(fp); fread(cur_board->bottom_mesg, LEGACY_BOTTOM_MESG_MAX + 1, 1, fp); cur_board->bottom_mesg[LEGACY_BOTTOM_MESG_MAX] = 0; cur_board->b_mesg_timer = fgetc(fp); cur_board->lazwall_start = fgetc(fp); cur_board->b_mesg_row = fgetc(fp); cur_board->b_mesg_col = (signed char)fgetc(fp); cur_board->scroll_x = (signed short)fgetw(fp); cur_board->scroll_y = (signed short)fgetw(fp); cur_board->locked_x = (signed short)fgetw(fp); cur_board->locked_y = (signed short)fgetw(fp); } else if(savegame) { size_t len; cur_board->last_key = fgetc(fp); cur_board->num_input = fgetw(fp); cur_board->input_size = fgetw(fp); len = fgetw(fp); if(len >= ROBOT_MAX_TR) len = ROBOT_MAX_TR - 1; fread(cur_board->input_string, len, 1, fp); cur_board->input_string[len] = 0; cur_board->player_last_dir = fgetc(fp); len = fgetw(fp); if(len >= ROBOT_MAX_TR) len = ROBOT_MAX_TR - 1; fread(cur_board->bottom_mesg, len, 1, fp); cur_board->bottom_mesg[len] = 0; cur_board->b_mesg_timer = fgetc(fp); cur_board->lazwall_start = fgetc(fp); cur_board->b_mesg_row = fgetc(fp); cur_board->b_mesg_col = (signed char)fgetc(fp); cur_board->scroll_x = (signed short)fgetw(fp); cur_board->scroll_y = (signed short)fgetw(fp); cur_board->locked_x = (signed short)fgetw(fp); cur_board->locked_y = (signed short)fgetw(fp); } cur_board->player_ns_locked = fgetc(fp); cur_board->player_ew_locked = fgetc(fp); cur_board->player_attack_locked = fgetc(fp); if(version < 0x0253 || savegame) { cur_board->volume = fgetc(fp); cur_board->volume_inc = fgetc(fp); cur_board->volume_target = fgetc(fp); } // Load robots num_robots = fgetc(fp); num_robots_active = 0; cur_board->robot_list = ccalloc(num_robots + 1, sizeof(struct robot *)); // Also allocate for name sorted list cur_board->robot_list_name_sorted = ccalloc(num_robots, sizeof(struct robot *)); // Any null objects being placed will later be optimized out if(num_robots) { for(i = 1; i <= num_robots; i++) { cur_robot = load_robot_allocate(fp, savegame, version); if(cur_robot->used) { cur_board->robot_list[i] = cur_robot; cur_board->robot_list_name_sorted[num_robots_active] = cur_robot; num_robots_active++; } else { // We don't need no null robot clear_robot(cur_robot); cur_board->robot_list[i] = NULL; } } } if(num_robots_active) { if(num_robots_active != num_robots) { cur_board->robot_list_name_sorted = crealloc(cur_board->robot_list_name_sorted, sizeof(struct robot *) * num_robots_active); } qsort(cur_board->robot_list_name_sorted, num_robots_active, sizeof(struct robot *), cmp_robots); } else { free(cur_board->robot_list_name_sorted); cur_board->robot_list_name_sorted = NULL; } cur_board->num_robots = num_robots; cur_board->num_robots_allocated = num_robots; cur_board->num_robots_active = num_robots_active; // Load scrolls num_scrolls = fgetc(fp); cur_board->scroll_list = ccalloc(num_scrolls + 1, sizeof(struct scroll *)); if(num_scrolls) { for(i = 1; i <= num_scrolls; i++) { cur_scroll = load_scroll_allocate(fp); if(cur_scroll->used) cur_board->scroll_list[i] = cur_scroll; else clear_scroll(cur_scroll); } } cur_board->num_scrolls = num_scrolls; cur_board->num_scrolls_allocated = num_scrolls; // Load sensors num_sensors = fgetc(fp); cur_board->sensor_list = ccalloc(num_sensors + 1, sizeof(struct sensor *)); if(num_sensors) { for(i = 1; i <= num_sensors; i++) { cur_sensor = load_sensor_allocate(fp); if(cur_sensor->used) cur_board->sensor_list[i] = cur_sensor; else clear_sensor(cur_sensor); } } cur_board->num_sensors = num_sensors; cur_board->num_sensors_allocated = num_sensors; }