diff --git a/include/xsystem4.h b/include/xsystem4.h index 3bdf14f..f81f71f 100644 --- a/include/xsystem4.h +++ b/include/xsystem4.h @@ -91,5 +91,6 @@ extern bool game_rance02_mg; extern bool game_rance6_mg; extern bool game_rance7_mg; extern bool game_rance8; +extern bool game_dungeons_and_dolls; #endif /* XSYSTEM4_H */ diff --git a/src/hacks.c b/src/hacks.c index 69c6bff..ca541f0 100644 --- a/src/hacks.c +++ b/src/hacks.c @@ -37,6 +37,7 @@ bool game_rance02_mg = false; bool game_rance6_mg = false; bool game_rance7_mg = false; bool game_rance8 = false; +bool game_dungeons_and_dolls = false; static void write_instruction0(struct buffer *out, enum opcode op) { @@ -205,6 +206,8 @@ void apply_game_specific_hacks(struct ain *ain) apply_rance7_hacks(ain); } else if (!strcmp(game_name, "ランス・クエスト") || !strcmp(game_name, "Rance Quest")) { game_rance8 = true; + } else if (!strcmp(game_name, "DUNGEONS&DOLLS")) { + game_dungeons_and_dolls = true; } free(game_name); } diff --git a/src/vm.c b/src/vm.c index 51d0b99..4b4a6f8 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2319,8 +2319,28 @@ static void vm_execute(void) } } +static void call_global_destructors(void) +{ + if (heap_size <= 0 || heap[0].ref <= 0) + return; + struct page *global_page = heap_get_page(0); + // Call global variable destructors, but do not unref them because the + // destructors may reference other global variables. + for (int i = global_page->nr_vars - 1; i >= 0; i--) { + if (variable_type(global_page, i, NULL, NULL) != AIN_STRUCT) + continue; + int slot = global_page->values[i].i; + delete_struct(heap_get_page(slot)->index, slot); + } +} + static void vm_free(void) { + if (game_dungeons_and_dolls) { + // Dungeons & Dolls saves the game state in destructors of global variables + call_global_destructors(); + } + // call library exit routines exit_libraries(); // flush call stack