// 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); required_string("+Radius:"); stuff_float(&s->radius); required_string("+Offset:"); stuff_float(&s->offset); // see if we have a valid weapon s->weapon_info_index = -1; s->weapon_info_index = weapon_name_lookup(weapon_name); if (s->weapon_info_index >= 0) { // valid Ssm_info_count++; } } } }
void parse_rank_tbl() { atexit(scoreing_close); char buf[MULTITEXT_LENGTH]; int rval, idx, persona; if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "rank.tbl", rval)); return; } read_file_text("rank.tbl", CF_TYPE_TABLES); reset_parse(); // parse in all the rank names idx = 0; skip_to_string("[RANK NAMES]"); ignore_white_space(); while ( required_string_either("#End", "$Name:") ) { Assert ( idx < NUM_RANKS ); required_string("$Name:"); stuff_string( Ranks[idx].name, F_NAME, NAME_LENGTH ); required_string("$Points:"); stuff_int( &Ranks[idx].points ); required_string("$Bitmap:"); stuff_string( Ranks[idx].bitmap, F_NAME, MAX_FILENAME_LEN ); required_string("$Promotion Voice Base:"); stuff_string( Ranks[idx].promotion_voice_base, F_NAME, MAX_FILENAME_LEN ); while (check_for_string("$Promotion Text:")) { required_string("$Promotion Text:"); stuff_string(buf, F_MULTITEXT, sizeof(buf)); drop_white_space(buf); compact_multitext_string(buf); persona = -1; if (optional_string("+Persona:")) { stuff_int(&persona); if (persona < 0) { Warning(LOCATION, "Debriefing text for %s rank is assigned to an invalid persona: %i (must be 0 or greater).\n", Ranks[idx].name, persona); continue; } } Ranks[idx].promotion_text[persona] = vm_strdup(buf); } if (Ranks[idx].promotion_text.find(-1) == Ranks[idx].promotion_text.end()) { Warning(LOCATION, "%s rank is missing default debriefing text.\n", Ranks[idx].name); Ranks[idx].promotion_text[-1] = ""; } idx++; } required_string("#End"); // be sure that all rank points are in order #ifndef NDEBUG for ( idx = 0; idx < NUM_RANKS-1; idx++ ) { if ( Ranks[idx].points >= Ranks[idx+1].points ) Int3(); } #endif }
void hud_shield_game_init() { char name[MAX_FILENAME_LEN+1] = ""; // read in hud.tbl read_file_text("hud.tbl"); reset_parse(); Hud_shield_filename_count = 0; required_string("#Shield Icons Begin"); while(!optional_string("#End")){ required_string("$Shield:"); stuff_string(name, F_NAME, NULL); // maybe store Assert(Hud_shield_filename_count < MAX_SHIELD_ICONS); if(Hud_shield_filename_count < MAX_SHIELD_ICONS){ strcpy(Hud_shield_filenames[Hud_shield_filename_count++], name); } } }
// ------------------------------------------------------------------------------------------------- // gamesnd_parse_soundstbl() will parse the sounds.tbl file, and load the specified sounds. // // void gamesnd_parse_soundstbl() { int rval; int num_game_sounds = 0; int num_iface_sounds = 0; // open localization lcl_ext_open(); gamesnd_init_sounds(); if ((rval = setjmp(parse_abort)) != 0) { Error(LOCATION, "Unable to parse sounds.tbl! Code = %i.\n", rval); } else { read_file_text("sounds.tbl"); reset_parse(); } // Parse the gameplay sounds section required_string("#Game Sounds Start"); while (required_string_either("#Game Sounds End","$Name:")) { Assert( num_game_sounds < MAX_GAME_SOUNDS); gamesnd_parse_line( &Snds[num_game_sounds], "$Name:" ); num_game_sounds++; } required_string("#Game Sounds End"); // Parse the interface sounds section required_string("#Interface Sounds Start"); while (required_string_either("#Interface Sounds End","$Name:")) { Assert( num_iface_sounds < MAX_INTERFACE_SOUNDS); gamesnd_parse_line(&Snds_iface[num_iface_sounds], "$Name:"); num_iface_sounds++; } required_string("#Interface Sounds End"); // parse flyby sound section required_string("#Flyby Sounds Start"); // read 2 terran sounds gamesnd_parse_line(&Snds_flyby[SPECIES_TERRAN][0], "$Terran:"); gamesnd_parse_line(&Snds_flyby[SPECIES_TERRAN][1], "$Terran:"); // 2 vasudan sounds gamesnd_parse_line(&Snds_flyby[SPECIES_VASUDAN][0], "$Vasudan:"); gamesnd_parse_line(&Snds_flyby[SPECIES_VASUDAN][1], "$Vasudan:"); gamesnd_parse_line(&Snds_flyby[SPECIES_SHIVAN][0], "$Shivan:"); gamesnd_parse_line(&Snds_flyby[SPECIES_SHIVAN][1], "$Shivan:"); required_string("#Flyby Sounds End"); // close localization lcl_ext_close(); }
void palman_load_pixels() { // open pixels.tbl read_file_text("pixels.tbl"); reset_parse(); // parse pixels while(!optional_string("#END")){ // nondarkening pixel if(required_string("+ND")){ stuff_byte(&Palman_non_darkening_default[Palman_num_nondarkening_default][0]); stuff_byte(&Palman_non_darkening_default[Palman_num_nondarkening_default][1]); stuff_byte(&Palman_non_darkening_default[Palman_num_nondarkening_default++][2]); } } // set this to be the active table palman_set_nondarkening(Palman_non_darkening_default, Palman_num_nondarkening_default); }
/** * Parse a sound effect entry by requiring the given tag at the beginning. * * @param gs The game_snd instance to fill in * @param tag The tag that's required before an entry * @param lookupVector If non-NULL used to look up @c +nocreate entries * * @return @c true when a new entry has been parsed and should be added to the list of known * entries. @c false otherwise, for example in case of @c +nocreate */ bool gamesnd_parse_line(game_snd *gs, const char *tag, SCP_vector<game_snd> *lookupVector = NULL) { Assertion(gs != NULL, "Invalid game_snd pointer passed to gamesnd_parse_line!"); required_string(tag); bool no_create = false; if (lookupVector != NULL) { if(optional_string("+nocreate")) { no_create = true; } } gamesnd_parse_entry(gs, no_create, lookupVector); return !no_create; }
// game init void ssm_init() { ssm_info bogus, *s; char weapon_name[NAME_LENGTH+1] = ""; read_file_text("ssm.tbl"); 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, NULL); // stuff data required_string("+Weapon:"); stuff_string(weapon_name, F_NAME, NULL); required_string("+Count:"); stuff_int(&s->count); required_string("+WarpRadius:"); stuff_float(&s->warp_radius); required_string("+WarpTime:"); stuff_float(&s->warp_time); required_string("+Radius:"); stuff_float(&s->radius); required_string("+Offset:"); stuff_float(&s->offset); // see if we have a valid weapon s->weapon_info_index = -1; s->weapon_info_index = weapon_name_lookup(weapon_name); if(s->weapon_info_index >= 0){ // valid Ssm_info_count++; } } } }
// ------------------------------------------------------------------------------------------------- // gamesnd_parse_line() // // Parse a sound effect line // void gamesnd_parse_line(game_snd *gs, char *tag) { int is_3d; required_string(tag); stuff_int(&gs->sig); stuff_string(gs->filename, F_NAME, ","); if ( !stricmp(gs->filename,NOX("empty")) ) { gs->filename[0] = 0; advance_to_eoln(NULL); return; } Mp++; stuff_int(&gs->preload); stuff_float(&gs->default_volume); stuff_int(&is_3d); if ( is_3d ) { gs->flags |= GAME_SND_USE_DS3D; stuff_int(&gs->min); stuff_int(&gs->max); } advance_to_eoln(NULL); }
/** * @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_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_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_species_tbl(const char *filename) { int i, rval; char species_name[NAME_LENGTH]; if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", (filename) ? filename : NOX("<default species_defs.tbl>"), rval)); return; } if (filename == NULL) read_file_text_from_array(defaults_get_file("species_defs.tbl")); else read_file_text(filename, CF_TYPE_TABLES); reset_parse(); // start parsing required_string("#SPECIES DEFS"); // no longer required: counted automatically if (optional_string("$NumSpecies:")) { int temp; stuff_int(&temp); } // begin reading data while (required_string_either("#END","$Species_Name:")) { bool no_create = false; species_info *species, new_species; species = &new_species; // Start Species - Get its name required_string("$Species_Name:"); stuff_string(species_name, F_NAME, NAME_LENGTH); if (optional_string("+nocreate")) { no_create = true; for (i = 0; i < (int)Species_info.size(); i++) { if (!stricmp(Species_info[i].species_name, species_name)) { species = &Species_info[i]; break; } } } else { strcpy_s(species->species_name, species_name); } // Goober5000 - IFF if (optional_string("$Default IFF:")) { bool iff_found = false; char temp_name[NAME_LENGTH]; stuff_string(temp_name, F_NAME, NAME_LENGTH); // search for it in iffs for (int iLoop = 0; iLoop < Num_iffs; iLoop++) { if (!stricmp(Iff_info[iLoop].iff_name, temp_name)) { species->default_iff = iLoop; iff_found = true; } } if (!iff_found) { species->default_iff = 0; Warning(LOCATION, "Species %s default IFF %s not found in iff_defs.tbl! Defaulting to %s.\n", species->species_name, temp_name, Iff_info[species->default_iff].iff_name); } } else if (!no_create) { // we have no idea which it could be, so default to 0 species->default_iff = 0; // let them know Warning(LOCATION, "$Default IFF not specified for species %s in species_defs.tbl! Defaulting to %s.\n", species->species_name, Iff_info[species->default_iff].iff_name); } // Goober5000 - FRED color if (optional_string("$FRED Color:") || optional_string("$FRED Colour:")) { stuff_int_list(species->fred_color.a1d, 3, RAW_INTEGER_TYPE); } else if (!no_create) { // set defaults to Volition's originals if (!stricmp(species->species_name, "Terran")) { species->fred_color.rgb.r = 0; species->fred_color.rgb.g = 0; species->fred_color.rgb.b = 192; } else if (!stricmp(species->species_name, "Vasudan")) { species->fred_color.rgb.r = 0; species->fred_color.rgb.g = 128; species->fred_color.rgb.b = 0; } else if (!stricmp(species->species_name, "Shivan")) { species->fred_color.rgb.r = 192; species->fred_color.rgb.g = 0; species->fred_color.rgb.b = 0; } else if (!stricmp(species->species_name, "Ancients") || !stricmp(species->species_name, "Ancient")) { species->fred_color.rgb.r = 192; species->fred_color.rgb.g = 0; species->fred_color.rgb.b = 192; } else { species->fred_color.rgb.r = 0; species->fred_color.rgb.g = 0; species->fred_color.rgb.b = 0; } // let them know Warning(LOCATION, "$FRED Color not specified for species %s in species_defs.tbl! Defaulting to (%d, %d, %d).\n", species->species_name, species->fred_color.rgb.r, species->fred_color.rgb.g, species->fred_color.rgb.b); } // stuff optional_string("$MiscAnims:"); // Get its Debris Texture if ((!no_create && required_string("+Debris_Texture:")) || optional_string("+Debris_Texture:")) { generic_bitmap_init(&species->debris_texture, NULL); stuff_string(species->debris_texture.filename, F_NAME, MAX_FILENAME_LEN); } // Shield Hit Animation if (optional_string("+Shield_Hit_ani:")) // Shouldn't be required -- LPine { generic_anim_init(&species->shield_anim, NULL); stuff_string(species->shield_anim.filename, F_NAME, MAX_FILENAME_LEN); } else if (!no_create) { species->shield_anim.filename[0] = '\0'; species->shield_anim.first_frame = -1; // Landmine to trip up anyone who does end up using this } // Thruster Anims parse_thrust_anims(species, no_create); // Thruster Glow Anims parse_thrust_glows(species, no_create); // Goober5000 - AWACS multiplier if (optional_string("$AwacsMultiplier:")) { stuff_float(&species->awacs_multiplier); } else if (!no_create) { // set defaults to Volition's originals if (!stricmp(species->species_name, "Vasudan")) species->awacs_multiplier = 1.25f; else if (!stricmp(species->species_name, "Shivan")) species->awacs_multiplier = 1.50f; else species->awacs_multiplier = 1.0f; // let them know Warning(LOCATION, "$AwacsMultiplier not specified for species %s in species_defs.tbl! Defaulting to %.2d.\n", species->species_name, species->awacs_multiplier); } // Goober5000 - countermeasure type // (we won't be able to resolve it until after we've parsed the weapons table) if (optional_string("$Countermeasure type:")) stuff_string(species->cmeasure_name, F_NAME, NAME_LENGTH); // don't add new entry if this is just a modified one if ( !no_create ) Species_info.push_back( new_species ); } required_string("#END"); // add tbl/tbm to multiplayer validation list extern void fs2netd_add_table_validation(const char *tblname); fs2netd_add_table_validation(filename); }
void parse_thrust_anims(species_info *species, bool no_create) { if (!no_create) { required_string("$ThrustAnims:"); generic_anim_init(&species->thruster_info.flames.normal, NULL); generic_anim_init(&species->thruster_info.flames.afterburn, NULL); generic_bitmap_init(&species->thruster_secondary_glow_info.normal, NULL); generic_bitmap_init(&species->thruster_secondary_glow_info.afterburn, NULL); generic_bitmap_init(&species->thruster_tertiary_glow_info.normal, NULL); generic_bitmap_init(&species->thruster_tertiary_glow_info.afterburn, NULL); generic_bitmap_init(&species->thruster_distortion_info.normal, NULL); generic_bitmap_init(&species->thruster_distortion_info.afterburn, NULL); } else if (!optional_string("$ThrustAnims:")) { return; } // favor new style if (no_create) { if (optional_string("+Pri_Normal:") || optional_string("+Normal:")) stuff_string(species->thruster_info.flames.normal.filename, F_NAME, MAX_FILENAME_LEN); } else { if (!optional_string("+Pri_Normal:")) required_string("+Normal:"); stuff_string(species->thruster_info.flames.normal.filename, F_NAME, MAX_FILENAME_LEN); } // if no primary thruster anim is wanted then clear it if ( !VALID_FNAME(species->thruster_info.flames.normal.filename) ) generic_anim_init(&species->thruster_info.flames.normal, NULL); // and again if (no_create) { if (optional_string("+Pri_Afterburn:") || optional_string("+Afterburn:")) stuff_string(species->thruster_info.flames.afterburn.filename, F_NAME, MAX_FILENAME_LEN); } else { if (!optional_string("+Pri_Afterburn:")) required_string("+Afterburn:"); stuff_string(species->thruster_info.flames.afterburn.filename, F_NAME, MAX_FILENAME_LEN); } // if no primary thruster anim is wanted then clear it if ( !VALID_FNAME(species->thruster_info.flames.afterburn.filename) ) generic_anim_init(&species->thruster_info.flames.afterburn, NULL); // extra thruster stuff, bah if (optional_string("+Sec_Normal:")) stuff_string(species->thruster_secondary_glow_info.normal.filename, F_NAME, MAX_FILENAME_LEN); // etc. if (optional_string("+Sec_Afterburn:")) stuff_string(species->thruster_secondary_glow_info.afterburn.filename, F_NAME, MAX_FILENAME_LEN); // etc. if (optional_string("+Ter_Normal:")) stuff_string(species->thruster_tertiary_glow_info.normal.filename, F_NAME, MAX_FILENAME_LEN); // etc. if (optional_string("+Ter_Afterburn:")) stuff_string(species->thruster_tertiary_glow_info.afterburn.filename, F_NAME, MAX_FILENAME_LEN); // etc. if (optional_string("+Dist_Normal:")) stuff_string(species->thruster_distortion_info.normal.filename, F_NAME, MAX_FILENAME_LEN); // etc. if (optional_string("+Dist_Afterburn:")) stuff_string(species->thruster_distortion_info.afterburn.filename, F_NAME, MAX_FILENAME_LEN); }
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_sound_environments() { char name[65] = { '\0' }; char template_name[65] = { '\0' }; EFXREVERBPROPERTIES *props; while (required_string_either("#Sound Environments End", "$Name:")) { required_string("$Name:"); stuff_string(name, F_NAME, sizeof(name)-1); if (optional_string("$Template:")) { stuff_string(template_name, F_NAME, sizeof(template_name)-1); } else { template_name[0] = '\0'; } ds_eax_get_prop(&props, name, template_name); if (optional_string("+Density:")) { stuff_float(&props->flDensity); CLAMP(props->flDensity, 0.0f, 1.0f); } if (optional_string("+Diffusion:")) { stuff_float(&props->flDiffusion); CLAMP(props->flDiffusion, 0.0f, 1.0f); } if (optional_string("+Gain:")) { stuff_float(&props->flGain); CLAMP(props->flGain, 0.0f, 1.0f); } if (optional_string("+Gain HF:")) { stuff_float(&props->flGainHF); CLAMP(props->flGainHF, 0.0f, 1.0f); } if (optional_string("+Gain LF:")) { stuff_float(&props->flGainLF); CLAMP(props->flGainLF, 0.0f, 1.0f); } if (optional_string("+Decay Time:")) { stuff_float(&props->flDecayTime); CLAMP(props->flDecayTime, 0.01f, 20.0f); } if (optional_string("+Decay HF Ratio:")) { stuff_float(&props->flDecayHFRatio); CLAMP(props->flDecayHFRatio, 0.1f, 20.0f); } if (optional_string("+Decay LF Ratio:")) { stuff_float(&props->flDecayLFRatio); CLAMP(props->flDecayLFRatio, 0.1f, 20.0f); } if (optional_string("+Reflections Gain:")) { stuff_float(&props->flReflectionsGain); CLAMP(props->flReflectionsGain, 0.0f, 3.16f); } if (optional_string("+Reflections Delay:")) { stuff_float(&props->flReflectionsDelay); CLAMP(props->flReflectionsDelay, 0.0f, 0.3f); } if (optional_string("+Reflections Pan:")) { stuff_float_list(props->flReflectionsPan, 3); CLAMP(props->flReflectionsPan[0], 0.0f, 1.0f); CLAMP(props->flReflectionsPan[1], 0.0f, 1.0f); CLAMP(props->flReflectionsPan[2], 0.0f, 1.0f); } if (optional_string("+Late Reverb Gain:")) { stuff_float(&props->flLateReverbGain); CLAMP(props->flLateReverbGain, 0.0f, 10.0f); } if (optional_string("+Late Reverb Delay:")) { stuff_float(&props->flLateReverbDelay); CLAMP(props->flLateReverbDelay, 0.0f, 0.1f); } if (optional_string("+Late Reverb Pan:")) { stuff_float_list(props->flLateReverbPan, 3); CLAMP(props->flLateReverbPan[0], 0.0f, 1.0f); CLAMP(props->flLateReverbPan[1], 0.0f, 1.0f); CLAMP(props->flLateReverbPan[2], 0.0f, 1.0f); } if (optional_string("+Echo Time:")) { stuff_float(&props->flEchoTime); CLAMP(props->flEchoTime, 0.075f, 0.25f); } if (optional_string("+Echo Depth:")) { stuff_float(&props->flEchoDepth); CLAMP(props->flEchoDepth, 0.0f, 1.0f); } if (optional_string("+Modulation Time:")) { stuff_float(&props->flModulationTime); CLAMP(props->flModulationTime, 0.004f, 4.0f); } if (optional_string("+Modulation Depth:")) { stuff_float(&props->flModulationDepth); CLAMP(props->flModulationDepth, 0.0f, 1.0f); } if (optional_string("+HF Reference:")) { stuff_float(&props->flHFReference); CLAMP(props->flHFReference, 1000.0f, 20000.0f); } if (optional_string("+LF Reference:")) { stuff_float(&props->flLFReference); CLAMP(props->flLFReference, 20.0f, 1000.0f); } if (optional_string("+Room Rolloff Factor:")) { stuff_float(&props->flRoomRolloffFactor); CLAMP(props->flRoomRolloffFactor, 0.0f, 10.0f); } if (optional_string("+Air Absorption Gain HF:")) { stuff_float(&props->flAirAbsorptionGainHF); CLAMP(props->flAirAbsorptionGainHF, 0.892f, 1.0f); } if (optional_string("+Decay HF Limit:")) { stuff_int(&props->iDecayHFLimit); CLAMP(props->iDecayHFLimit, 0, 1); } } required_string("#Sound Environments End"); }
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); }
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_colors(const char *filename) { Assertion(filename != NULL, "parse_colors() called on NULL; get a coder!\n"); read_file_text(filename, CF_TYPE_TABLES); int err_code; if ((err_code = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %d.\n", filename, err_code)); return; } reset_parse(); // we search for the colors based on their order of definition above // if the color isn't found, we just use default values if (optional_string("#Start Colors")) { // vars for holding rgba values int rgba[4] = {0,0,0,0}; int i, j; char* color_names[TOTAL_COLORS] = { "$Blue:", "$Bright Blue:", "$Green:", "$Bright Green:", "$Black:", "$Grey:", "$Silver:", "$White:", "$Bright White:", "$Violet Gray:", "$Violet:", "$Dim Red:", "$Red:", "$Bright Red:", "$Pink:", "$Light Pink:", "$Yellow:", "$Bright Yellow:", "$UI Light Green:", "$UI Green:", "$UI Light Pink:", "$UI Pink:" }; // now for each color, check if it's corresponding string is there for (i = 0; i < TOTAL_COLORS; i++) { if (optional_string(color_names[i])) { // if so, get its rgba values and initialise it using them mprintf(("'%s' has been redefined.\n", color_names[i])); //if (check_for_string("(")) { stuff_int_list(rgba, 4, RAW_INTEGER_TYPE); for (j = 0; j < 4; j++) { if (rgba[j] < 0) { Warning(LOCATION, "RGBA value for '%s' in %s too low (%d), capping to 0.\n", color_names[i], filename, rgba[j]); rgba[j] = 0; } else if (rgba[j] > 255) { Warning(LOCATION, "RGBA value for '%s' in %s too high (%d), capping to 255.\n", color_names[i], filename, rgba[j]); rgba[j] = 255; } } //} else { // stuff_hex_list(rgba, 4); //} gr_init_alphacolor(COLOR_LIST[i], rgba[0], rgba[1], rgba[2], rgba[3]); } } required_string("#End"); } }
void parse_medal_tbl() { int rval, i; int num_badges = 0; // open localization lcl_ext_open(); if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "medals.tbl", rval)); lcl_ext_close(); return; } read_file_text("medals.tbl", CF_TYPE_TABLES); reset_parse(); // parse in all the rank names Num_medals = 0; required_string("#Medals"); while (required_string_either("#End", "$Name:")) { medal_stuff temp_medal; required_string("$Name:"); stuff_string(temp_medal.name, F_NAME, NAME_LENGTH); required_string("$Bitmap:"); stuff_string(temp_medal.bitmap, F_NAME, MAX_FILENAME_LEN); required_string("$Num mods:"); stuff_int(&temp_medal.num_versions); // 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]; 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); //stuff_string(Badge_info[bi].wave2, F_NAME, NULL, MAX_FILENAME_LEN); if (optional_string("$Wavefile Base:")) stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN); //required_string("$Wavefile 2:"); //stuff_string(Badge_info[bi].wave2, F_NAME, NULL, MAX_FILENAME_LEN); required_string("$Promotion Text:"); stuff_string(buf, F_MULTITEXT, sizeof(buf)); temp_medal.promotion_text = vm_strdup(buf); // since badges (ace ranks) are handled a little differently we need to know // which we are in the list of badges. temp_medal.badge_num = num_badges++; } Medals.push_back(temp_medal); } required_string("#End"); Num_medals = Medals.size(); Assert(Num_medals == MAX_MEDALS); // 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; } // close localization lcl_ext_close(); }
void script_parse_table(char* filename) { script_state* st = &Script_system; int rval; if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval)); return; } read_file_text(filename, CF_TYPE_TABLES); reset_parse(); if (optional_string("#Global Hooks")) { //int num = 42; //Script_system.SetHookVar("Version", 'i', &num); if (optional_string("$Global:")) { Script_globalhook = st->ParseChunk("Global"); } if (optional_string("$Splash:")) { Script_splashhook = st->ParseChunk("Splash"); } if (optional_string("$GameInit:")) { Script_gameinithook = st->ParseChunk("GameInit"); } if (optional_string("$Simulation:")) { Script_simulationhook = st->ParseChunk("Simulation"); } if (optional_string("$HUD:")) { Script_hudhook = st->ParseChunk("HUD"); } required_string("#End"); } /* if(optional_string("#State Hooks")) { while(optional_string("$State:")) { char buf[NAME_LENGTH]; int idx; stuff_string(buf, F_NAME, sizeof(buf)); idx = gameseq_get_state_idx(buf); if(optional_string("$Hook:")) { if(idx > -1) { GS_state_hooks[idx] = st->ParseChunk(buf); } else { st->ParseChunk(buf); } } } required_string("#End"); } */ if (optional_string("#Conditional Hooks")) { while (st->ParseCondition(filename)); required_string("#End"); } // add tbl/tbm to multiplayer validation list extern void fs2netd_add_table_validation(char* tblname); fs2netd_add_table_validation(filename); }
/** * 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; } }
bool generate() { code_.Clear(); code_ += "{"; code_ += " \"$schema\": \"http://json-schema.org/draft-04/schema#\","; code_ += " \"definitions\": {"; for (auto e = parser_.enums_.vec.cbegin(); e != parser_.enums_.vec.cend(); ++e) { code_ += " \"" + GenFullName(*e) + "\" : {"; code_ += " " + GenType("string") + ","; std::string enumdef(" \"enum\": ["); for (auto enum_value = (*e)->vals.vec.begin(); enum_value != (*e)->vals.vec.end(); ++enum_value) { enumdef.append("\"" + (*enum_value)->name + "\""); if (*enum_value != (*e)->vals.vec.back()) { enumdef.append(", "); } } enumdef.append("]"); code_ += enumdef; code_ += " },"; // close type } for (auto s = parser_.structs_.vec.cbegin(); s != parser_.structs_.vec.cend(); ++s) { const auto &structure = *s; code_ += " \"" + GenFullName(structure) + "\" : {"; code_ += " " + GenType("object") + ","; std::string comment; const auto &comment_lines = structure->doc_comment; for (auto comment_line = comment_lines.cbegin(); comment_line != comment_lines.cend(); ++comment_line) { comment.append(*comment_line); } if (comment.size() > 0) { code_ += " \"description\" : \"" + comment + "\","; } code_ += " \"properties\" : {"; const auto &properties = structure->fields.vec; for (auto prop = properties.cbegin(); prop != properties.cend(); ++prop) { const auto &property = *prop; std::string typeLine(" \"" + property->name + "\" : { " + GenType(property->value.type) + " }"); if (property != properties.back()) { typeLine.append(","); } code_ += typeLine; } code_ += " },"; // close properties std::vector<FieldDef *> requiredProperties; std::copy_if(properties.begin(), properties.end(), back_inserter(requiredProperties), [](FieldDef const *prop) { return prop->required; }); if (requiredProperties.size() > 0) { std::string required_string(" \"required\" : ["); for (auto req_prop = requiredProperties.cbegin(); req_prop != requiredProperties.cend(); ++req_prop) { required_string.append("\"" + (*req_prop)->name + "\""); if (*req_prop != requiredProperties.back()) { required_string.append(", "); } } required_string.append("],"); code_ += required_string; } code_ += " \"additionalProperties\" : false"; std::string closeType(" }"); if (*s != parser_.structs_.vec.back()) { closeType.append(","); } code_ += closeType; // close type } code_ += " },"; // close definitions // mark root type code_ += " \"$ref\" : \"#/definitions/" + GenFullName(parser_.root_struct_def_) + "\""; code_ += "}"; // close schema root const std::string file_path = GeneratedFileName(path_, file_name_); const std::string final_code = code_.ToString(); return SaveFile(file_path.c_str(), final_code, false); }
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; } }
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; } }
// parses help.tbl and populates help_overlaylist[] void parse_helptbl(const char *filename) { int overlay_id, currcount, vtxcount; char name[HELP_MAX_NAME_LENGTH]; char buf[HELP_MAX_STRING_LENGTH + 1]; int i, j, rval; SCP_vector<help_pline> pline_temp; help_pline pline_temp2; SCP_vector<help_text> text_temp; help_text text_temp2; SCP_vector<help_right_bracket> rbracket_temp; help_right_bracket rbracket_temp2; SCP_vector<help_left_bracket> lbracket_temp; help_left_bracket lbracket_temp2; vec3d vec3d_temp; if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval)); return; } read_file_text(filename, CF_TYPE_TABLES); reset_parse(); // for each overlay... while (optional_string("$")) { stuff_string(name, F_NAME, HELP_MAX_NAME_LENGTH); overlay_id = help_overlay_get_index(name); if (overlay_id < 0) { if (num_help_overlays >= MAX_HELP_OVERLAYS) { Warning(LOCATION, "Could not load help overlay after '%s' as maximum number of help overlays was reached (Max is %d)", help_overlaylist[overlay_id - 1].name, MAX_HELP_OVERLAYS); if (!skip_to_string("$end")) { Error(LOCATION, "Couldn't find $end. Help.tbl or -hlp.tbm is invalid.\n"); } continue; } else { overlay_id = num_help_overlays; strcpy_s(help_overlaylist[overlay_id].name, name); num_help_overlays++; } } // clear out counters in the overlay struct help_overlaylist[overlay_id].plinecount = 0; help_overlaylist[overlay_id].textcount = 0; help_overlaylist[overlay_id].rbracketcount = 0; help_overlaylist[overlay_id].lbracketcount = 0; help_overlaylist[overlay_id].fontlist.clear(); help_overlaylist[overlay_id].plinelist.clear(); help_overlaylist[overlay_id].textlist.clear(); help_overlaylist[overlay_id].rbracketlist.clear(); help_overlaylist[overlay_id].lbracketlist.clear(); if (optional_string("+resolutions")) { stuff_int(&help_overlaylist[overlay_id].num_resolutions); } else { help_overlaylist[overlay_id].num_resolutions = 2; } if (help_overlaylist[overlay_id].num_resolutions < 1) { Error(LOCATION, "+resolutions in %s is %d. (Must be 1 or greater)", filename, help_overlaylist[overlay_id].num_resolutions); } if (optional_string("+font")) { int font; for (i=0; i<help_overlaylist[overlay_id].num_resolutions; i++) { stuff_int(&font); help_overlaylist[overlay_id].fontlist.push_back(font); } } else { for (i=0; i<help_overlaylist[overlay_id].num_resolutions; i++) { help_overlaylist[overlay_id].fontlist.push_back(FONT1); } } for (i=0; i<help_overlaylist[overlay_id].num_resolutions; i++) { help_overlaylist[overlay_id].plinelist.push_back(pline_temp); help_overlaylist[overlay_id].textlist.push_back(text_temp); help_overlaylist[overlay_id].rbracketlist.push_back(rbracket_temp); help_overlaylist[overlay_id].lbracketlist.push_back(lbracket_temp); } int type; // read in all elements for this overlay while ((type = required_string_one_of(5, "+pline", "+text", "+right_bracket", "+left_bracket", "$end")) != 4) { // Doing it this way means an error lists "$end" at the end, which seems appropriate. -MageKing17 switch (type) { case 0: // +pline required_string("+pline"); currcount = help_overlaylist[overlay_id].plinecount; int a, b; // temp vars to read in int before cast to float; // read number of pline vertices stuff_int(&vtxcount); // get vertex coordinates for each resolution for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) { help_overlaylist[overlay_id].plinelist.at(i).push_back(pline_temp2); for (j = 0; j < vtxcount; j++) { help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.push_back(vec3d_temp); help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtxcount = vtxcount; stuff_int(&a); stuff_int(&b); help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.at(j).xyz.x = (float)a; help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.at(j).xyz.y = (float)b; help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.at(j).xyz.z = 0.0f; } } help_overlaylist[overlay_id].plinecount++; break; case 1: // +text required_string("+text"); currcount = help_overlaylist[overlay_id].textcount; // get coordinates for each resolution for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) { help_overlaylist[overlay_id].textlist.at(i).push_back(text_temp2); stuff_int(&(help_overlaylist[overlay_id].textlist.at(i).at(currcount).x_coord)); stuff_int(&(help_overlaylist[overlay_id].textlist.at(i).at(currcount).y_coord)); } // get string (always use the first resolution) stuff_string(buf, F_MESSAGE, sizeof(buf)); help_overlaylist[overlay_id].textlist.at(0).at(currcount).string = vm_strdup(buf); help_overlaylist[overlay_id].textcount++; break; case 2: // +right_bracket required_string("+right_bracket"); currcount = help_overlaylist[overlay_id].rbracketcount; // get coordinates for each resolution for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) { help_overlaylist[overlay_id].rbracketlist.at(i).push_back(rbracket_temp2); stuff_int(&(help_overlaylist[overlay_id].rbracketlist.at(i).at(currcount).x_coord)); stuff_int(&(help_overlaylist[overlay_id].rbracketlist.at(i).at(currcount).y_coord)); } help_overlaylist[overlay_id].rbracketcount++; break; case 3: // +left_bracket required_string("+left_bracket"); currcount = help_overlaylist[overlay_id].lbracketcount; // get coordinates for each resolution for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) { help_overlaylist[overlay_id].lbracketlist.at(i).push_back(lbracket_temp2); stuff_int(&(help_overlaylist[overlay_id].lbracketlist.at(i).at(currcount).x_coord)); stuff_int(&(help_overlaylist[overlay_id].lbracketlist.at(i).at(currcount).y_coord)); } help_overlaylist[overlay_id].lbracketcount++; break; case -1: // -noparseerrors is set break; case 4: // $end default: Assertion(false, "This should never happen.\n"); break; } } // end while required_string("$end"); } // end while }
// ------------------------------------------------------------------------------------------------- // gamesnd_parse_soundstbl() will parse the sounds.tbl file, and load the specified sounds. // // void gamesnd_parse_soundstbl() { int rval; int num_game_sounds = 0; int num_iface_sounds = 0; int i; char cstrtemp[NAME_LENGTH+3]; char* missing_species_names = NULL; ubyte* missing_species = NULL; int sanity_check = 0; gamesnd_init_sounds(); // open localization lcl_ext_open(); if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "sounds.tbl", rval)); lcl_ext_close(); return; } read_file_text("sounds.tbl", CF_TYPE_TABLES); reset_parse(); // Parse the gameplay sounds section required_string("#Game Sounds Start"); while (required_string_either("#Game Sounds End", "$Name:")) { Assert(num_game_sounds < Num_game_sounds); gamesnd_parse_line(&Snds[num_game_sounds], "$Name:"); num_game_sounds++; gamesnd_add_sound_slot(GAME_SND, num_game_sounds); } required_string("#Game Sounds End"); // Parse the interface sounds section required_string("#Interface Sounds Start"); while (required_string_either("#Interface Sounds End", "$Name:")) { Assert(num_iface_sounds < Num_iface_sounds); gamesnd_parse_line(&Snds_iface[num_iface_sounds], "$Name:"); num_iface_sounds++; gamesnd_add_sound_slot(IFACE_SND, num_iface_sounds); } required_string("#Interface Sounds End"); // parse flyby sound section required_string("#Flyby Sounds Start"); missing_species_names = new char[Species_info.size() * (NAME_LENGTH + 2)]; missing_species = new ubyte[Species_info.size()]; memset(missing_species_names, 0, Species_info.size() * (NAME_LENGTH + 2)); memset(missing_species, 1, Species_info.size()); // assume they are all missing while (!check_for_string("#Flyby Sounds End") && (sanity_check <= (int)Species_info.size())) { for (i = 0; i < (int)Species_info.size(); i++) { species_info* species = &Species_info[i]; sprintf(cstrtemp, "$%s:", species->species_name); if (check_for_string(cstrtemp)) { gamesnd_parse_line(&species->snd_flyby_fighter, cstrtemp); gamesnd_parse_line(&species->snd_flyby_bomber, cstrtemp); missing_species[i] = 0; sanity_check--; } else { sanity_check++; } } } // if we are missing any species then report it for (i = 0; i < (int)Species_info.size(); i++) { if (missing_species[i]) { strcat(missing_species_names, Species_info[i].species_name); strcat(missing_species_names, "\n"); } } if (strlen(missing_species_names)) { Error(LOCATION, "The following species are missing flyby sounds in sounds.tbl:\n%s", missing_species_names); } delete[] missing_species_names; delete[] missing_species; required_string("#Flyby Sounds End"); // close localization lcl_ext_close(); }
void parse_everything_else(const char *filename) { Assertion(filename != NULL, "parse_everything_else() called on NULL; get a coder!\n"); read_file_text(filename, CF_TYPE_TABLES); int err_code; if ((err_code = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %d.\n", filename, err_code)); return; } reset_parse(); int rgba[4] = {0,0,0,0}; // reusable temp vars int i, j; SCP_string temp; if (optional_string("#Start Colors")) { // Skip this section; we already parsed it in every file. skip_to_string("#End", NULL); } //Team coloring if (optional_string("#Team Colors")) { while (required_string_either("#End", "$Team Name:")) { required_string("$Team Name:"); // required to move the parse pointer forward team_color temp_color; char temp2[NAME_LENGTH]; stuff_string(temp2, F_NAME, NAME_LENGTH); temp = temp2; if (!stricmp(temp2, "none")) { Warning(LOCATION, "Team color in '%s' defined with a name of '%s'; this won't be usable due to 'None' being used for a lack of a team color by the engine.\n", filename, temp2); } if (required_string("$Team Stripe Color:")) { int rgb[3]; stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); for (i = 0; i < 3; i++) { CLAMP(rgb[i], 0, 255); } temp_color.stripe.r = rgb[0] / 255.0f; temp_color.stripe.g = rgb[1] / 255.0f; temp_color.stripe.b = rgb[2] / 255.0f; } if (required_string("$Team Base Color:")) { int rgb[3]; stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); for (i = 0; i < 3; i++) { CLAMP(rgb[i], 0, 255); } temp_color.base.r = rgb[0] / 255.0f; temp_color.base.g = rgb[1] / 255.0f; temp_color.base.b = rgb[2] / 255.0f; } if (Team_Colors.find(temp) == Team_Colors.end()) { // Only push to the vector if the team isn't already defined. Team_Names.push_back(temp); } Team_Colors[temp] = temp_color; } required_string("#End"); } // Previously-hardcoded interface colors if (optional_string("#Interface Colors")) { char *color_names[INTERFACE_COLORS] = { "$Text Normal:", "$Text Subselected:", "$Text Selected:", "$Text Error:", "$Text Error Highlighted:", "$Text Active:", "$Text Active Highlighted:", "$Text Heading:", "$More Indicator:", "$Bright More Indicator:", "$Bright:", "$Normal:", }; // now for each color, check if its corresponding string is there for (i = 0; i < INTERFACE_COLORS; i++) { if (optional_string(color_names[i])) { // if so, get its rgba values and initialise it using them mprintf(("'%s' has been redefined.\n", color_names[i])); if ( check_for_string("(") ) { // If we have a list of integers, use them. stuff_int_list(rgba, 4, RAW_INTEGER_TYPE); for (j = 0; j < 4; j++) { if (rgba[j] < 0) { Warning(LOCATION, "RGBA value for '%s' in %s too low (%d), capping to 0.\n", color_names[i], filename, rgba[j]); rgba[j] = 0; } else if (rgba[j] > 255) { Warning(LOCATION, "RGBA value for '%s' in %s too high (%d), capping to 255.\n", color_names[i], filename, rgba[j]); rgba[j] = 255; } } gr_init_alphacolor(interface_colors[i], rgba[0], rgba[1], rgba[2], rgba[3]); //} else if (check_for_string("#")) { // stuff_hex_list(rgba, 4); // gr_init_alphacolor(interface_colors[i], rgba[0], rgba[1], rgba[2], rgba[3]); } else { // We have a string; it should be the name of a color to use. stuff_string(temp, F_NAME); for (j = 0; j < TOTAL_COLORS; j++) { if ( !temp.compare(COLOR_NAMES[j]) ) { break; } } if ( j == TOTAL_COLORS ) { Warning(LOCATION, "Unknown color '%s' in %s, for definition of '%s'; using default ('%s').\n", temp.c_str(), filename, color_names[i], COLOR_NAMES[interface_defaults[i]]); } else { Assertion(j >= 0 && j < TOTAL_COLORS, "Attempting to copy nonexistant color (%d out of 0-%d)!\n", j, TOTAL_COLORS-1); memcpy(interface_colors[i], COLOR_LIST[j], sizeof(color)); } } } } required_string("#End"); } // Text color tags; for briefings, command briefings, debriefings, and the fiction viewer if (optional_string("#Color Tags")) { while (required_string_either("$Tag:", "#End") < 1) { required_string("$Tag:"); color temp_color; char tag; stuff_string(temp, F_RAW); if (temp[0] == '$') { if (temp[1] == '\0') { Error(LOCATION, "%s - found a '$Tag:' entry with a solitary '$'.\n", filename); } tag = temp[1]; if (temp[2] != '\0') { Warning(LOCATION, "%s - tag '$%c' has extra text in its definition.\n", filename, tag); } } else if (temp[0] == '\0') { Error(LOCATION, "%s - found a '$Tag:' entry with no tag.\n", filename); } else { tag = temp[0]; if (temp[1] != '\0') { Warning(LOCATION, "%s - tag '$%c' has extra text in its definition.\n", filename, tag); } } if (Tagged_Colors.find(tag) == Tagged_Colors.end()) { // Only push the tag to our list of tags if it's actually new, not just a redefinition. Color_Tags.push_back(tag); } switch(required_string_one_of(4, "+Color:", "+Friendly", "+Hostile", "+Neutral")) { case 0: // +Color required_string("+Color:"); rgba[0] = rgba[1] = rgba[2] = 0; rgba[3] = 255; // Odds are pretty high you want it to have full alpha... if ( check_for_string("(") ) { stuff_int_list(rgba, 4, RAW_INTEGER_TYPE); for (j = 0; j < 4; j++) { if (rgba[j] < 0) { Warning(LOCATION, "RGBA value for '$%c' in %s too low (%d), capping to 0.\n", tag, filename, rgba[j]); rgba[j] = 0; } else if (rgba[j] > 255) { Warning(LOCATION, "RGBA value for '$%c' in %s too high (%d), capping to 255.\n", tag, filename, rgba[j]); rgba[j] = 255; } } gr_init_alphacolor(&temp_color, rgba[0], rgba[1], rgba[2], rgba[3]); Custom_Colors[tag] = temp_color; Tagged_Colors[tag] = &Custom_Colors[tag]; //} else if ( check_for_string ("#") ) { // stuff_hex_list(rgba, 4); // gr_init_alphacolor(&temp_color, rgba[0], rgba[1], rgba[2], rgba[3]); // Custom_Colors[tag] = temp_color; // Tagged_Colors[tag] = &Custom_Colors[tag]; } else { // We have a string; it should be the name of a color to use. stuff_string(temp, F_NAME); for (j = 0; j < TOTAL_COLORS; j++) { if ( !temp.compare(COLOR_NAMES[j]) ) { break; } } if ( j == TOTAL_COLORS ) { Error(LOCATION, "Unknown color '%s' in %s, for definition of tag '$%c'.\n", temp.c_str(), filename, tag); } Tagged_Colors[tag] = COLOR_LIST[j]; } break; case 1: // +Friendly required_string("+Friendly"); Tagged_Colors[tag] = &Brief_color_green; break; case 2: // +Hostile required_string("+Hostile"); Tagged_Colors[tag] = &Brief_color_red; break; case 3: // +Neutral required_string("+Neutral"); Tagged_Colors[tag] = &Brief_color_legacy_neutral; break; case -1: // -noparseerrors is set if (Tagged_Colors.find(tag) == Tagged_Colors.end()) { // It was a new color, but since we haven't actually defined it... Color_Tags.pop_back(); } break; default: Assertion(false, "MageKing17 made a coding error somewhere, and you should laugh at him (and report this error).\n"); break; } } required_string("#End"); } Assertion(Color_Tags.size() == Tagged_Colors.size(), "Color_Tags and Tagged_Colors size mismatch; get a coder!\n"); if (optional_string("#Default Text Colors")) { char* color_names[MAX_DEFAULT_TEXT_COLORS] = { "$Fiction Viewer:", "$Command Briefing:", "$Briefing:", "$Redalert Briefing:", "$Debriefing:", "$Recommendation:", "$Loop Briefing:", }; char *color_value[MAX_DEFAULT_TEXT_COLORS] = { &default_fiction_viewer_color, &default_command_briefing_color, &default_briefing_color, &default_redalert_briefing_color, &default_debriefing_color, &default_recommendation_color, &default_loop_briefing_color, }; for (i = 0; i < MAX_DEFAULT_TEXT_COLORS; i++) { if ( optional_string(color_names[i]) ) { stuff_string(temp, F_RAW); if (temp[0] == '$') { if (temp[1] == '\0') { Error(LOCATION, "%s - default text color '%s' entry with a solitary '$'.\n", filename, color_names[i]); } *color_value[i] = temp[1]; if (temp[2] != '\0') { Warning(LOCATION, "%s - default text color '%s' has extra text after the tag '$%c'.\n", filename, color_names[i], *color_value[i]); } } else if (temp[0] == '\0') { Error(LOCATION, "%s - default text color '%s' entry with no tag.\n", filename, color_names[i]); } else { *color_value[i] = temp[0]; if (temp[1] != '\0') { Warning(LOCATION, "%s - default text color '%s' has extra text after the tag '$%c'.\n", filename, color_names[i], *color_value[i]); } } if (Tagged_Colors.find(*color_value[i]) == Tagged_Colors.end()) { // Just mprintf() this information instead of complaining with a Warning(); the tag might be defined in a later-loading TBM, and if it isn't, nothing too terrible will happen. mprintf(("%s - default text color '%s' set to non-existant tag '$%c'.\n", filename, color_names[i], *color_value[i])); } } } required_string("#End"); } }
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; } }
// initialization stuff for cutscenes void cutscene_init() { atexit(cutscene_close); char buf[MULTITEXT_LENGTH]; int rval; cutscene_info cutinfo; // open localization lcl_ext_open(); if ((rval = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "cutscenes.tbl", rval)); lcl_ext_close(); 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:") ) { memset(&cutinfo, 0, sizeof(cutscene_info)); 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); required_string("$cd:"); stuff_int( &cutinfo.cd ); 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"); // close localization lcl_ext_close(); }
void parse_sound_table(const char* filename) { try { read_file_text(filename, CF_TYPE_TABLES); reset_parse(); // Parse the gameplay sounds section if (optional_string("#Game Sounds Start")) { while (!check_for_string("#Game Sounds End")) { game_snd tempSound; if (gamesnd_parse_line(&tempSound, "$Name:", &Snds)) { Snds.push_back(game_snd(tempSound)); } } required_string("#Game Sounds End"); } // Parse the interface sounds section if (optional_string("#Interface Sounds Start")) { while (!check_for_string("#Interface Sounds End")) { game_snd tempSound; if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface)) { Snds_iface.push_back(game_snd(tempSound)); Snds_iface_handle.push_back(-1); } } required_string("#Interface Sounds End"); } // parse flyby sound section if (optional_string("#Flyby Sounds Start")) { char species_name_tag[NAME_LENGTH + 2]; int sanity_check = 0; size_t i; while (!check_for_string("#Flyby Sounds End") && (sanity_check <= (int)Species_info.size())) { for (i = 0; i < Species_info.size(); i++) { species_info *species = &Species_info[i]; sprintf(species_name_tag, "$%s:", species->species_name); if (check_for_string(species_name_tag)) { gamesnd_parse_line(&species->snd_flyby_fighter, species_name_tag); gamesnd_parse_line(&species->snd_flyby_bomber, species_name_tag); sanity_check--; } else { sanity_check++; } } } required_string("#Flyby Sounds End"); } if (optional_string("#Sound Environments Start")) { parse_sound_environments(); } } catch (const parse::ParseException& e) { mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what())); return; } gamesnd_add_retail_default_enhanced_sound_data(); }