// initialization stuff for cutscenes void cutscene_init() { atexit(cutscene_close); char buf[MULTITEXT_LENGTH]; int rval; cutscene_info cutinfo; if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "cutscenes.tbl", rval)); return; } read_file_text("cutscenes.tbl", CF_TYPE_TABLES); reset_parse(); // parse in all the cutscenes Cutscenes.clear(); skip_to_string("#Cutscenes"); ignore_white_space(); bool isFirstCutscene = true; while ( required_string_either("#End", "$Filename:") ) { required_string("$Filename:"); stuff_string( cutinfo.filename, F_PATHNAME, MAX_FILENAME_LEN ); required_string("$Name:"); stuff_string( cutinfo.name, F_NAME, NAME_LENGTH ); required_string("$Description:"); stuff_string(buf, F_MULTITEXT, sizeof(buf)); drop_white_space(buf); compact_multitext_string(buf); cutinfo.description = vm_strdup(buf); if (optional_string("$cd:")) stuff_int( &cutinfo.cd ); else cutinfo.cd = 0; cutinfo.viewable = false; if (isFirstCutscene) { isFirstCutscene = false; // The original code assumes the first movie is the intro, so always viewable cutinfo.viewable = true; } if (optional_string("$Always Viewable:")) { stuff_boolean(&cutinfo.viewable); } Cutscenes.push_back(cutinfo); } required_string("#End"); }
// utility void set_flag(ai_profile_t *profile, const char *name, AI::Profile_Flags flag) { if (optional_string(name)) { bool val; stuff_boolean(&val); profile->flags.set(flag, val); } }
// utility void set_flag(ai_profile_t *profile, char *name, int flag, int type) { if (optional_string(name)) { bool val; stuff_boolean(&val); if (type == AIP_FLAG) { if (val) profile->flags |= flag; else profile->flags &= ~flag; } else { if (val) profile->flags2 |= flag; else profile->flags2 &= ~flag; } } }
void parse_medal_tbl() { int i; try { read_file_text("medals.tbl", CF_TYPE_TABLES); reset_parse(); required_string("#Medals"); // special background information if (optional_string("+Background Bitmap:")) { stuff_string(Medals_background_filename, F_NAME, NAME_LENGTH); } else { strcpy_s(Medals_background_filename, Default_medals_background_filename); } // special mask information if (optional_string("+Mask Bitmap:")) { stuff_string(Medals_mask_filename, F_NAME, NAME_LENGTH); } else { strcpy_s(Medals_mask_filename, Default_medals_mask_filename); } // configurable hotspot for the exit button if (optional_string("+Exit Button Hotspot Index:")) { stuff_int(&Exit_button_hotspot_override); } // special positioning for player callsign if (optional_string("+Callsign Position 640:")) { stuff_int(&Medals_callsign_coords[GR_640].x); stuff_int(&Medals_callsign_coords[GR_640].y); } else { Medals_callsign_coords[GR_640].x = Default_medals_callsign_coords[GR_640][0]; Medals_callsign_coords[GR_640].y = Default_medals_callsign_coords[GR_640][1]; } if (optional_string("+Callsign Position 1024:")) { stuff_int(&Medals_callsign_coords[GR_1024].x); stuff_int(&Medals_callsign_coords[GR_1024].y); } else { Medals_callsign_coords[GR_1024].x = Default_medals_callsign_coords[GR_1024][0]; Medals_callsign_coords[GR_1024].y = Default_medals_callsign_coords[GR_1024][1]; } // special positioning for medal label if (optional_string("+Label Position 640:")) { stuff_int(&Medals_label_coords[GR_640].x); stuff_int(&Medals_label_coords[GR_640].y); stuff_int(&Medals_label_coords[GR_640].w); } else { Medals_label_coords[GR_640].x = Default_medals_label_coords[GR_640][0]; Medals_label_coords[GR_640].y = Default_medals_label_coords[GR_640][1]; Medals_label_coords[GR_640].w = Default_medals_label_coords[GR_640][2]; } if (optional_string("+Label Position 1024:")) { stuff_int(&Medals_label_coords[GR_1024].x); stuff_int(&Medals_label_coords[GR_1024].y); stuff_int(&Medals_label_coords[GR_1024].w); } else { Medals_label_coords[GR_1024].x = Default_medals_label_coords[GR_1024][0]; Medals_label_coords[GR_1024].y = Default_medals_label_coords[GR_1024][1]; Medals_label_coords[GR_1024].w = Default_medals_label_coords[GR_1024][2]; } // parse in all the medal names Num_medals = 0; while (required_string_either("#End", "$Name:")) { medal_stuff temp_medal; medal_display_info temp_display; required_string("$Name:"); stuff_string(temp_medal.name, F_NAME, NAME_LENGTH); // is this rank? if so, save it if (!stricmp(temp_medal.name, "Rank")) Rank_medal_index = Num_medals; required_string("$Bitmap:"); stuff_string(temp_medal.bitmap, F_NAME, MAX_FILENAME_LEN); if (optional_string("+Position 640:")) { stuff_int(&temp_display.coords[GR_640].x); stuff_int(&temp_display.coords[GR_640].y); } else if (Num_medals < NUM_MEDALS_FS2) { temp_display.coords[GR_640].x = Default_medal_coords[GR_640][Num_medals][0]; temp_display.coords[GR_640].y = Default_medal_coords[GR_640][Num_medals][1]; } else { Warning(LOCATION, "No default GR_640 position for medal '%s'!", temp_medal.name); temp_display.coords[GR_640].x = 0; temp_display.coords[GR_640].y = 0; } if (optional_string("+Position 1024:")) { stuff_int(&temp_display.coords[GR_1024].x); stuff_int(&temp_display.coords[GR_1024].y); } else if (Num_medals < NUM_MEDALS_FS2) { temp_display.coords[GR_1024].x = Default_medal_coords[GR_1024][Num_medals][0]; temp_display.coords[GR_1024].y = Default_medal_coords[GR_1024][Num_medals][1]; } else { Warning(LOCATION, "No default GR_1024 position for medal '%s'!", temp_medal.name); temp_display.coords[GR_1024].x = 0; temp_display.coords[GR_1024].y = 0; } if (optional_string("+Debriefing Bitmap:")) { stuff_string(temp_medal.debrief_bitmap, F_NAME, MAX_FILENAME_LEN); } else if (Num_medals < NUM_MEDALS_FS2) { strcpy_s(temp_medal.debrief_bitmap, Default_debriefing_bitmaps[Num_medals]); } else { Warning(LOCATION, "No default debriefing bitmap for medal '%s'!", temp_medal.name); strcpy_s(temp_medal.debrief_bitmap, ""); } required_string("$Num mods:"); stuff_int(&temp_medal.num_versions); // this is dumb temp_medal.version_starts_at_1 = (Num_medals == Rank_medal_index); if (optional_string("+Version starts at 1:")) { stuff_boolean(&temp_medal.version_starts_at_1); } if (optional_string("+Available From Start:")) { stuff_boolean(&temp_medal.available_from_start); } // some medals are based on kill counts. When string +Num Kills: is present, we know that // this medal is a badge and should be treated specially if (optional_string("+Num Kills:")) { char buf[MULTITEXT_LENGTH]; int persona; stuff_int(&temp_medal.kills_needed); if (optional_string("$Wavefile 1:")) stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN); if (optional_string("$Wavefile 2:")) stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN); if (optional_string("$Wavefile Base:")) stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN); while (check_for_string("$Promotion Text:")) { required_string("$Promotion Text:"); stuff_string(buf, F_MULTITEXT, sizeof(buf)); persona = -1; if (optional_string("+Persona:")) { stuff_int(&persona); if (persona < 0) { Warning(LOCATION, "Debriefing text for %s is assigned to an invalid persona: %i (must be 0 or greater).\n", temp_medal.name, persona); continue; } } temp_medal.promotion_text[persona] = SCP_string(buf); } if (temp_medal.promotion_text.find(-1) == temp_medal.promotion_text.end()) { Warning(LOCATION, "%s medal is missing default debriefing text.\n", temp_medal.name); temp_medal.promotion_text[-1] = ""; } } Medals.push_back(temp_medal); Medal_display_info.push_back(temp_display); Num_medals++; } required_string("#End"); // be sure that we know where the rank is if (Rank_medal_index < 0) { Warning(LOCATION, "Could not find the 'Rank' medal!"); Rank_medal_index = 0; } // be sure that the badges kill numbers show up in order //WMC - I don't think this is needed anymore due to my changes to post-mission functions //but I'm keeping it here to be sure. int prev_badge_kills = 0; for (i = 0; i < Num_medals; i++) { if (Medals[i].kills_needed < prev_badge_kills && Medals[i].kills_needed != 0) Error(LOCATION, "Badges must appear sorted by lowest kill # first in medals.tbl\nFind Allender for most information."); if (Medals[i].kills_needed > 0) prev_badge_kills = Medals[i].kills_needed; } } catch (const parse::ParseException& e) { mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "medals.tbl", e.what())); return; } }
/** * @brief Parses controlconfigdefault.tbl, and overrides the default control configuration for each valid entry in the .tbl */ void control_config_common_load_overrides() { LoadEnumsIntoMaps(); try { if (cf_exists_full("controlconfigdefaults.tbl", CF_TYPE_TABLES)) { read_file_text("controlconfigdefaults.tbl", CF_TYPE_TABLES); } else { read_file_text_from_default(defaults_get_file("controlconfigdefaults.tbl")); } reset_parse(); // start parsing // TODO: Split this out into more helps. Too many tabs! while(optional_string("#ControlConfigOverride")) { config_item *cfg_preset = new config_item[CCFG_MAX + 1]; std::copy(Control_config, Control_config + CCFG_MAX + 1, cfg_preset); Control_config_presets.push_back(cfg_preset); SCP_string preset_name; if (optional_string("$Name:")) { stuff_string_line(preset_name); } else { preset_name = "<unnamed preset>"; } Control_config_preset_names.push_back(preset_name); while (required_string_either("#End","$Bind Name:")) { const int iBufferLength = 64; char szTempBuffer[iBufferLength]; required_string("$Bind Name:"); stuff_string(szTempBuffer, F_NAME, iBufferLength); const size_t cCntrlAryLength = sizeof(Control_config) / sizeof(Control_config[0]); for (size_t i = 0; i < cCntrlAryLength; ++i) { config_item& r_ccConfig = cfg_preset[i]; if (!strcmp(szTempBuffer, r_ccConfig.text)) { /** * short key_default; * short joy_default; * char tab; * bool hasXSTR; * char type; */ int iTemp; if (optional_string("$Key Default:")) { if (optional_string("NONE")) { r_ccConfig.key_default = (short)-1; } else { stuff_string(szTempBuffer, F_NAME, iBufferLength); r_ccConfig.key_default = (short)mKeyNameToVal[szTempBuffer]; } } if (optional_string("$Joy Default:")) { stuff_int(&iTemp); r_ccConfig.joy_default = (short)iTemp; } if (optional_string("$Key Mod Shift:")) { stuff_int(&iTemp); r_ccConfig.key_default |= (iTemp == 1) ? KEY_SHIFTED : 0; } if (optional_string("$Key Mod Alt:")) { stuff_int(&iTemp); r_ccConfig.key_default |= (iTemp == 1) ? KEY_ALTED : 0; } if (optional_string("$Key Mod Ctrl:")) { stuff_int(&iTemp); r_ccConfig.key_default |= (iTemp == 1) ? KEY_CTRLED : 0; } if (optional_string("$Category:")) { stuff_string(szTempBuffer, F_NAME, iBufferLength); r_ccConfig.tab = (char)mCCTabNameToVal[szTempBuffer]; } if (optional_string("$Has XStr:")) { stuff_int(&iTemp); r_ccConfig.hasXSTR = (iTemp == 1); } if (optional_string("$Type:")) { stuff_string(szTempBuffer, F_NAME, iBufferLength); r_ccConfig.type = (char)mCCTypeNameToVal[szTempBuffer]; } if (optional_string("+Disable")) { r_ccConfig.disabled = true; } if (optional_string("$Disable:")) { stuff_boolean(&r_ccConfig.disabled); } // Nerf the buffer now. szTempBuffer[0] = '\0'; } else if ((i + 1) == cCntrlAryLength) { error_display(1, "Bind Name not found: %s\n", szTempBuffer); advance_to_eoln(NULL); ignore_white_space(); return; } } } required_string("#End"); } } catch (const parse::ParseException& e) { mprintf(("TABLES: Unable to parse 'controlconfigdefaults.tbl'! Error message = %s.\n", e.what())); return; } // Overwrite the control config with the first preset that was found if (!Control_config_presets.empty()) { std::copy(Control_config_presets[0], Control_config_presets[0] + CCFG_MAX + 1, Control_config); } }
void parse_ai_profiles_tbl(const char *filename) { int i; char profile_name[NAME_LENGTH]; ai_profile_t dummy_profile; char *saved_Mp = NULL; char buf[NAME_LENGTH]; try { if (filename == NULL) read_file_text_from_default(defaults_get_file("ai_profiles.tbl")); else read_file_text(filename, CF_TYPE_TABLES); reset_parse(); // start parsing required_string("#AI Profiles"); // new default? if (optional_string("$Default Profile:")) stuff_string(Default_profile_name, F_NAME, NAME_LENGTH); // begin reading data while (required_string_either("#End", "$Profile Name:")) { ai_profile_t *profile = &dummy_profile; ai_profile_t *previous_profile = NULL; bool no_create = false; // get the name required_string("$Profile Name:"); stuff_string(profile_name, F_NAME, NAME_LENGTH); // see if it exists for (i = 0; i < Num_ai_profiles; i++) { if (!stricmp(Ai_profiles[i].profile_name, profile_name)) { previous_profile = &Ai_profiles[i]; break; } } // modular table stuff if (optional_string("+nocreate")) { no_create = true; // use the previous one if possible, // otherwise continue to use the dummy one if (previous_profile != NULL) profile = previous_profile; } else { // don't create multiple profiles with the same name if (previous_profile != NULL) { Warning(LOCATION, "An ai profile named '%s' already exists! The new one will not be created.\n", profile_name); } else { // make sure we're under the limit if (Num_ai_profiles >= MAX_AI_PROFILES) { Warning(LOCATION, "Too many profiles in ai_profiles.tbl! Max is %d.\n", MAX_AI_PROFILES - 1); // -1 because one is built-in skip_to_string("#End", NULL); break; } profile = &Ai_profiles[Num_ai_profiles]; Num_ai_profiles++; } } // initialize profile if we're not building from a previously parsed one if (!no_create) { // base profile, so zero it out if (profile == &Ai_profiles[0]) { profile->reset(); } // brand new profile, so set it to the base defaults else { *profile = Ai_profiles[0]; } } // set the name strcpy_s(profile->profile_name, profile_name); // fill in any and all settings; they're all optional and can be in any order while (!check_for_string("$Profile Name:") && !check_for_string("#End")) { if (optional_string("$Player Afterburner Recharge Scale:")) parse_float_list(profile->afterburner_recharge_scale, NUM_SKILL_LEVELS); if (optional_string("$Max Beam Friendly Fire Damage:")) parse_float_list(profile->beam_friendly_damage_cap, NUM_SKILL_LEVELS); if (optional_string("$Player Countermeasure Life Scale:")) parse_float_list(profile->cmeasure_life_scale, NUM_SKILL_LEVELS); if (optional_string("$AI Countermeasure Firing Chance:")) parse_float_list(profile->cmeasure_fire_chance, NUM_SKILL_LEVELS); if (optional_string("$AI In Range Time:")) parse_float_list(profile->in_range_time, NUM_SKILL_LEVELS); if (optional_string("$AI Always Links Ammo Weapons:")) parse_float_list(profile->link_ammo_levels_always, NUM_SKILL_LEVELS); if (optional_string("$AI Maybe Links Ammo Weapons:")) parse_float_list(profile->link_ammo_levels_maybe, NUM_SKILL_LEVELS); if (optional_string("$Primary Ammo Burst Multiplier:")) parse_float_list(profile->primary_ammo_burst_mult, NUM_SKILL_LEVELS); if (optional_string("$AI Always Links Energy Weapons:")) parse_float_list(profile->link_energy_levels_always, NUM_SKILL_LEVELS); if (optional_string("$AI Maybe Links Energy Weapons:")) parse_float_list(profile->link_energy_levels_maybe, NUM_SKILL_LEVELS); if (optional_string("$Max Missles Locked on Player:") || optional_string("$Max Missiles Locked on Player:")) parse_int_list(profile->max_allowed_player_homers, NUM_SKILL_LEVELS); if (optional_string("$Max Player Attackers:")) parse_int_list(profile->max_attackers, NUM_SKILL_LEVELS); if (optional_string("$Max Incoming Asteroids:")) parse_int_list(profile->max_incoming_asteroids, NUM_SKILL_LEVELS); if (optional_string("$Player Damage Factor:") || optional_string("$AI Damage Reduction to Player Hull:")) parse_float_list(profile->player_damage_scale, NUM_SKILL_LEVELS); if (optional_string("$Player Subsys Damage Factor:") || optional_string("$AI Damage Reduction to Player Subsys:")) parse_float_list(profile->subsys_damage_scale, NUM_SKILL_LEVELS); // represented in fractions of F1_0 if (optional_string("$Predict Position Delay:")) { int iLoop; float temp_list[NUM_SKILL_LEVELS]; parse_float_list(temp_list, NUM_SKILL_LEVELS); for (iLoop = 0; iLoop < NUM_SKILL_LEVELS; iLoop++) profile->predict_position_delay[iLoop] = fl2f(temp_list[iLoop]); } if (optional_string("$AI Shield Manage Delay:") || optional_string("$AI Shield Manage Delays:")) parse_float_list(profile->shield_manage_delay, NUM_SKILL_LEVELS); if (optional_string("$Friendly AI Fire Delay Scale:")) parse_float_list(profile->ship_fire_delay_scale_friendly, NUM_SKILL_LEVELS); if (optional_string("$Hostile AI Fire Delay Scale:")) parse_float_list(profile->ship_fire_delay_scale_hostile, NUM_SKILL_LEVELS); if (optional_string("$Friendly AI Secondary Fire Delay Scale:")) parse_float_list(profile->ship_fire_secondary_delay_scale_friendly, NUM_SKILL_LEVELS); if (optional_string("$Hostile AI Secondary Fire Delay Scale:")) parse_float_list(profile->ship_fire_secondary_delay_scale_hostile, NUM_SKILL_LEVELS); if (optional_string("$AI Turn Time Scale:")) parse_float_list(profile->turn_time_scale, NUM_SKILL_LEVELS); if (optional_string("$Glide Attack Percent:")) { parse_float_list(profile->glide_attack_percent, NUM_SKILL_LEVELS); //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0 //While we're at it, verify the range for (i = 0; i < NUM_SKILL_LEVELS; i++) { if (profile->glide_attack_percent[i] < 0.0f || profile->glide_attack_percent[i] > 100.0f) { Warning(LOCATION, "$Glide Attack Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->glide_attack_percent[i]); profile->glide_attack_percent[i] = 0.0f; } profile->glide_attack_percent[i] /= 100.0; } } if (optional_string("$Circle Strafe Percent:")) { parse_float_list(profile->circle_strafe_percent, NUM_SKILL_LEVELS); //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0 //While we're at it, verify the range for (i = 0; i < NUM_SKILL_LEVELS; i++) { if (profile->circle_strafe_percent[i] < 0.0f || profile->circle_strafe_percent[i] > 100.0f) { Warning(LOCATION, "$Circle Strafe Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->circle_strafe_percent[i]); profile->circle_strafe_percent[i] = 0.0f; } profile->circle_strafe_percent[i] /= 100.0; } } if (optional_string("$Glide Strafe Percent:")) { parse_float_list(profile->glide_strafe_percent, NUM_SKILL_LEVELS); //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0 //While we're at it, verify the range for (i = 0; i < NUM_SKILL_LEVELS; i++) { if (profile->glide_strafe_percent[i] < 0.0f || profile->glide_strafe_percent[i] > 100.0f) { Warning(LOCATION, "$Glide Strafe Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->glide_strafe_percent[i]); profile->glide_strafe_percent[i] = 0.0f; } profile->glide_strafe_percent[i] /= 100.0; } } if (optional_string("$Random Sidethrust Percent:")) { parse_float_list(profile->random_sidethrust_percent, NUM_SKILL_LEVELS); //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0 //While we're at it, verify the range for (i = 0; i < NUM_SKILL_LEVELS; i++) { if (profile->random_sidethrust_percent[i] < 0.0f || profile->random_sidethrust_percent[i] > 100.0f) { Warning(LOCATION, "$Random Sidethrust Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->random_sidethrust_percent[i]); profile->random_sidethrust_percent[i] = 0.0f; } profile->random_sidethrust_percent[i] /= 100.0; } } if (optional_string("$Stalemate Time Threshold:")) parse_float_list(profile->stalemate_time_thresh, NUM_SKILL_LEVELS); if (optional_string("$Stalemate Distance Threshold:")) parse_float_list(profile->stalemate_dist_thresh, NUM_SKILL_LEVELS); if (optional_string("$Player Shield Recharge Scale:")) parse_float_list(profile->shield_energy_scale, NUM_SKILL_LEVELS); if (optional_string("$Player Weapon Recharge Scale:")) parse_float_list(profile->weapon_energy_scale, NUM_SKILL_LEVELS); if (optional_string("$Max Turret Target Ownage:")) parse_int_list(profile->max_turret_ownage_target, NUM_SKILL_LEVELS); if (optional_string("$Max Turret Player Ownage:")) parse_int_list(profile->max_turret_ownage_player, NUM_SKILL_LEVELS); if (optional_string("$Percentage Required For Kill Scale:")) parse_float_list(profile->kill_percentage_scale, NUM_SKILL_LEVELS); if (optional_string("$Percentage Required For Assist Scale:")) parse_float_list(profile->assist_percentage_scale, NUM_SKILL_LEVELS); if (optional_string("$Percentage Awarded For Capship Assist:")) parse_float_list(profile->assist_award_percentage_scale, NUM_SKILL_LEVELS); if (optional_string("$Repair Penalty:")) parse_int_list(profile->repair_penalty, NUM_SKILL_LEVELS); if (optional_string("$Delay Before Allowing Bombs to Be Shot Down:")) parse_float_list(profile->delay_bomb_arm_timer, NUM_SKILL_LEVELS); if (optional_string("$Chance AI Has to Fire Missiles at Player:")) parse_int_list(profile->chance_to_use_missiles_on_plr, NUM_SKILL_LEVELS); if (optional_string("$Max Aim Update Delay:")) parse_float_list(profile->max_aim_update_delay, NUM_SKILL_LEVELS); if (optional_string("$Turret Max Aim Update Delay:")) parse_float_list(profile->turret_max_aim_update_delay, NUM_SKILL_LEVELS); if (optional_string("$Player Autoaim FOV:")) { float fov_list[NUM_SKILL_LEVELS]; parse_float_list(fov_list, NUM_SKILL_LEVELS); for (i = 0; i < NUM_SKILL_LEVELS; i++) { //Enforce range if (fov_list[i] < 0.0f || fov_list[i] >= 360.0f) { Warning(LOCATION, "$Player Autoaim FOV should be >= 0 and < 360.0 (read %f). Setting to 0.", fov_list[i]); fov_list[i] = 0.0f; } //Convert units profile->player_autoaim_fov[i] = fov_list[i] * PI / 180.0f; } } if (optional_string("$Detail Distance Multiplier:")) parse_float_list(profile->detail_distance_mult, MAX_DETAIL_LEVEL + 1); set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AI::Profile_Flags::Big_ships_can_attack_beam_turrets_on_untargeted_ships); set_flag(profile, "$smart primary weapon selection:", AI::Profile_Flags::Smart_primary_weapon_selection); set_flag(profile, "$smart secondary weapon selection:", AI::Profile_Flags::Smart_secondary_weapon_selection); set_flag(profile, "$smart shield management:", AI::Profile_Flags::Smart_shield_management); set_flag(profile, "$smart afterburner management:", AI::Profile_Flags::Smart_afterburner_management); set_flag(profile, "$free afterburner use:", AI::Profile_Flags::Free_afterburner_use); set_flag(profile, "$allow rapid secondary dumbfire:", AI::Profile_Flags::Allow_rapid_secondary_dumbfire); set_flag(profile, "$huge turret weapons ignore bombs:", AI::Profile_Flags::Huge_turret_weapons_ignore_bombs); set_flag(profile, "$don't insert random turret fire delay:", AI::Profile_Flags::Dont_insert_random_turret_fire_delay); set_flag(profile, "$hack improve non-homing swarm turret fire accuracy:", AI::Profile_Flags::Hack_improve_non_homing_swarm_turret_fire_accuracy); set_flag(profile, "$shockwaves damage small ship subsystems:", AI::Profile_Flags::Shockwaves_damage_small_ship_subsystems); set_flag(profile, "$navigation subsystem governs warpout capability:", AI::Profile_Flags::Navigation_subsys_governs_warp); set_flag(profile, "$ignore lower bound for minimum speed of docked ship:", AI::Profile_Flags::No_min_dock_speed_cap); set_flag(profile, "$disable linked fire penalty:", AI::Profile_Flags::Disable_linked_fire_penalty); set_flag(profile, "$disable weapon damage scaling:", AI::Profile_Flags::Disable_weapon_damage_scaling); set_flag(profile, "$use additive weapon velocity:", AI::Profile_Flags::Use_additive_weapon_velocity); set_flag(profile, "$use newtonian dampening:", AI::Profile_Flags::Use_newtonian_dampening); set_flag(profile, "$include beams for kills and assists:", AI::Profile_Flags::Include_beams_in_stat_calcs); set_flag(profile, "$score kills based on damage caused:", AI::Profile_Flags::Kill_scoring_scales_with_damage); set_flag(profile, "$score assists based on damage caused:", AI::Profile_Flags::Assist_scoring_scales_with_damage); set_flag(profile, "$allow event and goal scoring in multiplayer:", AI::Profile_Flags::Allow_multi_event_scoring); set_flag(profile, "$fix linked primary weapon decision bug:", AI::Profile_Flags::Fix_linked_primary_bug); set_flag(profile, "$prevent turrets targeting too distant bombs:", AI::Profile_Flags::Prevent_targeting_bombs_beyond_range); set_flag(profile, "$smart subsystem targeting for turrets:", AI::Profile_Flags::Smart_subsystem_targeting_for_turrets); set_flag(profile, "$fix heat seekers homing on stealth ships bug:", AI::Profile_Flags::Fix_heat_seeker_stealth_bug); set_flag(profile, "$multi allow empty primaries:", AI::Profile_Flags::Multi_allow_empty_primaries); set_flag(profile, "$multi allow empty secondaries:", AI::Profile_Flags::Multi_allow_empty_secondaries); set_flag(profile, "$allow turrets target weapons freely:", AI::Profile_Flags::Allow_turrets_target_weapons_freely); set_flag(profile, "$use only single fov for turrets:", AI::Profile_Flags::Use_only_single_fov_for_turrets); set_flag(profile, "$allow vertical dodge:", AI::Profile_Flags::Allow_vertical_dodge); set_flag(profile, "$force beam turrets to use normal fov:", AI::Profile_Flags::Force_beam_turret_fov); set_flag(profile, "$fix ai class bug:", AI::Profile_Flags::Fix_ai_class_bug); set_flag(profile, "$turrets ignore targets radius in range checks:", AI::Profile_Flags::Turrets_ignore_target_radius); set_flag(profile, "$no extra collision avoidance vs player:", AI::Profile_Flags::No_special_player_avoid); set_flag(profile, "$perform fewer checks for death screams:", AI::Profile_Flags::Perform_fewer_scream_checks); set_flag(profile, "$advanced turret fov edge checks:", AI::Profile_Flags::Advanced_turret_fov_edge_checks); set_flag(profile, "$require turrets to have target in fov:", AI::Profile_Flags::Require_turret_to_have_target_in_fov); set_flag(profile, "$all ships manage shields:", AI::Profile_Flags::All_ships_manage_shields); set_flag(profile, "$ai aims from ship center:", AI::Profile_Flags::Ai_aims_from_ship_center); set_flag(profile, "$allow primary link at mission start:", AI::Profile_Flags::Allow_primary_link_at_start); set_flag(profile, "$allow beams to damage bombs:", AI::Profile_Flags::Beams_damage_weapons); set_flag(profile, "$disable weapon damage scaling for player:", AI::Profile_Flags::Player_weapon_scale_fix); set_flag(profile, "$countermeasures affect aspect seekers:", AI::Profile_Flags::Aspect_lock_countermeasure); set_flag(profile, "$ai guards specific ship in wing:", AI::Profile_Flags::Ai_guards_specific_ship_in_wing); profile->ai_path_mode = AI_PATH_MODE_NORMAL; if (optional_string("$ai path mode:")) { stuff_string(buf, F_NAME, NAME_LENGTH); int j = ai_path_type_match(buf); if (j >= 0) { profile->ai_path_mode = j; } else { Warning(LOCATION, "Invalid ai path mode '%s' specified", buf); } } set_flag(profile, "$no warp camera:", AI::Profile_Flags::No_warp_camera); set_flag(profile, "$fix ai path order bug:", AI::Profile_Flags::Fix_ai_path_order_bug); set_flag(profile, "$strict turret-tagged-only targeting:", AI::Profile_Flags::Strict_turred_tagged_only_targeting); set_flag(profile, "$aspect bomb invulnerability fix:", AI::Profile_Flags::Aspect_invulnerability_fix); set_flag(profile, "$glide decay requires thrust:", AI::Profile_Flags::Glide_decay_requires_thrust); set_flag(profile, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships); set_flag(profile, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range); profile->bay_arrive_speed_mult = 1.0f; profile->bay_depart_speed_mult = 1.0f; if (optional_string("$bay arrive speed multiplier:")) { stuff_float(&profile->bay_arrive_speed_mult); } if (optional_string("$bay depart speed multiplier:")) { stuff_float(&profile->bay_depart_speed_mult); } // ---------- // compatibility if (optional_string("$perform less checks for death screams:")) { mprintf(("Warning: \"$perform less checks for death screams\" flag is deprecated in favor of \"$perform fewer checks for death screams\"\n")); bool temp; stuff_boolean(&temp); profile->flags.set(AI::Profile_Flags::Perform_fewer_scream_checks, temp); } if (optional_string("$allow primary link delay:")) { mprintf(("Warning: \"$allow primary link delay\" flag is deprecated in favor of \"$allow primary link at mission start\"\n")); bool temp; stuff_boolean(&temp); profile->flags.set(AI::Profile_Flags::Allow_primary_link_at_start, !temp); } // if we've been through once already and are at the same place, force a move if (saved_Mp && (saved_Mp == Mp)) { char tmp[60]; memset(tmp, 0, 60); strncpy(tmp, Mp, 59); mprintf(("WARNING: Unrecognized parameter in ai_profiles: %s\n", tmp)); Mp++; } // find next valid option if (!skip_to_start_of_string_either("$", "#")) break; saved_Mp = Mp; } } required_string("#End"); } catch (const parse::ParseException& e) { mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", (filename) ? filename : "<default ai_profiles.tbl>", e.what())); return; } // add tbl/tbm to multiplayer validation list extern void fs2netd_add_table_validation(const char *tblname); fs2netd_add_table_validation(filename); }
void parse_mod_table(const char *filename) { int rval; // SCP_vector<SCP_string> lines; // open localization lcl_ext_open(); if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", (filename) ? filename : "<default game_settings.tbl>", rval)); lcl_ext_close(); return; } if (filename == NULL) read_file_text_from_array(defaults_get_file("game_settings.tbl")); else read_file_text(filename, CF_TYPE_TABLES); reset_parse(); // start parsing optional_string("#CAMPAIGN SETTINGS"); if (optional_string("$Default Campaign File Name:")) { char temp[MAX_FILENAME_LEN]; stuff_string(temp, F_NAME, MAX_FILENAME_LEN); // remove extension? if (drop_extension(temp)) { mprintf(("Game Settings Table: Removed extension on default campaign file name %s\n", temp)); } // check length int maxlen = (MAX_FILENAME_LEN - 4); int len = strlen(temp); if (len > maxlen) { Warning(LOCATION, "Token too long: [%s]. Length = %i. Max is %i.\n", temp, len, maxlen); temp[maxlen] = 0; } strcpy_s(Default_campaign_file_name, temp); } if (optional_string("#Ignored Campaign File Names")) { SCP_string campaign_name; while (optional_string("$Campaign File Name:")) { stuff_string(campaign_name, F_NAME); // remove extension? if (drop_extension(campaign_name)) { mprintf(("Game Settings Table: Removed extension on ignored campaign file name %s\n", campaign_name.c_str())); } Ignored_campaigns.push_back(campaign_name); } } optional_string("#HUD SETTINGS"); // how long should the game wait before displaying a directive? if (optional_string("$Directive Wait Time:")) { stuff_int(&Directive_wait_time); } if (optional_string("$Cutscene camera displays HUD:")) { stuff_boolean(&Cutscene_camera_displays_hud); } // compatibility if (optional_string("$Cutscene camera disables HUD:")) { mprintf(("Game Settings Table: \"$$Cutscene camera disables HUD\" is deprecated in favor of \"$Cutscene camera displays HUD\"\n")); bool temp; stuff_boolean(&temp); Cutscene_camera_displays_hud = !temp; } if (optional_string("$Full color head animations:")) { stuff_boolean(&Full_color_head_anis); } // compatibility if (optional_string("$Color head animations with hud colors:")) { mprintf(("Game Settings Table: \"$Color head animations with hud colors\" is deprecated in favor of \"$Full color head animations\"\n")); bool temp; stuff_boolean(&temp); Full_color_head_anis = !temp; } optional_string("#SEXP SETTINGS"); if (optional_string("$Loop SEXPs Then Arguments:")) { stuff_boolean(&True_loop_argument_sexps); if (True_loop_argument_sexps) { mprintf(("Game Settings Table: Using Reversed Loops For SEXP Arguments\n")); } else { mprintf(("Game Settings Table: Using Standard Loops For SEXP Arguments\n")); } } if (optional_string("$Use Alternate Chaining Behavior:")) { stuff_boolean(&Alternate_chaining_behavior); if (Alternate_chaining_behavior) { mprintf(("Game Settings Table: Using alternate event chaining behavior\n")); } else { mprintf(("Game Settings Table: Using standard event chaining behavior\n")); } } optional_string("#GRAPHICS SETTINGS"); if (optional_string("$Enable External Shaders:")) { stuff_boolean(&Enable_external_shaders); if (Enable_external_shaders) mprintf(("Game Settings Table: External shaders are enabled\n")); else mprintf(("Game Settings Table: External shaders are DISABLED\n")); } if (optional_string("$Default Detail Level:")) { int detail_level; stuff_int(&detail_level); mprintf(("Game Settings Table: Setting default detail level to %i of %i-%i\n", detail_level, 0, NUM_DEFAULT_DETAIL_LEVELS-1)); if (detail_level < 0 || detail_level > NUM_DEFAULT_DETAIL_LEVELS-1) { Warning(LOCATION, "Invalid detail level: %i, setting to %i\n", detail_level, Default_detail_level); } else { Default_detail_level = detail_level; } } optional_string("#NETWORK SETTINGS"); if (optional_string("$FS2NetD port:")) { stuff_int(&FS2NetD_port); if (FS2NetD_port) mprintf(("Game Settings Table: FS2NetD connecting to port %i\n", FS2NetD_port)); } optional_string("#OTHER SETTINGS"); if (optional_string("$Fixed Turret Collisions:")) { stuff_boolean(&Fixed_turret_collisions); } if (optional_string("$Damage Impacted Subsystem First:")) { stuff_boolean(&Damage_impacted_subsystem_first); } if (optional_string("$Default ship select effect:")) { char effect[NAME_LENGTH]; stuff_string(effect, F_NAME, NAME_LENGTH); if (!stricmp(effect, "FS2")) Default_ship_select_effect = 2; else if (!stricmp(effect, "FS1")) Default_ship_select_effect = 1; else if (!stricmp(effect, "off")) Default_ship_select_effect = 0; } if (optional_string("$Default weapon select effect:")) { char effect[NAME_LENGTH]; stuff_string(effect, F_NAME, NAME_LENGTH); if (!stricmp(effect, "FS2")) Default_weapon_select_effect = 2; else if (!stricmp(effect, "FS1")) Default_weapon_select_effect = 1; else if (!stricmp(effect, "off")) Default_weapon_select_effect = 0; } if (optional_string("$Weapons inherit parent collision group:")) { stuff_boolean(&Weapons_inherit_parent_collision_group); if (Weapons_inherit_parent_collision_group) mprintf(("Game Settings Table: Weapons inherit parent collision group\n")); } if (optional_string("$Flight controls follow eyepoint orientation:")) { stuff_boolean(&Flight_controls_follow_eyepoint_orientation); if (Flight_controls_follow_eyepoint_orientation) mprintf(("Game Settings Table: Flight controls follow eyepoint orientation\n")); } required_string("#END"); // close localization lcl_ext_close(); }
void parse_gamesnd_new(game_snd* gs, bool no_create) { char name[MAX_FILENAME_LEN]; // New extended format found stuff_string(name, F_NAME, MAX_FILENAME_LEN); if (!stricmp(name, NOX("empty"))) { gs->filename[0] = 0; return; } // If the name _doesn't_ match <same> put it into gs->filename; if (stricmp(name, "<same>")) { strcpy_s(gs->filename, name); } else if (!no_create) { // Throw an error if <same> was specified but we are creating a new entry error_display(1, "'<same>' is only allowed if +nocreate was specified!"); return; } if (required_string_no_create("+Preload:", no_create)) { stuff_boolean(&gs->preload); } if (required_string_no_create("+Volume:", no_create)) { stuff_float(&gs->default_volume); } if (optional_string("+3D Sound:")) { gs->flags |= GAME_SND_USE_DS3D; required_string("+Attenuation start:"); stuff_int(&gs->min); required_string("+Attenuation end:"); stuff_int(&gs->max); } else { gs->min = 0; gs->max = 0; } // jg18 - enhanced sound parameters if (optional_string("+Priority:")) { SCP_string priority_string; stuff_string(priority_string, F_NAME); EnhancedSoundPriority priority = convert_to_enhanced_priority(priority_string.c_str()); if (priority != SND_ENHANCED_PRIORITY_INVALID) { gs->enhanced_sound_data.priority= priority; } // else case not needed since conversion function displays message on error } if (optional_string("+Limit:")) { int temp_limit; stuff_int(&temp_limit); if ((temp_limit > 0) && (static_cast<uint>(temp_limit) <= SND_ENHANCED_MAX_LIMIT)) { gs->enhanced_sound_data.limit = (unsigned int)temp_limit; } else { error_display(1, "Invalid enhanced sound limit: %d\n", temp_limit); } } }
void parse_ssm(const char *filename) { char weapon_name[NAME_LENGTH]; try { read_file_text(filename, CF_TYPE_TABLES); reset_parse(); // parse the table while(required_string_either("#end", "$SSM:")) { required_string("$SSM:"); ssm_info s; int string_index; // name stuff_string(s.name, F_NAME, NAME_LENGTH); if (*s.name == 0) { sprintf(s.name, "SSM " SIZE_T_ARG, Ssm_info.size()); mprintf(("Found an SSM entry without a name. Assigning \"%s\".\n", s.name)); } // stuff data required_string("+Weapon:"); stuff_string(weapon_name, F_NAME, NAME_LENGTH); string_index = optional_string_either("+Count:", "+Min Count:"); if (string_index == 0) { stuff_int(&s.count); s.max_count = -1; } else if (string_index == 1) { stuff_int(&s.count); required_string("+Max Count:"); stuff_int(&s.max_count); } else { s.count = 1; s.max_count = -1; } required_string("+WarpRadius:"); stuff_float(&s.warp_radius); if (optional_string("+WarpTime:")) { stuff_float(&s.warp_time); // According to fireballs.cpp, "Warp lifetime must be at least 4 seconds!" if ( (s.warp_time) < 4.0f) { // So let's warn them before they try to use it, shall we? Warning(LOCATION, "Expected a '+WarpTime:' value equal or greater than 4.0, found '%f' in weapon '%s'.\n Setting to 4.0, please check and set to a number 4.0 or greater!\n", s.warp_time, weapon_name); // And then make the Assert obsolete -- Zacam s.warp_time = 4.0f; } } else { s.warp_time = 4.0f; } string_index = required_string_either("+Radius:", "+Min Radius:"); if (string_index == 0) { required_string("+Radius:"); stuff_float(&s.radius); s.max_radius = -1.0f; } else { required_string("+Min Radius:"); stuff_float(&s.radius); required_string("+Max Radius:"); stuff_float(&s.max_radius); } string_index = optional_string_either("+Offset:", "+Min Offset:"); if (string_index == 0) { stuff_float(&s.offset); s.max_offset = -1.0f; } else if (string_index == 1) { stuff_float(&s.offset); required_string("+Max Offset:"); stuff_float(&s.max_offset); } else { s.offset = 0.0f; s.max_offset = -1.0f; } if (optional_string("+Shape:")) { switch(required_string_one_of(3, "Point", "Circle", "Sphere")) { case 0: required_string("Point"); s.shape = SSM_SHAPE_POINT; break; case 1: required_string("Circle"); case -1: // If we're ignoring parse errors and can't identify the shape, go with a circle. s.shape = SSM_SHAPE_CIRCLE; break; case 2: required_string("Sphere"); s.shape = SSM_SHAPE_SPHERE; break; default: Assertion(false, "Impossible return value from required_string_one_of(); get a coder!\n"); } } else { s.shape = SSM_SHAPE_CIRCLE; } if (optional_string("+HUD Message:")) stuff_boolean(&s.send_message); else s.send_message = true; if (optional_string("+Custom Message:")) { stuff_string(s.message, F_NAME, NAME_LENGTH); s.use_custom_message = true; } s.sound_index = -1; parse_sound("+Alarm Sound:", &s.sound_index, s.name); // see if we have a valid weapon s.weapon_info_index = weapon_info_lookup(weapon_name); if(s.weapon_info_index >= 0) { // valid int existing = ssm_info_lookup(s.name); if (existing >= 0) { // Redefined the existing entry instead of adding a duplicate. Ssm_info[existing] = s; } else { Ssm_info.push_back(s); } } } } catch (const parse::ParseException& e) { mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what())); return; } }
/** * Parse the table */ void iff_init() { char traitor_name[NAME_LENGTH]; char attack_names[MAX_IFFS][MAX_IFFS][NAME_LENGTH]; struct { char iff_name[NAME_LENGTH]; int color_index; } observed_color_table[MAX_IFFS][MAX_IFFS]; int num_attack_names[MAX_IFFS]; int num_observed_colors[MAX_IFFS]; int i, j, k; int string_idx; try { // Goober5000 - if table doesn't exist, use the default table if (cf_exists_full("iff_defs.tbl", CF_TYPE_TABLES)) read_file_text("iff_defs.tbl", CF_TYPE_TABLES); else read_file_text_from_array(defaults_get_file("iff_defs.tbl")); reset_parse(); // parse the table -------------------------------------------------------- required_string("#IFFs"); // get the traitor required_string("$Traitor IFF:"); stuff_string(traitor_name, F_NAME, NAME_LENGTH); int rgb[3]; // check if alternate colours are wanted to be used for these // Marks various stuff... like asteroids if ((optional_string("$Selection Color:")) || (optional_string("$Selection Colour:"))) { stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); iff_init_color(rgb[0], rgb[1], rgb[2]); } else iff_init_color(0xff, 0xff, 0xff); // Marks the ship currently saying something if ((optional_string("$Message Color:")) || (optional_string("$Message Colour:"))) { stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); iff_init_color(rgb[0], rgb[1], rgb[2]); } else iff_init_color(0x7f, 0x7f, 0x7f); // Marks the tagged ships if ((optional_string("$Tagged Color:")) || (optional_string("$Tagged Colour:"))) { stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); iff_init_color(rgb[0], rgb[1], rgb[2]); } else iff_init_color(0xff, 0xff, 0x00); // init radar blips colour table int a_bright, a_dim; bool alternate_blip_color = false; for (i = 0; i < 5; i++) { for (j = 0; j < 2; j++) { for (k = 0; k < 3; k++) { radar_iff_color[i][j][k] = -1; } } } // if the bright/dim scaling is wanted to be changed if (optional_string("$Dimmed IFF brightness:")) { int dim_iff_brightness; stuff_int(&dim_iff_brightness); Assert(dim_iff_brightness >= 0 && dim_iff_brightness <= HUD_COLOR_ALPHA_MAX); *iff_color_brightness = dim_iff_brightness; } else *iff_color_brightness = 4; // alternate = use same method as with ship blips // retail = use 1/2 intensities if (optional_string("$Use Alternate Blip Coloring:") || optional_string("$Use Alternate Blip Colouring:")) { stuff_boolean(&alternate_blip_color); } // Parse blip colours, their order is hardcoded. if ((optional_string("$Missile Blip Color:")) || (optional_string("$Missile Blip Colour:"))) { stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); for (i = 0; i < 3; i++) { Assert(rgb[i] >= 0 && rgb[i] <= 255); radar_iff_color[0][1][i] = rgb[i]; radar_iff_color[0][0][i] = rgb[i] / 2; } } if ((optional_string("$Navbuoy Blip Color:")) || (optional_string("$Navbuoy Blip Colour:"))) { stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); for (i = 0; i < 3; i++) { Assert(rgb[i] >= 0 && rgb[i] <= 255); radar_iff_color[1][1][i] = rgb[i]; radar_iff_color[1][0][i] = rgb[i] / 2; } } if ((optional_string("$Warping Blip Color:")) || (optional_string("$Warping Blip Colour:"))) { stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); for (i = 0; i < 3; i++) { Assert(rgb[i] >= 0 && rgb[i] <= 255); radar_iff_color[2][1][i] = rgb[i]; radar_iff_color[2][0][i] = rgb[i] / 2; } } if ((optional_string("$Node Blip Color:")) || (optional_string("$Node Blip Colour:"))) { stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); for (i = 0; i < 3; i++) { Assert(rgb[i] >= 0 && rgb[i] <= 255); radar_iff_color[3][1][i] = rgb[i]; radar_iff_color[3][0][i] = rgb[i] / 2; } } if ((optional_string("$Tagged Blip Color:")) || (optional_string("$Tagged Blip Colour:"))) { stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); for (i = 0; i < 3; i++) { Assert(rgb[i] >= 0 && rgb[i] <= 255); radar_iff_color[4][1][i] = rgb[i]; radar_iff_color[4][0][i] = rgb[i] / 2; } } if (alternate_blip_color == true) { a_bright = iff_get_alpha_value(true); a_dim = iff_get_alpha_value(false); for (i = 0; i < 5; i++) { if (radar_iff_color[i][0][0] >= 0) { for (j = 0; j < 3; j++) { radar_iff_color[i][0][j] = radar_iff_color[i][1][j]; } radar_iff_color[i][1][3] = a_bright; radar_iff_color[i][0][3] = a_dim; } } } else { for (i = 0; i < 5; i++) { if (radar_iff_color[i][0][0] >= 0) { radar_iff_color[i][0][3] = 255; radar_iff_color[i][1][3] = 255; } } } if (optional_string("$Radar Target ID Flags:")) { parse_string_flag_list((int*)&radar_target_id_flags, rti_flags, Num_rti_flags); if (optional_string("+reset")) radar_target_id_flags = 0; } // begin reading data Num_iffs = 0; while (required_string_either("#End", "$IFF Name:")) { iff_info *iff; int cur_iff; // make sure we're under the limit if (Num_iffs >= MAX_IFFS) { Warning(LOCATION, "Too many iffs in iffs_defs.tbl! Max is %d.\n", MAX_IFFS); skip_to_start_of_string("#End", NULL); break; } // add new IFF iff = &Iff_info[Num_iffs]; cur_iff = Num_iffs; Num_iffs++; // get required IFF info ---------------------------------------------- // get the iff name required_string("$IFF Name:"); stuff_string(iff->iff_name, F_NAME, NAME_LENGTH); // get the iff color if (check_for_string("$Colour:")) required_string("$Colour:"); else required_string("$Color:"); stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); iff->color_index = iff_init_color(rgb[0], rgb[1], rgb[2]); // get relationships between IFFs ------------------------------------- // get the list of iffs attacked if (optional_string("$Attacks:")) num_attack_names[cur_iff] = stuff_string_list(attack_names[cur_iff], MAX_IFFS); else num_attack_names[cur_iff] = 0; // get the list of observed colors num_observed_colors[cur_iff] = 0; while (optional_string("+Sees")) { // get iff observed stuff_string_until(observed_color_table[cur_iff][num_observed_colors[cur_iff]].iff_name, "As:", NAME_LENGTH); required_string("As:"); // get color observed stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); observed_color_table[cur_iff][num_observed_colors[cur_iff]].color_index = iff_init_color(rgb[0], rgb[1], rgb[2]); // increment num_observed_colors[cur_iff]++; } // get flags ---------------------------------------------------------- // get iff flags iff->flags = 0; if (optional_string("$Flags:")) { char flag_strings[MAX_IFF_FLAGS][NAME_LENGTH]; int num_strings = stuff_string_list(flag_strings, MAX_IFF_FLAGS); for (string_idx = 0; string_idx < num_strings; string_idx++) { if (!stricmp(NOX("support allowed"), flag_strings[string_idx])) iff->flags |= IFFF_SUPPORT_ALLOWED; else if (!stricmp(NOX("exempt from all teams at war"), flag_strings[string_idx])) iff->flags |= IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR; else if (!stricmp(NOX("orders hidden"), flag_strings[string_idx])) iff->flags |= IFFF_ORDERS_HIDDEN; else if (!stricmp(NOX("orders shown"), flag_strings[string_idx])) iff->flags |= IFFF_ORDERS_SHOWN; else if (!stricmp(NOX("wing name hidden"), flag_strings[string_idx])) iff->flags |= IFFF_WING_NAME_HIDDEN; else Warning(LOCATION, "Bogus string in iff flags: %s\n", flag_strings[string_idx]); } } // get default ship flags iff->default_parse_flags = 0; if (optional_string("$Default Ship Flags:")) { i = 0; j = 0; char flag_strings[MAX_PARSE_OBJECT_FLAGS][NAME_LENGTH]; int num_strings = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS); for (i = 0; i < num_strings; i++) { for (j = 0; j < MAX_PARSE_OBJECT_FLAGS; j++) { if (!stricmp(flag_strings[i], Parse_object_flags[j])) { iff->default_parse_flags |= (1 << j); break; } } } if (j == MAX_PARSE_OBJECT_FLAGS) Warning(LOCATION, "Bogus string in iff default ship flags: %s\n", flag_strings[i]); } // again iff->default_parse_flags2 = 0; if (optional_string("$Default Ship Flags2:")) { i = 0; j = 0; char flag_strings[MAX_PARSE_OBJECT_FLAGS_2][NAME_LENGTH]; int num_strings = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS_2); for (i = 0; i < num_strings; i++) { for (j = 0; j < MAX_PARSE_OBJECT_FLAGS_2; j++) { if (!stricmp(flag_strings[i], Parse_object_flags_2[j])) { iff->default_parse_flags2 |= (1 << j); break; } } } if (j == MAX_PARSE_OBJECT_FLAGS_2) Warning(LOCATION, "Bogus string in iff default ship flags2: %s\n", flag_strings[i]); } // this is cleared between each level but let's just set it here for thoroughness iff->ai_rearm_timestamp = timestamp(-1); } required_string("#End"); // now resolve the relationships ------------------------------------------ // first get the traitor Iff_traitor = iff_lookup(traitor_name); if (Iff_traitor < 0) { Iff_traitor = 0; Warning(LOCATION, "Traitor IFF %s not found in iff_defs.tbl! Defaulting to %s.\n", traitor_name, Iff_info[Iff_traitor].iff_name); } // next get the attackees and colors for (int cur_iff = 0; cur_iff < Num_iffs; cur_iff++) { iff_info *iff = &Iff_info[cur_iff]; // clear the iffs to be attacked iff->attackee_bitmask = 0; iff->attackee_bitmask_all_teams_at_war = 0; // clear the observed colors for (j = 0; j < MAX_IFFS; j++) iff->observed_color_index[j] = -1; // resolve the list names for (int list_index = 0; list_index < MAX_IFFS; list_index++) { // are we within the number of attackees listed? if (list_index < num_attack_names[cur_iff]) { // find out who int target_iff = iff_lookup(attack_names[cur_iff][list_index]); // valid? if (target_iff >= 0) iff->attackee_bitmask |= iff_get_mask(target_iff); else Warning(LOCATION, "Attack target IFF %s not found for IFF %s in iff_defs.tbl!\n", attack_names[cur_iff][list_index], iff->iff_name); } // are we within the number of colors listed? if (list_index < num_observed_colors[cur_iff]) { // find out who int target_iff = iff_lookup(observed_color_table[cur_iff][list_index].iff_name); // valid? if (target_iff >= 0) iff->observed_color_index[target_iff] = observed_color_table[cur_iff][list_index].color_index; else Warning(LOCATION, "Observed color IFF %s not found for IFF %s in iff_defs.tbl!\n", observed_color_table[cur_iff][list_index].iff_name, iff->iff_name); } } // resolve the all teams at war relationships if (iff->flags & IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR) { // exempt, so use standard attacks iff->attackee_bitmask_all_teams_at_war = iff->attackee_bitmask; } else { // nonexempt, so build bitmask of all other nonexempt teams for (int other_iff = 0; other_iff < Num_iffs; other_iff++) { // skip myself (unless I attack myself normally) if ((other_iff == cur_iff) && !iff_x_attacks_y(cur_iff, cur_iff)) continue; // skip anyone exempt if (Iff_info[other_iff].flags & IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR) continue; // add everyone else iff->attackee_bitmask_all_teams_at_war |= iff_get_mask(other_iff); } } } // add tbl/tbm to multiplayer validation list extern void fs2netd_add_table_validation(const char *tblname); fs2netd_add_table_validation("iff_defs.tbl"); } catch (const parse::ParseException& e) { mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "iff_defs.tbl", e.what())); return; } }
static bool opengl_post_init_table() { bool warned = false; try { if (cf_exists_full("post_processing.tbl", CF_TYPE_TABLES)) read_file_text("post_processing.tbl", CF_TYPE_TABLES); else read_file_text_from_default(defaults_get_file("post_processing.tbl")); reset_parse(); if (optional_string("#Effects")) { while (!required_string_one_of(3, "$Name:", "#Ship Effects", "#End")) { char tbuf[NAME_LENGTH + 1] = { 0 }; post_effect_t eff; required_string("$Name:"); stuff_string(tbuf, F_NAME, NAME_LENGTH); eff.name = tbuf; required_string("$Uniform:"); stuff_string(tbuf, F_NAME, NAME_LENGTH); eff.uniform_name = tbuf; required_string("$Define:"); stuff_string(tbuf, F_NAME, NAME_LENGTH); eff.define_name = tbuf; required_string("$AlwaysOn:"); stuff_boolean(&eff.always_on); required_string("$Default:"); stuff_float(&eff.default_intensity); eff.intensity = eff.default_intensity; required_string("$Div:"); stuff_float(&eff.div); required_string("$Add:"); stuff_float(&eff.add); // Post_effects index is used for flag checks, so we can't have more than 32 if (Post_effects.size() < 32) { Post_effects.push_back(eff); } else if (!warned) { mprintf(("WARNING: post_processing.tbl can only have a max of 32 effects! Ignoring extra...\n")); warned = true; } } } //Built-in per-ship effects ship_effect se1; strcpy_s(se1.name, "FS1 Ship select"); se1.shader_effect = 0; se1.disables_rendering = false; se1.invert_timer = false; Ship_effects.push_back(se1); if (optional_string("#Ship Effects")) { while (!required_string_one_of(3, "$Name:", "#Light Shafts", "#End")) { ship_effect se; char tbuf[NAME_LENGTH] = { 0 }; required_string("$Name:"); stuff_string(tbuf, F_NAME, NAME_LENGTH); strcpy_s(se.name, tbuf); required_string("$Shader Effect:"); stuff_int(&se.shader_effect); required_string("$Disables Rendering:"); stuff_boolean(&se.disables_rendering); required_string("$Invert timer:"); stuff_boolean(&se.invert_timer); Ship_effects.push_back(se); } } if (optional_string("#Light Shafts")) { required_string("$AlwaysOn:"); stuff_boolean(&ls_on); required_string("$Density:"); stuff_float(&ls_density); required_string("$Falloff:"); stuff_float(&ls_falloff); required_string("$Weight:"); stuff_float(&ls_weight); required_string("$Intensity:"); stuff_float(&ls_intensity); required_string("$Sample Number:"); stuff_int(&ls_samplenum); ls_cpintensity = ls_weight; for (int i = 1; i < ls_samplenum; i++) ls_cpintensity += ls_weight * pow(ls_falloff, i); ls_cpintensity *= ls_intensity; } required_string("#End"); return true; } catch (const parse::ParseException& e) { mprintf(("Unable to parse 'post_processing.tbl'! Error message = %s.\n", e.what())); return false; } }
void parse_mod_table(const char *filename) { // SCP_vector<SCP_string> lines; try { if (filename == NULL) read_file_text_from_default(defaults_get_file("game_settings.tbl")); else read_file_text(filename, CF_TYPE_TABLES); reset_parse(); // start parsing optional_string("#GAME SETTINGS"); if (optional_string("$Minimum version:")) { int major = 0; int minor = 0; int build = 0; int revision = 0; required_string("+Major:"); stuff_int(&major); required_string("+Minor:"); stuff_int(&minor); required_string("+Build:"); stuff_int(&build); if (optional_string("+Revision:")) { stuff_int(&revision); } mprintf(("Game Settings Table: Parsed minimum version of %s\n", version::format_version(major, minor, build, revision).c_str())); if (!version::check_at_least(major, minor, build, revision)) { Error(LOCATION, "This modification needs at least version %s of FreeSpace Open. However, the current is only %s!", version::format_version(major, minor, build, revision).c_str(), version::format_version(FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD, FS_VERSION_REVIS).c_str()); } } optional_string("#CAMPAIGN SETTINGS"); if (optional_string("$Default Campaign File Name:")) { char temp[MAX_FILENAME_LEN]; stuff_string(temp, F_NAME, MAX_FILENAME_LEN); // remove extension? if (drop_extension(temp)) { mprintf(("Game Settings Table: Removed extension on default campaign file name %s\n", temp)); } // check length size_t maxlen = (MAX_FILENAME_LEN - 4); auto len = strlen(temp); if (len > maxlen) { Warning(LOCATION, "Token too long: [%s]. Length = " SIZE_T_ARG ". Max is " SIZE_T_ARG ".\n", temp, len, maxlen); temp[maxlen] = 0; } strcpy_s(Default_campaign_file_name, temp); } if (optional_string("#Ignored Campaign File Names")) { SCP_string campaign_name; while (optional_string("$Campaign File Name:")) { stuff_string(campaign_name, F_NAME); // remove extension? if (drop_extension(campaign_name)) { mprintf(("Game Settings Table: Removed extension on ignored campaign file name %s\n", campaign_name.c_str())); } Ignored_campaigns.push_back(campaign_name); } } if (optional_string("$Red-alert applies to delayed ships:")) { stuff_boolean(&Red_alert_applies_to_delayed_ships); if (Red_alert_applies_to_delayed_ships) { mprintf(("Game Settings Table: Red-alert stats will be loaded for ships that arrive later in missions\n")); } else { mprintf(("Game Settings Table: Red-alert stats will NOT be loaded for ships that arrive later in missions (this is retail behavior)\n")); } } optional_string("#HUD SETTINGS"); // how long should the game wait before displaying a directive? if (optional_string("$Directive Wait Time:")) { stuff_int(&Directive_wait_time); } if (optional_string("$Cutscene camera displays HUD:")) { stuff_boolean(&Cutscene_camera_displays_hud); } // compatibility if (optional_string("$Cutscene camera disables HUD:")) { mprintf(("Game Settings Table: \"$$Cutscene camera disables HUD\" is deprecated in favor of \"$Cutscene camera displays HUD\"\n")); bool temp; stuff_boolean(&temp); Cutscene_camera_displays_hud = !temp; } if (optional_string("$Full color head animations:")) { stuff_boolean(&Full_color_head_anis); } // compatibility if (optional_string("$Color head animations with hud colors:")) { mprintf(("Game Settings Table: \"$Color head animations with hud colors\" is deprecated in favor of \"$Full color head animations\"\n")); bool temp; stuff_boolean(&temp); Full_color_head_anis = !temp; } optional_string("#SEXP SETTINGS"); if (optional_string("$Loop SEXPs Then Arguments:")) { stuff_boolean(&True_loop_argument_sexps); if (True_loop_argument_sexps) { mprintf(("Game Settings Table: Using Reversed Loops For SEXP Arguments\n")); } else { mprintf(("Game Settings Table: Using Standard Loops For SEXP Arguments\n")); } } if (optional_string("$Use Alternate Chaining Behavior:")) { stuff_boolean(&Alternate_chaining_behavior); if (Alternate_chaining_behavior) { mprintf(("Game Settings Table: Using alternate event chaining behavior\n")); } else { mprintf(("Game Settings Table: Using standard event chaining behavior\n")); } } optional_string("#GRAPHICS SETTINGS"); if (optional_string("$Enable External Shaders:")) { stuff_boolean(&Enable_external_shaders); if (Enable_external_shaders) mprintf(("Game Settings Table: External shaders are enabled\n")); else mprintf(("Game Settings Table: External shaders are DISABLED\n")); } if (optional_string("$Default Detail Level:")) { int detail_level; stuff_int(&detail_level); mprintf(("Game Settings Table: Setting default detail level to %i of %i-%i\n", detail_level, 0, NUM_DEFAULT_DETAIL_LEVELS - 1)); if (detail_level < 0 || detail_level > NUM_DEFAULT_DETAIL_LEVELS - 1) { Warning(LOCATION, "Invalid detail level: %i, setting to %i\n", detail_level, Default_detail_level); } else { Default_detail_level = detail_level; } } if (optional_string("$Briefing Window FOV:")) { float fov; stuff_float(&fov); mprintf(("Game Settings Table: Setting briefing window FOV from %f to %f\n", Briefing_window_FOV, fov)); Briefing_window_FOV = fov; } if (optional_string("$Generic Pain Flash Factor:")) { stuff_float(&Generic_pain_flash_factor); if (Generic_pain_flash_factor != 1.0f) mprintf(("Game Settings Table: Setting generic pain flash factor to %.2f\n", Generic_pain_flash_factor)); } if (optional_string("$Shield Pain Flash Factor:")) { stuff_float(&Shield_pain_flash_factor); if (Shield_pain_flash_factor != 0.0f) mprintf(("Game Settings Table: Setting shield pain flash factor to %.2f\n", Shield_pain_flash_factor)); } optional_string("#NETWORK SETTINGS"); if (optional_string("$FS2NetD port:")) { stuff_int(&FS2NetD_port); if (FS2NetD_port) mprintf(("Game Settings Table: FS2NetD connecting to port %i\n", FS2NetD_port)); } optional_string("#SOUND SETTINGS"); if (optional_string("$Default Sound Volume:")) { stuff_float(&Master_sound_volume); } if (optional_string("$Default Music Volume:")) { stuff_float(&Master_event_music_volume); } if (optional_string("$Default Voice Volume:")) { stuff_float(&Master_voice_volume); } optional_string("#FRED SETTINGS"); if (optional_string("$Disable Hard Coded Message Head Ani Files:")) { stuff_boolean(&Disable_hc_message_ani); if (Disable_hc_message_ani) { mprintf(("Game Settings Table: FRED - Disabling Hard Coded Message Ani Files\n")); } else { mprintf(("Game Settings Table: FRED - Using Hard Coded Message Ani Files\n")); } } optional_string("#OTHER SETTINGS"); if (optional_string("$Fixed Turret Collisions:")) { stuff_boolean(&Fixed_turret_collisions); } if (optional_string("$Damage Impacted Subsystem First:")) { stuff_boolean(&Damage_impacted_subsystem_first); } if (optional_string("$Default ship select effect:")) { char effect[NAME_LENGTH]; stuff_string(effect, F_NAME, NAME_LENGTH); if (!stricmp(effect, "FS2")) Default_ship_select_effect = 2; else if (!stricmp(effect, "FS1")) Default_ship_select_effect = 1; else if (!stricmp(effect, "off")) Default_ship_select_effect = 0; } if (optional_string("$Default weapon select effect:")) { char effect[NAME_LENGTH]; stuff_string(effect, F_NAME, NAME_LENGTH); if (!stricmp(effect, "FS2")) Default_weapon_select_effect = 2; else if (!stricmp(effect, "FS1")) Default_weapon_select_effect = 1; else if (!stricmp(effect, "off")) Default_weapon_select_effect = 0; } if (optional_string("$Weapons inherit parent collision group:")) { stuff_boolean(&Weapons_inherit_parent_collision_group); if (Weapons_inherit_parent_collision_group) mprintf(("Game Settings Table: Weapons inherit parent collision group\n")); } if (optional_string("$Flight controls follow eyepoint orientation:")) { stuff_boolean(&Flight_controls_follow_eyepoint_orientation); if (Flight_controls_follow_eyepoint_orientation) mprintf(("Game Settings Table: Flight controls follow eyepoint orientation\n")); } if (optional_string("$Beams Use Damage Factors:")) { stuff_boolean(&Beams_use_damage_factors); if (Beams_use_damage_factors) { mprintf(("Game Settings Table: Beams will use Damage Factors\n")); } else { mprintf(("Game Settings Table: Beams will ignore Damage Factors (retail behavior)\n")); } } if (optional_string("$Default fiction viewer UI:")) { char ui_name[NAME_LENGTH]; stuff_string(ui_name, F_NAME, NAME_LENGTH); if (!stricmp(ui_name, "auto")) Default_fiction_viewer_ui = -1; else { int ui_index = fiction_viewer_ui_name_to_index(ui_name); if (ui_index >= 0) Default_fiction_viewer_ui = ui_index; else Warning(LOCATION, "Unrecognized fiction viewer UI: %s", ui_name); } } required_string("#END"); } catch (const parse::ParseException& e) { mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", (filename) ? filename : "<default game_settings.tbl>", e.what())); return; } }
void parse_ai_profiles_tbl(const char *filename) { int i; char profile_name[NAME_LENGTH]; ai_profile_t dummy_profile; char *saved_Mp = NULL; char buf[NAME_LENGTH]; try { if (filename == NULL) read_file_text_from_default(defaults_get_file("ai_profiles.tbl")); else read_file_text(filename, CF_TYPE_TABLES); reset_parse(); // start parsing required_string("#AI Profiles"); // new default? if (optional_string("$Default Profile:")) stuff_string(Default_profile_name, F_NAME, NAME_LENGTH); // begin reading data while (required_string_either("#End", "$Profile Name:")) { ai_profile_t *profile = &dummy_profile; ai_profile_t *previous_profile = NULL; bool no_create = false; // get the name required_string("$Profile Name:"); stuff_string(profile_name, F_NAME, NAME_LENGTH); // see if it exists for (i = 0; i < Num_ai_profiles; i++) { if (!stricmp(Ai_profiles[i].profile_name, profile_name)) { previous_profile = &Ai_profiles[i]; break; } } // modular table stuff if (optional_string("+nocreate")) { no_create = true; // use the previous one if possible, // otherwise continue to use the dummy one if (previous_profile != NULL) profile = previous_profile; } else { // don't create multiple profiles with the same name if (previous_profile != NULL) { Warning(LOCATION, "An ai profile named '%s' already exists! The new one will not be created.\n", profile_name); } else { // make sure we're under the limit if (Num_ai_profiles >= MAX_AI_PROFILES) { Warning(LOCATION, "Too many profiles in ai_profiles.tbl! Max is %d.\n", MAX_AI_PROFILES - 1); // -1 because one is built-in skip_to_string("#End", NULL); break; } profile = &Ai_profiles[Num_ai_profiles]; Num_ai_profiles++; } } // initialize profile if we're not building from a previously parsed one if (!no_create) { // base profile, so zero it out if (profile == &Ai_profiles[0]) { memset(profile, 0, sizeof(ai_profile_t)); } // brand new profile, so set it to the base defaults else { memcpy(profile, &Ai_profiles[0], sizeof(ai_profile_t)); } } // set the name strcpy_s(profile->profile_name, profile_name); // fill in any and all settings; they're all optional and can be in any order while (!check_for_string("$Profile Name:") && !check_for_string("#End")) { if (optional_string("$Player Afterburner Recharge Scale:")) parse_float_list(profile->afterburner_recharge_scale, NUM_SKILL_LEVELS); if (optional_string("$Max Beam Friendly Fire Damage:")) parse_float_list(profile->beam_friendly_damage_cap, NUM_SKILL_LEVELS); if (optional_string("$Player Countermeasure Life Scale:")) parse_float_list(profile->cmeasure_life_scale, NUM_SKILL_LEVELS); if (optional_string("$AI Countermeasure Firing Chance:")) parse_float_list(profile->cmeasure_fire_chance, NUM_SKILL_LEVELS); if (optional_string("$AI In Range Time:")) parse_float_list(profile->in_range_time, NUM_SKILL_LEVELS); if (optional_string("$AI Always Links Ammo Weapons:")) parse_float_list(profile->link_ammo_levels_always, NUM_SKILL_LEVELS); if (optional_string("$AI Maybe Links Ammo Weapons:")) parse_float_list(profile->link_ammo_levels_maybe, NUM_SKILL_LEVELS); if (optional_string("$Primary Ammo Burst Multiplier:")) parse_float_list(profile->primary_ammo_burst_mult, NUM_SKILL_LEVELS); if (optional_string("$AI Always Links Energy Weapons:")) parse_float_list(profile->link_energy_levels_always, NUM_SKILL_LEVELS); if (optional_string("$AI Maybe Links Energy Weapons:")) parse_float_list(profile->link_energy_levels_maybe, NUM_SKILL_LEVELS); if (optional_string("$Max Missles Locked on Player:") || optional_string("$Max Missiles Locked on Player:")) parse_int_list(profile->max_allowed_player_homers, NUM_SKILL_LEVELS); if (optional_string("$Max Player Attackers:")) parse_int_list(profile->max_attackers, NUM_SKILL_LEVELS); if (optional_string("$Max Incoming Asteroids:")) parse_int_list(profile->max_incoming_asteroids, NUM_SKILL_LEVELS); if (optional_string("$Player Damage Factor:") || optional_string("$AI Damage Reduction to Player Hull:")) parse_float_list(profile->player_damage_scale, NUM_SKILL_LEVELS); if (optional_string("$Player Subsys Damage Factor:") || optional_string("$AI Damage Reduction to Player Subsys:")) parse_float_list(profile->subsys_damage_scale, NUM_SKILL_LEVELS); // represented in fractions of F1_0 if (optional_string("$Predict Position Delay:")) { int iLoop; float temp_list[NUM_SKILL_LEVELS]; parse_float_list(temp_list, NUM_SKILL_LEVELS); for (iLoop = 0; iLoop < NUM_SKILL_LEVELS; iLoop++) profile->predict_position_delay[iLoop] = fl2f(temp_list[iLoop]); } if (optional_string("$AI Shield Manage Delay:") || optional_string("$AI Shield Manage Delays:")) parse_float_list(profile->shield_manage_delay, NUM_SKILL_LEVELS); if (optional_string("$Friendly AI Fire Delay Scale:")) parse_float_list(profile->ship_fire_delay_scale_friendly, NUM_SKILL_LEVELS); if (optional_string("$Hostile AI Fire Delay Scale:")) parse_float_list(profile->ship_fire_delay_scale_hostile, NUM_SKILL_LEVELS); if (optional_string("$Friendly AI Secondary Fire Delay Scale:")) parse_float_list(profile->ship_fire_secondary_delay_scale_friendly, NUM_SKILL_LEVELS); if (optional_string("$Hostile AI Secondary Fire Delay Scale:")) parse_float_list(profile->ship_fire_secondary_delay_scale_hostile, NUM_SKILL_LEVELS); if (optional_string("$AI Turn Time Scale:")) parse_float_list(profile->turn_time_scale, NUM_SKILL_LEVELS); if (optional_string("$Glide Attack Percent:")) { parse_float_list(profile->glide_attack_percent, NUM_SKILL_LEVELS); //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0 //While we're at it, verify the range for (i = 0; i < NUM_SKILL_LEVELS; i++) { if (profile->glide_attack_percent[i] < 0.0f || profile->glide_attack_percent[i] > 100.0f) { Warning(LOCATION, "$Glide Attack Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->glide_attack_percent[i]); profile->glide_attack_percent[i] = 0.0f; } profile->glide_attack_percent[i] /= 100.0; } } if (optional_string("$Circle Strafe Percent:")) { parse_float_list(profile->circle_strafe_percent, NUM_SKILL_LEVELS); //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0 //While we're at it, verify the range for (i = 0; i < NUM_SKILL_LEVELS; i++) { if (profile->circle_strafe_percent[i] < 0.0f || profile->circle_strafe_percent[i] > 100.0f) { Warning(LOCATION, "$Circle Strafe Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->circle_strafe_percent[i]); profile->circle_strafe_percent[i] = 0.0f; } profile->circle_strafe_percent[i] /= 100.0; } } if (optional_string("$Glide Strafe Percent:")) { parse_float_list(profile->glide_strafe_percent, NUM_SKILL_LEVELS); //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0 //While we're at it, verify the range for (i = 0; i < NUM_SKILL_LEVELS; i++) { if (profile->glide_strafe_percent[i] < 0.0f || profile->glide_strafe_percent[i] > 100.0f) { Warning(LOCATION, "$Glide Strafe Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->glide_strafe_percent[i]); profile->glide_strafe_percent[i] = 0.0f; } profile->glide_strafe_percent[i] /= 100.0; } } if (optional_string("$Random Sidethrust Percent:")) { parse_float_list(profile->random_sidethrust_percent, NUM_SKILL_LEVELS); //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0 //While we're at it, verify the range for (i = 0; i < NUM_SKILL_LEVELS; i++) { if (profile->random_sidethrust_percent[i] < 0.0f || profile->random_sidethrust_percent[i] > 100.0f) { Warning(LOCATION, "$Random Sidethrust Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->random_sidethrust_percent[i]); profile->random_sidethrust_percent[i] = 0.0f; } profile->random_sidethrust_percent[i] /= 100.0; } } if (optional_string("$Stalemate Time Threshold:")) parse_float_list(profile->stalemate_time_thresh, NUM_SKILL_LEVELS); if (optional_string("$Stalemate Distance Threshold:")) parse_float_list(profile->stalemate_dist_thresh, NUM_SKILL_LEVELS); if (optional_string("$Player Shield Recharge Scale:")) parse_float_list(profile->shield_energy_scale, NUM_SKILL_LEVELS); if (optional_string("$Player Weapon Recharge Scale:")) parse_float_list(profile->weapon_energy_scale, NUM_SKILL_LEVELS); if (optional_string("$Max Turret Target Ownage:")) parse_int_list(profile->max_turret_ownage_target, NUM_SKILL_LEVELS); if (optional_string("$Max Turret Player Ownage:")) parse_int_list(profile->max_turret_ownage_player, NUM_SKILL_LEVELS); if (optional_string("$Percentage Required For Kill Scale:")) parse_float_list(profile->kill_percentage_scale, NUM_SKILL_LEVELS); if (optional_string("$Percentage Required For Assist Scale:")) parse_float_list(profile->assist_percentage_scale, NUM_SKILL_LEVELS); if (optional_string("$Percentage Awarded For Capship Assist:")) parse_float_list(profile->assist_award_percentage_scale, NUM_SKILL_LEVELS); if (optional_string("$Repair Penalty:")) parse_int_list(profile->repair_penalty, NUM_SKILL_LEVELS); if (optional_string("$Delay Before Allowing Bombs to Be Shot Down:")) parse_float_list(profile->delay_bomb_arm_timer, NUM_SKILL_LEVELS); if (optional_string("$Chance AI Has to Fire Missiles at Player:")) parse_int_list(profile->chance_to_use_missiles_on_plr, NUM_SKILL_LEVELS); if (optional_string("$Max Aim Update Delay:")) parse_float_list(profile->max_aim_update_delay, NUM_SKILL_LEVELS); if (optional_string("$Turret Max Aim Update Delay:")) parse_float_list(profile->turret_max_aim_update_delay, NUM_SKILL_LEVELS); if (optional_string("$Player Autoaim FOV:")) { float fov_list[NUM_SKILL_LEVELS]; parse_float_list(fov_list, NUM_SKILL_LEVELS); for (i = 0; i < NUM_SKILL_LEVELS; i++) { //Enforce range if (fov_list[i] < 0.0f || fov_list[i] >= 360.0f) { Warning(LOCATION, "$Player Autoaim FOV should be >= 0 and < 360.0 (read %f). Setting to 0.", fov_list[i]); fov_list[i] = 0.0f; } //Convert units profile->player_autoaim_fov[i] = fov_list[i] * PI / 180.0f; } } if (optional_string("$Detail Distance Multiplier:")) parse_float_list(profile->detail_distance_mult, NUM_SKILL_LEVELS); set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS, AIP_FLAG); set_flag(profile, "$smart primary weapon selection:", AIPF_SMART_PRIMARY_WEAPON_SELECTION, AIP_FLAG); set_flag(profile, "$smart secondary weapon selection:", AIPF_SMART_SECONDARY_WEAPON_SELECTION, AIP_FLAG); set_flag(profile, "$smart shield management:", AIPF_SMART_SHIELD_MANAGEMENT, AIP_FLAG); set_flag(profile, "$smart afterburner management:", AIPF_SMART_AFTERBURNER_MANAGEMENT, AIP_FLAG); set_flag(profile, "$allow rapid secondary dumbfire:", AIPF_ALLOW_RAPID_SECONDARY_DUMBFIRE, AIP_FLAG); set_flag(profile, "$huge turret weapons ignore bombs:", AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS, AIP_FLAG); set_flag(profile, "$don't insert random turret fire delay:", AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY, AIP_FLAG); set_flag(profile, "$hack improve non-homing swarm turret fire accuracy:", AIPF_HACK_IMPROVE_NON_HOMING_SWARM_TURRET_FIRE_ACCURACY, AIP_FLAG); set_flag(profile, "$shockwaves damage small ship subsystems:", AIPF_SHOCKWAVES_DAMAGE_SMALL_SHIP_SUBSYSTEMS, AIP_FLAG); set_flag(profile, "$navigation subsystem governs warpout capability:", AIPF_NAVIGATION_SUBSYS_GOVERNS_WARP, AIP_FLAG); set_flag(profile, "$ignore lower bound for minimum speed of docked ship:", AIPF_NO_MIN_DOCK_SPEED_CAP, AIP_FLAG); set_flag(profile, "$disable linked fire penalty:", AIPF_DISABLE_LINKED_FIRE_PENALTY, AIP_FLAG); set_flag(profile, "$disable weapon damage scaling:", AIPF_DISABLE_WEAPON_DAMAGE_SCALING, AIP_FLAG); set_flag(profile, "$use additive weapon velocity:", AIPF_USE_ADDITIVE_WEAPON_VELOCITY, AIP_FLAG); set_flag(profile, "$use newtonian dampening:", AIPF_USE_NEWTONIAN_DAMPENING, AIP_FLAG); set_flag(profile, "$include beams for kills and assists:", AIPF_INCLUDE_BEAMS_IN_STAT_CALCS, AIP_FLAG); set_flag(profile, "$score kills based on damage caused:", AIPF_KILL_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG); set_flag(profile, "$score assists based on damage caused:", AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG); set_flag(profile, "$allow event and goal scoring in multiplayer:", AIPF_ALLOW_MULTI_EVENT_SCORING, AIP_FLAG); set_flag(profile, "$fix linked primary weapon decision bug:", AIPF_FIX_LINKED_PRIMARY_BUG, AIP_FLAG); set_flag(profile, "$prevent turrets targeting too distant bombs:", AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE, AIP_FLAG); set_flag(profile, "$smart subsystem targeting for turrets:", AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS, AIP_FLAG); set_flag(profile, "$fix heat seekers homing on stealth ships bug:", AIPF_FIX_HEAT_SEEKER_STEALTH_BUG, AIP_FLAG); set_flag(profile, "$multi allow empty primaries:", AIPF_MULTI_ALLOW_EMPTY_PRIMARIES, AIP_FLAG); set_flag(profile, "$multi allow empty secondaries:", AIPF_MULTI_ALLOW_EMPTY_SECONDARIES, AIP_FLAG); set_flag(profile, "$allow turrets target weapons freely:", AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY, AIP_FLAG); set_flag(profile, "$use only single fov for turrets:", AIPF_USE_ONLY_SINGLE_FOV_FOR_TURRETS, AIP_FLAG); set_flag(profile, "$allow vertical dodge:", AIPF_ALLOW_VERTICAL_DODGE, AIP_FLAG); set_flag(profile, "$force beam turrets to use normal fov:", AIPF_FORCE_BEAM_TURRET_FOV, AIP_FLAG); set_flag(profile, "$fix ai class bug:", AIPF_FIX_AI_CLASS_BUG, AIP_FLAG); set_flag(profile, "$turrets ignore targets radius in range checks:", AIPF2_TURRETS_IGNORE_TARGET_RADIUS, AIP_FLAG2); set_flag(profile, "$no extra collision avoidance vs player:", AIPF2_NO_SPECIAL_PLAYER_AVOID, AIP_FLAG2); set_flag(profile, "$perform fewer checks for death screams:", AIPF2_PERFORM_FEWER_SCREAM_CHECKS, AIP_FLAG2); set_flag(profile, "$advanced turret fov edge checks:", AIPF2_ADVANCED_TURRET_FOV_EDGE_CHECKS, AIP_FLAG2); set_flag(profile, "$require turrets to have target in fov:", AIPF2_REQUIRE_TURRET_TO_HAVE_TARGET_IN_FOV, AIP_FLAG2); set_flag(profile, "$all ships manage shields:", AIPF2_ALL_SHIPS_MANAGE_SHIELDS, AIP_FLAG2); set_flag(profile, "$ai aims from ship center:", AIPF2_AI_AIMS_FROM_SHIP_CENTER, AIP_FLAG2); set_flag(profile, "$allow primary link at mission start:", AIPF2_ALLOW_PRIMARY_LINK_AT_START, AIP_FLAG2); set_flag(profile, "$allow beams to damage bombs:", AIPF2_BEAMS_DAMAGE_WEAPONS, AIP_FLAG2); set_flag(profile, "$disable weapon damage scaling for player:", AIPF2_PLAYER_WEAPON_SCALE_FIX, AIP_FLAG2); set_flag(profile, "$countermeasures affect aspect seekers:", AIPF2_ASPECT_LOCK_COUNTERMEASURE, AIP_FLAG2); set_flag(profile, "$ai guards specific ship in wing:", AIPF2_AI_GUARDS_SPECIFIC_SHIP_IN_WING, AIP_FLAG2); profile->ai_path_mode = AI_PATH_MODE_NORMAL; if (optional_string("$ai path mode:")) { stuff_string(buf, F_NAME, NAME_LENGTH); int j = ai_path_type_match(buf); if (j >= 0) { profile->ai_path_mode = j; } else { Warning(LOCATION, "Invalid ai path mode '%s' specified", buf); } } set_flag(profile, "$no warp camera:", AIPF2_NO_WARP_CAMERA, AIP_FLAG2); set_flag(profile, "$fix ai path order bug:", AIPF2_FIX_AI_PATH_ORDER_BUG, AIP_FLAG2); set_flag(profile, "$strict turret-tagged-only targeting:", AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING, AIP_FLAG2); set_flag(profile, "$aspect bomb invulnerability fix:", AIPF2_ASPECT_INVULNERABILITY_FIX, AIP_FLAG2); set_flag(profile, "$glide decay requires thrust:", AIPF2_GLIDE_DECAY_REQUIRES_THRUST, AIP_FLAG2); set_flag(profile, "$ai can slow down when attacking big ships:", AIPF2_AI_CAN_SLOW_DOWN_ATTACKING_BIG_SHIPS, AIP_FLAG2); profile->bay_arrive_speed_mult = 1.0f; profile->bay_depart_speed_mult = 1.0f; if (optional_string("$bay arrive speed multiplier:")) { stuff_float(&profile->bay_arrive_speed_mult); } if (optional_string("$bay depart speed multiplier:")) { stuff_float(&profile->bay_depart_speed_mult); } // ---------- // compatibility if (optional_string("$perform less checks for death screams:")) { mprintf(("Warning: \"$perform less checks for death screams\" flag is deprecated in favor of \"$perform fewer checks for death screams\"\n")); bool temp; stuff_boolean(&temp); if (temp) profile->flags2 |= AIPF2_PERFORM_FEWER_SCREAM_CHECKS; else profile->flags2 &= ~AIPF2_PERFORM_FEWER_SCREAM_CHECKS; } if (optional_string("$allow primary link delay:")) { mprintf(("Warning: \"$allow primary link delay\" flag is deprecated in favor of \"$allow primary link at mission start\"\n")); bool temp; stuff_boolean(&temp); if (temp) profile->flags2 &= ~AIPF2_ALLOW_PRIMARY_LINK_AT_START; else profile->flags2 |= AIPF2_ALLOW_PRIMARY_LINK_AT_START; } // if we've been through once already and are at the same place, force a move if (saved_Mp && (saved_Mp == Mp)) { char tmp[60]; memset(tmp, 0, 60); strncpy(tmp, Mp, 59); mprintf(("WARNING: Unrecognized parameter in ai_profiles: %s\n", tmp)); Mp++; } // find next valid option skip_to_start_of_string_either("$", "#"); saved_Mp = Mp; } } required_string("#End"); } catch (const parse::ParseException& e) { mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", (filename) ? filename : "<default ai_profiles.tbl>", e.what())); return; } // add tbl/tbm to multiplayer validation list extern void fs2netd_add_table_validation(const char *tblname); fs2netd_add_table_validation(filename); }
// game init void ssm_init() { int rval; ssm_info bogus, *s; char weapon_name[NAME_LENGTH]; if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "ssm.tbl", rval)); return; } read_file_text("ssm.tbl", CF_TYPE_TABLES); reset_parse(); // parse the table Ssm_info_count = 0; while(!optional_string("#end")){ // another ssm definition if(optional_string("$SSM:")){ // pointer to info struct if(Ssm_info_count >= MAX_SSM_TYPES){ s = &bogus; } else { s = &Ssm_info[Ssm_info_count]; } // name stuff_string(s->name, F_NAME, NAME_LENGTH); // stuff data required_string("+Weapon:"); stuff_string(weapon_name, F_NAME, NAME_LENGTH); required_string("+Count:"); stuff_int(&s->count); required_string("+WarpRadius:"); stuff_float(&s->warp_radius); required_string("+WarpTime:"); stuff_float(&s->warp_time); // According to fireballs.cpp, "Warp lifetime must be at least 4 seconds!" if ( (s->warp_time) < 4.0f) { // So let's warn them before they try to use it, shall we? Warning(LOCATION, "Expected a '+WarpTime:' value equal or greater than 4.0, found '%f' in weapon '%s'.\n Setting to 4.0, please check and set to a number 4.0 or greater!\n", s->warp_time, weapon_name); // And then make the Assert obsolete -- Zacam s->warp_time = 4.0f; } required_string("+Radius:"); stuff_float(&s->radius); required_string("+Offset:"); stuff_float(&s->offset); if (optional_string("+HUD Message:")) stuff_boolean(&s->send_message); else s->send_message = true; if (optional_string("+Custom Message:")) { stuff_string(s->message, F_NAME, NAME_LENGTH); s->use_custom_message = true; } // see if we have a valid weapon s->weapon_info_index = -1; s->weapon_info_index = weapon_info_lookup(weapon_name); if(s->weapon_info_index >= 0){ // valid Ssm_info_count++; } } } }
void parse_autopilot_table(char *filename) { int rval; SCP_vector<SCP_string> lines; // open localization lcl_ext_open(); if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", (filename) ? filename : "<default autopilot.tbl>", rval)); lcl_ext_close(); return; } if (filename == NULL) read_file_text_from_array(defaults_get_file("autopilot.tbl")); else read_file_text(filename, CF_TYPE_TABLES); reset_parse(); required_string("#Autopilot"); // autopilot link distance required_string("$Link Distance:"); stuff_int(&NavLinkDistance); if (optional_string("$Interrupt autopilot if enemy within distance:")) stuff_int(&AutopilotMinEnemyDistance); else AutopilotMinEnemyDistance = 5000; if (optional_string("$Interrupt autopilot if asteroid within distance:")) stuff_int(&AutopilotMinAsteroidDistance); else AutopilotMinAsteroidDistance = 1000; if (optional_string("$Lock Weapons During Autopilot:")) stuff_boolean(&LockWeaponsDuringAutopilot); else LockWeaponsDuringAutopilot = false; // optional no cutscene bars if (optional_string("+No_Cutscene_Bars")) UseCutsceneBars = false; // optional no cutscene bars if (optional_string("+No_Autopilot_Interrupt")) Cmdline_autopilot_interruptable = 0; // No Nav selected message char *msg_tags[] = { "$No Nav Selected:", "$Gliding:", "$Too Close:", "$Hostiles:", "$Linked:", "$Hazard:", "$Support Present:", "$Support Working:" }; for (int i = 0; i < NP_NUM_MESSAGES; i++) { required_string(msg_tags[i]); required_string("+Msg:"); stuff_string(NavMsgs[i].message, F_MESSAGE, 256); required_string("+Snd File:"); stuff_string(NavMsgs[i].filename, F_NAME, 256); } required_string("#END"); // close localization lcl_ext_close(); }