From f522d20dd40df9db44fc52770cae2ec0a2723ecf Mon Sep 17 00:00:00 2001 From: William JCM Date: Wed, 2 Mar 2022 14:43:02 +0100 Subject: [PATCH] SaveTool: fragment SaveTool_MassViewer.cpp. This will make maintenance easier. I hope. --- src/CMakeLists.txt | 3 + src/Maps/StyleNames.h | 8 +- src/SaveTool/SaveTool.h | 3 + src/SaveTool/SaveTool_MassViewer.cpp | 920 +------------------ src/SaveTool/SaveTool_MassViewer_Armour.cpp | 198 ++++ src/SaveTool/SaveTool_MassViewer_Frame.cpp | 307 +++++++ src/SaveTool/SaveTool_MassViewer_Weapons.cpp | 475 ++++++++++ 7 files changed, 996 insertions(+), 918 deletions(-) create mode 100644 src/SaveTool/SaveTool_MassViewer_Armour.cpp create mode 100644 src/SaveTool/SaveTool_MassViewer_Frame.cpp create mode 100644 src/SaveTool/SaveTool_MassViewer_Weapons.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index afc8ac7..6e8d616 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,9 @@ add_executable(MassBuilderSaveTool WIN32 SaveTool/SaveTool_drawMainMenu.cpp SaveTool/SaveTool_MainManager.cpp SaveTool/SaveTool_MassViewer.cpp + SaveTool/SaveTool_MassViewer_Frame.cpp + SaveTool/SaveTool_MassViewer_Armour.cpp + SaveTool/SaveTool_MassViewer_Weapons.cpp SaveTool/SaveTool_ProfileManager.cpp ProfileManager/ProfileManager.h ProfileManager/ProfileManager.cpp diff --git a/src/Maps/StyleNames.h b/src/Maps/StyleNames.h index 960ecb1..048509a 100644 --- a/src/Maps/StyleNames.h +++ b/src/Maps/StyleNames.h @@ -22,7 +22,9 @@ using namespace Magnum; -static const std::map style_names { +extern const std::map style_names +#ifdef STYLENAMES_DEFINITION +{ {0, "Custom Style 1"}, {1, "Custom Style 2"}, {2, "Custom Style 3"}, @@ -185,4 +187,6 @@ static const std::map style_names { {225, "Dark Brown Camo"}, {226, "Blue Camo"}, {227, "Dark Blue Camo"}, -}; +} +#endif +; diff --git a/src/SaveTool/SaveTool.h b/src/SaveTool/SaveTool.h index 5341c7a..b871df8 100644 --- a/src/SaveTool/SaveTool.h +++ b/src/SaveTool/SaveTool.h @@ -121,6 +121,7 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener void drawArmour(); void drawCustomArmourStyles(); void drawWeapons(); + void drawWeaponCategory(const char* name, Containers::ArrayView weapons_view, bool& dirty, const char* payload_type, const char* payload_tooltip); void drawWeaponEditor(Weapon& weapon); void drawGlobalStyles(); void drawTuning(); @@ -238,6 +239,8 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener Containers::Pointer _massManager; Mass* _currentMass{nullptr}; + Weapon* _currentWeapon = nullptr; + Containers::Pointer _fileWatcher; enum watchID { SaveDir = 0, diff --git a/src/SaveTool/SaveTool_MassViewer.cpp b/src/SaveTool/SaveTool_MassViewer.cpp index fa4675f..578b2e9 100644 --- a/src/SaveTool/SaveTool_MassViewer.cpp +++ b/src/SaveTool/SaveTool_MassViewer.cpp @@ -19,19 +19,18 @@ #include #include "../Maps/Accessories.h" -#include "../Maps/ArmourSets.h" + +#define STYLENAMES_DEFINITION #include "../Maps/StyleNames.h" #include "../FontAwesome/IconsFontAwesome5.h" #include "SaveTool.h" -static Weapon* current_weapon = nullptr; - void SaveTool::drawMassViewer() { if(!_currentMass || _currentMass->state() != Mass::State::Valid) { _currentMass = nullptr; - current_weapon = nullptr; + _currentWeapon = nullptr; _uiState = UiState::MainManager; _queue.addToast(Toast::Type::Error, "The selected M.A.S.S. isn't valid anymore."); return; @@ -80,7 +79,7 @@ void SaveTool::drawMassViewer() { ImGui::TableSetColumnIndex(3); if(ImGui::SmallButton(ICON_FA_TIMES)) { - current_weapon = nullptr; + _currentWeapon = nullptr; _currentMass = nullptr; _uiState = UiState::MainManager; _jointsDirty = false; @@ -152,917 +151,6 @@ void SaveTool::drawMassViewer() { ImGui::End(); } -void SaveTool::drawFrameInfo() { - if(!_currentMass || _currentMass->state() != Mass::State::Valid) { - return; - } - - if(!ImGui::BeginChild("##FrameInfo")) { - ImGui::EndChild(); - return; - } - - ImGui::BeginGroup(); - - if(ImGui::BeginChild("##JointSliders", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 300.0f}, true, ImGuiWindowFlags_MenuBar)) { - if(ImGui::BeginMenuBar()) { - ImGui::TextUnformatted("Joint sliders"); - - ImGui::EndMenuBar(); - } - - drawJointSliders(); - } - ImGui::EndChild(); - - if(ImGui::BeginChild("##FrameStyles", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 0.0f}, true, ImGuiWindowFlags_MenuBar)) { - if(ImGui::BeginMenuBar()) { - ImGui::TextUnformatted("Frame styles"); - - ImGui::EndMenuBar(); - } - - drawFrameStyles(); - } - ImGui::EndChild(); - - ImGui::EndGroup(); - - ImGui::SameLine(); - - if(ImGui::BeginChild("##EyeFlare", {0.0f, 0.0f}, true, ImGuiWindowFlags_MenuBar)) { - if(ImGui::BeginMenuBar()) { - ImGui::TextUnformatted("Eye flare colour"); - drawHelpMarker("Right-click the picker for more options.", 250.0f); - - ImGui::EndMenuBar(); - } - - drawEyeColourPicker(); - } - ImGui::EndChild(); - - ImGui::EndChild(); -} - -void SaveTool::drawJointSliders() { - if(!_currentMass || _currentMass->state() != Mass::State::Valid) { - return; - } - - ImGui::TextWrapped("In-game values are multiplied by 100.\nFor example, 0.500 here is equal to 50 in-game."); - - if(ImGui::BeginTable("##JointSliderTable", 2, ImGuiTableFlags_Borders)) { - ImGui::TableSetupColumn("##SliderLabel", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("##Sliders", ImGuiTableColumnFlags_WidthStretch); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - drawAlignedText("Neck"); - ImGui::TableSetColumnIndex(1); - ImGui::SetNextItemWidth(-1.0f); - if(ImGui::SliderFloat("##NeckSlider", &_currentMass->jointSliders().neck, 0.0f, 1.0f)) { - _jointsDirty = true; - } - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - drawAlignedText("Body"); - ImGui::TableSetColumnIndex(1); - ImGui::SetNextItemWidth(-1.0f); - if(ImGui::SliderFloat("##BodySlider", &_currentMass->jointSliders().body, 0.0f, 1.0f)) { - _jointsDirty = true; - } - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - drawAlignedText("Shoulders"); - ImGui::TableSetColumnIndex(1); - ImGui::SetNextItemWidth(-1.0f); - if(ImGui::SliderFloat("##ShouldersSlider", &_currentMass->jointSliders().shoulders, 0.0f, 1.0f)) { - _jointsDirty = true; - } - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - drawAlignedText("Hips"); - ImGui::TableSetColumnIndex(1); - ImGui::SetNextItemWidth(-1.0f); - if(ImGui::SliderFloat("##HipsSlider", &_currentMass->jointSliders().hips, 0.0f, 1.0f)) { - _jointsDirty = true; - } - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - drawAlignedText("Arms"); - ImGui::TableSetColumnIndex(1); - ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{2.0f, 1.0f}); - if(ImGui::BeginTable("##UpperLowerArmsLayoutTable", 2)) { - ImGui::TableSetupColumn("##UpperArms", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("##LowerArms", ImGuiTableColumnFlags_WidthStretch); - - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(-1.0f); - if(ImGui::SliderFloat("##UpperArmsSlider", &_currentMass->jointSliders().upperArms, 0.0f, 1.0f, "Upper: %.3f")) { - _jointsDirty = true; - } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(-1.0f); - if(ImGui::SliderFloat("##LowerArmsSlider", &_currentMass->jointSliders().lowerArms, 0.0f, 1.0f, "Lower: %.3f")) { - _jointsDirty = true; - } - - ImGui::EndTable(); - } - ImGui::PopStyleVar(); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - drawAlignedText("Legs"); - ImGui::TableSetColumnIndex(1); - ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{2.0f, 1.0f}); - if(ImGui::BeginTable("##UpperLowerLegsLayoutTable", 2)) { - ImGui::TableSetupColumn("##UpperLegs", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("##LowerLegs", ImGuiTableColumnFlags_WidthStretch); - - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(-1.0f); - if(ImGui::SliderFloat("##UpperLegsSlider", &_currentMass->jointSliders().upperLegs, 0.0f, 1.0f, "Upper: %.3f")) { - _jointsDirty = true; - } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(-1.0f); - if(ImGui::SliderFloat("##LowerLegsSlider", &_currentMass->jointSliders().lowerLegs, 0.0f, 1.0f, "Lower: %.3f")) { - _jointsDirty = true; - } - - ImGui::EndTable(); - } - ImGui::PopStyleVar(); - - ImGui::EndTable(); - } - - if(!_jointsDirty) { - ImGui::BeginDisabled(); - ImGui::Button(ICON_FA_SAVE " Save"); - ImGui::SameLine(); - ImGui::Button(ICON_FA_UNDO " Reset"); - ImGui::EndDisabled(); - } - else { - if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { - if(!_currentMass->writeJointSliders()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - _jointsDirty = false; - } - ImGui::SameLine(); - if(ImGui::Button(ICON_FA_UNDO " Reset")) { - _currentMass->getJointSliders(); - _jointsDirty = false; - } - } -} - -void SaveTool::drawFrameStyles() { - if(!_currentMass || _currentMass->state() != Mass::State::Valid) { - return; - } - - for(Int i = 0; i < 4; i++) { - drawAlignedText("Slot %d:", i + 1); - - ImGui::SameLine(); - - ImGui::PushID(i); - - if(ImGui::BeginCombo("##Style", getStyleName(_currentMass->frameStyles()[i], _currentMass->frameCustomStyles()))) { - for(const auto& style : style_names) { - if(ImGui::Selectable(getStyleName(style.first, _currentMass->frameCustomStyles()), _currentMass->frameStyles()[i] == style.first)) { - _currentMass->frameStyles()[i] = style.first; - _stylesDirty = true; - } - } - - ImGui::EndCombo(); - } - - ImGui::PopID(); - } - - if(!_stylesDirty) { - ImGui::BeginDisabled(); - ImGui::Button(ICON_FA_SAVE " Save"); - ImGui::SameLine(); - ImGui::Button(ICON_FA_UNDO " Reset"); - ImGui::EndDisabled(); - } - else { - if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { - if(!_currentMass->writeFrameStyles()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - _stylesDirty = false; - } - ImGui::SameLine(); - if(ImGui::Button(ICON_FA_UNDO " Reset")) { - _currentMass->getFrameStyles(); - _stylesDirty = false; - } - } -} - -void SaveTool::drawEyeColourPicker() { - if(!_currentMass || _currentMass->state() != Mass::State::Valid) { - return; - } - - if(ImGui::ColorPicker3("##EyeFlarePicker", &_currentMass->eyeFlareColour().x())) { - _eyeFlareDirty = true; - } - - if(!_eyeFlareDirty) { - ImGui::BeginDisabled(); - ImGui::Button(ICON_FA_SAVE " Save"); - ImGui::SameLine(); - ImGui::Button(ICON_FA_UNDO " Reset"); - ImGui::EndDisabled(); - } - else { - if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { - if(!_currentMass->writeEyeFlareColour()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - _eyeFlareDirty = false; - } - ImGui::SameLine(); - if(ImGui::Button(ICON_FA_UNDO " Reset")) { - _currentMass->getEyeFlareColour(); - _eyeFlareDirty = false; - } - } -} - -void SaveTool::drawCustomFrameStyles() { - if(!_currentMass || _currentMass->state() != Mass::State::Valid) { - return; - } - - if(!ImGui::BeginChild("##FrameStyles")) { - ImGui::EndChild(); - return; - } - - ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game."); - - for(UnsignedInt i = 0; i < _currentMass->frameCustomStyles().size(); i++) { - ImGui::PushID(i); - DCSResult result; - result = drawCustomStyle(_currentMass->frameCustomStyles()[i]); - switch(result) { - case DCS_ResetStyle: - _currentMass->getFrameCustomStyles(); - break; - case DCS_Save: - if(!_currentMass->writeFrameCustomStyle(i)) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - break; - default: - break; - } - ImGui::PopID(); - } - - ImGui::EndChild(); -} - -void SaveTool::drawArmour() { - if(!_currentMass || _currentMass->state() != Mass::State::Valid) { - return; - } - - if(ImGui::Button(ICON_FA_UNDO_ALT " Reset all")) { - _currentMass->getArmourParts(); - } - - if(!ImGui::BeginChild("##ArmourParts")) { - ImGui::EndChild(); - return; - } - - static const char* slot_labels[] = { - #define c(enumerator, strenum, name) name, - #include "../Maps/ArmourSlots.hpp" - #undef c - }; - - for(UnsignedInt i = 0; i < _currentMass->armourParts().size(); i++) { - ImGui::PushID(i); - - auto& part = _currentMass->armourParts()[i]; - - static char header[129] = {'\0'}; - - std::memset(header, '\0', 129); - - if(armour_sets.find(part.id) != armour_sets.cend()) { - std::snprintf(header, 128, "%s: %s###%u", slot_labels[UnsignedInt(part.slot)], armour_sets.at(part.id).name, UnsignedInt(part.slot)); - } - else { - std::snprintf(header, 128, "%s: %i###%u", slot_labels[UnsignedInt(part.slot)], part.id, UnsignedInt(part.slot)); - } - - if(ImGui::CollapsingHeader(header)) { - ImGui::BeginGroup(); - - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() * 0.491f); - if(ImGui::BeginListBox("##ChangePart")) { - if(std::strncmp("Neck", slot_labels[UnsignedInt(part.slot)], 4) != 0) { - for(auto& set : armour_sets) { - if(ImGui::Selectable(set.second.name, set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) { - part.id = set.first; - } - } - } - else { - for(auto& set : armour_sets) { - if(!set.second.neck_compatible) { - continue; - } - - if(ImGui::Selectable(set.second.name, set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) { - part.id = set.first; - } - } - } - ImGui::EndListBox(); - } - - ImGui::EndGroup(); - - ImGui::SameLine(); - - ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); - - ImGui::SameLine(); - - ImGui::BeginGroup(); - - ImGui::TextUnformatted("Styles:"); - - for(Int j = 0; j < 4; j++) { - drawAlignedText("Slot %d:", j + 1); - - ImGui::SameLine(); - - ImGui::PushID(j); - - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() - 2.0f); - if(ImGui::BeginCombo("##Style", getStyleName(part.styles[j], _currentMass->armourCustomStyles()))) { - for(const auto& style : style_names) { - if(ImGui::Selectable(getStyleName(style.first, _currentMass->armourCustomStyles()), part.styles[j] == style.first)) { - part.styles[j] = style.first; - } - } - - ImGui::EndCombo(); - } - - ImGui::PopID(); - } - - ImGui::EndGroup(); - - ImGui::Separator(); - - ImGui::PushID("Decal"); - - drawAlignedText("Showing/editing decal"); - for(UnsignedLong j = 0; j < part.decals.size(); j++) { - ImGui::SameLine(); - ImGui::RadioButton(std::to_string(j + 1).c_str(), &_selectedArmourDecals[i], j); - } - - drawDecalEditor(part.decals[_selectedArmourDecals[i]]); - - ImGui::PopID(); - - if(!part.accessories.size()) { - ImGui::Separator(); - - ImGui::PushID("Accessory"); - - drawAlignedText("Showing/editing accessory"); - for(UnsignedInt j = 0; j < part.accessories.size(); j++) { - ImGui::SameLine(); - ImGui::RadioButton(std::string{char(65 + j)}.c_str(), &_selectedArmourAccessories[i], j); - } - - drawAccessoryEditor(part.accessories[_selectedArmourAccessories[i]], _currentMass->armourCustomStyles()); - - ImGui::PopID(); - } - - ImGui::Separator(); - - if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { - if(!_currentMass->writeArmourPart(part.slot)) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - } - } - - ImGui::PopID(); - } - - ImGui::EndChild(); -} - -void SaveTool::drawCustomArmourStyles() { - if(!_currentMass || _currentMass->state() != Mass::State::Valid) { - return; - } - - if(!ImGui::BeginChild("##ArmourStyles")) { - ImGui::EndChild(); - return; - } - - ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game."); - - for(UnsignedInt i = 0; i < _currentMass->armourCustomStyles().size(); i++) { - ImGui::PushID(i); - DCSResult result; - result = drawCustomStyle(_currentMass->armourCustomStyles()[i]); - switch(result) { - case DCS_ResetStyle: - _currentMass->getArmourCustomStyles(); - break; - case DCS_Save: - if(_currentMass->writeArmourCustomStyle(i)) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - break; - default: - break; - } - ImGui::PopID(); - } - - ImGui::EndChild(); -} - -void SaveTool::drawWeapons() { - if(!_currentMass || _currentMass->state() != Mass::State::Valid) { - current_weapon = nullptr; - return; - } - - const Float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); - - ImGui::BeginGroup(); - - if(!ImGui::BeginTable("##WeaponsList", 1, - ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_BordersInnerH, - {ImGui::GetContentRegionAvailWidth() * 0.2f, -footer_height_to_reserve})) - { - return; - } - - ImGui::TableSetupColumn("Weapon"); - - int id = 0; - -#define weapcat(header, array, dirty, payload_type, payload_tooltip) \ - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); \ - ImGui::TableNextColumn(); \ - ImGui::TextUnformatted(header); \ - \ - for(UnsignedInt i = 0; i < _currentMass->array().size(); i++) { \ - auto& weapon = _currentMass->array()[i]; \ - \ - ImGui::TableNextRow(); \ - ImGui::TableNextColumn(); \ - ImGui::PushID(id); \ - if(ImGui::Selectable(weapon.name.c_str(), current_weapon == &weapon)) { \ - current_weapon = &weapon; \ - } \ - if(ImGui::BeginDragDropSource()) { \ - ImGui::SetDragDropPayload(payload_type, &i, sizeof(UnsignedInt)); \ - if(ImGui::GetIO().KeyCtrl) { \ - ImGui::Text(payload_tooltip " %i - %s (copy)", i + 1, weapon.name.c_str()); \ - } \ - else { \ - ImGui::Text(payload_tooltip " %i - %s", i + 1, weapon.name.c_str()); \ - } \ - ImGui::EndDragDropSource(); \ - } \ - if(ImGui::BeginDragDropTarget()) { \ - if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(payload_type)) { \ - int index = *static_cast(payload->Data); \ - \ - if(!ImGui::GetIO().KeyCtrl) { \ - if(current_weapon == &_currentMass->array()[index]) { \ - current_weapon = &_currentMass->array()[i]; \ - } \ - else if (current_weapon == &_currentMass->array()[i]) { \ - current_weapon = &_currentMass->array()[index]; \ - } \ - \ - std::swap(_currentMass->array()[index], _currentMass->array()[i]); \ - } \ - else { \ - _currentMass->array()[i] = _currentMass->array()[index]; \ - } \ - (dirty) = true; \ - } \ - \ - ImGui::EndDragDropTarget(); \ - } \ - \ - ImGui::PopID(); \ - id++; \ - \ - if(weapon.attached == true) { \ - ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, 0x1F008CFFu); \ - } \ - } - - weapcat("Melee weapons", meleeWeapons, _meleeDirty, "MeleeWeapon", "Melee weapon") - weapcat("Shield", shields, _shieldsDirty, "Shield", "Shield") - weapcat("Bullet shooters", bulletShooters, _bShootersDirty, "BShooter", "Bullet shooter") - weapcat("Energy shooters", energyShooters, _eShootersDirty, "EShooter", "Energy shooter") - weapcat("Bullet launchers", bulletLaunchers, _bLaunchersDirty, "BLauncher", "Bullet launcher") - weapcat("Energy launchers", energyLaunchers, _eLaunchersDirty, "ELauncher", "Energy launcher") - -#undef weapcat - - ImGui::EndTable(); - - bool dirty = _meleeDirty || _shieldsDirty || _bShootersDirty || _eShootersDirty || _bLaunchersDirty || _eLaunchersDirty; - - if(!dirty) { - ImGui::BeginDisabled(); - } - - if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { - if(_meleeDirty) { - if(!_currentMass->writeMeleeWeapons()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - else { - _meleeDirty = false; - } - } - - if(_shieldsDirty) { - if(!_currentMass->writeShields()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - else { - _shieldsDirty = false; - } - } - - if(_bShootersDirty) { - if(!_currentMass->writeBulletShooters()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - else { - _bShootersDirty = false; - } - } - - if(_eShootersDirty) { - if(_currentMass->writeEnergyShooters()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - else { - _eShootersDirty = false; - } - } - - if(_bLaunchersDirty) { - if(_currentMass->writeBulletLaunchers()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - else { - _bLaunchersDirty = false; - } - } - - if(_eLaunchersDirty) { - if(_currentMass->writeEnergyLaunchers()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - else { - _eLaunchersDirty = false; - } - } - } - - ImGui::SameLine(); - - if(ImGui::Button(ICON_FA_UNDO_ALT " Reset")) { - if(_meleeDirty) { - _currentMass->getMeleeWeapons(); - _meleeDirty = false; - } - if(_shieldsDirty) { - _currentMass->getShields(); - _shieldsDirty = false; - } - if(_bShootersDirty) { - _currentMass->getBulletShooters(); - _bShootersDirty = false; - } - if(_eShootersDirty) { - _currentMass->getEnergyShooters(); - _eShootersDirty = false; - } - if(_bLaunchersDirty) { - _currentMass->getBulletLaunchers(); - _bLaunchersDirty = false; - } - if(_eLaunchersDirty) { - _currentMass->getEnergyLaunchers(); - _eLaunchersDirty = false; - } - } - - if(!dirty) { - ImGui::EndDisabled(); - } - - ImGui::EndGroup(); - - ImGui::SameLine(); - - if(!current_weapon) { - ImGui::TextUnformatted("No weapon selected."); - return; - } - - ImGui::BeginGroup(); - - if(!ImGui::BeginChild("##WeaponChild", {0.0f, -footer_height_to_reserve})) { - ImGui::EndChild(); - return; - } - - drawWeaponEditor(*current_weapon); - - ImGui::EndChild(); - - ImGui::Separator(); - - if(drawUnsafeWidget([](){ return ImGui::Button(ICON_FA_SAVE " Save changes to weapon category"); })) { - switch(current_weapon->type) { - case WeaponType::Melee: - if(!_currentMass->writeMeleeWeapons()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - break; - case WeaponType::Shield: - if(!_currentMass->writeShields()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - break; - case WeaponType::BulletShooter: - if(!_currentMass->writeBulletShooters()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - break; - case WeaponType::EnergyShooter: - if(!_currentMass->writeEnergyShooters()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - break; - case WeaponType::BulletLauncher: - if(!_currentMass->writeBulletLaunchers()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - break; - case WeaponType::EnergyLauncher: - if(!_currentMass->writeEnergyLaunchers()) { - _queue.addToast(Toast::Type::Error, _currentMass->lastError()); - } - break; - default: - _queue.addToast(Toast::Type::Error, "Unknown weapon type"); - - } - } - - ImGui::SameLine(); - - if(ImGui::Button(ICON_FA_UNDO_ALT " Reset weapon category")) { - switch(current_weapon->type) { - case WeaponType::Melee: - _currentMass->getMeleeWeapons(); - break; - case WeaponType::Shield: - _currentMass->getShields(); - break; - case WeaponType::BulletShooter: - _currentMass->getBulletShooters(); - break; - case WeaponType::EnergyShooter: - _currentMass->getEnergyShooters(); - break; - case WeaponType::BulletLauncher: - _currentMass->getBulletLaunchers(); - break; - case WeaponType::EnergyLauncher: - _currentMass->getEnergyLaunchers(); - break; - default: - _queue.addToast(Toast::Type::Error, "Unknown weapon type"); - } - } - - ImGui::EndGroup(); -} - -void SaveTool::drawWeaponEditor(Weapon& weapon) { - if(!_currentMass || _currentMass->state() != Mass::State::Valid || !current_weapon) { - return; - } - - static const char* labels[] { - #define c(enumerator, strenum, name) name, - #include "../Maps/WeaponTypes.hpp" - #undef c - }; - - drawAlignedText("%s: %s", labels[UnsignedInt(weapon.type)], weapon.name.c_str()); - - ImGui::SameLine(); - - static Containers::StaticArray<33, char> name_buf{ValueInit}; - if(ImGui::Button(ICON_FA_EDIT " Rename")) { - for(auto& c : name_buf) { - c = '\0'; - } - std::strncpy(name_buf.data(), weapon.name.c_str(), 32); - ImGui::OpenPopup("name_edit"); - } - if(drawRenamePopup(name_buf)) { - weapon.name = name_buf.data(); - } - - ImGui::BeginGroup(); - drawAlignedText("Equipped:"); - - if(weapon.type != WeaponType::Shield) { - drawAlignedText("Damage type:"); - } - - if(weapon.type == WeaponType::Melee) { - drawAlignedText("Dual-wield:"); - - drawAlignedText("Custom effect mode:"); - - drawAlignedText("Custom effect colour:"); - } - ImGui::EndGroup(); - - ImGui::SameLine(); - - ImGui::BeginGroup(); - ImGui::Checkbox("##EquippedCheckbox", &weapon.attached); - - if(weapon.type != WeaponType::Shield) { - if(weapon.type == WeaponType::Melee && - ImGui::RadioButton("Physical##NoElement", weapon.damageType == DamageType::Physical)) - { - weapon.damageType = DamageType::Physical; - } - else if((weapon.type == WeaponType::BulletShooter || weapon.type == WeaponType::BulletLauncher) && - ImGui::RadioButton("Piercing##NoElement", weapon.damageType == DamageType::Piercing)) - { - weapon.damageType = DamageType::Piercing; - } - else if((weapon.type == WeaponType::EnergyShooter || weapon.type == WeaponType::EnergyLauncher) && - ImGui::RadioButton("Plasma##NoElement", weapon.damageType == DamageType::Plasma)) - { - weapon.damageType = DamageType::Plasma; - } - ImGui::SameLine(); - if(ImGui::RadioButton("Heat##Heat", weapon.damageType == DamageType::Heat)) { - weapon.damageType = DamageType::Heat; - } - ImGui::SameLine(); - if(ImGui::RadioButton("Freeze##Freeze", weapon.damageType == DamageType::Freeze)) { - weapon.damageType = DamageType::Freeze; - } - ImGui::SameLine(); - if(ImGui::RadioButton("Shock##Shock", weapon.damageType == DamageType::Freeze)) { - weapon.damageType = DamageType::Freeze; - } - } - - if(weapon.type == WeaponType::Melee) { - ImGui::Checkbox("##DualWield", &weapon.dualWield); - - if(ImGui::RadioButton("Default##Default", weapon.effectColourMode == EffectColourMode::Default)) { - weapon.effectColourMode = EffectColourMode::Default; - } - ImGui::SameLine(); - if(ImGui::RadioButton("Custom##Custom", weapon.effectColourMode == EffectColourMode::Custom)) { - weapon.effectColourMode = EffectColourMode::Custom; - } - - bool custom_effect = (weapon.effectColourMode == EffectColourMode::Custom); - if(!custom_effect) { - ImGui::BeginDisabled(); - } - - ImGui::ColorEdit3("##CustomEffectColourPicker", &weapon.effectColour.x(), ImGuiColorEditFlags_HDR|ImGuiColorEditFlags_Float); - - if(!custom_effect) { - ImGui::EndDisabled(); - } - } - ImGui::EndGroup(); - - ImGui::Separator(); - - if(ImGui::CollapsingHeader("Weapon parts")) { - drawAlignedText("Viewing/editing part:"); - for(Int i = 0; UnsignedLong(i) < weapon.parts.size(); i++) { - if(UnsignedLong(_selectedWeaponPart) >= weapon.parts.size()) { - _selectedWeaponPart = 0; - } - ImGui::SameLine(); - ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponPart, i); - } - - auto& part = weapon.parts[_selectedWeaponPart]; - - ImGui::Text("ID: %i", part.id); - - if(ImGui::BeginChild("##PartDetails", {0.0f, 0.0f}, true)) { - ImGui::TextUnformatted("Styles:"); - - for(Int i = 0; i < 4; i++) { - drawAlignedText("Slot %d:", i + 1); - - ImGui::SameLine(); - - ImGui::PushID(i); - - if(ImGui::BeginCombo("##Style", getStyleName(part.styles[i], weapon.customStyles))) { - for(const auto& style: style_names) { - if(ImGui::Selectable(getStyleName(style.first, weapon.customStyles), - part.styles[i] == style.first)) { - part.styles[i] = style.first; - } - } - - ImGui::EndCombo(); - } - - ImGui::PopID(); - } - - ImGui::Separator(); - - ImGui::PushID("Decal"); - - drawAlignedText("Showing/editing decal"); - for(UnsignedLong i = 0; i < part.decals.size(); i++) { - ImGui::SameLine(); - ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponDecal, i); - } - - drawDecalEditor(part.decals[_selectedWeaponDecal]); - - ImGui::PopID(); - - if(part.accessories.size() != 0) { - ImGui::Separator(); - - ImGui::PushID("Accessory"); - - drawAlignedText("Showing/editing accessory"); - for(UnsignedLong i = 0; i < part.accessories.size(); i++) { - ImGui::SameLine(); - ImGui::RadioButton(std::string{char(65 + i)}.c_str(), &_selectedWeaponAccessory, i); - } - - drawAccessoryEditor(part.accessories[_selectedWeaponAccessory], weapon.customStyles); - - ImGui::PopID(); - } - } - - ImGui::EndChild(); - } -} - void SaveTool::drawGlobalStyles() { if(!_currentMass || _currentMass->state() != Mass::State::Valid) { return; diff --git a/src/SaveTool/SaveTool_MassViewer_Armour.cpp b/src/SaveTool/SaveTool_MassViewer_Armour.cpp new file mode 100644 index 0000000..a3120ad --- /dev/null +++ b/src/SaveTool/SaveTool_MassViewer_Armour.cpp @@ -0,0 +1,198 @@ +// MassBuilderSaveTool +// Copyright (C) 2021-2022 Guillaume Jacquemin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "../FontAwesome/IconsFontAwesome5.h" + +#include "../Maps/ArmourSets.h" +#include "../Maps/StyleNames.h" + +#include "SaveTool.h" + +void SaveTool::drawArmour() { + if(!_currentMass || _currentMass->state() != Mass::State::Valid) { + return; + } + + if(ImGui::Button(ICON_FA_UNDO_ALT " Reset all")) { + _currentMass->getArmourParts(); + } + + if(!ImGui::BeginChild("##ArmourParts")) { + ImGui::EndChild(); + return; + } + + static const char* slot_labels[] = { +#define c(enumerator, strenum, name) name, +#include "../Maps/ArmourSlots.hpp" +#undef c + }; + + for(UnsignedInt i = 0; i < _currentMass->armourParts().size(); i++) { + ImGui::PushID(i); + + auto& part = _currentMass->armourParts()[i]; + + static char header[129] = {'\0'}; + + std::memset(header, '\0', 129); + + if(armour_sets.find(part.id) != armour_sets.cend()) { + std::snprintf(header, 128, "%s: %s###%u", slot_labels[UnsignedInt(part.slot)], armour_sets.at(part.id).name, UnsignedInt(part.slot)); + } + else { + std::snprintf(header, 128, "%s: %i###%u", slot_labels[UnsignedInt(part.slot)], part.id, UnsignedInt(part.slot)); + } + + if(ImGui::CollapsingHeader(header)) { + ImGui::BeginGroup(); + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() * 0.491f); + if(ImGui::BeginListBox("##ChangePart")) { + if(std::strncmp("Neck", slot_labels[UnsignedInt(part.slot)], 4) != 0) { + for(auto& set : armour_sets) { + if(ImGui::Selectable(set.second.name, set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) { + part.id = set.first; + } + } + } + else { + for(auto& set : armour_sets) { + if(!set.second.neck_compatible) { + continue; + } + + if(ImGui::Selectable(set.second.name, set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) { + part.id = set.first; + } + } + } + ImGui::EndListBox(); + } + + ImGui::EndGroup(); + + ImGui::SameLine(); + + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + + ImGui::SameLine(); + + ImGui::BeginGroup(); + + ImGui::TextUnformatted("Styles:"); + + for(Int j = 0; j < 4; j++) { + drawAlignedText("Slot %d:", j + 1); + + ImGui::SameLine(); + + ImGui::PushID(j); + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() - 2.0f); + if(ImGui::BeginCombo("##Style", getStyleName(part.styles[j], _currentMass->armourCustomStyles()))) { + for(const auto& style : style_names) { + if(ImGui::Selectable(getStyleName(style.first, _currentMass->armourCustomStyles()), part.styles[j] == style.first)) { + part.styles[j] = style.first; + } + } + + ImGui::EndCombo(); + } + + ImGui::PopID(); + } + + ImGui::EndGroup(); + + ImGui::Separator(); + + ImGui::PushID("Decal"); + + drawAlignedText("Showing/editing decal"); + for(UnsignedInt j = 0; j < part.decals.size(); j++) { + ImGui::SameLine(); + ImGui::RadioButton(std::to_string(j + 1).c_str(), &_selectedArmourDecals[i], j); + } + + drawDecalEditor(part.decals[_selectedArmourDecals[i]]); + + ImGui::PopID(); + + if(!part.accessories.size()) { + ImGui::Separator(); + + ImGui::PushID("Accessory"); + + drawAlignedText("Showing/editing accessory"); + for(UnsignedInt j = 0; j < part.accessories.size(); j++) { + ImGui::SameLine(); + ImGui::RadioButton(std::string{char(65 + j)}.c_str(), &_selectedArmourAccessories[i], j); + } + + drawAccessoryEditor(part.accessories[_selectedArmourAccessories[i]], _currentMass->armourCustomStyles()); + + ImGui::PopID(); + } + + ImGui::Separator(); + + if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { + if(!_currentMass->writeArmourPart(part.slot)) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + } + } + + ImGui::PopID(); + } + + ImGui::EndChild(); +} + +void SaveTool::drawCustomArmourStyles() { + if(!_currentMass || _currentMass->state() != Mass::State::Valid) { + return; + } + + if(!ImGui::BeginChild("##ArmourStyles")) { + ImGui::EndChild(); + return; + } + + ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game."); + + for(UnsignedInt i = 0; i < _currentMass->armourCustomStyles().size(); i++) { + ImGui::PushID(i); + DCSResult result; + result = drawCustomStyle(_currentMass->armourCustomStyles()[i]); + switch(result) { + case DCS_ResetStyle: + _currentMass->getArmourCustomStyles(); + break; + case DCS_Save: + if(_currentMass->writeArmourCustomStyle(i)) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + break; + default: + break; + } + ImGui::PopID(); + } + + ImGui::EndChild(); +} diff --git a/src/SaveTool/SaveTool_MassViewer_Frame.cpp b/src/SaveTool/SaveTool_MassViewer_Frame.cpp new file mode 100644 index 0000000..8aae76f --- /dev/null +++ b/src/SaveTool/SaveTool_MassViewer_Frame.cpp @@ -0,0 +1,307 @@ +// MassBuilderSaveTool +// Copyright (C) 2021-2022 Guillaume Jacquemin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "../FontAwesome/IconsFontAwesome5.h" + +#include "../Maps/StyleNames.h" + +#include "SaveTool.h" + +void SaveTool::drawFrameInfo() { + if(!_currentMass || _currentMass->state() != Mass::State::Valid) { + return; + } + + if(!ImGui::BeginChild("##FrameInfo")) { + ImGui::EndChild(); + return; + } + + ImGui::BeginGroup(); + + if(ImGui::BeginChild("##JointSliders", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 300.0f}, true, ImGuiWindowFlags_MenuBar)) { + if(ImGui::BeginMenuBar()) { + ImGui::TextUnformatted("Joint sliders"); + + ImGui::EndMenuBar(); + } + + drawJointSliders(); + } + ImGui::EndChild(); + + if(ImGui::BeginChild("##FrameStyles", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 0.0f}, true, ImGuiWindowFlags_MenuBar)) { + if(ImGui::BeginMenuBar()) { + ImGui::TextUnformatted("Frame styles"); + + ImGui::EndMenuBar(); + } + + drawFrameStyles(); + } + ImGui::EndChild(); + + ImGui::EndGroup(); + + ImGui::SameLine(); + + if(ImGui::BeginChild("##EyeFlare", {0.0f, 0.0f}, true, ImGuiWindowFlags_MenuBar)) { + if(ImGui::BeginMenuBar()) { + ImGui::TextUnformatted("Eye flare colour"); + drawHelpMarker("Right-click the picker for more options.", 250.0f); + + ImGui::EndMenuBar(); + } + + drawEyeColourPicker(); + } + ImGui::EndChild(); + + ImGui::EndChild(); +} + +void SaveTool::drawJointSliders() { + if(!_currentMass || _currentMass->state() != Mass::State::Valid) { + return; + } + + ImGui::TextWrapped("In-game values are multiplied by 100.\nFor example, 0.500 here is equal to 50 in-game."); + + if(ImGui::BeginTable("##JointSliderTable", 2, ImGuiTableFlags_Borders)) { + ImGui::TableSetupColumn("##SliderLabel", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("##Sliders", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + drawAlignedText("Neck"); + ImGui::TableSetColumnIndex(1); + ImGui::SetNextItemWidth(-1.0f); + if(ImGui::SliderFloat("##NeckSlider", &_currentMass->jointSliders().neck, 0.0f, 1.0f)) { + _jointsDirty = true; + } + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + drawAlignedText("Body"); + ImGui::TableSetColumnIndex(1); + ImGui::SetNextItemWidth(-1.0f); + if(ImGui::SliderFloat("##BodySlider", &_currentMass->jointSliders().body, 0.0f, 1.0f)) { + _jointsDirty = true; + } + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + drawAlignedText("Shoulders"); + ImGui::TableSetColumnIndex(1); + ImGui::SetNextItemWidth(-1.0f); + if(ImGui::SliderFloat("##ShouldersSlider", &_currentMass->jointSliders().shoulders, 0.0f, 1.0f)) { + _jointsDirty = true; + } + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + drawAlignedText("Hips"); + ImGui::TableSetColumnIndex(1); + ImGui::SetNextItemWidth(-1.0f); + if(ImGui::SliderFloat("##HipsSlider", &_currentMass->jointSliders().hips, 0.0f, 1.0f)) { + _jointsDirty = true; + } + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + drawAlignedText("Arms"); + ImGui::TableSetColumnIndex(1); + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{2.0f, 1.0f}); + if(ImGui::BeginTable("##UpperLowerArmsLayoutTable", 2)) { + ImGui::TableSetupColumn("##UpperArms", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("##LowerArms", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(-1.0f); + if(ImGui::SliderFloat("##UpperArmsSlider", &_currentMass->jointSliders().upperArms, 0.0f, 1.0f, "Upper: %.3f")) { + _jointsDirty = true; + } + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(-1.0f); + if(ImGui::SliderFloat("##LowerArmsSlider", &_currentMass->jointSliders().lowerArms, 0.0f, 1.0f, "Lower: %.3f")) { + _jointsDirty = true; + } + + ImGui::EndTable(); + } + ImGui::PopStyleVar(); + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + drawAlignedText("Legs"); + ImGui::TableSetColumnIndex(1); + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{2.0f, 1.0f}); + if(ImGui::BeginTable("##UpperLowerLegsLayoutTable", 2)) { + ImGui::TableSetupColumn("##UpperLegs", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("##LowerLegs", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(-1.0f); + if(ImGui::SliderFloat("##UpperLegsSlider", &_currentMass->jointSliders().upperLegs, 0.0f, 1.0f, "Upper: %.3f")) { + _jointsDirty = true; + } + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(-1.0f); + if(ImGui::SliderFloat("##LowerLegsSlider", &_currentMass->jointSliders().lowerLegs, 0.0f, 1.0f, "Lower: %.3f")) { + _jointsDirty = true; + } + + ImGui::EndTable(); + } + ImGui::PopStyleVar(); + + ImGui::EndTable(); + } + + if(!_jointsDirty) { + ImGui::BeginDisabled(); + ImGui::Button(ICON_FA_SAVE " Save"); + ImGui::SameLine(); + ImGui::Button(ICON_FA_UNDO " Reset"); + ImGui::EndDisabled(); + } + else { + if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { + if(!_currentMass->writeJointSliders()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + _jointsDirty = false; + } + ImGui::SameLine(); + if(ImGui::Button(ICON_FA_UNDO " Reset")) { + _currentMass->getJointSliders(); + _jointsDirty = false; + } + } +} + +void SaveTool::drawFrameStyles() { + if(!_currentMass || _currentMass->state() != Mass::State::Valid) { + return; + } + + for(Int i = 0; i < 4; i++) { + drawAlignedText("Slot %d:", i + 1); + + ImGui::SameLine(); + + ImGui::PushID(i); + + if(ImGui::BeginCombo("##Style", getStyleName(_currentMass->frameStyles()[i], _currentMass->frameCustomStyles()))) { + for(const auto& style : style_names) { + if(ImGui::Selectable(getStyleName(style.first, _currentMass->frameCustomStyles()), _currentMass->frameStyles()[i] == style.first)) { + _currentMass->frameStyles()[i] = style.first; + _stylesDirty = true; + } + } + + ImGui::EndCombo(); + } + + ImGui::PopID(); + } + + if(!_stylesDirty) { + ImGui::BeginDisabled(); + ImGui::Button(ICON_FA_SAVE " Save"); + ImGui::SameLine(); + ImGui::Button(ICON_FA_UNDO " Reset"); + ImGui::EndDisabled(); + } + else { + if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { + if(!_currentMass->writeFrameStyles()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + _stylesDirty = false; + } + ImGui::SameLine(); + if(ImGui::Button(ICON_FA_UNDO " Reset")) { + _currentMass->getFrameStyles(); + _stylesDirty = false; + } + } +} + +void SaveTool::drawEyeColourPicker() { + if(!_currentMass || _currentMass->state() != Mass::State::Valid) { + return; + } + + if(ImGui::ColorPicker3("##EyeFlarePicker", &_currentMass->eyeFlareColour().x())) { + _eyeFlareDirty = true; + } + + if(!_eyeFlareDirty) { + ImGui::BeginDisabled(); + ImGui::Button(ICON_FA_SAVE " Save"); + ImGui::SameLine(); + ImGui::Button(ICON_FA_UNDO " Reset"); + ImGui::EndDisabled(); + } + else { + if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { + if(!_currentMass->writeEyeFlareColour()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + _eyeFlareDirty = false; + } + ImGui::SameLine(); + if(ImGui::Button(ICON_FA_UNDO " Reset")) { + _currentMass->getEyeFlareColour(); + _eyeFlareDirty = false; + } + } +} + +void SaveTool::drawCustomFrameStyles() { + if(!_currentMass || _currentMass->state() != Mass::State::Valid) { + return; + } + + if(!ImGui::BeginChild("##FrameStyles")) { + ImGui::EndChild(); + return; + } + + ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game."); + + for(UnsignedInt i = 0; i < _currentMass->frameCustomStyles().size(); i++) { + ImGui::PushID(i); + DCSResult result; + result = drawCustomStyle(_currentMass->frameCustomStyles()[i]); + switch(result) { + case DCS_ResetStyle: + _currentMass->getFrameCustomStyles(); + break; + case DCS_Save: + if(!_currentMass->writeFrameCustomStyle(i)) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + break; + default: + break; + } + ImGui::PopID(); + } + + ImGui::EndChild(); +} diff --git a/src/SaveTool/SaveTool_MassViewer_Weapons.cpp b/src/SaveTool/SaveTool_MassViewer_Weapons.cpp new file mode 100644 index 0000000..afac126 --- /dev/null +++ b/src/SaveTool/SaveTool_MassViewer_Weapons.cpp @@ -0,0 +1,475 @@ +// MassBuilderSaveTool +// Copyright (C) 2021-2022 Guillaume Jacquemin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "../FontAwesome/IconsFontAwesome5.h" + +#include "../Maps/StyleNames.h" + +#include "SaveTool.h" + +void SaveTool::drawWeapons() { + if(!_currentMass || _currentMass->state() != Mass::State::Valid) { + _currentWeapon = nullptr; + return; + } + + const Float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + + ImGui::BeginGroup(); + + if(!ImGui::BeginTable("##WeaponsList", 1, + ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_BordersInnerH, + {ImGui::GetContentRegionAvailWidth() * 0.2f, -footer_height_to_reserve})) + { + ImGui::EndGroup(); + return; + } + + ImGui::TableSetupColumn("Weapon"); + + drawWeaponCategory("Melee weapons", _currentMass->meleeWeapons(), _meleeDirty, "MeleeWeapon", "Melee weapon"); + drawWeaponCategory("Shield", _currentMass->shields(), _shieldsDirty, "Shield", "Shield"); + drawWeaponCategory("Bullet shooters", _currentMass->bulletShooters(), _bShootersDirty, "BShooter", "Bullet shooter"); + drawWeaponCategory("Energy shooters", _currentMass->energyShooters(), _eShootersDirty, "EShooter", "Energy shooter"); + drawWeaponCategory("Bullet launchers", _currentMass->bulletLaunchers(), _bLaunchersDirty, "BLauncher", "Bullet launcher"); + drawWeaponCategory("Energy launchers", _currentMass->energyLaunchers(), _eLaunchersDirty, "ELauncher", "Energy launcher"); + + ImGui::EndTable(); + + bool dirty = _meleeDirty || _shieldsDirty || _bShootersDirty || _eShootersDirty || _bLaunchersDirty || _eLaunchersDirty; + + if(!dirty) { + ImGui::BeginDisabled(); + } + + if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { + if(_meleeDirty) { + if(!_currentMass->writeMeleeWeapons()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + else { + _meleeDirty = false; + } + } + + if(_shieldsDirty) { + if(!_currentMass->writeShields()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + else { + _shieldsDirty = false; + } + } + + if(_bShootersDirty) { + if(!_currentMass->writeBulletShooters()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + else { + _bShootersDirty = false; + } + } + + if(_eShootersDirty) { + if(_currentMass->writeEnergyShooters()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + else { + _eShootersDirty = false; + } + } + + if(_bLaunchersDirty) { + if(_currentMass->writeBulletLaunchers()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + else { + _bLaunchersDirty = false; + } + } + + if(_eLaunchersDirty) { + if(_currentMass->writeEnergyLaunchers()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + else { + _eLaunchersDirty = false; + } + } + } + + ImGui::SameLine(); + + if(ImGui::Button(ICON_FA_UNDO_ALT " Reset")) { + if(_meleeDirty) { + _currentMass->getMeleeWeapons(); + _meleeDirty = false; + } + if(_shieldsDirty) { + _currentMass->getShields(); + _shieldsDirty = false; + } + if(_bShootersDirty) { + _currentMass->getBulletShooters(); + _bShootersDirty = false; + } + if(_eShootersDirty) { + _currentMass->getEnergyShooters(); + _eShootersDirty = false; + } + if(_bLaunchersDirty) { + _currentMass->getBulletLaunchers(); + _bLaunchersDirty = false; + } + if(_eLaunchersDirty) { + _currentMass->getEnergyLaunchers(); + _eLaunchersDirty = false; + } + } + + if(!dirty) { + ImGui::EndDisabled(); + } + + ImGui::EndGroup(); + + ImGui::SameLine(); + + if(!_currentWeapon) { + ImGui::TextUnformatted("No weapon selected."); + return; + } + + ImGui::BeginGroup(); + + if(!ImGui::BeginChild("##WeaponChild", {0.0f, -footer_height_to_reserve})) { + ImGui::EndChild(); + return; + } + + drawWeaponEditor(*_currentWeapon); + + ImGui::EndChild(); + + ImGui::Separator(); + + if(drawUnsafeWidget([](){ return ImGui::Button(ICON_FA_SAVE " Save changes to weapon category"); })) { + switch(_currentWeapon->type) { + case WeaponType::Melee: + if(!_currentMass->writeMeleeWeapons()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + break; + case WeaponType::Shield: + if(!_currentMass->writeShields()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + break; + case WeaponType::BulletShooter: + if(!_currentMass->writeBulletShooters()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + break; + case WeaponType::EnergyShooter: + if(!_currentMass->writeEnergyShooters()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + break; + case WeaponType::BulletLauncher: + if(!_currentMass->writeBulletLaunchers()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + break; + case WeaponType::EnergyLauncher: + if(!_currentMass->writeEnergyLaunchers()) { + _queue.addToast(Toast::Type::Error, _currentMass->lastError()); + } + break; + default: + _queue.addToast(Toast::Type::Error, "Unknown weapon type"); + + } + } + + ImGui::SameLine(); + + if(ImGui::Button(ICON_FA_UNDO_ALT " Reset weapon category")) { + switch(_currentWeapon->type) { + case WeaponType::Melee: + _currentMass->getMeleeWeapons(); + break; + case WeaponType::Shield: + _currentMass->getShields(); + break; + case WeaponType::BulletShooter: + _currentMass->getBulletShooters(); + break; + case WeaponType::EnergyShooter: + _currentMass->getEnergyShooters(); + break; + case WeaponType::BulletLauncher: + _currentMass->getBulletLaunchers(); + break; + case WeaponType::EnergyLauncher: + _currentMass->getEnergyLaunchers(); + break; + default: + _queue.addToast(Toast::Type::Error, "Unknown weapon type"); + } + } + + ImGui::EndGroup(); +} + +void SaveTool::drawWeaponCategory(const char* name, Containers::ArrayView weapons_view, bool& dirty, + const char* payload_type, const char* payload_tooltip) +{ + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(name); + + ImGui::PushID(payload_type); + + for(UnsignedInt i = 0; i < weapons_view.size(); i++) { + auto& weapon = weapons_view[i]; + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::PushID(i); + + if(ImGui::Selectable(weapon.name.c_str(), _currentWeapon == &weapon)) { + _currentWeapon = &weapon; + } + if(ImGui::BeginDragDropSource()) { + ImGui::SetDragDropPayload(payload_type, &i, sizeof(UnsignedInt)); + if(ImGui::GetIO().KeyCtrl) { + ImGui::Text("%s %i - %s (copy)", payload_tooltip, i + 1, weapon.name.c_str()); + } + else { + ImGui::Text("%s %i - %s", payload_tooltip, i + 1, weapon.name.c_str()); + } + ImGui::EndDragDropSource(); + } + if(ImGui::BeginDragDropTarget()) { + if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(payload_type)) { + int index = *static_cast(payload->Data); + + if(!ImGui::GetIO().KeyCtrl) { + if(_currentWeapon == &weapons_view[index]) { + _currentWeapon = &weapons_view[i]; + } + else if (_currentWeapon == &weapons_view[i]) { + _currentWeapon = &weapons_view[index]; + } + + std::swap(weapons_view[index], weapons_view[i]); + } + else { + weapons_view[i] = weapons_view[index]; + } + dirty = true; + } + + ImGui::EndDragDropTarget(); + } + + ImGui::PopID(); + + if(weapon.attached == true) { + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, 0x1F008CFFu); + } + } + + ImGui::PopID(); +} + +void SaveTool::drawWeaponEditor(Weapon& weapon) { + if(!_currentMass || _currentMass->state() != Mass::State::Valid || !_currentWeapon) { + return; + } + + static const char* labels[] { +#define c(enumerator, strenum, name) name, +#include "../Maps/WeaponTypes.hpp" +#undef c + }; + + drawAlignedText("%s: %s", labels[UnsignedInt(weapon.type)], weapon.name.c_str()); + + ImGui::SameLine(); + + static Containers::StaticArray<33, char> name_buf{ValueInit}; + if(ImGui::Button(ICON_FA_EDIT " Rename")) { + for(auto& c : name_buf) { + c = '\0'; + } + std::strncpy(name_buf.data(), weapon.name.c_str(), 32); + ImGui::OpenPopup("name_edit"); + } + if(drawRenamePopup(name_buf)) { + weapon.name = name_buf.data(); + } + + ImGui::BeginGroup(); + drawAlignedText("Equipped:"); + + if(weapon.type != WeaponType::Shield) { + drawAlignedText("Damage type:"); + } + + if(weapon.type == WeaponType::Melee) { + drawAlignedText("Dual-wield:"); + + drawAlignedText("Custom effect mode:"); + + drawAlignedText("Custom effect colour:"); + } + ImGui::EndGroup(); + + ImGui::SameLine(); + + ImGui::BeginGroup(); + ImGui::Checkbox("##EquippedCheckbox", &weapon.attached); + + if(weapon.type != WeaponType::Shield) { + if(weapon.type == WeaponType::Melee && + ImGui::RadioButton("Physical##NoElement", weapon.damageType == DamageType::Physical)) + { + weapon.damageType = DamageType::Physical; + } + else if((weapon.type == WeaponType::BulletShooter || weapon.type == WeaponType::BulletLauncher) && + ImGui::RadioButton("Piercing##NoElement", weapon.damageType == DamageType::Piercing)) + { + weapon.damageType = DamageType::Piercing; + } + else if((weapon.type == WeaponType::EnergyShooter || weapon.type == WeaponType::EnergyLauncher) && + ImGui::RadioButton("Plasma##NoElement", weapon.damageType == DamageType::Plasma)) + { + weapon.damageType = DamageType::Plasma; + } + ImGui::SameLine(); + if(ImGui::RadioButton("Heat##Heat", weapon.damageType == DamageType::Heat)) { + weapon.damageType = DamageType::Heat; + } + ImGui::SameLine(); + if(ImGui::RadioButton("Freeze##Freeze", weapon.damageType == DamageType::Freeze)) { + weapon.damageType = DamageType::Freeze; + } + ImGui::SameLine(); + if(ImGui::RadioButton("Shock##Shock", weapon.damageType == DamageType::Freeze)) { + weapon.damageType = DamageType::Freeze; + } + } + + if(weapon.type == WeaponType::Melee) { + ImGui::Checkbox("##DualWield", &weapon.dualWield); + + if(ImGui::RadioButton("Default##Default", weapon.effectColourMode == EffectColourMode::Default)) { + weapon.effectColourMode = EffectColourMode::Default; + } + ImGui::SameLine(); + if(ImGui::RadioButton("Custom##Custom", weapon.effectColourMode == EffectColourMode::Custom)) { + weapon.effectColourMode = EffectColourMode::Custom; + } + + bool custom_effect = (weapon.effectColourMode == EffectColourMode::Custom); + if(!custom_effect) { + ImGui::BeginDisabled(); + } + + ImGui::ColorEdit3("##CustomEffectColourPicker", &weapon.effectColour.x(), ImGuiColorEditFlags_HDR|ImGuiColorEditFlags_Float); + + if(!custom_effect) { + ImGui::EndDisabled(); + } + } + ImGui::EndGroup(); + + ImGui::Separator(); + + if(ImGui::CollapsingHeader("Weapon parts")) { + drawAlignedText("Viewing/editing part:"); + for(Int i = 0; UnsignedLong(i) < weapon.parts.size(); i++) { + if(UnsignedLong(_selectedWeaponPart) >= weapon.parts.size()) { + _selectedWeaponPart = 0; + } + ImGui::SameLine(); + ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponPart, i); + } + + auto& part = weapon.parts[_selectedWeaponPart]; + + ImGui::Text("ID: %i", part.id); + + if(ImGui::BeginChild("##PartDetails", {0.0f, 0.0f}, true)) { + ImGui::TextUnformatted("Styles:"); + + for(Int i = 0; i < 4; i++) { + drawAlignedText("Slot %d:", i + 1); + + ImGui::SameLine(); + + ImGui::PushID(i); + + if(ImGui::BeginCombo("##Style", getStyleName(part.styles[i], weapon.customStyles))) { + for(const auto& style: style_names) { + if(ImGui::Selectable(getStyleName(style.first, weapon.customStyles), + part.styles[i] == style.first)) { + part.styles[i] = style.first; + } + } + + ImGui::EndCombo(); + } + + ImGui::PopID(); + } + + ImGui::Separator(); + + ImGui::PushID("Decal"); + + drawAlignedText("Showing/editing decal"); + for(UnsignedLong i = 0; i < part.decals.size(); i++) { + ImGui::SameLine(); + ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponDecal, i); + } + + drawDecalEditor(part.decals[_selectedWeaponDecal]); + + ImGui::PopID(); + + if(part.accessories.size() != 0) { + ImGui::Separator(); + + ImGui::PushID("Accessory"); + + drawAlignedText("Showing/editing accessory"); + for(UnsignedLong i = 0; i < part.accessories.size(); i++) { + ImGui::SameLine(); + ImGui::RadioButton(std::string{char(65 + i)}.c_str(), &_selectedWeaponAccessory, i); + } + + drawAccessoryEditor(part.accessories[_selectedWeaponAccessory], weapon.customStyles); + + ImGui::PopID(); + } + } + + ImGui::EndChild(); + } +}