Skip to content

Commit

Permalink
Save the current output file mode in saved games.
Browse files Browse the repository at this point in the history
  • Loading branch information
AliceLR committed Nov 30, 2023
1 parent 9f88ffe commit 44bf5d7
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 70 deletions.
4 changes: 4 additions & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ USERS
+ Robotic debugger watchpoints can now watch for particular
counter or string values. Leaving the value field blank will
still check for any value.
+ The output file mode (FWRITE_OPEN, FWRITE_MODIFY, or
FWRITE_APPEND) is now stored in save files. This fixes a bug
where the output file would be reopened in the wrong mode (ab)
when reloading a saved game.
+ editor_show_thing_toggles is now enabled by default.
- board_editor_hide_help and robot_editor_hide_help are no
longer enabled by default for accessibility.
Expand Down
16 changes: 16 additions & 0 deletions docs/fileform.html
Original file line number Diff line number Diff line change
Expand Up @@ -2504,6 +2504,7 @@ <h3>World Properties</h3>
| `0x8078` | Output filename | string | Save-only
| `0x807C` | Output file position | int(d) | Save-only
| `0x807D` | Output file delimiter | int(ds) | Save-only
| `0x807E` | Output file mode | int(b) | Save-only, 2.93+ <a href="#world290note1">(2)</a>
| `0x8080` | Multiplier | int(ds) | Save-only
| `0x8081` | Divider | int(ds) | Save-only
| `0x8082` | Circle divisions | int(ds) | Save-only
Expand All @@ -2518,6 +2519,21 @@ <h3>World Properties</h3>
terminated, and may leave parts of previous world names in the loaded
name if it is not.
</li>
<li id="world290note2">
This field may be omitted. Valid output file mode values:
<div class="markdown">
| Value | Mode |
|-------|--------------|
| 0 | none/unknown
| 1 | `w+b`
| 2 | `r+b`
| 3 | `a+b`
</div>
Files opened in mode <code>w+b</code> should be reopened in mode
<code>r+b</code>. The output file is currently write-only, so
<code>wb</code> and <code>ab</code> are used in Robotic instead
of <code>w+b</code> and <code>a+b</code> for now.
</li>
</ol>
<h4 id="statctrprop290">Status Counter Properties</h4>
As of 2.93, the status counters are a nested properties file. Status
Expand Down
103 changes: 37 additions & 66 deletions src/counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -2887,6 +2887,30 @@ static struct robot *get_robot_by_id(struct world *mzx_world, int id)
return NULL;
}

static void fread_close(struct world *mzx_world)
{
if(!mzx_world->input_is_dir && mzx_world->input_file)
vfclose(mzx_world->input_file);

if(mzx_world->input_is_dir && mzx_world->input_directory)
vdir_close(mzx_world->input_directory);

mzx_world->input_file_name[0] = '\0';
mzx_world->input_file = NULL;
mzx_world->input_directory = NULL;
mzx_world->input_is_dir = false;
}

static void fwrite_close(struct world *mzx_world)
{
if(mzx_world->output_file)
vfclose(mzx_world->output_file);

mzx_world->output_file_name[0] = '\0';
mzx_world->output_file = NULL;
mzx_world->output_mode = FWRITE_MODE_UNKNOWN;
}

int set_counter_special(struct world *mzx_world, char *char_value,
int value, int id)
{
Expand All @@ -2899,25 +2923,15 @@ int set_counter_special(struct world *mzx_world, char *char_value,
{
case FOPEN_FREAD:
{
mzx_world->input_file_name[0] = 0;
fread_close(mzx_world);

if(char_value[0])
{
char *translated_path = cmalloc(MAX_PATH);
char *translated_path = (char *)cmalloc(MAX_PATH);
int err;

if(!mzx_world->input_is_dir && mzx_world->input_file)
{
vfclose(mzx_world->input_file);
mzx_world->input_file = NULL;
}

if(mzx_world->input_is_dir)
{
vdir_close(mzx_world->input_directory);
mzx_world->input_directory = NULL;
mzx_world->input_is_dir = false;
}
if(!translated_path)
return 0;

err = fsafetranslate(char_value, translated_path, MAX_PATH);

Expand All @@ -2937,97 +2951,54 @@ int set_counter_special(struct world *mzx_world, char *char_value,

free(translated_path);
}
else
{
if(!mzx_world->input_is_dir && mzx_world->input_file)
{
vfclose(mzx_world->input_file);
mzx_world->input_file = NULL;
}

if(mzx_world->input_is_dir)
{
vdir_close(mzx_world->input_directory);
mzx_world->input_directory = NULL;
mzx_world->input_is_dir = false;
}
}

break;
}

case FOPEN_FWRITE:
{
mzx_world->output_file_name[0] = 0;
fwrite_close(mzx_world);

if(char_value[0])
{
if(mzx_world->output_file)
vfclose(mzx_world->output_file);

mzx_world->output_file = fsafeopen(char_value, "wb");
if(mzx_world->output_file)
strcpy(mzx_world->output_file_name, char_value);
}
else
{
if(mzx_world->output_file)
{
vfclose(mzx_world->output_file);
mzx_world->output_file = NULL;
strcpy(mzx_world->output_file_name, char_value);
mzx_world->output_mode = FWRITE_MODE_TRUNCATE;
}
}

break;
}

case FOPEN_FAPPEND:
{
mzx_world->output_file_name[0] = 0;
fwrite_close(mzx_world);

if(char_value[0])
{
if(mzx_world->output_file)
vfclose(mzx_world->output_file);

mzx_world->output_file = fsafeopen(char_value, "ab");
if(mzx_world->output_file)
strcpy(mzx_world->output_file_name, char_value);
}
else
{
if(mzx_world->output_file)
{
vfclose(mzx_world->output_file);
mzx_world->output_file = NULL;
strcpy(mzx_world->output_file_name, char_value);
mzx_world->output_mode = FWRITE_MODE_APPEND;
}
}

break;
}

case FOPEN_FMODIFY:
{
mzx_world->output_file_name[0] = 0;
fwrite_close(mzx_world);

if(char_value[0])
{
if(mzx_world->output_file)
vfclose(mzx_world->output_file);

mzx_world->output_file = fsafeopen(char_value, "r+b");
if(mzx_world->output_file)
strcpy(mzx_world->output_file_name, char_value);
}
else
{
if(mzx_world->output_file)
{
vfclose(mzx_world->output_file);
mzx_world->output_file = NULL;
strcpy(mzx_world->output_file_name, char_value);
mzx_world->output_mode = FWRITE_MODE_MODIFY;
}
}

break;
}

Expand Down
4 changes: 4 additions & 0 deletions src/utils/downver.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ static void convert_293_to_292_world_info(struct downver_state *dv,
save_prop_c(ident, dv->screen_mode, dest);
break;

case WPROP_OUTPUT_MODE:
/* Added in 2.93 */
break;

default:
save_prop_p(ident, &prop, dest);
break;
Expand Down
23 changes: 21 additions & 2 deletions src/world.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,9 @@ static inline int save_world_info(struct world *mzx_world,
save_prop_s(WPROP_OUTPUT_FILE_NAME, mzx_world->output_file_name, mf);
save_prop_d(WPROP_OUTPUT_POS, mzx_world->temp_output_pos, mf);
save_prop_d(WPROP_FWRITE_DELIMITER, mzx_world->fwrite_delimiter, mf);
if(file_version >= V293)
save_prop_c(WPROP_OUTPUT_MODE, mzx_world->output_mode, mf);

save_prop_d(WPROP_MULTIPLIER, mzx_world->multiplier, mf);
save_prop_d(WPROP_DIVIDER, mzx_world->divider, mf);
save_prop_d(WPROP_C_DIVISIONS, mzx_world->c_divisions, mf);
Expand Down Expand Up @@ -567,6 +570,7 @@ static inline enum val_result validate_world_info(struct world *mzx_world,
check(WPROP_OUTPUT_FILE_NAME);
check(WPROP_OUTPUT_POS);
check(WPROP_FWRITE_DELIMITER);
// ignore optional WPROP_OUTPUT_MODE (2.93)
check(WPROP_MULTIPLIER);
check(WPROP_DIVIDER);
check(WPROP_C_DIVISIONS);
Expand Down Expand Up @@ -1038,6 +1042,16 @@ static inline void load_world_info(struct world *mzx_world,
mzx_world->fwrite_delimiter = load_prop_int(prop) & 255;
break;

case WPROP_OUTPUT_MODE:
if_savegame
if(*file_version >= V293)
{
int tmp = load_prop_int_u(prop, FWRITE_MODE_UNKNOWN, FWRITE_MODE_MAX);
mzx_world->output_mode =
tmp < FWRITE_MODE_MAX ? (enum fwrite_mode)tmp : FWRITE_MODE_UNKNOWN;
}
break;

case WPROP_MULTIPLIER:
if_savegame
mzx_world->multiplier = load_prop_int(prop);
Expand Down Expand Up @@ -2890,8 +2904,12 @@ static void load_world(struct world *mzx_world, struct zip_archive *zp,
// Open output file
if(mzx_world->output_file_name[0])
{
mzx_world->output_file =
fsafeopen(mzx_world->output_file_name, "ab");
// Truncation occurred during the initial FWRITE_APPEND,
// so wb and r+b should both be reopened as r+b.
if(mzx_world->output_mode == FWRITE_MODE_APPEND)
mzx_world->output_file = fsafeopen(mzx_world->output_file_name, "ab");
else
mzx_world->output_file = fsafeopen(mzx_world->output_file_name, "r+b");

if(mzx_world->output_file)
{
Expand Down Expand Up @@ -3531,6 +3549,7 @@ void clear_world(struct world *mzx_world)
vfclose(mzx_world->output_file);
mzx_world->output_file = NULL;
}
mzx_world->output_mode = FWRITE_MODE_UNKNOWN;

mzx_world->current_cycle_odd = false;
mzx_world->current_cycle_frozen = false;
Expand Down
5 changes: 3 additions & 2 deletions src/world_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ enum status_counters_prop
#define COUNT_WORLD_PROPS ( 1 + 3 + 4 + 16 + 4 + 1)
#define BOUND_WORLD_PROPS (BOARD_NAME_SIZE + 5 + 455 + 24 + 9 + STATCTR_PROP_SIZE)

#define COUNT_SAVE_PROPS ( 2 + 32 + 3 + 1)
#define BOUND_SAVE_PROPS ( 2 + 120 + 3*MAX_PATH + NUM_KEYS)
#define COUNT_SAVE_PROPS ( 2 + 33 + 3 + 1)
#define BOUND_SAVE_PROPS ( 2 + 121 + 3*MAX_PATH + NUM_KEYS)

// For world files, use WORLD_PROP_SIZE
// For save files, use WORLD_PROP_SIZE + SAVE_PROP_SIZE
Expand Down Expand Up @@ -194,6 +194,7 @@ enum world_prop
WPROP_OUTPUT_FILE_NAME = 0x8078, // MAX_PATH
WPROP_OUTPUT_POS = 0x807C, // 4
WPROP_FWRITE_DELIMITER = 0x807D, // 4
WPROP_OUTPUT_MODE = 0x807E, // 1
WPROP_MULTIPLIER = 0x8080, // 4
WPROP_DIVIDER = 0x8081, // 4
WPROP_C_DIVISIONS = 0x8082, // 4
Expand Down
10 changes: 10 additions & 0 deletions src/world_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ enum change_game_state_value
CHANGE_STATE_REQUEST_EXIT
};

enum fwrite_mode
{
FWRITE_MODE_UNKNOWN,
FWRITE_MODE_TRUNCATE,
FWRITE_MODE_MODIFY,
FWRITE_MODE_APPEND,
FWRITE_MODE_MAX
};

struct world
{
// 0 if a world has been loaded, 1 if it hasn't
Expand Down Expand Up @@ -129,6 +138,7 @@ struct world
vfile *input_file;
vdir *input_directory;
boolean input_is_dir;
enum fwrite_mode output_mode;
int temp_input_pos;
int temp_output_pos;
int commands;
Expand Down

0 comments on commit 44bf5d7

Please sign in to comment.