// 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(); _currentMass->getBulletLauncherAttachments(); } if(!ImGui::BeginChild("##ArmourParts", {0.0f, 0.0f}, true)) { ImGui::EndChild(); return; } static Containers::StringView 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(int(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)].data(), armour_sets.at(part.id).name.data(), UnsignedInt(part.slot)); } else { std::snprintf(header, 128, "%s: %i###%u", slot_labels[UnsignedInt(part.slot)].data(), part.id, UnsignedInt(part.slot)); } if(ImGui::CollapsingHeader(header)) { ImGui::BeginGroup(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.491f); if(ImGui::BeginListBox("##ChangePart")) { if(std::strncmp("Neck", slot_labels[UnsignedInt(part.slot)].data(), 4) != 0) { for(auto& set : armour_sets) { if(ImGui::Selectable(set.second.name.data(), 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.data(), 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::GetContentRegionAvail().x - 2.0f); if(ImGui::BeginCombo("##Style", getStyleName(part.styles[j], _currentMass->armourCustomStyles()).data())) { for(const auto& style : style_names) { if(ImGui::Selectable(getStyleName(style.first, _currentMass->armourCustomStyles()).data(), 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], int(j)); } drawDecalEditor(part.decals[_selectedArmourDecals[i]]); ImGui::PopID(); if(part.accessories.size() != 0) { 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], int(j)); } drawAccessoryEditor(part.accessories[_selectedArmourAccessories[i]], _currentMass->armourCustomStyles()); ImGui::PopID(); } ImGui::Separator(); if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { _modifiedBySaveTool = true; if(!_currentMass->writeArmourPart(part.slot)) { _modifiedBySaveTool = false; _queue.addToast(Toast::Type::Error, _currentMass->lastError()); } } } ImGui::PopID(); } if(_currentMass->bulletLauncherAttachmentStyle() != BulletLauncherAttachmentStyle::NotFound && ImGui::CollapsingHeader("Bullet launcher placement")) { drawAlignedText("Attachment style:"_s); ImGui::SameLine(); ImGui::RadioButton("Active one", _currentMass->bulletLauncherAttachmentStyle() == BulletLauncherAttachmentStyle::ActiveOne); ImGui::SameLine(); ImGui::RadioButton("Active one per slot", _currentMass->bulletLauncherAttachmentStyle() == BulletLauncherAttachmentStyle::ActiveOnePerSlot); ImGui::SameLine(); ImGui::RadioButton("All equipped", _currentMass->bulletLauncherAttachmentStyle() == BulletLauncherAttachmentStyle::AllEquipped); ImGui::Separator(); drawAlignedText("Launcher slot:"); ImGui::SameLine(); ImGui::RadioButton("1", &_selectedBLPlacement, 0); ImGui::SameLine(); ImGui::RadioButton("2", &_selectedBLPlacement, 1); ImGui::SameLine(); ImGui::RadioButton("3", &_selectedBLPlacement, 2); ImGui::SameLine(); ImGui::RadioButton("4", &_selectedBLPlacement, 3); auto& placement = _currentMass->bulletLauncherAttachments()[_selectedBLPlacement]; static const Containers::StringView socket_labels[] = { #define c(enumerator, enumstr, name) name, #include "../Maps/BulletLauncherSockets.hpp" #undef c }; drawAlignedText("Socket:"); ImGui::SameLine(); if(ImGui::BeginCombo("##Socket", socket_labels[UnsignedInt(placement.socket)].data())) { for(UnsignedInt i = 0; i < (sizeof(socket_labels) / sizeof(socket_labels[0])); i++) { if(ImGui::Selectable(socket_labels[i].data(), i == UnsignedInt(placement.socket), ImGuiSelectableFlags_SpanAvailWidth)) { placement.socket = static_cast(i); } } ImGui::EndCombo(); } if(placement.socket != BulletLauncherSocket::Auto) { ImGui::BeginGroup(); drawAlignedText("Relative position:"); drawAlignedText("Offset position:"); drawAlignedText("Relative rotation:"); drawAlignedText("Offset rotation:"); drawAlignedText("Scale:"); ImGui::EndGroup(); ImGui::SameLine(); ImGui::BeginGroup(); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::DragFloat("##RelPosX", &placement.relativeLocation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##RelPosY", &placement.relativeLocation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##RelPosZ", &placement.relativeLocation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f"); ImGui::PopItemWidth(); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::SliderFloat("##OffPosX", &placement.offsetLocation.x(), -500.0f, +500.0f, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##OffPosY", &placement.offsetLocation.y(), -500.0f, +500.0f, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##OffPosZ", &placement.offsetLocation.z(), -500.0f, +500.0f, "Z: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(); drawHelpMarker("+/-500.0 = +/-250 in-game"); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::DragFloat("##RotX", &placement.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##RotY", &placement.relativeRotation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Yaw: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::DragFloat("##RotZ", &placement.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f"); ImGui::PopItemWidth(); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::SliderFloat("##RotOffsetZ", &placement.offsetRotation.z(), -180.0f, +180.0f, "Roll: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##RotOffsetX", &placement.offsetRotation.x(), -30.0f, +30.0f, "Pitch: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##RotOffsetY", &placement.offsetRotation.y(), -30.0f, +30.0f, "Yaw: %.3f"); ImGui::PopItemWidth(); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::SliderFloat("##ScaleX", &placement.relativeScale.x(), 0.5f, 1.5f, "X: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##ScaleY", &placement.relativeScale.y(), 0.5f, 1.5f, "Y: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SliderFloat("##ScaleZ", &placement.relativeScale.z(), 0.5f, 1.5f, "Z: %.3f"); ImGui::PopItemWidth(); ImGui::SameLine(); drawHelpMarker("0.5 = 50 in-game\n1.5 = 150 in-game"); ImGui::EndGroup(); } _modifiedBySaveTool = true; if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); }) && !_currentMass->writeBulletLauncherAttachments()) { _modifiedBySaveTool = false; _queue.addToast(Toast::Type::Error, _currentMass->lastError()); } } 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(int(i)); DCSResult result; result = drawCustomStyle(_currentMass->armourCustomStyles()[i]); switch(result) { case DCS_ResetStyle: _currentMass->getArmourCustomStyles(); break; case DCS_Save: _modifiedBySaveTool = true; if(!_currentMass->writeArmourCustomStyle(i)) { _modifiedBySaveTool = false; _queue.addToast(Toast::Type::Error, _currentMass->lastError()); } break; default: break; } ImGui::PopID(); } ImGui::EndChild(); }