From 67ebeb438e5ebc8f85b7b7638102d7896ed0343e Mon Sep 17 00:00:00 2001 From: mjn-mixael Date: Wed, 1 May 2024 15:02:08 -0500 Subject: [PATCH] custom strings for ships and weapons --- code/mission/missionparse.cpp | 5 ++- code/mission/missionparse.h | 8 ++-- code/scripting/api/objs/shipclass.cpp | 60 +++++++++++++++++++++++++ code/scripting/api/objs/weaponclass.cpp | 60 +++++++++++++++++++++++++ code/ship/ship.cpp | 27 +++++++++++ code/ship/ship.h | 2 + code/weapon/weapon.h | 2 + code/weapon/weapons.cpp | 21 +++++++++ fred2/customstringsdlg.cpp | 4 +- fred2/customstringsdlg.h | 2 +- 10 files changed, 182 insertions(+), 9 deletions(-) diff --git a/code/mission/missionparse.cpp b/code/mission/missionparse.cpp index e0e943e3e7..d0b7ec8688 100644 --- a/code/mission/missionparse.cpp +++ b/code/mission/missionparse.cpp @@ -486,7 +486,8 @@ const std::shared_ptr> O const std::shared_ptr> OnLoadoutAboutToParseHook = scripting::Hook<>::Factory("On Loadout About To Parse", "Called during mission load just before parsing the team loadout.",{}); -mission_custom_string* get_custom_string_by_name(SCP_string name) { +custom_string* get_custom_string_by_name(SCP_string name) + { for (size_t i = 0; i < The_mission.custom_strings.size(); i++) { if (The_mission.custom_strings[i].name == name) { return &The_mission.custom_strings[i]; @@ -6166,7 +6167,7 @@ void parse_custom_data(mission* pm) if (optional_string("$begin_custom_strings")) { while (optional_string("$Name:")) { - mission_custom_string cs; + custom_string cs; // The name of the string stuff_string(cs.name, F_NAME); diff --git a/code/mission/missionparse.h b/code/mission/missionparse.h index 3ed31f85ac..02959103a4 100644 --- a/code/mission/missionparse.h +++ b/code/mission/missionparse.h @@ -130,11 +130,11 @@ typedef struct mission_default_custom_data { SCP_string description; } mission_default_custom_data; -typedef struct mission_custom_string { +typedef struct custom_string { SCP_string name; SCP_string value; SCP_string text; -} mission_custom_string; +} custom_string; // descriptions of flags for FRED template @@ -195,7 +195,7 @@ typedef struct mission { SCP_map custom_data; - SCP_vector custom_strings; + SCP_vector custom_strings; void Reset( ); @@ -569,7 +569,7 @@ void clear_texture_replacements(); subsys_status *parse_get_subsys_status(p_object *pobjp, const char *subsys_name); // MjnMixael -mission_custom_string* get_custom_string_by_name(SCP_string name); +custom_string* get_custom_string_by_name(SCP_string name); #endif diff --git a/code/scripting/api/objs/shipclass.cpp b/code/scripting/api/objs/shipclass.cpp index 3e1de4edd1..e4724641e3 100644 --- a/code/scripting/api/objs/shipclass.cpp +++ b/code/scripting/api/objs/shipclass.cpp @@ -1173,6 +1173,66 @@ ADE_FUNC(hasCustomData, l_Shipclass, nullptr, "Detects whether the ship class ha return ade_set_args(L, "b", result); } +ADE_VIRTVAR(CustomStrings, + l_Shipclass, + nullptr, + "Gets the indexed custom string table for this ship. Each item in the table is a table with the following values: " + "Name - the name of the custom string, Value - the value associated with the custom string, String - the custom " + "string itself.", + "table", + "The ship's custom data table") +{ + int idx; + if (!ade_get_args(L, "o", l_Shipclass.Get(&idx))) + return ADE_RETURN_NIL; + + if (idx < 0 || idx >= ship_info_size()) + return ADE_RETURN_NIL; + + ship_info* sip = &Ship_info[idx]; + + if (ADE_SETTING_VAR) { + LuaError(L, "Setting Custom Data is not supported"); + } + + auto table = luacpp::LuaTable::create(L); + + int cnt = 0; + + for (const auto& cs : sip->custom_strings) { + cnt++; + auto item = luacpp::LuaTable::create(L); + + item.addValue("Name", luacpp::LuaValue::createValue(Script_system.GetLuaSession(), cs.name)); + item.addValue("Value", luacpp::LuaValue::createValue(Script_system.GetLuaSession(), cs.value)); + item.addValue("String", luacpp::LuaValue::createValue(Script_system.GetLuaSession(), cs.text)); + + table.addValue(cnt, item); + } + + return ade_set_args(L, "t", &table); +} + +ADE_FUNC(hasCustomStrings, + l_Shipclass, + nullptr, + "Detects whether the ship has any custom strings", + "boolean", + "true if the ship's custom_strings is not empty, false otherwise") +{ + int idx; + if (!ade_get_args(L, "o", l_Shipclass.Get(&idx))) + return ADE_RETURN_NIL; + + if (idx < 0 || idx >= ship_info_size()) + return ADE_RETURN_NIL; + + ship_info* sip = &Ship_info[idx]; + + bool result = !sip->custom_strings.empty(); + return ade_set_args(L, "b", result); +} + ADE_FUNC(isValid, l_Shipclass, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs") { int idx; diff --git a/code/scripting/api/objs/weaponclass.cpp b/code/scripting/api/objs/weaponclass.cpp index 670b6d77b5..1dd0fac56f 100644 --- a/code/scripting/api/objs/weaponclass.cpp +++ b/code/scripting/api/objs/weaponclass.cpp @@ -621,6 +621,66 @@ ADE_FUNC(hasCustomData, l_Weaponclass, nullptr, "Detects whether the weapon clas return ade_set_args(L, "b", result); } +ADE_VIRTVAR(CustomStrings, + l_Weaponclass, + nullptr, + "Gets the indexed custom string table for this weapon. Each item in the table is a table with the following values: " + "Name - the name of the custom string, Value - the value associated with the custom string, String - the custom " + "string itself.", + "table", + "The weapon's custom data table") +{ + int idx; + if (!ade_get_args(L, "o", l_Weaponclass.Get(&idx))) + return ADE_RETURN_NIL; + + if (idx < 0 || idx >= weapon_info_size()) + return ADE_RETURN_NIL; + + weapon_info* wip = &Weapon_info[idx]; + + if (ADE_SETTING_VAR) { + LuaError(L, "Setting Custom Data is not supported"); + } + + auto table = luacpp::LuaTable::create(L); + + int cnt = 0; + + for (const auto& cs : wip->custom_strings) { + cnt++; + auto item = luacpp::LuaTable::create(L); + + item.addValue("Name", luacpp::LuaValue::createValue(Script_system.GetLuaSession(), cs.name)); + item.addValue("Value", luacpp::LuaValue::createValue(Script_system.GetLuaSession(), cs.value)); + item.addValue("String", luacpp::LuaValue::createValue(Script_system.GetLuaSession(), cs.text)); + + table.addValue(cnt, item); + } + + return ade_set_args(L, "t", &table); +} + +ADE_FUNC(hasCustomStrings, + l_Weaponclass, + nullptr, + "Detects whether the weapon has any custom strings", + "boolean", + "true if the weapon's custom_strings is not empty, false otherwise") +{ + int idx; + if (!ade_get_args(L, "o", l_Weaponclass.Get(&idx))) + return ADE_RETURN_NIL; + + if (idx < 0 || idx >= weapon_info_size()) + return ADE_RETURN_NIL; + + weapon_info* wip = &Weapon_info[idx]; + + bool result = !wip->custom_strings.empty(); + return ade_set_args(L, "b", result); +} + ADE_VIRTVAR(InTechDatabase, l_Weaponclass, "boolean", "Gets or sets whether this weapon class is visible in the tech room", "boolean", "True or false") { int idx; diff --git a/code/ship/ship.cpp b/code/ship/ship.cpp index 926e2d6d17..304dd9df42 100644 --- a/code/ship/ship.cpp +++ b/code/ship/ship.cpp @@ -1287,6 +1287,8 @@ void ship_info::clone(const ship_info& other) custom_data = other.custom_data; + custom_strings = other.custom_strings; + rcs_thrusters = other.rcs_thrusters; radar_image_2d_idx = other.radar_image_2d_idx; @@ -1619,6 +1621,8 @@ void ship_info::move(ship_info&& other) std::swap(custom_data, other.custom_data); + std::swap(custom_strings, other.custom_strings); + std::swap(rcs_thrusters, other.rcs_thrusters); radar_image_2d_idx = other.radar_image_2d_idx; @@ -2072,6 +2076,8 @@ ship_info::ship_info() custom_data.clear(); + custom_strings.clear(); + radar_image_2d_idx = -1; radar_color_image_2d_idx = -1; radar_image_size = -1; @@ -5138,6 +5144,27 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool parse_string_map(sip->custom_data, "$end_custom_data", "+Val:"); } + if (optional_string("$Custom Strings")) { + while (optional_string("$Name:")) { + custom_string cs; + + // The name of the string + stuff_string(cs.name, F_NAME); + + // Arbitrary string value used for grouping strings together + required_string("+Value:"); + stuff_string(cs.value, F_NAME); + + // The string text itself + required_string("+String:"); + stuff_string(cs.text, F_MULTITEXT); + + sip->custom_strings.push_back(cs); + } + + required_string("$end_custom_strings"); + } + int n_subsystems = 0; int n_excess_subsystems = 0; int cont_flag = 1; diff --git a/code/ship/ship.h b/code/ship/ship.h index 5ebcffb2dc..7c3d63bd35 100644 --- a/code/ship/ship.h +++ b/code/ship/ship.h @@ -1460,6 +1460,8 @@ public: SCP_map custom_data; + SCP_vector custom_strings; + SCP_vector rcs_thrusters; int radar_image_2d_idx; diff --git a/code/weapon/weapon.h b/code/weapon/weapon.h index 507cd31a0e..60a6016dd8 100644 --- a/code/weapon/weapon.h +++ b/code/weapon/weapon.h @@ -613,6 +613,8 @@ struct weapon_info SCP_map custom_data; + SCP_vector custom_strings; + decals::creation_info impact_decal; actions::ProgramSet on_create_program; diff --git a/code/weapon/weapons.cpp b/code/weapon/weapons.cpp index 5b18f6a3f2..bcd3f70f83 100644 --- a/code/weapon/weapons.cpp +++ b/code/weapon/weapons.cpp @@ -3752,6 +3752,27 @@ int parse_weapon(int subtype, bool replace, const char *filename) parse_string_map(wip->custom_data, "$end_custom_data", "+Val:"); } + if (optional_string("$Custom Strings")) { + while (optional_string("$Name:")) { + custom_string cs; + + // The name of the string + stuff_string(cs.name, F_NAME); + + // Arbitrary string value used for grouping strings together + required_string("+Value:"); + stuff_string(cs.value, F_NAME); + + // The string text itself + required_string("+String:"); + stuff_string(cs.text, F_MULTITEXT); + + wip->custom_strings.push_back(cs); + } + + required_string("$end_custom_strings"); + } + return w_id; } diff --git a/fred2/customstringsdlg.cpp b/fred2/customstringsdlg.cpp index e11de00d13..2cf37d4556 100644 --- a/fred2/customstringsdlg.cpp +++ b/fred2/customstringsdlg.cpp @@ -139,7 +139,7 @@ void CustomStringsDlg::OnListerSelectionChange() Assertion(index >= 0 && index < static_cast(m_custom_strings.size()), "Selected an invalid custom string! Please report."); const SCP_string& key = m_lister_keys[index]; - const mission_custom_string *cs = nullptr; + const custom_string *cs = nullptr; for (size_t i = 0; i <= m_custom_strings.size(); i++) { if (m_custom_strings[i].name == key) { @@ -165,7 +165,7 @@ void CustomStringsDlg::add_pair_entry() return; } - mission_custom_string cs; + custom_string cs; CEdit* key_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_KEY); CString key_str; diff --git a/fred2/customstringsdlg.h b/fred2/customstringsdlg.h index 0dbcd062db..74f306621d 100644 --- a/fred2/customstringsdlg.h +++ b/fred2/customstringsdlg.h @@ -64,7 +64,7 @@ class CustomStringsDlg : public CDialog { bool m_text_edit_focus; - SCP_vector m_custom_strings; + SCP_vector m_custom_strings; // read-only view of data pair keys SCP_vector m_lister_keys;