Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 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 | #include <ctype.h> |
||
| 23 | #include <inttypes.h> |
||
| 24 | |||
| 25 | |||
| 2 | pmbaty | 26 | extern int filter_level; |
| 1 | pmbaty | 27 | |
| 28 | |||
| 29 | void disable_fixes_and_enhancements() { |
||
| 30 | enable_crouch_after_climbing = 0; |
||
| 31 | enable_freeze_time_during_end_music = 0; |
||
| 32 | enable_remember_guard_hp = 0; |
||
| 33 | fix_gate_sounds = 0; |
||
| 34 | fix_two_coll_bug = 0; |
||
| 35 | fix_infinite_down_bug = 0; |
||
| 36 | fix_gate_drawing_bug = 0; |
||
| 37 | fix_bigpillar_climb = 0; |
||
| 38 | fix_jump_distance_at_edge = 0; |
||
| 39 | fix_edge_distance_check_when_climbing = 0; |
||
| 40 | fix_painless_fall_on_guard = 0; |
||
| 41 | fix_wall_bump_triggers_tile_below = 0; |
||
| 42 | fix_stand_on_thin_air = 0; |
||
| 43 | fix_press_through_closed_gates = 0; |
||
| 44 | fix_grab_falling_speed = 0; |
||
| 45 | fix_skeleton_chomper_blood = 0; |
||
| 46 | fix_move_after_drink = 0; |
||
| 47 | fix_loose_left_of_potion = 0; |
||
| 48 | fix_guard_following_through_closed_gates = 0; |
||
| 49 | fix_safe_landing_on_spikes = 0; |
||
| 50 | fix_glide_through_wall = 0; |
||
| 51 | fix_drop_through_tapestry = 0; |
||
| 52 | fix_land_against_gate_or_tapestry = 0; |
||
| 53 | fix_unintended_sword_strike = 0; |
||
| 54 | fix_retreat_without_leaving_room = 0; |
||
| 55 | fix_running_jump_through_tapestry= 0; |
||
| 56 | fix_push_guard_into_wall = 0; |
||
| 57 | fix_jump_through_wall_above_gate = 0; |
||
| 58 | fix_chompers_not_starting = 0; |
||
| 59 | fix_feather_interrupted_by_leveldoor = 0; |
||
| 60 | fix_offscreen_guards_disappearing = 0; |
||
| 61 | fix_move_after_sheathe = 0; |
||
| 62 | } |
||
| 63 | |||
| 64 | // .ini file parser adapted from https://gist.github.com/OrangeTide/947070 |
||
| 65 | /* Load an .ini format file |
||
| 66 | * filename - path to a file |
||
| 67 | * report - callback can return non-zero to stop, the callback error code is |
||
| 68 | * returned from this function. |
||
| 69 | * return - return 0 on success |
||
| 70 | */ |
||
| 71 | int ini_load(const char *filename, |
||
| 72 | int (*report)(const char *section, const char *name, const char *value)) |
||
| 73 | { |
||
| 74 | char name[64]; |
||
| 75 | char value[256]; |
||
| 76 | char section[128] = ""; |
||
| 77 | char *s; |
||
| 78 | FILE *f; |
||
| 79 | int cnt; |
||
| 80 | |||
| 81 | f = fopen(filename, "r"); |
||
| 82 | if (!f) { |
||
| 83 | return -1; |
||
| 84 | } |
||
| 85 | |||
| 86 | while (!feof(f)) { |
||
| 87 | if (fscanf(f, "[%127[^];\n]]\n", section) == 1) { |
||
| 88 | } else if ((cnt = fscanf(f, " %63[^=;\n] = %255[^;\n]", name, value))) { |
||
| 89 | if (cnt == 1) |
||
| 90 | *value = 0; |
||
| 91 | for (s = name + strlen(name) - 1; s > name && isspace(*s); s--) |
||
| 92 | *s = 0; |
||
| 93 | for (s = value + strlen(value) - 1; s > value && isspace(*s); s--) |
||
| 94 | *s = 0; |
||
| 95 | report(section, name, value); |
||
| 96 | } |
||
| 97 | fscanf(f, " ;%*[^\n]"); |
||
| 98 | fscanf(f, " \n"); |
||
| 99 | } |
||
| 100 | |||
| 101 | fclose(f); |
||
| 102 | return 0; |
||
| 103 | } |
||
| 104 | |||
| 105 | #define MAX_NAME_LENGTH 20 |
||
| 106 | typedef struct ini_value_list_type { |
||
| 107 | const char (* names)[][MAX_NAME_LENGTH]; |
||
| 108 | word num_names; |
||
| 109 | } ini_value_list_type; |
||
| 110 | |||
| 111 | const char level_type_names[][MAX_NAME_LENGTH] = {"dungeon", "palace"}; |
||
| 112 | const char guard_type_names[][MAX_NAME_LENGTH] = {"guard", "fat", "skel", "vizier", "shadow"}; |
||
| 113 | const char tile_type_names[][MAX_NAME_LENGTH] = { |
||
| 114 | "empty", "floor", "spike", "pillar", "gate", // 0..4 |
||
| 115 | "stuck", "closer", "doortop_with_floor", "bigpillar_bottom", "bigpillar_top", // 5..9 |
||
| 116 | "potion", "loose", "doortop", "mirror", "debris", // 10..14 |
||
| 117 | "opener", "level_door_left", "level_door_right", "chomper", "torch", // 15..19 |
||
| 118 | "wall", "skeleton", "sword", "balcony_left", "balcony_right", // 20..24 |
||
| 119 | "lattice_pillar", "lattice_down", "lattice_small", "lattice_left", "lattice_right", // 25..29 |
||
| 120 | "torch_with_debris", // 30 |
||
| 121 | }; |
||
| 122 | |||
| 123 | ini_value_list_type level_type_names_list = {&level_type_names, COUNT(level_type_names)}; |
||
| 124 | ini_value_list_type guard_type_names_list = {&guard_type_names, COUNT(guard_type_names)}; |
||
| 125 | ini_value_list_type tile_type_names_list = {&tile_type_names, COUNT(tile_type_names)}; |
||
| 126 | |||
| 127 | #define INI_NO_VALID_NAME -9999 |
||
| 128 | |||
| 129 | static inline int ini_get_named_value(const char* value, ini_value_list_type* value_names) { |
||
| 130 | if (value_names != NULL) { |
||
| 131 | int i; |
||
| 132 | char *base_ptr = (char *) value_names->names; |
||
| 133 | for (i = 0; i < value_names->num_names; ++i) { |
||
| 134 | char *name = (base_ptr + i * MAX_NAME_LENGTH); |
||
| 135 | if (strcasecmp(value, name) == 0) return i; |
||
| 136 | } |
||
| 137 | } |
||
| 138 | return INI_NO_VALID_NAME; // failure |
||
| 139 | } |
||
| 140 | |||
| 141 | static inline int ini_process_boolean(const char* curr_name, const char* value, const char* option_name, byte* target) { |
||
| 142 | if(strcasecmp(curr_name, option_name) == 0) { |
||
| 143 | if (strcasecmp(value, "true") == 0) *target = 1; |
||
| 144 | else if (strcasecmp(value, "false") == 0) *target = 0; |
||
| 145 | return 1; // finished; don't look for more possible options that curr_name can be |
||
| 146 | } |
||
| 147 | return 0; // not the right option; should check another option_name |
||
| 148 | } |
||
| 149 | |||
| 150 | #define ini_process_numeric_func(data_type) \ |
||
| 151 | static inline int ini_process_##data_type(const char* curr_name, const char* value, const char* option_name, data_type* target, ini_value_list_type* value_names) { \ |
||
| 152 | if(strcasecmp(curr_name, option_name) == 0) { \ |
||
| 153 | if (strcasecmp(value, "default") != 0) { \ |
||
| 154 | int named_value = ini_get_named_value(value, value_names); \ |
||
| 155 | *target = (named_value == INI_NO_VALID_NAME) ? ((data_type) strtoimax(value, NULL, 0)) : ((data_type) named_value); \ |
||
| 156 | } \ |
||
| 157 | return 1; /* finished; don't look for more possible options that curr_name can be */ \ |
||
| 158 | } \ |
||
| 159 | return 0; /* not the right option; should check another option_name */ \ |
||
| 160 | } |
||
| 161 | ini_process_numeric_func(word) |
||
| 162 | ini_process_numeric_func(short) |
||
| 163 | ini_process_numeric_func(byte) |
||
| 164 | ini_process_numeric_func(int) |
||
| 165 | |||
| 166 | static int global_ini_callback(const char *section, const char *name, const char *value) |
||
| 167 | { |
||
| 168 | //fprintf(stdout, "[%s] '%s'='%s'\n", section, name, value); |
||
| 169 | |||
| 170 | #define check_ini_section(section_name) (strcasecmp(section, section_name) == 0) |
||
| 171 | |||
| 172 | // Make sure that we return successfully as soon as name matches the correct option_name |
||
| 173 | #define process_word(option_name, target, value_names) \ |
||
| 174 | if (ini_process_word(name, value, option_name, target, value_names)) return 1; |
||
| 175 | |||
| 176 | #define process_short(option_name, target, value_names) \ |
||
| 177 | if (ini_process_short(name, value, option_name, target, value_names)) return 1; |
||
| 178 | |||
| 179 | #define process_byte(option_name, target, value_names) \ |
||
| 180 | if (ini_process_byte(name, value, option_name, target, value_names)) return 1; |
||
| 181 | |||
| 182 | #define process_int(option_name, target, value_names) \ |
||
| 183 | if (ini_process_int(name, value, option_name, target, value_names)) return 1; |
||
| 184 | |||
| 185 | #define process_boolean(option_name, target) \ |
||
| 186 | if (ini_process_boolean(name, value, option_name, target)) return 1; |
||
| 187 | |||
| 188 | if (check_ini_section("General")) { |
||
| 189 | process_boolean("enable_copyprot", &enable_copyprot); |
||
| 190 | process_boolean("enable_mixer", &enable_mixer); |
||
| 7 | pmbaty | 191 | process_int("mixer_volume", &mixer_volume, NULL); |
| 1 | pmbaty | 192 | process_boolean("enable_fade", &enable_fade); |
| 193 | process_boolean("enable_flash", &enable_flash); |
||
| 194 | process_boolean("enable_text", &enable_text); |
||
| 195 | process_boolean("enable_info_screen", &enable_info_screen); |
||
| 196 | process_boolean("start_fullscreen", &start_fullscreen); |
||
| 197 | process_word("pop_window_width", &pop_window_width, NULL); |
||
| 198 | process_word("pop_window_height", &pop_window_height, NULL); |
||
| 199 | process_boolean("use_correct_aspect_ratio", &use_correct_aspect_ratio); |
||
| 200 | process_boolean("use_integer_scaling", &use_integer_scaling); |
||
| 201 | process_boolean("enable_controller_rumble", &enable_controller_rumble); |
||
| 202 | process_boolean("joystick_only_horizontal", &joystick_only_horizontal); |
||
| 203 | process_int("joystick_threshold", &joystick_threshold, NULL); |
||
| 204 | |||
| 205 | if (strcasecmp(name, "levelset") == 0) { |
||
| 206 | if (value[0] == '\0' || strcasecmp(value, "original") == 0 || strcasecmp(value, "default") == 0) { |
||
| 207 | use_custom_levelset = 0; |
||
| 208 | } else { |
||
| 209 | use_custom_levelset = 1; |
||
| 210 | strcpy(levelset_name, value); |
||
| 211 | } |
||
| 212 | return 1; |
||
| 213 | } |
||
| 214 | } |
||
| 215 | |||
| 216 | if (check_ini_section("AdditionalFeatures")) { |
||
| 217 | process_boolean("enable_quicksave", &enable_quicksave); |
||
| 218 | process_boolean("enable_quicksave_penalty", &enable_quicksave_penalty); |
||
| 219 | |||
| 220 | #ifdef USE_REPLAY |
||
| 221 | process_boolean("enable_replay", &enable_replay); |
||
| 222 | |||
| 223 | if (strcasecmp(name, "replays_folder") == 0) { |
||
| 224 | if (value[0] != '\0' && strcasecmp(value, "default") != 0) { |
||
| 225 | strcpy(replays_folder, value); |
||
| 226 | } |
||
| 227 | return 1; |
||
| 228 | } |
||
| 229 | #endif |
||
| 230 | #ifdef USE_LIGHTING |
||
| 231 | process_boolean("enable_lighting", &enable_lighting); |
||
| 232 | #endif |
||
| 2 | pmbaty | 233 | process_int("filter_level", &filter_level, NULL); |
| 1 | pmbaty | 234 | } |
| 235 | |||
| 236 | if (check_ini_section("Enhancements")) { |
||
| 237 | if (strcasecmp(name, "use_fixes_and_enhancements") == 0) { |
||
| 238 | if (strcasecmp(value, "true") == 0) use_fixes_and_enhancements = 1; |
||
| 239 | else if (strcasecmp(value, "false") == 0) use_fixes_and_enhancements = 0; |
||
| 240 | else if (strcasecmp(value, "prompt") == 0) use_fixes_and_enhancements = 2; |
||
| 241 | return 1; |
||
| 242 | } |
||
| 243 | process_boolean("enable_crouch_after_climbing", &enable_crouch_after_climbing); |
||
| 244 | process_boolean("enable_freeze_time_during_end_music", &enable_freeze_time_during_end_music); |
||
| 245 | process_boolean("enable_remember_guard_hp", &enable_remember_guard_hp); |
||
| 246 | process_boolean("fix_gate_sounds", &fix_gate_sounds); |
||
| 247 | process_boolean("fix_two_coll_bug", &fix_two_coll_bug); |
||
| 248 | process_boolean("fix_infinite_down_bug", &fix_infinite_down_bug); |
||
| 249 | process_boolean("fix_gate_drawing_bug", &fix_gate_drawing_bug); |
||
| 250 | process_boolean("fix_bigpillar_climb", &fix_bigpillar_climb); |
||
| 251 | process_boolean("fix_jump_distance_at_edge", &fix_jump_distance_at_edge); |
||
| 252 | process_boolean("fix_edge_distance_check_when_climbing", &fix_edge_distance_check_when_climbing); |
||
| 253 | process_boolean("fix_painless_fall_on_guard", &fix_painless_fall_on_guard); |
||
| 254 | process_boolean("fix_wall_bump_triggers_tile_below", &fix_wall_bump_triggers_tile_below); |
||
| 255 | process_boolean("fix_stand_on_thin_air", &fix_stand_on_thin_air); |
||
| 256 | process_boolean("fix_press_through_closed_gates", &fix_press_through_closed_gates); |
||
| 257 | process_boolean("fix_grab_falling_speed", &fix_grab_falling_speed); |
||
| 258 | process_boolean("fix_skeleton_chomper_blood", &fix_skeleton_chomper_blood); |
||
| 259 | process_boolean("fix_move_after_drink", &fix_move_after_drink); |
||
| 260 | process_boolean("fix_loose_left_of_potion", &fix_loose_left_of_potion); |
||
| 261 | process_boolean("fix_guard_following_through_closed_gates", &fix_guard_following_through_closed_gates); |
||
| 262 | process_boolean("fix_safe_landing_on_spikes", &fix_safe_landing_on_spikes); |
||
| 263 | process_boolean("fix_glide_through_wall", &fix_glide_through_wall); |
||
| 264 | process_boolean("fix_drop_through_tapestry", &fix_drop_through_tapestry); |
||
| 265 | process_boolean("fix_land_against_gate_or_tapestry", &fix_land_against_gate_or_tapestry); |
||
| 266 | process_boolean("fix_unintended_sword_strike", &fix_unintended_sword_strike); |
||
| 267 | process_boolean("fix_retreat_without_leaving_room", &fix_retreat_without_leaving_room); |
||
| 268 | process_boolean("fix_running_jump_through_tapestry", &fix_running_jump_through_tapestry); |
||
| 269 | process_boolean("fix_push_guard_into_wall", &fix_push_guard_into_wall); |
||
| 270 | process_boolean("fix_jump_through_wall_above_gate", &fix_jump_through_wall_above_gate); |
||
| 271 | process_boolean("fix_chompers_not_starting", &fix_chompers_not_starting); |
||
| 272 | process_boolean("fix_feather_interrupted_by_leveldoor", &fix_feather_interrupted_by_leveldoor); |
||
| 273 | process_boolean("fix_offscreen_guards_disappearing", &fix_offscreen_guards_disappearing); |
||
| 274 | process_boolean("fix_move_after_sheathe", &fix_move_after_sheathe); |
||
| 275 | } |
||
| 276 | |||
| 277 | if (check_ini_section("CustomGameplay")) { |
||
| 278 | process_word("start_minutes_left", &start_minutes_left, NULL); |
||
| 279 | process_word("start_ticks_left", &start_ticks_left, NULL); |
||
| 280 | process_word("start_hitp", &start_hitp, NULL); |
||
| 281 | process_word("max_hitp_allowed", &max_hitp_allowed, NULL); |
||
| 282 | process_word("saving_allowed_first_level", &saving_allowed_first_level, NULL); |
||
| 283 | process_word("saving_allowed_last_level", &saving_allowed_last_level, NULL); |
||
| 284 | process_boolean("start_upside_down", &start_upside_down); |
||
| 285 | process_boolean("start_in_blind_mode", &start_in_blind_mode); |
||
| 286 | process_word("copyprot_level", ©prot_level, NULL); |
||
| 287 | process_byte("drawn_tile_top_level_edge", &drawn_tile_top_level_edge, &tile_type_names_list); |
||
| 288 | process_byte("drawn_tile_left_level_edge", &drawn_tile_left_level_edge, &tile_type_names_list); |
||
| 289 | process_byte("level_edge_hit_tile", &level_edge_hit_tile, &tile_type_names_list); |
||
| 290 | process_boolean("allow_triggering_any_tile", &allow_triggering_any_tile); |
||
| 291 | // TODO: Maybe allow automatically choosing the correct WDA, depending on the loaded VDUNGEON.DAT? |
||
| 292 | process_boolean("enable_wda_in_palace", &enable_wda_in_palace); |
||
| 293 | |||
| 294 | // Options that change the hard-coded color palette (options 'vga_color_0', 'vga_color_1', ...) |
||
| 295 | static const char prefix[] = "vga_color_"; |
||
| 296 | static const size_t prefix_len = sizeof(prefix)-1; |
||
| 297 | int ini_palette_color = -1; |
||
| 298 | if (strncasecmp(name, prefix, prefix_len) == 0 && sscanf(name+prefix_len, "%d", &ini_palette_color) == 1) { |
||
| 299 | if (!(ini_palette_color >= 0 && ini_palette_color <= 15)) return 0; |
||
| 300 | |||
| 301 | byte rgb[3] = {0}; |
||
| 302 | if (strcasecmp(value, "default") != 0) { |
||
| 303 | // We want to parse an rgb string with three entries like this: "255, 255, 255" |
||
| 304 | char* start = (char*) value; |
||
| 305 | char* end = (char*) value; |
||
| 306 | int i; |
||
| 307 | for (i = 0; i < 3 && *end != '\0'; ++i) { |
||
| 308 | rgb[i] = (byte) strtol(start, &end, 0); // convert this entry into a number 0..255 |
||
| 309 | |||
| 310 | while (*end == ',' || *end == ' ') { |
||
| 311 | ++end; // skip delimiter characters or whitespace |
||
| 312 | } |
||
| 313 | start = end; // start parsing the next entry here |
||
| 314 | } |
||
| 315 | } |
||
| 316 | rgb_type* palette_color = &vga_palette[ini_palette_color]; |
||
| 317 | palette_color->r = rgb[0] / 4; // the palette uses values 0..63, not 0..255 |
||
| 318 | palette_color->g = rgb[1] / 4; |
||
| 319 | palette_color->b = rgb[2] / 4; |
||
| 320 | return 1; |
||
| 321 | } |
||
| 322 | process_word("first_level", &first_level, NULL); |
||
| 323 | process_boolean("skip_title", &skip_title); |
||
| 324 | process_word("shift_L_allowed_until_level", &shift_L_allowed_until_level, NULL); |
||
| 325 | process_word("shift_L_reduced_minutes", &shift_L_reduced_minutes, NULL); |
||
| 326 | process_word("shift_L_reduced_ticks", &shift_L_reduced_ticks, NULL); |
||
| 327 | } // end of section [CustomGameplay] |
||
| 328 | |||
| 329 | // [Level 1], etc. |
||
| 330 | int ini_level = -1; |
||
| 331 | if (strncasecmp(section, "Level ", 6) == 0 && sscanf(section+6, "%d", &ini_level) == 1) { |
||
| 332 | if (ini_level >= 0 && ini_level <= 15) { |
||
| 333 | // TODO: And maybe allow new types in addition to the existing ones. |
||
| 334 | process_byte("level_type", &tbl_level_type[ini_level], &level_type_names_list); |
||
| 335 | process_word("level_color", &tbl_level_color[ini_level], NULL); |
||
| 336 | process_short("guard_type", &tbl_guard_type[ini_level], &guard_type_names_list); |
||
| 337 | process_byte("guard_hp", &tbl_guard_hp[ini_level], NULL); |
||
| 338 | |||
| 339 | byte cutscene_index = 0xFF; |
||
| 340 | if (ini_process_byte(name, value, "cutscene", &cutscene_index, NULL) == 1) { |
||
| 341 | if (cutscene_index < COUNT(tbl_cutscenes_lookup)) { |
||
| 342 | tbl_cutscenes_by_index[ini_level] = cutscene_index; |
||
| 343 | tbl_cutscenes[ini_level] = tbl_cutscenes_lookup[cutscene_index]; |
||
| 344 | } |
||
| 345 | return 1; |
||
| 346 | } |
||
| 347 | } else { |
||
| 348 | // TODO: warning? |
||
| 349 | } |
||
| 350 | } |
||
| 351 | return 0; |
||
| 352 | } |
||
| 353 | |||
| 354 | // Callback for a mod-specific INI configuration (that may overrule SDLPoP.ini for SOME but not all options): |
||
| 355 | static int mod_ini_callback(const char *section, const char *name, const char *value) { |
||
| 356 | if (check_ini_section("Enhancements") || check_ini_section("CustomGameplay") || |
||
| 357 | strncasecmp(section, "Level ", 6) == 0 || |
||
| 358 | strcasecmp(name, "enable_copyprot") == 0 || |
||
| 359 | strcasecmp(name, "enable_quicksave") == 0 || |
||
| 360 | strcasecmp(name, "enable_quicksave_penalty") == 0 |
||
| 361 | ) { |
||
| 362 | global_ini_callback(section, name, value); |
||
| 363 | } |
||
| 364 | return 0; |
||
| 365 | } |
||
| 366 | |||
| 367 | void load_global_options() { |
||
| 368 | ini_load(locate_file("game.ini"), global_ini_callback); // global configuration |
||
| 369 | } |
||
| 370 | |||
| 371 | void check_mod_param() { |
||
| 372 | // The 'mod' command line argument can override the levelset choice in SDLPoP.ini |
||
| 373 | // usage: prince mod "Mod Name" |
||
| 374 | const char* mod_param = check_param("mod"); |
||
| 375 | if (mod_param != NULL) { |
||
| 376 | use_custom_levelset = true; |
||
| 377 | memset(levelset_name, 0, sizeof(levelset_name)); |
||
| 378 | strncpy(levelset_name, mod_param, sizeof(levelset_name)); |
||
| 379 | } |
||
| 380 | } |
||
| 381 | |||
| 382 | void load_mod_options() { |
||
| 383 | // load mod-specific INI configuration |
||
| 384 | if (use_custom_levelset) { |
||
| 385 | char filename[POP_MAX_PATH]; |
||
| 386 | snprintf(filename, sizeof(filename), "mods/%s/%s", levelset_name, "mod.ini"); |
||
| 387 | ini_load(filename, mod_ini_callback); |
||
| 388 | } |
||
| 389 | |||
| 390 | if (!use_fixes_and_enhancements) disable_fixes_and_enhancements(); |
||
| 391 | } |
||
| 392 | |||
| 393 | void show_use_fixes_and_enhancements_prompt() { |
||
| 394 | if (use_fixes_and_enhancements != 2) return; |
||
| 395 | draw_rect(&screen_rect, 0); |
||
| 396 | show_text(&screen_rect, 0, 0, |
||
| 397 | "\n" |
||
| 398 | "Enable bug fixes and\n" |
||
| 399 | "gameplay enhancements?\n" |
||
| 400 | "\n" |
||
| 401 | "NOTE:\n" |
||
| 402 | "This option disables some game quirks.\n" |
||
| 403 | "Certain tricks will no longer work by default.\n" |
||
| 404 | "\n" |
||
| 405 | "\n" |
||
| 406 | "Y: enhanced behavior \n" |
||
| 407 | "N: original behavior \n" |
||
| 408 | "\n" |
||
| 409 | "Y / N ?\n" |
||
| 410 | "\n" |
||
| 411 | "\n" |
||
| 412 | "\n" |
||
| 413 | "You can fine-tune your preferences\n" |
||
| 414 | "and/or bypass this screen by editing the file\n" |
||
| 415 | "'SDLPoP.ini'" |
||
| 416 | ); |
||
| 417 | while (use_fixes_and_enhancements == 2 ) { |
||
| 418 | idle(); |
||
| 419 | switch (key_test_quit()) { |
||
| 420 | case SDL_SCANCODE_Y: |
||
| 421 | use_fixes_and_enhancements = 1; |
||
| 422 | printf("Enabling game fixes and enhancements.\n"); |
||
| 423 | break; |
||
| 424 | case SDL_SCANCODE_N: |
||
| 425 | use_fixes_and_enhancements = 0; |
||
| 426 | printf("Disabling game fixes and enhancements.\n"); |
||
| 427 | break; |
||
| 428 | } |
||
| 429 | } |
||
| 430 | if (!use_fixes_and_enhancements) disable_fixes_and_enhancements(); |
||
| 431 | } |
||
| 432 | |||
| 433 |