diff --git a/code/mission/missionparse.cpp b/code/mission/missionparse.cpp index 086d27f3bc6..6c065fc9b00 100644 --- a/code/mission/missionparse.cpp +++ b/code/mission/missionparse.cpp @@ -2865,7 +2865,7 @@ bool p_object::has_display_name() { return flags[Mission::Parse_Object_Flags::SF_Has_display_name]; } -extern int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, const char *info_type_name, const char *sip_name); +extern int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, const char *info_type_name, const char *sip_name, bool set_special_warp_physics = false); /** * Mp points at the text of an object, which begins with the "$Name:" field. diff --git a/code/parse/parselo.cpp b/code/parse/parselo.cpp index edd121a4a8f..ef7c3d812fc 100644 --- a/code/parse/parselo.cpp +++ b/code/parse/parselo.cpp @@ -2845,20 +2845,35 @@ void stuff_boolean_flag(int *i, int flag, bool a_to_eol) // Stuffs a boolean value pointed at by Mp. // YES/NO (supporting 1/0 now as well) // Now supports localization :) -WMC - void stuff_boolean(bool *b, bool a_to_eol) { - char token[32]; - stuff_string_white(token, sizeof(token)/sizeof(char)); + char token[NAME_LENGTH]; + stuff_string_white(token); if(a_to_eol) advance_to_eoln(NULL); - if( isdigit(token[0])) + if (!parse_boolean(token, b)) + { + *b = false; + error_display(0, "Boolean '%s' type unknown; assuming 'no/false'", token); + } + + diag_printf("Stuffed bool: %s\n", (b) ? NOX("true") : NOX("false")); +} + +// Parses a token into a boolean value, if the token is recognized. If so, the boolean parameter is assigned the value and the function returns true; +// if not, the boolean parameter is not assigned and the function returns false. +bool parse_boolean(const char *token, bool *b) +{ + Assertion(token != nullptr && b != nullptr, "Parameters must not be NULL!"); + + if(isdigit(token[0])) { if(token[0] != '0') *b = true; else *b = false; + return true; } else { @@ -2871,6 +2886,7 @@ void stuff_boolean(bool *b, bool a_to_eol) || !stricmp(token, "HIja'") || !stricmp(token, "HISlaH")) //Klingon { *b = true; + return true; } else if(!stricmp(token, "no") || !stricmp(token, "false") @@ -2883,15 +2899,12 @@ void stuff_boolean(bool *b, bool a_to_eol) || !stricmp(token, "ghobe'")) //Klingon { *b = false; - } - else - { - *b = false; - error_display(0, "Boolean '%s' type unknown; assuming 'no/false'",token); + return true; } } - diag_printf("Stuffed bool: %s\n", (b) ? NOX("true") : NOX("false")); + // token not recognized + return false; } // Stuff an integer value (cast to a ubyte) pointed at by Mp. diff --git a/code/parse/parselo.h b/code/parse/parselo.h index 2d042a381c7..d6a69ab03ca 100644 --- a/code/parse/parselo.h +++ b/code/parse/parselo.h @@ -255,6 +255,7 @@ extern void stuff_parenthesized_vec3d(vec3d *vp); extern void stuff_boolean(int *i, bool a_to_eol=true); extern void stuff_boolean(bool *b, bool a_to_eol=true); extern void stuff_boolean_flag(int *i, int flag, bool a_to_eol=true); +extern bool parse_boolean(const char *token, bool*b); template int string_lookup(const char* str1, T strlist, size_t max, const char* description = nullptr, bool say_errors = false) diff --git a/code/ship/ship.cpp b/code/ship/ship.cpp index 5cc411db1dc..26cdec5108a 100644 --- a/code/ship/ship.cpp +++ b/code/ship/ship.cpp @@ -2646,7 +2646,7 @@ static int parse_and_add_briefing_icon_info() * * If we are creating a ship, we want to inherit the parameters of the ship class, then override on a field-by-field basis. */ -int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, const char *info_type_name, const char *info_name) +int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, const char *info_type_name, const char *info_name, bool set_special_warp_physics) { Assert(info_type_name != nullptr); Assert(info_name != nullptr); @@ -2677,7 +2677,7 @@ int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, c params.warp_type = j | WT_DEFAULT_WITH_FIREBALL; } else { - Warning(LOCATION, "Invalid %s '%s' specified for %s '%s'", str, buf, info_type_name, info_name); + error_display(0, "Invalid %s '%s' specified for %s '%s'", str, buf, info_type_name, info_name); params.warp_type = WT_DEFAULT; } } @@ -2699,7 +2699,7 @@ int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, c if (t_time > 0.0f) params.warpout_engage_time = fl2i(t_time*1000.0f); else - Warning(LOCATION, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); + error_display(0, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); } } @@ -2711,7 +2711,7 @@ int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, c if (speed > 0.0f) params.speed = speed; else - Warning(LOCATION, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); + error_display(0, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); } sprintf(str, "%s time:", prefix); @@ -2722,7 +2722,7 @@ int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, c if (t_time > 0.0f) params.time = fl2i(t_time*1000.0f); else - Warning(LOCATION, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); + error_display(0, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); } sprintf(str, "%s %s exp:", prefix, direction == WarpDirection::WARP_IN ? "decel" : "accel"); @@ -2733,7 +2733,7 @@ int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, c if (accel_exp >= 0.0f) params.accel_exp = accel_exp; else - Warning(LOCATION, "%s specified as less than 0 on %s '%s'; value ignored", str, info_type_name, info_name); + error_display(0, "%s specified as less than 0 on %s '%s'; value ignored", str, info_type_name, info_name); } sprintf(str, "%s radius:", prefix); @@ -2744,7 +2744,7 @@ int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, c if (rad > 0.0f) params.radius = rad; else - Warning(LOCATION, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); + error_display(0, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); } sprintf(str, "%s animation:", prefix); @@ -2753,6 +2753,16 @@ int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, c stuff_string(params.anim, F_NAME, MAX_FILENAME_LEN); } + // we might need to explicitly set this flag; but if so, the modder has the option of unsetting it + if (set_special_warp_physics) + params.special_warp_physics = true; + + sprintf(str, "$Special warp%s physics:", (direction == WarpDirection::WARP_IN) ? "in" : "out"); + if (optional_string(str)) + { + stuff_boolean(¶ms.special_warp_physics); + } + if (direction == WarpDirection::WARP_OUT) { sprintf(str, "$Player warpout speed:"); @@ -2763,7 +2773,7 @@ int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, c if (speed > 0.0f) params.warpout_player_speed = speed; else - Warning(LOCATION, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); + error_display(0, "%s specified as 0 or less on %s '%s'; value ignored", str, info_type_name, info_name); } } @@ -3507,17 +3517,43 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool } } - // the first time we get to this point, initialize to the species parameter indexes (which may be -1) + bool is_supercap_for_warp_params = false; if (first_time) { + // the first time we get to this point, initialize to the species parameter indexes (which may be -1) sip->warpin_params_index = Species_info[sip->species].warpin_params_index; sip->warpout_params_index = Species_info[sip->species].warpout_params_index; + + // figure out whether this is a supercap by doing some parse gymnastics + // (flags are parsed several lines later, so we need to skip ahead, peek at the flags, and jump back) + pause_parse(); + if (skip_to_string("$Flags:", "$Name:") == 1) { + // cache the flag definition so we don't have to keep looking it up + static auto supercap_flag_def = std::find_if(std::begin(Ship_flags), std::end(Ship_flags), [](const flag_def_list_new &item) { + return item.def == Ship::Info_Flags::Supercap; + }); + + // look up the flag in this flag list + if (supercap_flag_def != std::end(Ship_flags)) { + SCP_vector flags; + stuff_string_list(flags); + auto supercap_string = std::find_if(flags.begin(), flags.end(), [](const SCP_string& item) { + return lcase_equal(item, supercap_flag_def->name); + }); + if (supercap_string != flags.end()) { + is_supercap_for_warp_params = true; + } + } + } + unpause_parse(); } // get ship parameters for warpin and warpout // Note: if the index is not -1, we must have already assigned warp parameters, probably because we are now // parsing a TBM. In that case, inherit from ourselves. - sip->warpin_params_index = parse_warp_params(sip->warpin_params_index >= 0 ? &Warp_params[sip->warpin_params_index] : nullptr, WarpDirection::WARP_IN, info_type_name, sip->name); - sip->warpout_params_index = parse_warp_params(sip->warpout_params_index >= 0 ? &Warp_params[sip->warpout_params_index] : nullptr, WarpDirection::WARP_OUT, info_type_name, sip->name); + // Note2: In retail, supercaps have the PF_SPECIAL_WARP_IN applied by default (but not PF_SPECIAL_WARP_OUT). So, + // if we are parsing a supercap for the first time, and this is a warpin, set the flag. + sip->warpin_params_index = parse_warp_params(sip->warpin_params_index >= 0 ? &Warp_params[sip->warpin_params_index] : nullptr, WarpDirection::WARP_IN, info_type_name, sip->name, first_time && is_supercap_for_warp_params); + sip->warpout_params_index = parse_warp_params(sip->warpout_params_index >= 0 ? &Warp_params[sip->warpout_params_index] : nullptr, WarpDirection::WARP_OUT, info_type_name, sip->name, false); // get ship explosion info shockwave_create_info *sci = &sip->shockwave; diff --git a/code/ship/shipfx.cpp b/code/ship/shipfx.cpp index 1b64b60fd9a..5813fee6604 100644 --- a/code/ship/shipfx.cpp +++ b/code/ship/shipfx.cpp @@ -3197,6 +3197,7 @@ bool WarpParams::operator==(const WarpParams &other) && time == other.time && accel_exp == other.accel_exp && warp_type == other.warp_type + && special_warp_physics == other.special_warp_physics && warpout_engage_time == other.warpout_engage_time && warpout_player_speed == other.warpout_player_speed; } @@ -3507,9 +3508,12 @@ int WE_Default::warpStart() compute_warpout_stuff(&effect_time, &pos); effect_time += SHIPFX_WARP_DELAY; - if (sip->flags[Ship::Info_Flags::Supercap]) { - // turn off warpin physics in case we're jumping out immediately - objp->phys_info.flags &= ~PF_SPECIAL_WARP_IN; + // turn off warpin physics in case we're jumping out immediately + objp->phys_info.flags &= ~PF_SPECIAL_WARP_IN; + + // maybe turn on warpout physics + if (params->special_warp_physics) { + objp->phys_info.flags |= PF_SPECIAL_WARP_OUT; } } @@ -3628,7 +3632,7 @@ int WE_Default::warpFrame(float frametime) this->warpEnd(); // notify physics to slow down - if (sip->flags[Ship::Info_Flags::Supercap]) { + if (params->special_warp_physics) { // let physics know this is a special warp in objp->phys_info.flags |= PF_SPECIAL_WARP_IN; } diff --git a/code/ship/shipfx.h b/code/ship/shipfx.h index e2452a77da9..3e2b073c322 100644 --- a/code/ship/shipfx.h +++ b/code/ship/shipfx.h @@ -97,6 +97,7 @@ class WarpParams int time = 0; // in ms float accel_exp = 1.0f; int warp_type = WT_DEFAULT; + bool special_warp_physics = false; // only valid for warpout int warpout_engage_time = -1; // in ms diff --git a/code/species_defs/species_defs.cpp b/code/species_defs/species_defs.cpp index 893e23a94ab..e9010e9463f 100644 --- a/code/species_defs/species_defs.cpp +++ b/code/species_defs/species_defs.cpp @@ -16,7 +16,7 @@ #include "ship/shipfx.h" #include "species_defs/species_defs.h" -extern int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, const char *info_type_name, const char *info_name); +extern int parse_warp_params(const WarpParams *inherit_from, WarpDirection direction, const char *info_type_name, const char *info_name, bool set_special_warp_physics = false); SCP_vector Species_info; diff --git a/fred2/fred.rc b/fred2/fred.rc index 134971bef03..36d2184e2e5 100644 --- a/fred2/fred.rc +++ b/fred2/fred.rc @@ -2287,13 +2287,13 @@ BEGIN PUSHBUTTON "IDB_PLAY",IDC_PLAY,235,62,17,15,BS_BITMAP,WS_EX_TRANSPARENT END -IDD_WARP_PARAMS DIALOGEX 0, 0, 271, 252 +IDD_WARP_PARAMS DIALOGEX 0, 0, 271, 271 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Warp Parameters" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,161,231,50,14 - PUSHBUTTON "Cancel",IDCANCEL,214,231,50,14 + DEFPUSHBUTTON "OK",IDOK,161,250,50,14 + PUSHBUTTON "Cancel",IDCANCEL,214,250,50,14 LTEXT "Warp Type",IDC_STATIC,7,41,99,8 COMBOBOX IDC_WARP_TYPE,161,39,103,196,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Start Sound",IDC_STATIC,7,60,99,8 @@ -2305,7 +2305,8 @@ BEGIN LTEXT "Acceleration Exponent (Hyperspace Only)",IDC_ACCEL_EXP_LABEL,7,155,143,8,WS_DISABLED LTEXT "Radius",IDC_STATIC,7,174,99,8 LTEXT "Animation (Homeworld Only)",IDC_ANIM_LABEL,7,193,99,8,WS_DISABLED - LTEXT "Player Warpout Speed",IDC_PLAYER_WARPOUT_SPEED_LABEL,7,212,99,8,WS_DISABLED + LTEXT "Special Warp Physics",IDC_STATIC,7,212,99,8 + LTEXT "Player Warpout Speed",IDC_PLAYER_WARPOUT_SPEED_LABEL,7,231,99,8,WS_DISABLED EDITTEXT IDC_END_SOUND,161,77,103,12,ES_AUTOHSCROLL EDITTEXT IDC_WARPOUT_ENGAGE_TIME,161,96,103,12,ES_AUTOHSCROLL EDITTEXT IDC_SPEED,161,115,103,12,ES_AUTOHSCROLL @@ -2313,7 +2314,8 @@ BEGIN EDITTEXT IDC_ACCEL_EXP,161,153,103,12,ES_AUTOHSCROLL EDITTEXT IDC_RADIUS,161,172,103,12,ES_AUTOHSCROLL EDITTEXT IDC_ANIM,161,191,103,12,ES_AUTOHSCROLL - EDITTEXT IDC_PLAYER_WARPOUT_SPEED,161,210,103,12,ES_AUTOHSCROLL + CONTROL "",IDC_SPECIAL_WARP_PHYSICS,"Button",BS_AUTOCHECKBOX,161,210,103,12 + EDITTEXT IDC_PLAYER_WARPOUT_SPEED,161,229,103,12,ES_AUTOHSCROLL LTEXT "All of these parameters are optional, and a mission designer will usually not need to override more than one or two. These parameters are the same as those found in ships.tbl.",IDC_STATIC,7,7,257,29 END diff --git a/fred2/missionsave.cpp b/fred2/missionsave.cpp index 7bef26ab5c5..e8704f44d6a 100644 --- a/fred2/missionsave.cpp +++ b/fred2/missionsave.cpp @@ -3355,6 +3355,11 @@ int CFred_mission_save::save_warp_params(WarpDirection direction, ship *shipp) fout("\n%s animation: %s", prefix, shipp_params->anim); } + if (shipp_params->special_warp_physics != sip_params->special_warp_physics) + { + fout("\n$Special warp%s physics: %s", direction == WarpDirection::WARP_IN ? "in" : "out", shipp_params->special_warp_physics ? "YES" : "NO"); + } + if (direction == WarpDirection::WARP_OUT && shipp_params->warpout_player_speed != sip_params->warpout_player_speed) { if (shipp_params->warpout_player_speed > 0.0f) diff --git a/fred2/resource.h b/fred2/resource.h index 741b6281745..170a9836af2 100644 --- a/fred2/resource.h +++ b/fred2/resource.h @@ -1228,6 +1228,7 @@ #define IDC_SPIN_EM_FALLOFF 1695 #define IDC_SPIN_NOISE_COLOR_B 1696 #define IDC_NOISE_COLOR_B 1697 +#define IDC_SPECIAL_WARP_PHYSICS 1698 #define IDC_NOISE_INTENSITY 1700 #define IDC_SPIN_NOISE_INTENSITY 1701 #define IDC_NOISE_RESOLUTION 1702 diff --git a/fred2/warpparamsdlg.cpp b/fred2/warpparamsdlg.cpp index a5f8958a6b7..09a032938b4 100644 --- a/fred2/warpparamsdlg.cpp +++ b/fred2/warpparamsdlg.cpp @@ -32,6 +32,7 @@ warp_params_dlg::warp_params_dlg(CWnd* pParent) : CDialog(warp_params_dlg::IDD, m_accel_exp = _T(""); m_radius = _T(""); m_anim = _T(""); + m_special_warp_physics = FALSE; m_player_warpout_speed = _T(""); //}}AFX_DATA_INIT } @@ -49,6 +50,7 @@ void warp_params_dlg::DoDataExchange(CDataExchange* pDX) DDX_Text(pDX, IDC_ACCEL_EXP, m_accel_exp); DDX_Text(pDX, IDC_RADIUS, m_radius); DDX_Text(pDX, IDC_ANIM, m_anim); + DDX_Check(pDX, IDC_SPECIAL_WARP_PHYSICS, m_special_warp_physics); DDX_Text(pDX, IDC_PLAYER_WARPOUT_SPEED, m_player_warpout_speed); //}}AFX_DATA_MAP } @@ -124,6 +126,8 @@ BOOL warp_params_dlg::OnInitDialog() if (strlen(params->anim) > 0) m_anim = params->anim; + m_special_warp_physics = params->special_warp_physics ? TRUE : FALSE; + if (params->warpout_player_speed > 0.0f) m_player_warpout_speed.Format(_T("%.2f"), params->warpout_player_speed); } @@ -229,6 +233,8 @@ void warp_params_dlg::OnOK() if (m_anim.GetLength() > 0) strcpy_s(params.anim, m_anim); + params.special_warp_physics = (m_special_warp_physics == TRUE); + if (!m_warp_in && m_player_warpout_speed.GetLength() > 0) { float speed = (float)atof(m_player_warpout_speed); diff --git a/fred2/warpparamsdlg.h b/fred2/warpparamsdlg.h index f1787692ed0..3821c24fc19 100644 --- a/fred2/warpparamsdlg.h +++ b/fred2/warpparamsdlg.h @@ -33,6 +33,7 @@ class warp_params_dlg : public CDialog CString m_accel_exp; CString m_radius; CString m_anim; + BOOL m_special_warp_physics; CString m_player_warpout_speed; //}}AFX_DATA diff --git a/qtfred/src/mission/missionsave.cpp b/qtfred/src/mission/missionsave.cpp index cd8b105034d..4b5d7cd1af0 100644 --- a/qtfred/src/mission/missionsave.cpp +++ b/qtfred/src/mission/missionsave.cpp @@ -3271,6 +3271,11 @@ int CFred_mission_save::save_warp_params(WarpDirection direction, ship *shipp) fout("\n%s animation: %s", prefix, shipp_params->anim); } + if (shipp_params->special_warp_physics != sip_params->special_warp_physics) + { + fout("\n$Special warp%s physics: %s", direction == WarpDirection::WARP_IN ? "in" : "out", shipp_params->special_warp_physics ? "YES" : "NO"); + } + if (direction == WarpDirection::WARP_OUT && shipp_params->warpout_player_speed != sip_params->warpout_player_speed) { if (shipp_params->warpout_player_speed > 0.0f)