Compare commits
45 commits
v1.3.0-pre
...
mass-viewe
Author | SHA1 | Date | |
---|---|---|---|
f522d20dd4 | |||
6208825aa6 | |||
572585e648 | |||
de2ba9ce7f | |||
d0ddc73852 | |||
a1c17b7138 | |||
350ad59f8e | |||
883d5d3f41 | |||
77d7eaefad | |||
82170b3078 | |||
88abf91047 | |||
955ec010b8 | |||
7cb9ea28b2 | |||
975f471a68 | |||
76210e147a | |||
5e06c48492 | |||
2ff32c4c78 | |||
4000421a8c | |||
8f1e3668a3 | |||
a6c0614979 | |||
2cabe6a3ba | |||
afc163f344 | |||
353a71d8ab | |||
bbc40d7c93 | |||
28db82c8a9 | |||
9f324c30fd | |||
41cd92352d | |||
940fe3feee | |||
d74a7bc219 | |||
51faed7210 | |||
8fb837bfc0 | |||
0ac1e759ca | |||
a4045e8e9b | |||
1ec4522baf | |||
13d09e4aa0 | |||
ed0c4a73bb | |||
8102d1d83a | |||
9a9c08391a | |||
51602c713a | |||
1621a4dbd5 | |||
7fb269f862 | |||
1378676bbc | |||
96768c1aab | |||
bd05a98820 | |||
7059295cb3 |
116 changed files with 2336 additions and 1510 deletions
|
@ -1,5 +1,5 @@
|
|||
# MassBuilderSaveTool
|
||||
# Copyright (C) 2021 Guillaume Jacquemin
|
||||
# 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# MassBuilderSaveTool
|
||||
# Copyright (C) 2021 Guillaume Jacquemin
|
||||
# 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
|
||||
|
@ -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
|
||||
|
@ -124,17 +127,28 @@ add_executable(MassBuilderSaveTool WIN32
|
|||
Profile/ResourceIDs.h
|
||||
MassManager/MassManager.h
|
||||
MassManager/MassManager.cpp
|
||||
Mass/Accessory.h
|
||||
Mass/ArmourPart.h
|
||||
Mass/CustomStyle.h
|
||||
Mass/Decal.h
|
||||
Mass/Joints.h
|
||||
Mass/Mass.h
|
||||
Mass/Mass.cpp
|
||||
Mass/Weapon.h
|
||||
Mass/Weapon.cpp
|
||||
Mass/WeaponPart.h
|
||||
Maps/Accessories.h
|
||||
Maps/ArmourSets.h
|
||||
Maps/ArmourSlots.h
|
||||
Maps/ArmourSlots.hpp
|
||||
Maps/DamageTypes.hpp
|
||||
Maps/EffectColourModes.hpp
|
||||
Maps/LastMissionId.h
|
||||
Maps/StoryProgress.h
|
||||
Maps/StyleNames.h
|
||||
Maps/WeaponTypes.h
|
||||
Maps/WeaponTypes.hpp
|
||||
ToastQueue/ToastQueue.h
|
||||
ToastQueue/ToastQueue.cpp
|
||||
Utilities/Crc32.h
|
||||
FontAwesome/IconsFontAwesome5.h
|
||||
FontAwesome/IconsFontAwesome5Brands.h
|
||||
resource.rc
|
||||
|
@ -153,6 +167,10 @@ endif()
|
|||
|
||||
target_link_options(MassBuilderSaveTool PRIVATE -static -static-libgcc -static-libstdc++)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||
target_link_options(MassBuilderSaveTool PRIVATE -Wl,-S)
|
||||
endif()
|
||||
|
||||
target_link_libraries(MassBuilderSaveTool PRIVATE
|
||||
Corrade::Containers
|
||||
Corrade::Utility
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
static const std::unordered_map<std::string, const char*> armour_slots {
|
||||
{"enuArmorSlots::NewEnumerator0", "Face"},
|
||||
{"enuArmorSlots::NewEnumerator1", "Upper head"},
|
||||
{"enuArmorSlots::NewEnumerator2", "Lower head"},
|
||||
{"enuArmorSlots::NewEnumerator3", "Neck"},
|
||||
{"enuArmorSlots::NewEnumerator4", "Upper body"},
|
||||
{"enuArmorSlots::NewEnumerator5", "Middle body"},
|
||||
{"enuArmorSlots::NewEnumerator23", "Backpack"},
|
||||
{"enuArmorSlots::NewEnumerator6", "Lower body"},
|
||||
{"enuArmorSlots::NewEnumerator7", "Front waist"},
|
||||
{"enuArmorSlots::NewEnumerator8", "Left front skirt"},
|
||||
{"enuArmorSlots::NewEnumerator9", "Right front skirt"},
|
||||
{"enuArmorSlots::NewEnumerator10", "Left side skirt"},
|
||||
{"enuArmorSlots::NewEnumerator11", "Right side skirt"},
|
||||
{"enuArmorSlots::NewEnumerator12", "Left back skirt"},
|
||||
{"enuArmorSlots::NewEnumerator13", "Right side skirt"},
|
||||
{"enuArmorSlots::NewEnumerator14", "Back waist"},
|
||||
{"enuArmorSlots::NewEnumerator15", "Left shoulder"},
|
||||
{"enuArmorSlots::NewEnumerator16", "Right shoulder"},
|
||||
{"enuArmorSlots::NewEnumerator17", "Left upper arm"},
|
||||
{"enuArmorSlots::NewEnumerator18", "Right upper arm"},
|
||||
{"enuArmorSlots::NewEnumerator19", "Left elbow"},
|
||||
{"enuArmorSlots::NewEnumerator20", "Right elbow"},
|
||||
{"enuArmorSlots::NewEnumerator21", "Left lower arm"},
|
||||
{"enuArmorSlots::NewEnumerator22", "Right lower arm"},
|
||||
{"enuArmorSlots::NewEnumerator24", "Left hand"},
|
||||
{"enuArmorSlots::NewEnumerator25", "Right hand"},
|
||||
{"enuArmorSlots::NewEnumerator26", "Left upper leg"},
|
||||
{"enuArmorSlots::NewEnumerator27", "Right upper leg"},
|
||||
{"enuArmorSlots::NewEnumerator28", "Left knee"},
|
||||
{"enuArmorSlots::NewEnumerator29", "Right knee"},
|
||||
{"enuArmorSlots::NewEnumerator30", "Left lower leg"},
|
||||
{"enuArmorSlots::NewEnumerator31", "Right lower leg"},
|
||||
{"enuArmorSlots::NewEnumerator32", "Left ankle"},
|
||||
{"enuArmorSlots::NewEnumerator33", "Right ankle"},
|
||||
{"enuArmorSlots::NewEnumerator34", "Left heel"},
|
||||
{"enuArmorSlots::NewEnumerator35", "Right heel"},
|
||||
{"enuArmorSlots::NewEnumerator36", "Left foot"},
|
||||
{"enuArmorSlots::NewEnumerator37", "Right foot"},
|
||||
};
|
56
src/Maps/ArmourSlots.hpp
Normal file
56
src/Maps/ArmourSlots.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifdef c
|
||||
c(Face, "enuArmorSlots::NewEnumerator0", "Face")
|
||||
c(UpperHead, "enuArmorSlots::NewEnumerator1", "Upper head")
|
||||
c(LowerHead, "enuArmorSlots::NewEnumerator2", "Lower head")
|
||||
c(Neck, "enuArmorSlots::NewEnumerator3", "Neck")
|
||||
c(UpperBody, "enuArmorSlots::NewEnumerator4", "Upper body")
|
||||
c(MiddleBody, "enuArmorSlots::NewEnumerator5", "Middle body")
|
||||
c(LowerBody, "enuArmorSlots::NewEnumerator6", "Lower body")
|
||||
c(FrontWaist, "enuArmorSlots::NewEnumerator7", "Front waist")
|
||||
c(LeftFrontSkirt, "enuArmorSlots::NewEnumerator8", "Left front skirt")
|
||||
c(RightFrontSkirt, "enuArmorSlots::NewEnumerator9", "Right front skirt")
|
||||
c(LeftSideSkirt, "enuArmorSlots::NewEnumerator10", "Left side skirt")
|
||||
c(RightSideSkirt, "enuArmorSlots::NewEnumerator11", "Right side skirt")
|
||||
c(LeftBackSkirt, "enuArmorSlots::NewEnumerator12", "Left back skirt")
|
||||
c(RightBackSkirt, "enuArmorSlots::NewEnumerator13", "Right back skirt")
|
||||
c(BackWaist, "enuArmorSlots::NewEnumerator14", "Back waist")
|
||||
c(LeftShoulder, "enuArmorSlots::NewEnumerator15", "Left shoulder")
|
||||
c(RightShoulder, "enuArmorSlots::NewEnumerator16", "Right shoulder")
|
||||
c(LeftUpperArm, "enuArmorSlots::NewEnumerator17", "Left upper arm")
|
||||
c(RightUpperArm, "enuArmorSlots::NewEnumerator18", "Right upper arm")
|
||||
c(LeftElbow, "enuArmorSlots::NewEnumerator19", "Left elbow")
|
||||
c(RightElbow, "enuArmorSlots::NewEnumerator20", "Right elbow")
|
||||
c(LeftLowerArm, "enuArmorSlots::NewEnumerator21", "Left lower arm")
|
||||
c(RightLowerArm, "enuArmorSlots::NewEnumerator22", "Right lower arm")
|
||||
c(Backpack, "enuArmorSlots::NewEnumerator23", "Backpack")
|
||||
c(LeftHand, "enuArmorSlots::NewEnumerator24", "Left hand")
|
||||
c(RightHand, "enuArmorSlots::NewEnumerator25", "Right hand")
|
||||
c(LeftUpperLeg, "enuArmorSlots::NewEnumerator26", "Left upper leg")
|
||||
c(RightUpperLeg, "enuArmorSlots::NewEnumerator27", "Right upper leg")
|
||||
c(LeftKnee, "enuArmorSlots::NewEnumerator28", "Left knee")
|
||||
c(RightKnee, "enuArmorSlots::NewEnumerator29", "Right knee")
|
||||
c(LeftLowerLeg, "enuArmorSlots::NewEnumerator30", "Left lower leg")
|
||||
c(RightLowerLeg, "enuArmorSlots::NewEnumerator31", "Right lower leg")
|
||||
c(LeftAnkle, "enuArmorSlots::NewEnumerator32", "Left ankle")
|
||||
c(RightAnkle, "enuArmorSlots::NewEnumerator33", "Right ankle")
|
||||
c(LeftHeel, "enuArmorSlots::NewEnumerator34", "Left heel")
|
||||
c(RightHeel, "enuArmorSlots::NewEnumerator35", "Right heel")
|
||||
c(LeftFoot, "enuArmorSlots::NewEnumerator36", "Left foot")
|
||||
c(RightFoot, "enuArmorSlots::NewEnumerator37", "Right foot")
|
||||
#endif
|
24
src/Maps/DamageTypes.hpp
Normal file
24
src/Maps/DamageTypes.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifdef c
|
||||
c(Physical, "enuDamageProperty::NewEnumerator0")
|
||||
c(Piercing, "enuDamageProperty::NewEnumerator1")
|
||||
c(Heat, "enuDamageProperty::NewEnumerator2")
|
||||
c(Freeze, "enuDamageProperty::NewEnumerator3")
|
||||
c(Shock, "enuDamageProperty::NewEnumerator4")
|
||||
c(Plasma, "enuDamageProperty::NewEnumerator5")
|
||||
#endif
|
20
src/Maps/EffectColourModes.hpp
Normal file
20
src/Maps/EffectColourModes.hpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifdef c
|
||||
c(Default, "enuWeaponEffectColorMode::NewEnumerator0")
|
||||
c(Custom, "enuWeaponEffectColorMode::NewEnumerator1")
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -33,6 +33,7 @@ static const std::map<Int, const char*> mission_id_map {{
|
|||
{0x006E, "Mission 11 - Tempestuous Sector"},
|
||||
{0x006F, "Mission 12 - Clashes of Metal"},
|
||||
{0x0070, "Mission 13 - The Sandstorm Glutton"},
|
||||
{0x0071, "Mission 14 - An Icy Investigation"},
|
||||
|
||||
// Hunting grounds
|
||||
{0x00C8, "Hunt 1 - Desert Pathway Safety"},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -22,7 +22,7 @@ struct StoryProgressPoint {
|
|||
Int id;
|
||||
const char* chapter;
|
||||
const char* point;
|
||||
const char* after = "";
|
||||
const char* after = nullptr;
|
||||
};
|
||||
|
||||
static const Corrade::Containers::Array<StoryProgressPoint> story_progress
|
||||
|
@ -88,5 +88,7 @@ static const Corrade::Containers::Array<StoryProgressPoint> story_progress
|
|||
{0x0579, "Chapter 2", "Returned to hangar", "After mission 13"},
|
||||
{0x057A, "Chapter 2", "Talked with Reina in development section", "After mission 13"},
|
||||
{0x057B, "Chapter 2", "Got briefing for challenges 1, 2, and 3", "After mission 13"},
|
||||
{0x057C, "Chapter 2", "Talked with Reina about device", "After mission 13"},
|
||||
{0x057D, "Chapter 2", "Got mission 14 briefing", "After mission 13"},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -22,7 +22,9 @@
|
|||
|
||||
using namespace Magnum;
|
||||
|
||||
static const std::map<Int, const char*> style_names {
|
||||
extern const std::map<Int, const char*> 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<Int, const char*> style_names {
|
|||
{225, "Dark Brown Camo"},
|
||||
{226, "Blue Camo"},
|
||||
{227, "Dark Blue Camo"},
|
||||
};
|
||||
}
|
||||
#endif
|
||||
;
|
||||
|
|
24
src/Maps/WeaponTypes.hpp
Normal file
24
src/Maps/WeaponTypes.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifdef c
|
||||
c(Melee, "enuWeaponTypes::NewEnumerator0", "Melee weapon")
|
||||
c(BulletShooter, "enuWeaponTypes::NewEnumerator1", "Bullet shooter")
|
||||
c(EnergyShooter, "enuWeaponTypes::NewEnumerator2", "Energy shooter")
|
||||
c(BulletLauncher, "enuWeaponTypes::NewEnumerator3", "Bullet launcher")
|
||||
c(EnergyLauncher, "enuWeaponTypes::NewEnumerator4", "Energy launcher")
|
||||
c(Shield, "enuWeaponTypes::NewEnumerator5", "Shield")
|
||||
#endif
|
36
src/Mass/Accessory.h
Normal file
36
src/Mass/Accessory.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <Corrade/Containers/StaticArray.h>
|
||||
|
||||
#include <Magnum/Magnum.h>
|
||||
#include <Magnum/Math/Vector3.h>
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
struct Accessory {
|
||||
Int attachIndex = -1;
|
||||
Int id = -1;
|
||||
Containers::StaticArray<2, Int> styles{ValueInit};
|
||||
Vector3 relativePosition{0.0f};
|
||||
Vector3 relativePositionOffset{0.0f};
|
||||
Vector3 relativeRotation{0.0f};
|
||||
Vector3 relativeRotationOffset{0.0f};
|
||||
Vector3 localScale{1.0f};
|
||||
};
|
79
src/Mass/ArmourPart.h
Normal file
79
src/Mass/ArmourPart.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Corrade/Containers/Array.h>
|
||||
#include <Corrade/Containers/StaticArray.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
#include "Decal.h"
|
||||
#include "Accessory.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
enum class ArmourSlot {
|
||||
Face = 0,
|
||||
UpperHead = 1,
|
||||
LowerHead = 2,
|
||||
Neck = 3,
|
||||
UpperBody = 4,
|
||||
MiddleBody = 5,
|
||||
LowerBody = 6,
|
||||
FrontWaist = 7,
|
||||
LeftFrontSkirt = 8,
|
||||
RightFrontSkirt = 9,
|
||||
LeftSideSkirt = 10,
|
||||
RightSideSkirt = 11,
|
||||
LeftBackSkirt = 12,
|
||||
RightBackSkirt = 13,
|
||||
BackWaist = 14,
|
||||
LeftShoulder = 15,
|
||||
RightShoulder = 16,
|
||||
LeftUpperArm = 17,
|
||||
RightUpperArm = 18,
|
||||
LeftElbow = 19,
|
||||
RightElbow = 20,
|
||||
LeftLowerArm = 21,
|
||||
RightLowerArm = 22,
|
||||
Backpack = 23,
|
||||
LeftHand = 24,
|
||||
RightHand = 25,
|
||||
LeftUpperLeg = 26,
|
||||
RightUpperLeg = 27,
|
||||
LeftKnee = 28,
|
||||
RightKnee = 29,
|
||||
LeftLowerLeg = 30,
|
||||
RightLowerLeg = 31,
|
||||
LeftAnkle = 32,
|
||||
RightAnkle = 33,
|
||||
LeftHeel = 34,
|
||||
RightHeel = 35,
|
||||
LeftFoot = 36,
|
||||
RightFoot = 37,
|
||||
};
|
||||
|
||||
struct ArmourPart {
|
||||
ArmourSlot slot = ArmourSlot::Face;
|
||||
Int id = 0;
|
||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
||||
Containers::Array<Decal> decals;
|
||||
Containers::Array<Accessory> accessories;
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -17,13 +17,23 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
static const std::unordered_map<std::string, const char*> weapon_types{
|
||||
{"enuWeaponTypes::NewEnumerator0", "Melee weapon"},
|
||||
{"enuWeaponTypes::NewEnumerator5", "Shield"},
|
||||
{"enuWeaponTypes::NewEnumerator1", "Bullet shooter"},
|
||||
{"enuWeaponTypes::NewEnumerator2", "Energy shooter"},
|
||||
{"enuWeaponTypes::NewEnumerator3", "Bullet launcher"},
|
||||
{"enuWeaponTypes::NewEnumerator4", "Energy launcher"},
|
||||
#include <Magnum/Magnum.h>
|
||||
#include <Magnum/Math/Color.h>
|
||||
#include <Magnum/Math/Vector2.h>
|
||||
|
||||
using namespace Magnum;
|
||||
|
||||
struct CustomStyle {
|
||||
std::string name;
|
||||
Color4 colour{0.0f};
|
||||
Float metallic = 0.5f;
|
||||
Float gloss = 0.5f;
|
||||
bool glow = false;
|
||||
|
||||
Int patternId = 0;
|
||||
Float opacity = 0.5f;
|
||||
Vector2 offset{0.5f};
|
||||
Float rotation = 0.0f;
|
||||
Float scale = 0.5f;
|
||||
};
|
38
src/Mass/Decal.h
Normal file
38
src/Mass/Decal.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Magnum/Magnum.h>
|
||||
#include <Magnum/Math/Color.h>
|
||||
#include <Magnum/Math/Vector2.h>
|
||||
|
||||
using namespace Magnum;
|
||||
|
||||
struct Decal {
|
||||
Int id = -1;
|
||||
Color4 colour{0.0f};
|
||||
Vector3 position{0.0f};
|
||||
Vector3 uAxis{0.0f};
|
||||
Vector3 vAxis{0.0f};
|
||||
Vector2 offset{0.5f};
|
||||
Float scale = 0.5f;
|
||||
Float rotation = 0.0f;
|
||||
bool flip = false;
|
||||
bool wrap = false;
|
||||
};
|
32
src/Mass/Joints.h
Normal file
32
src/Mass/Joints.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
using namespace Magnum;
|
||||
|
||||
struct Joints {
|
||||
Float neck = 0.0f;
|
||||
Float body = 0.0f;
|
||||
Float shoulders = 0.0f;
|
||||
Float hips = 0.0f;
|
||||
Float upperArms = 0.0f;
|
||||
Float lowerArms = 0.0f;
|
||||
Float upperLegs = 0.0f;
|
||||
Float lowerLegs = 0.0f;
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -14,8 +14,6 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <Corrade/Containers/Array.h>
|
||||
|
@ -35,8 +33,6 @@
|
|||
|
||||
#include "Mass.h"
|
||||
|
||||
std::string Mass::_lastError;
|
||||
|
||||
Mass::Mass(const std::string& path) {
|
||||
_folder = Utility::Directory::path(path);
|
||||
_filename = Utility::Directory::filename(path);
|
||||
|
@ -50,28 +46,28 @@ auto Mass::lastError() -> std::string const& {
|
|||
|
||||
auto Mass::getNameFromFile(const std::string& path) -> Containers::Optional<std::string> {
|
||||
if(!Utility::Directory::exists(path)) {
|
||||
_lastError = path + " couldn't be found.";
|
||||
Utility::Error{} << path.c_str() << "couldn't be found.";
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
UESaveFile mass{path};
|
||||
|
||||
if(!mass.valid()) {
|
||||
_lastError = "The unit file seems to be corrupt.";
|
||||
Utility::Error{} << "The unit file seems to be corrupt.";
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
auto unit_data = mass.at<GenericStructProperty>("UnitData");
|
||||
|
||||
if(!unit_data) {
|
||||
_lastError = "Couldn't find unit data in the file.";
|
||||
Utility::Error{} << "Couldn't find unit data in the file.";
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
auto name_prop = unit_data->at<StringProperty>("Name_45_A037C5D54E53456407BDF091344529BB");
|
||||
|
||||
if(!name_prop) {
|
||||
_lastError = "Couldn't find the name in the file.";
|
||||
Utility::Error{} << "Couldn't find the name in the file.";
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
|
@ -174,13 +170,10 @@ void Mass::refreshValues() {
|
|||
return;
|
||||
}
|
||||
|
||||
if(!_demo)
|
||||
{
|
||||
getGlobalStyles();
|
||||
if(_state == State::Invalid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
getTuning();
|
||||
if(_state == State::Invalid) {
|
||||
|
@ -193,7 +186,7 @@ void Mass::refreshValues() {
|
|||
return;
|
||||
}
|
||||
|
||||
_steamId = account_prop->value;
|
||||
_account = account_prop->value;
|
||||
|
||||
_state = State::Valid;
|
||||
}
|
||||
|
@ -232,10 +225,6 @@ auto Mass::state() -> State {
|
|||
return _state;
|
||||
}
|
||||
|
||||
auto Mass::demo() const -> bool {
|
||||
return _demo;
|
||||
}
|
||||
|
||||
auto Mass::dirty() const -> bool {
|
||||
return _dirty;
|
||||
}
|
||||
|
@ -385,7 +374,7 @@ auto Mass::writeJointSliders() -> bool {
|
|||
frame_prop->properties = std::move(temp);
|
||||
|
||||
if(!_mass->saveToFile()) {
|
||||
_lastError = "Couldn't write data to " + _filename;
|
||||
_lastError = _mass->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -452,7 +441,7 @@ auto Mass::writeFrameStyles() -> bool {
|
|||
}
|
||||
|
||||
if(!_mass->saveToFile()) {
|
||||
_lastError = "Couldn't write data to " + _filename;
|
||||
_lastError = _mass->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -489,18 +478,21 @@ auto Mass::writeEyeFlareColour() -> bool {
|
|||
auto unit_data = _mass->at<GenericStructProperty>("UnitData");
|
||||
if(!unit_data) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "No unit data in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto frame = unit_data->at<GenericStructProperty>("Frame_3_F92B0F6A44A15088AF7F41B9FF290653");
|
||||
if(!frame) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "No frame data in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto eye_flare_prop = frame->at<ColourStructProperty>("EyeFlareColor_36_AF79999C40FCA0E88A2F9A84488A38CA");
|
||||
if(!eye_flare_prop) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "No eye flare property in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -509,7 +501,12 @@ auto Mass::writeEyeFlareColour() -> bool {
|
|||
eye_flare_prop->b = _frame.eyeFlare.b();
|
||||
eye_flare_prop->a = _frame.eyeFlare.a();
|
||||
|
||||
return _mass->saveToFile();
|
||||
if(!_mass->saveToFile()) {
|
||||
_lastError = _mass->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Mass::frameCustomStyles() -> Containers::ArrayView<CustomStyle> {
|
||||
|
@ -539,18 +536,21 @@ void Mass::getFrameCustomStyles() {
|
|||
|
||||
auto Mass::writeFrameCustomStyle(UnsignedLong index) -> bool {
|
||||
if(index > _frame.customStyles.size()) {
|
||||
_lastError = "Style index out of range.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData");
|
||||
if(!unit_data) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "No unit data in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto frame_styles = unit_data->at<ArrayProperty>("FrameStyle_44_04A44C9440363CCEC5443D98BFAF22AA");
|
||||
if(!frame_styles) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "No frame styles in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -583,7 +583,15 @@ void Mass::getArmourParts() {
|
|||
auto part_prop = armour_array->at<GenericStructProperty>(i);
|
||||
auto& part = _armour.parts[i];
|
||||
|
||||
part.slot = part_prop->at<ByteProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C")->enumValue;
|
||||
auto& armour_slot = part_prop->at<ByteProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C")->enumValue;
|
||||
#define c(enumerator, strenum, name) if(armour_slot == (strenum)) { part.slot = ArmourSlot::enumerator; } else
|
||||
#include "../Maps/ArmourSlots.hpp"
|
||||
#undef c
|
||||
{
|
||||
_state = State::Invalid;
|
||||
Utility::Warning{} << "Invalid armour slot enum value in getArmourParts().";
|
||||
}
|
||||
|
||||
part.id = part_prop->at<IntProperty>("ID_5_ACD101864D3481DE96EDACACC09BDD25")->value;
|
||||
|
||||
auto part_styles = part_prop->at<ArrayProperty>("Styles_47_3E31870441DFD7DB8BEE5C85C26B365B");
|
||||
|
@ -607,44 +615,58 @@ void Mass::getArmourParts() {
|
|||
return;
|
||||
}
|
||||
|
||||
if(decals_array->items.size() != part.decals.size()) {
|
||||
part.demoDecals = decals_array->items.size();
|
||||
_demo = true;
|
||||
}
|
||||
part.decals = Containers::Array<Decal>{decals_array->items.size()};
|
||||
|
||||
getDecals(part.decals, decals_array);
|
||||
|
||||
if(!_demo) {
|
||||
auto accs_array = part_prop->at<ArrayProperty>("Accessories_52_D902DD4241FA0050C2529596255153F3");
|
||||
if(!accs_array) {
|
||||
_demo = true;
|
||||
part.accessories = Containers::Array<Accessory>{};
|
||||
continue;
|
||||
}
|
||||
|
||||
if(accs_array->items.size() != part.accessories.size()) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
if(part.accessories.size() != accs_array->items.size()) {
|
||||
part.accessories = Containers::Array<Accessory>{accs_array->items.size()};
|
||||
}
|
||||
|
||||
getAccessories(part.accessories, accs_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Mass::writeArmourPart(UnsignedLong index) -> bool {
|
||||
if(index > _armour.parts.size()) {
|
||||
return false;
|
||||
}
|
||||
auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
||||
auto& part = *std::find_if(_armour.parts.begin(), _armour.parts.end(), [&slot](const ArmourPart& part){ return slot == part.slot; });
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData");
|
||||
|
||||
auto armour_array = unit_data->at<ArrayProperty>("Armor_10_12E266C44116DDAF57E99ABB575A4B3C");
|
||||
|
||||
auto part_prop = armour_array->at<GenericStructProperty>(index);
|
||||
const char* slot_str = nullptr;
|
||||
switch(slot) {
|
||||
#define c(enumerator, strenum, name) case ArmourSlot::enumerator: \
|
||||
slot_str = strenum; \
|
||||
break;
|
||||
#include "../Maps/ArmourSlots.hpp"
|
||||
#undef c
|
||||
}
|
||||
|
||||
auto& part = _armour.parts[index];
|
||||
GenericStructProperty* part_prop = nullptr;
|
||||
|
||||
if(part_prop->at<ByteProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C")->enumValue != part.slot) {
|
||||
for(UnsignedInt i = 0; i < armour_array->items.size(); i++) {
|
||||
part_prop = armour_array->at<GenericStructProperty>(i);
|
||||
if(slot_str != part_prop->at<StringProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C")->value) {
|
||||
part_prop = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if(!part_prop) {
|
||||
_lastError = "Couldn't find the armour part for slot ";
|
||||
switch(slot) {
|
||||
#define c(enumerator, strenum, name) case ArmourSlot::enumerator: \
|
||||
_lastError += "ArmourSlot::" #enumerator "."; \
|
||||
break;
|
||||
#include "../Maps/ArmourSlots.hpp"
|
||||
#undef c
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -656,75 +678,19 @@ auto Mass::writeArmourPart(UnsignedLong index) -> bool {
|
|||
}
|
||||
|
||||
auto decals_array = part_prop->at<ArrayProperty>("Decals_42_F358794A4F18497970F56BA9627D3603");
|
||||
for(UnsignedInt i = 0; i < decals_array->items.size(); i++) {
|
||||
auto decal_prop = decals_array->at<GenericStructProperty>(i);
|
||||
auto& decal = part.decals[i];
|
||||
writeDecals(part.decals, decals_array);
|
||||
|
||||
decal_prop->at<IntProperty>("ID_3_694C0B35404D8A3168AEC89026BC8CF9")->value = decal.id;
|
||||
auto colour_prop = decal_prop->at<ColourStructProperty>("Color_8_1B0B9D2B43DA6AAB9FA549B374D3E606");
|
||||
colour_prop->r = decal.colour.r();
|
||||
colour_prop->g = decal.colour.g();
|
||||
colour_prop->b = decal.colour.b();
|
||||
colour_prop->a = decal.colour.a();
|
||||
auto pos_prop = decal_prop->at<VectorStructProperty>("Position_41_022C8FE84E1AAFE587261E88F2C72250");
|
||||
pos_prop->x = decal.position.x();
|
||||
pos_prop->y = decal.position.y();
|
||||
pos_prop->z = decal.position.z();
|
||||
auto u_prop = decal_prop->at<VectorStructProperty>("UAxis_37_EBEB715F45491AECACCC07A1AE4646D1");
|
||||
u_prop->x = decal.uAxis.x();
|
||||
u_prop->y = decal.uAxis.y();
|
||||
u_prop->z = decal.uAxis.z();
|
||||
auto v_prop = decal_prop->at<VectorStructProperty>("VAxis_39_C31EB2664EE202CAECFBBB84100B5E35");
|
||||
v_prop->x = decal.vAxis.x();
|
||||
v_prop->y = decal.vAxis.y();
|
||||
v_prop->z = decal.vAxis.z();
|
||||
auto offset_prop = decal_prop->at<Vector2DStructProperty>("Offset_29_B02BBBB74FC60F5EDBEBAB8020738020");
|
||||
offset_prop->x = decal.offset.x();
|
||||
offset_prop->y = decal.offset.y();
|
||||
decal_prop->at<FloatProperty>("Scale_32_959D1C2747AFD8D62808468235CBBA40")->value = decal.scale;
|
||||
decal_prop->at<FloatProperty>("Rotation_27_12D7C314493D203D5C2326A03C5F910F")->value = decal.rotation;
|
||||
decal_prop->at<BoolProperty>("Flip_35_CECCFB184CCD9412BD93FE9A8B656BE1")->value = decal.flip;
|
||||
decal_prop->at<BoolProperty>("Wrap_43_A7C68CDF4A92AF2ECDA53F953EE7CA62")->value = decal.wrap;
|
||||
}
|
||||
|
||||
if(!_demo) {
|
||||
if(part.accessories.size() != 0) {
|
||||
auto accs_array = part_prop->at<ArrayProperty>("Accessories_52_D902DD4241FA0050C2529596255153F3");
|
||||
|
||||
for(UnsignedInt i = 0; i < accs_array->items.size(); i++) {
|
||||
auto acc_prop = accs_array->at<GenericStructProperty>(i);
|
||||
|
||||
auto& accessory = part.accessories[i];
|
||||
|
||||
acc_prop->at<IntProperty>("AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20")->value = accessory.attachIndex;
|
||||
acc_prop->at<IntProperty>("ID_4_5757B32647BAE263266259B8A7DFFFC1")->value = accessory.id;
|
||||
auto acc_styles = acc_prop->at<ArrayProperty>("Styles_7_91DEB0F24E24D13FC9472882C11D0DFD");
|
||||
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
|
||||
acc_styles->at<IntProperty>(j)->value = accessory.styles[j];
|
||||
}
|
||||
auto rel_pos_prop = acc_prop->at<VectorStructProperty>("RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1");
|
||||
rel_pos_prop->x = accessory.relativePosition.x();
|
||||
rel_pos_prop->y = accessory.relativePosition.y();
|
||||
rel_pos_prop->z = accessory.relativePosition.z();
|
||||
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>("RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6");
|
||||
rel_pos_offset_prop->x = accessory.relativePositionOffset.x();
|
||||
rel_pos_offset_prop->y = accessory.relativePositionOffset.y();
|
||||
rel_pos_offset_prop->z = accessory.relativePositionOffset.z();
|
||||
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>("RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0");
|
||||
rel_rot_prop->x = accessory.relativeRotation.x();
|
||||
rel_rot_prop->y = accessory.relativeRotation.y();
|
||||
rel_rot_prop->z = accessory.relativeRotation.z();
|
||||
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>("RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA");
|
||||
rel_rot_offset_prop->x = accessory.relativeRotationOffset.x();
|
||||
rel_rot_offset_prop->y = accessory.relativeRotationOffset.y();
|
||||
rel_rot_offset_prop->z = accessory.relativeRotationOffset.z();
|
||||
auto local_scale_prop = acc_prop->at<VectorStructProperty>("LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53");
|
||||
local_scale_prop->x = accessory.localScale.x();
|
||||
local_scale_prop->y = accessory.localScale.y();
|
||||
local_scale_prop->z = accessory.localScale.z();
|
||||
}
|
||||
writeAccessories(part.accessories, accs_array);
|
||||
}
|
||||
|
||||
return _mass->saveToFile();
|
||||
if(!_mass->saveToFile()) {
|
||||
_lastError = _mass->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Mass::armourCustomStyles() -> Containers::ArrayView<CustomStyle> {
|
||||
|
@ -754,17 +720,20 @@ void Mass::getArmourCustomStyles() {
|
|||
|
||||
auto Mass::writeArmourCustomStyle(UnsignedLong index) -> bool {
|
||||
if(index > _armour.customStyles.size()) {
|
||||
_lastError = "Style index out of range.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData");
|
||||
if(!unit_data) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "Couldn't find unit data in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto armour_styles = unit_data->at<ArrayProperty>("ArmorStyle_42_E2F6AC3647788CB366BD469B3B7E899E");
|
||||
if(!armour_styles) {
|
||||
_lastError = "Couldn't find armour custom styles in " + _filename;
|
||||
_state = State::Invalid;
|
||||
return false;
|
||||
}
|
||||
|
@ -857,13 +826,12 @@ void Mass::getGlobalStyles() {
|
|||
|
||||
auto global_styles = unit_data->at<ArrayProperty>("GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B");
|
||||
if(!global_styles) {
|
||||
_state = State::Invalid;
|
||||
_globalStyles = Containers::Array<CustomStyle>{0};
|
||||
return;
|
||||
}
|
||||
|
||||
if(global_styles->items.size() != _globalStyles.size()) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
_globalStyles = Containers::Array<CustomStyle>{global_styles->items.size()};
|
||||
}
|
||||
|
||||
getCustomStyles(_globalStyles, global_styles);
|
||||
|
@ -871,18 +839,21 @@ void Mass::getGlobalStyles() {
|
|||
|
||||
auto Mass::writeGlobalStyle(UnsignedLong index) -> bool {
|
||||
if(index > _globalStyles.size()) {
|
||||
_lastError = "Global style index out of range";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData");
|
||||
if(!unit_data) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "No unit data found in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto global_styles = unit_data->at<ArrayProperty>("GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B");
|
||||
if(!global_styles) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "No global styles found in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -930,18 +901,28 @@ auto Mass::techs() -> Containers::ArrayView<Int> {
|
|||
return _tuning.techIds;
|
||||
}
|
||||
|
||||
auto Mass::updateSteamId(const std::string& steam_id) -> bool {
|
||||
_steamId = steam_id;
|
||||
auto Mass::account() -> const std::string& {
|
||||
return _account;
|
||||
}
|
||||
|
||||
auto Mass::updateAccount(const std::string& new_account) -> bool {
|
||||
_account = new_account;
|
||||
|
||||
auto account = _mass->at<StringProperty>("Account");
|
||||
if(!account) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "Couldn't find the account property.";
|
||||
return false;
|
||||
}
|
||||
|
||||
account->value = steam_id;
|
||||
account->value = new_account;
|
||||
|
||||
return _mass->saveToFile();
|
||||
if(!_mass->saveToFile()) {
|
||||
_lastError = _mass->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mass::getCustomStyles(Containers::ArrayView<CustomStyle> styles, ArrayProperty* style_array) {
|
||||
|
@ -969,11 +950,17 @@ void Mass::getCustomStyles(Containers::ArrayView<CustomStyle> styles, ArrayPrope
|
|||
|
||||
auto Mass::setCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool {
|
||||
if(!style_array) {
|
||||
_lastError = "Mass::setCustomStyle(): style_array is null.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto style_prop = style_array->at<GenericStructProperty>(index);
|
||||
|
||||
if(!style_prop) {
|
||||
_lastError = "Style index is out of range in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
style_prop->at<StringProperty>("Name_27_1532115A46EF2B2FA283908DF561A86B")->value = style.name;
|
||||
auto colour_prop = style_prop->at<ColourStructProperty>("Color_5_F0D383DF40474C9464AE48A0984A212E");
|
||||
colour_prop->r = style.colour.r();
|
||||
|
@ -990,7 +977,12 @@ auto Mass::setCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayPro
|
|||
style_prop->at<FloatProperty>("Rotation_25_EC2DFAD84AD0A6BD3FA841ACD52EDD6D")->value = style.rotation;
|
||||
style_prop->at<FloatProperty>("Scale_26_19DF0708409262183E1247B317137671")->value = style.scale;
|
||||
|
||||
return _mass->saveToFile();
|
||||
if(!_mass->saveToFile()) {
|
||||
_lastError = _mass->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mass::getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array) {
|
||||
|
@ -1016,161 +1008,10 @@ void Mass::getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_a
|
|||
}
|
||||
}
|
||||
|
||||
void Mass::getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array) {
|
||||
for(UnsignedInt i = 0; i < accessory_array->items.size(); i++) {
|
||||
auto acc_prop = accessory_array->at<GenericStructProperty>(i);
|
||||
auto& accessory = accessories[i];
|
||||
|
||||
accessory.attachIndex = acc_prop->at<IntProperty>("AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20")->value;
|
||||
accessory.id = acc_prop->at<IntProperty>("ID_4_5757B32647BAE263266259B8A7DFFFC1")->value;
|
||||
auto acc_styles = acc_prop->at<ArrayProperty>("Styles_7_91DEB0F24E24D13FC9472882C11D0DFD");
|
||||
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
|
||||
accessory.styles[j] = acc_styles->at<IntProperty>(j)->value;
|
||||
}
|
||||
auto rel_pos_prop = acc_prop->at<VectorStructProperty>("RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1");
|
||||
accessory.relativePosition = Vector3{rel_pos_prop->x, rel_pos_prop->y, rel_pos_prop->z};
|
||||
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>("RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6");
|
||||
accessory.relativePositionOffset = Vector3{rel_pos_offset_prop->x, rel_pos_offset_prop->y, rel_pos_offset_prop->z};
|
||||
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>("RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0");
|
||||
accessory.relativeRotation = Vector3{rel_rot_prop->x, rel_rot_prop->y, rel_rot_prop->z};
|
||||
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>("RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA");
|
||||
accessory.relativeRotationOffset = Vector3{rel_rot_offset_prop->x, rel_rot_offset_prop->y, rel_rot_offset_prop->z};
|
||||
auto local_scale_prop = acc_prop->at<VectorStructProperty>("LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53");
|
||||
accessory.localScale = Vector3{local_scale_prop->x, local_scale_prop->y, local_scale_prop->z};
|
||||
}
|
||||
}
|
||||
|
||||
void Mass::getWeaponType(const char* prop_name, Containers::ArrayView<Weapon> weapon_array) {
|
||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData");
|
||||
if(!unit_data) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
||||
if(!prop) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if(prop->items.size() != weapon_array.size()) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < weapon_array.size(); i++) {
|
||||
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
||||
auto& weapon = weapon_array[i];
|
||||
|
||||
weapon.name = weapon_prop->at<StringProperty>("Name_13_7BF0D31F4E50C50C47231BB36A485D92")->value;
|
||||
weapon.type = weapon_prop->at<ByteProperty>("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976")->enumValue;
|
||||
|
||||
auto parts_prop = weapon_prop->at<ArrayProperty>("Element_6_8E4617CC4B2C1F1490435599784EC6E0");
|
||||
weapon.parts = Containers::Array<WeaponPart>{ValueInit, parts_prop->items.size()};
|
||||
|
||||
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
||||
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
||||
auto& part = weapon.parts[j];
|
||||
|
||||
part.id = part_prop->at<IntProperty>("ID_2_A74D75434308158E5926178822DD28EE")->value;
|
||||
|
||||
auto part_styles = part_prop->at<ArrayProperty>("Styles_17_994C97C34A90667BE5B716BFD0B97588");
|
||||
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
||||
part.styles[k] = part_styles->at<IntProperty>(k)->value;
|
||||
}
|
||||
|
||||
auto part_decals = part_prop->at<ArrayProperty>("Decals_13_8B81112B453D7230C0CDE982185E14F1");
|
||||
if(part_decals->items.size() != part.decals.size()) {
|
||||
_demo = true;
|
||||
part.demoDecals = part_decals->items.size();
|
||||
}
|
||||
|
||||
getDecals(part.decals, part_decals);
|
||||
|
||||
if(!_demo) {
|
||||
auto part_accs = part_prop->at<ArrayProperty>("Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C");
|
||||
if(!part_accs) {
|
||||
_demo = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(part_accs->items.size() != part.accessories.size()) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
getAccessories(part.accessories, part_accs);
|
||||
}
|
||||
}
|
||||
|
||||
auto custom_styles = weapon_prop->at<ArrayProperty>("Styles_10_8C3C82444B986AD7A99595AD4985912D");
|
||||
if(!custom_styles) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if(custom_styles->items.size() != weapon.customStyles.size()) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
getCustomStyles(weapon.customStyles, custom_styles);
|
||||
|
||||
weapon.attached = weapon_prop->at<BoolProperty>("Attach_15_D00AABBD4AD6A04778D56D81E51927B3")->value;
|
||||
weapon.damageType = weapon_prop->at<ByteProperty>("DamageType_18_E1FFA53540591A9087EC698117A65C83")->enumValue;
|
||||
weapon.dualWield = weapon_prop->at<BoolProperty>("DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222")->value;
|
||||
weapon.effectColourMode = weapon_prop->at<ByteProperty>("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014")->enumValue;
|
||||
auto effect_colour = weapon_prop->at<ColourStructProperty>("ColorEfx_26_D921B62946C493E487455A831F4520AC");
|
||||
weapon.effectColour = Color4{effect_colour->r, effect_colour->g, effect_colour->b, effect_colour->a};
|
||||
}
|
||||
}
|
||||
|
||||
auto Mass::writeWeaponType(const char* prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool {
|
||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData");
|
||||
if(!unit_data) {
|
||||
_state = State::Invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
||||
if(!prop) {
|
||||
_state = State::Invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(prop->items.size() != weapon_array.size()) {
|
||||
_state = State::Invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < weapon_array.size(); i++) {
|
||||
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
||||
auto& weapon = weapon_array[i];
|
||||
|
||||
weapon_prop->at<StringProperty>("Name_13_7BF0D31F4E50C50C47231BB36A485D92")->value = weapon.name;
|
||||
weapon_prop->at<ByteProperty>("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976")->enumValue = weapon.type;
|
||||
|
||||
auto parts_prop = weapon_prop->at<ArrayProperty>("Element_6_8E4617CC4B2C1F1490435599784EC6E0");
|
||||
if(parts_prop->items.size() != weapon.parts.size()) {
|
||||
_state = State::Invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
||||
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
||||
auto& part = weapon.parts[j];
|
||||
|
||||
part_prop->at<IntProperty>("ID_2_A74D75434308158E5926178822DD28EE")->value = part.id;
|
||||
|
||||
auto part_styles = part_prop->at<ArrayProperty>("Styles_17_994C97C34A90667BE5B716BFD0B97588");
|
||||
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
||||
part_styles->at<IntProperty>(k)->value = part.styles[k];
|
||||
}
|
||||
|
||||
auto part_decals = part_prop->at<ArrayProperty>("Decals_13_8B81112B453D7230C0CDE982185E14F1");
|
||||
for(UnsignedInt k = 0; k < part_decals->items.size(); k++) {
|
||||
auto decal_prop = part_decals->at<GenericStructProperty>(k);
|
||||
auto& decal = part.decals[k];
|
||||
void Mass::writeDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array) {
|
||||
for(UnsignedInt i = 0; i < decal_array->items.size(); i++) {
|
||||
auto decal_prop = decal_array->at<GenericStructProperty>(i);
|
||||
auto& decal = decals[i];
|
||||
|
||||
decal_prop->at<IntProperty>("ID_3_694C0B35404D8A3168AEC89026BC8CF9")->value = decal.id;
|
||||
auto colour_prop = decal_prop->at<ColourStructProperty>("Color_8_1B0B9D2B43DA6AAB9FA549B374D3E606");
|
||||
|
@ -1198,31 +1039,246 @@ auto Mass::writeWeaponType(const char* prop_name, Containers::ArrayView<Weapon>
|
|||
decal_prop->at<BoolProperty>("Flip_35_CECCFB184CCD9412BD93FE9A8B656BE1")->value = decal.flip;
|
||||
decal_prop->at<BoolProperty>("Wrap_43_A7C68CDF4A92AF2ECDA53F953EE7CA62")->value = decal.wrap;
|
||||
}
|
||||
}
|
||||
|
||||
void Mass::getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array) {
|
||||
for(UnsignedInt i = 0; i < accessory_array->items.size(); i++) {
|
||||
auto acc_prop = accessory_array->at<GenericStructProperty>(i);
|
||||
auto& accessory = accessories[i];
|
||||
|
||||
accessory.attachIndex = acc_prop->at<IntProperty>("AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20")->value;
|
||||
accessory.id = acc_prop->at<IntProperty>("ID_4_5757B32647BAE263266259B8A7DFFFC1")->value;
|
||||
auto acc_styles = acc_prop->at<ArrayProperty>("Styles_7_91DEB0F24E24D13FC9472882C11D0DFD");
|
||||
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
|
||||
accessory.styles[j] = acc_styles->at<IntProperty>(j)->value;
|
||||
}
|
||||
auto rel_pos_prop = acc_prop->at<VectorStructProperty>("RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1");
|
||||
accessory.relativePosition = Vector3{rel_pos_prop->x, rel_pos_prop->y, rel_pos_prop->z};
|
||||
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>("RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6");
|
||||
accessory.relativePositionOffset = Vector3{rel_pos_offset_prop->x, rel_pos_offset_prop->y, rel_pos_offset_prop->z};
|
||||
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>("RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0");
|
||||
accessory.relativeRotation = Vector3{rel_rot_prop->x, rel_rot_prop->y, rel_rot_prop->z};
|
||||
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>("RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA");
|
||||
accessory.relativeRotationOffset = Vector3{rel_rot_offset_prop->x, rel_rot_offset_prop->y, rel_rot_offset_prop->z};
|
||||
auto local_scale_prop = acc_prop->at<VectorStructProperty>("LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53");
|
||||
accessory.localScale = Vector3{local_scale_prop->x, local_scale_prop->y, local_scale_prop->z};
|
||||
}
|
||||
}
|
||||
|
||||
void Mass::writeAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accs_array) {
|
||||
for(UnsignedInt i = 0; i < accs_array->items.size(); i++) {
|
||||
auto acc_prop = accs_array->at<GenericStructProperty>(i);
|
||||
auto& accessory = accessories[i];
|
||||
|
||||
acc_prop->at<IntProperty>("AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20")->value = accessory.attachIndex;
|
||||
acc_prop->at<IntProperty>("ID_4_5757B32647BAE263266259B8A7DFFFC1")->value = accessory.id;
|
||||
auto acc_styles = acc_prop->at<ArrayProperty>("Styles_7_91DEB0F24E24D13FC9472882C11D0DFD");
|
||||
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
|
||||
acc_styles->at<IntProperty>(j)->value = accessory.styles[j];
|
||||
}
|
||||
auto rel_pos_prop = acc_prop->at<VectorStructProperty>("RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1");
|
||||
rel_pos_prop->x = accessory.relativePosition.x();
|
||||
rel_pos_prop->y = accessory.relativePosition.y();
|
||||
rel_pos_prop->z = accessory.relativePosition.z();
|
||||
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>("RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6");
|
||||
rel_pos_offset_prop->x = accessory.relativePositionOffset.x();
|
||||
rel_pos_offset_prop->y = accessory.relativePositionOffset.y();
|
||||
rel_pos_offset_prop->z = accessory.relativePositionOffset.z();
|
||||
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>("RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0");
|
||||
rel_rot_prop->x = accessory.relativeRotation.x();
|
||||
rel_rot_prop->y = accessory.relativeRotation.y();
|
||||
rel_rot_prop->z = accessory.relativeRotation.z();
|
||||
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>("RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA");
|
||||
rel_rot_offset_prop->x = accessory.relativeRotationOffset.x();
|
||||
rel_rot_offset_prop->y = accessory.relativeRotationOffset.y();
|
||||
rel_rot_offset_prop->z = accessory.relativeRotationOffset.z();
|
||||
auto local_scale_prop = acc_prop->at<VectorStructProperty>("LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53");
|
||||
local_scale_prop->x = accessory.localScale.x();
|
||||
local_scale_prop->y = accessory.localScale.y();
|
||||
local_scale_prop->z = accessory.localScale.z();
|
||||
}
|
||||
}
|
||||
|
||||
void Mass::getWeaponType(const char* prop_name, Containers::ArrayView<Weapon> weapon_array) {
|
||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData");
|
||||
if(!unit_data) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
||||
if(!prop) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if(prop->items.size() != weapon_array.size()) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < weapon_array.size(); i++) {
|
||||
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
||||
auto& weapon = weapon_array[i];
|
||||
|
||||
weapon.name = weapon_prop->at<StringProperty>("Name_13_7BF0D31F4E50C50C47231BB36A485D92")->value;
|
||||
auto& weapon_type = weapon_prop->at<ByteProperty>("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976")->enumValue;
|
||||
#define c(enumerator, strenum, name) if(weapon_type == (strenum)) { weapon.type = WeaponType::enumerator; } else
|
||||
#include "../Maps/WeaponTypes.hpp"
|
||||
#undef c
|
||||
{
|
||||
_state = State::Invalid;
|
||||
Utility::Warning{} << "Invalid weapon type enum value in getWeaponType().";
|
||||
}
|
||||
|
||||
auto parts_prop = weapon_prop->at<ArrayProperty>("Element_6_8E4617CC4B2C1F1490435599784EC6E0");
|
||||
weapon.parts = Containers::Array<WeaponPart>{ValueInit, parts_prop->items.size()};
|
||||
|
||||
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
||||
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
||||
auto& part = weapon.parts[j];
|
||||
|
||||
part.id = part_prop->at<IntProperty>("ID_2_A74D75434308158E5926178822DD28EE")->value;
|
||||
|
||||
auto part_styles = part_prop->at<ArrayProperty>("Styles_17_994C97C34A90667BE5B716BFD0B97588");
|
||||
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
||||
part.styles[k] = part_styles->at<IntProperty>(k)->value;
|
||||
}
|
||||
|
||||
auto part_decals = part_prop->at<ArrayProperty>("Decals_13_8B81112B453D7230C0CDE982185E14F1");
|
||||
if(part_decals->items.size() != part.decals.size()) {
|
||||
part.decals = Containers::Array<Decal>{part_decals->items.size()};
|
||||
}
|
||||
|
||||
getDecals(part.decals, part_decals);
|
||||
|
||||
if(!_demo) {
|
||||
auto part_accs = part_prop->at<ArrayProperty>("Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C");
|
||||
if(!part_accs) {
|
||||
_demo = true;
|
||||
part.accessories = Containers::Array<Accessory>{0};
|
||||
continue;
|
||||
}
|
||||
|
||||
if(part_accs->items.size() != part.accessories.size()) {
|
||||
_state = State::Invalid;
|
||||
return false;
|
||||
part.accessories = Containers::Array<Accessory>{part_accs->items.size()};
|
||||
}
|
||||
|
||||
getAccessories(part.accessories, part_accs);
|
||||
}
|
||||
}
|
||||
|
||||
auto custom_styles = weapon_prop->at<ArrayProperty>("Styles_10_8C3C82444B986AD7A99595AD4985912D");
|
||||
if(!custom_styles) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if(custom_styles->items.size() != weapon.customStyles.size()) {
|
||||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
getCustomStyles(weapon.customStyles, custom_styles);
|
||||
|
||||
weapon.attached = weapon_prop->at<BoolProperty>("Attach_15_D00AABBD4AD6A04778D56D81E51927B3")->value;
|
||||
auto& damage_type = weapon_prop->at<ByteProperty>("DamageType_18_E1FFA53540591A9087EC698117A65C83")->enumValue;
|
||||
#define c(enumerator, strenum) if(damage_type == (strenum)) { weapon.damageType = DamageType::enumerator; } else
|
||||
#include "../Maps/DamageTypes.hpp"
|
||||
#undef c
|
||||
{
|
||||
_state = State::Invalid;
|
||||
Utility::Warning{} << "Invalid damage type enum value in getWeaponType().";
|
||||
}
|
||||
weapon.dualWield = weapon_prop->at<BoolProperty>("DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222")->value;
|
||||
auto& effect_colour_mode = weapon_prop->at<ByteProperty>("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014")->enumValue;
|
||||
#define c(enumerator, strenum) if(effect_colour_mode == (strenum)) { weapon.effectColourMode = EffectColourMode::enumerator; } else
|
||||
#include "../Maps/EffectColourModes.hpp"
|
||||
#undef c
|
||||
{
|
||||
_state = State::Invalid;
|
||||
Utility::Warning{} << "Invalid effect colour mode in getWeaponType().";
|
||||
}
|
||||
auto effect_colour = weapon_prop->at<ColourStructProperty>("ColorEfx_26_D921B62946C493E487455A831F4520AC");
|
||||
weapon.effectColour = Color4{effect_colour->r, effect_colour->g, effect_colour->b, effect_colour->a};
|
||||
}
|
||||
}
|
||||
|
||||
auto Mass::writeWeaponType(const char* prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool {
|
||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData");
|
||||
if(!unit_data) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "No unit data in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
||||
if(!prop) {
|
||||
_state = State::Invalid;
|
||||
_lastError = std::string{prop_name} + " not found in " + _filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(prop->items.size() != weapon_array.size()) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "Weapon type array size mismatch.";
|
||||
return false;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < weapon_array.size(); i++) {
|
||||
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
||||
auto& weapon = weapon_array[i];
|
||||
|
||||
weapon_prop->at<StringProperty>("Name_13_7BF0D31F4E50C50C47231BB36A485D92")->value = weapon.name;
|
||||
switch(weapon.type) {
|
||||
#define c(enumerator, strenum, name) case WeaponType::enumerator: weapon_prop->at<ByteProperty>("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976")->enumValue = strenum; break;
|
||||
#include "../Maps/WeaponTypes.hpp"
|
||||
#undef c
|
||||
default:
|
||||
Utility::Warning{} << "Invalid weapon type enum value in writeWeaponType().";
|
||||
}
|
||||
|
||||
auto parts_prop = weapon_prop->at<ArrayProperty>("Element_6_8E4617CC4B2C1F1490435599784EC6E0");
|
||||
if(parts_prop->items.size() != weapon.parts.size()) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "Weapon parts array size mismatch.";
|
||||
return false;
|
||||
}
|
||||
|
||||
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
||||
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
||||
auto& part = weapon.parts[j];
|
||||
|
||||
part_prop->at<IntProperty>("ID_2_A74D75434308158E5926178822DD28EE")->value = part.id;
|
||||
|
||||
auto part_styles = part_prop->at<ArrayProperty>("Styles_17_994C97C34A90667BE5B716BFD0B97588");
|
||||
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
||||
part_styles->at<IntProperty>(k)->value = part.styles[k];
|
||||
}
|
||||
|
||||
auto part_decals = part_prop->at<ArrayProperty>("Decals_13_8B81112B453D7230C0CDE982185E14F1");
|
||||
writeDecals(part.decals, part_decals);
|
||||
|
||||
auto part_accs = part_prop->at<ArrayProperty>("Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C");
|
||||
if(!part_accs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(part_accs->items.size() != part.accessories.size()) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "Accessories array size mismatch.";
|
||||
return false;
|
||||
}
|
||||
|
||||
writeAccessories(part.accessories, part_accs);
|
||||
}
|
||||
|
||||
auto custom_styles = weapon_prop->at<ArrayProperty>("Styles_10_8C3C82444B986AD7A99595AD4985912D");
|
||||
if(!custom_styles) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "No custom styles found for weapon.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(custom_styles->items.size() != weapon.customStyles.size()) {
|
||||
_state = State::Invalid;
|
||||
_lastError = "Custom styles array size mismatch.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1231,9 +1287,23 @@ auto Mass::writeWeaponType(const char* prop_name, Containers::ArrayView<Weapon>
|
|||
}
|
||||
|
||||
weapon_prop->at<BoolProperty>("Attach_15_D00AABBD4AD6A04778D56D81E51927B3")->value = weapon.attached;
|
||||
weapon_prop->at<ByteProperty>("DamageType_18_E1FFA53540591A9087EC698117A65C83")->enumValue = weapon.damageType;
|
||||
switch(weapon.damageType) {
|
||||
#define c(enumerator, strenum) case DamageType::enumerator: weapon_prop->at<ByteProperty>("DamageType_18_E1FFA53540591A9087EC698117A65C83")->enumValue = strenum; break;
|
||||
#include "../Maps/DamageTypes.hpp"
|
||||
#undef c
|
||||
default:
|
||||
Utility::Warning{} << "Unknown damage type enum value in writeWeaponType().";
|
||||
}
|
||||
weapon_prop->at<BoolProperty>("DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222")->value = weapon.dualWield;
|
||||
weapon_prop->at<ByteProperty>("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014")->enumValue = weapon.effectColourMode;
|
||||
switch(weapon.effectColourMode) {
|
||||
#define c(enumerator, enumstr) case EffectColourMode::enumerator: \
|
||||
weapon_prop->at<ByteProperty>("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014")->enumValue = enumstr; \
|
||||
break;
|
||||
#include "../Maps/EffectColourModes.hpp"
|
||||
#undef c
|
||||
default:
|
||||
Utility::Warning{} << "Unknown effect colour mode in writeWeaponType().";
|
||||
}
|
||||
auto effect_colour = weapon_prop->at<ColourStructProperty>("ColorEfx_26_D921B62946C493E487455A831F4520AC");
|
||||
effect_colour->r = weapon.effectColour.r();
|
||||
effect_colour->g = weapon.effectColour.g();
|
||||
|
@ -1241,7 +1311,12 @@ auto Mass::writeWeaponType(const char* prop_name, Containers::ArrayView<Weapon>
|
|||
effect_colour->a = weapon.effectColour.a();
|
||||
}
|
||||
|
||||
return _mass->saveToFile();
|
||||
if(!_mass->saveToFile()) {
|
||||
_lastError = _mass->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mass::getTuningCategory(const char* big_node_prop_name, Int& big_node_id,
|
||||
|
|
107
src/Mass/Mass.h
107
src/Mass/Mass.h
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -27,6 +27,14 @@
|
|||
#include <Magnum/Math/Vector2.h>
|
||||
#include <Magnum/Math/Vector3.h>
|
||||
|
||||
#include "Joints.h"
|
||||
#include "CustomStyle.h"
|
||||
#include "Decal.h"
|
||||
#include "Accessory.h"
|
||||
#include "ArmourPart.h"
|
||||
#include "WeaponPart.h"
|
||||
#include "Weapon.h"
|
||||
|
||||
#include "../UESaveFile/UESaveFile.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
@ -34,84 +42,6 @@ using namespace Magnum;
|
|||
|
||||
struct ArrayProperty;
|
||||
|
||||
struct Joints {
|
||||
Float neck = 0.0f;
|
||||
Float body = 0.0f;
|
||||
Float shoulders = 0.0f;
|
||||
Float hips = 0.0f;
|
||||
Float upperArms = 0.0f;
|
||||
Float lowerArms = 0.0f;
|
||||
Float upperLegs = 0.0f;
|
||||
Float lowerLegs = 0.0f;
|
||||
};
|
||||
|
||||
struct CustomStyle {
|
||||
std::string name;
|
||||
Color4 colour{0.0f};
|
||||
Float metallic = 0.5f;
|
||||
Float gloss = 0.5f;
|
||||
bool glow = false;
|
||||
|
||||
Int patternId = 0;
|
||||
Float opacity = 0.5f;
|
||||
Vector2 offset{0.5f};
|
||||
Float rotation = 0.0f;
|
||||
Float scale = 0.5f;
|
||||
};
|
||||
|
||||
struct Decal {
|
||||
Int id = -1;
|
||||
Color4 colour{0.0f};
|
||||
Vector3 position{0.0f};
|
||||
Vector3 uAxis{0.0f};
|
||||
Vector3 vAxis{0.0f};
|
||||
Vector2 offset{0.5f};
|
||||
Float scale = 0.5f;
|
||||
Float rotation = 0.0f;
|
||||
bool flip = false;
|
||||
bool wrap = false;
|
||||
};
|
||||
|
||||
struct Accessory {
|
||||
Int attachIndex = -1;
|
||||
Int id = -1;
|
||||
Containers::StaticArray<2, Int> styles{ValueInit};
|
||||
Vector3 relativePosition{0.0f};
|
||||
Vector3 relativePositionOffset{0.0f};
|
||||
Vector3 relativeRotation{0.0f};
|
||||
Vector3 relativeRotationOffset{0.0f};
|
||||
Vector3 localScale{1.0f};
|
||||
};
|
||||
|
||||
struct ArmourPart {
|
||||
std::string slot;
|
||||
Int id = 0;
|
||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
||||
UnsignedInt demoDecals = 8;
|
||||
Containers::StaticArray<8, Decal> decals{ValueInit};
|
||||
Containers::StaticArray<8, Accessory> accessories{ValueInit};
|
||||
};
|
||||
|
||||
struct WeaponPart {
|
||||
Int id = 0;
|
||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
||||
UnsignedInt demoDecals = 8;
|
||||
Containers::StaticArray<8, Decal> decals{ValueInit};
|
||||
Containers::StaticArray<8, Accessory> accessories{ValueInit};
|
||||
};
|
||||
|
||||
struct Weapon {
|
||||
std::string name;
|
||||
std::string type;
|
||||
Containers::Array<WeaponPart> parts;
|
||||
Containers::StaticArray<16, CustomStyle> customStyles{ValueInit};
|
||||
bool attached = false;
|
||||
std::string damageType;
|
||||
bool dualWield = false;
|
||||
std::string effectColourMode;
|
||||
Color4 effectColour{0.0f};
|
||||
};
|
||||
|
||||
class Mass {
|
||||
public:
|
||||
enum class State : UnsignedByte {
|
||||
|
@ -126,7 +56,7 @@ class Mass {
|
|||
Mass(Mass&&) = default;
|
||||
Mass& operator=(Mass&&) = default;
|
||||
|
||||
static auto lastError() -> std::string const&;
|
||||
auto lastError() -> std::string const&;
|
||||
|
||||
static auto getNameFromFile(const std::string& path) -> Containers::Optional<std::string>;
|
||||
|
||||
|
@ -139,8 +69,6 @@ class Mass {
|
|||
|
||||
auto state() -> State;
|
||||
|
||||
auto demo() const -> bool;
|
||||
|
||||
auto dirty() const -> bool;
|
||||
void setDirty(bool dirty = true);
|
||||
|
||||
|
@ -162,7 +90,7 @@ class Mass {
|
|||
|
||||
auto armourParts() -> Containers::ArrayView<ArmourPart>;
|
||||
void getArmourParts();
|
||||
auto writeArmourPart(UnsignedLong index) -> bool;
|
||||
auto writeArmourPart(ArmourSlot slot) -> bool;
|
||||
|
||||
auto armourCustomStyles() -> Containers::ArrayView<CustomStyle>;
|
||||
void getArmourCustomStyles();
|
||||
|
@ -207,14 +135,18 @@ class Mass {
|
|||
auto architecture() -> Int&;
|
||||
auto techs() -> Containers::ArrayView<Int>;
|
||||
|
||||
auto updateSteamId(const std::string& steam_id) -> bool;
|
||||
auto account() -> std::string const&;
|
||||
auto updateAccount(const std::string& new_account) -> bool;
|
||||
|
||||
private:
|
||||
void getCustomStyles(Containers::ArrayView<CustomStyle> styles, ArrayProperty* style_array);
|
||||
auto setCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool;
|
||||
|
||||
void getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array);
|
||||
void writeDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array);
|
||||
|
||||
void getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array);
|
||||
void writeAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accs_array);
|
||||
|
||||
void getWeaponType(const char* prop_name, Containers::ArrayView<Weapon> weapon_array);
|
||||
auto writeWeaponType(const char* prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool;
|
||||
|
@ -224,12 +156,11 @@ class Mass {
|
|||
|
||||
Containers::Optional<UESaveFile> _mass;
|
||||
|
||||
static std::string _lastError;
|
||||
std::string _lastError;
|
||||
|
||||
std::string _folder;
|
||||
std::string _filename;
|
||||
State _state = State::Empty;
|
||||
bool _demo = false;
|
||||
|
||||
bool _dirty = false;
|
||||
|
||||
|
@ -260,7 +191,7 @@ class Mass {
|
|||
Containers::StaticArray<4, Weapon> energyLaunchers;
|
||||
} _weapons;
|
||||
|
||||
Containers::StaticArray<16, CustomStyle> _globalStyles;
|
||||
Containers::Array<CustomStyle> _globalStyles;
|
||||
|
||||
struct {
|
||||
Int engineId;
|
||||
|
@ -273,5 +204,5 @@ class Mass {
|
|||
Containers::StaticArray<7, Int> techIds;
|
||||
} _tuning;
|
||||
|
||||
std::string _steamId;
|
||||
std::string _account;
|
||||
};
|
||||
|
|
49
src/Mass/Weapon.cpp
Normal file
49
src/Mass/Weapon.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Weapon.h"
|
||||
|
||||
Weapon::Weapon(const Weapon& other) {
|
||||
name = other.name;
|
||||
type = other.type;
|
||||
parts = Containers::Array<WeaponPart>{other.parts.size()};
|
||||
for(UnsignedInt i = 0; i < parts.size(); i++) {
|
||||
parts[i] = other.parts[i];
|
||||
}
|
||||
customStyles = other.customStyles;
|
||||
attached = other.attached;
|
||||
damageType = other.damageType;
|
||||
dualWield = other.dualWield;
|
||||
effectColourMode = other.effectColourMode;
|
||||
effectColour = other.effectColour;
|
||||
}
|
||||
|
||||
Weapon& Weapon::operator=(const Weapon& other) {
|
||||
name = other.name;
|
||||
type = other.type;
|
||||
parts = Containers::Array<WeaponPart>{other.parts.size()};
|
||||
for(UnsignedInt i = 0; i < parts.size(); i++) {
|
||||
parts[i] = other.parts[i];
|
||||
}
|
||||
customStyles = other.customStyles;
|
||||
attached = other.attached;
|
||||
damageType = other.damageType;
|
||||
dualWield = other.dualWield;
|
||||
effectColourMode = other.effectColourMode;
|
||||
effectColour = other.effectColour;
|
||||
|
||||
return *this;
|
||||
}
|
74
src/Mass/Weapon.h
Normal file
74
src/Mass/Weapon.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Corrade/Containers/Array.h>
|
||||
#include <Corrade/Containers/StaticArray.h>
|
||||
|
||||
#include <Magnum/Magnum.h>
|
||||
#include <Magnum/Math/Color.h>
|
||||
|
||||
#include "WeaponPart.h"
|
||||
#include "CustomStyle.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
enum class WeaponType {
|
||||
Melee = 0,
|
||||
Shield = 5,
|
||||
BulletShooter = 1,
|
||||
EnergyShooter = 2,
|
||||
BulletLauncher = 3,
|
||||
EnergyLauncher = 4,
|
||||
};
|
||||
|
||||
enum class DamageType {
|
||||
Physical = 0,
|
||||
Piercing = 1,
|
||||
Plasma = 5,
|
||||
Heat = 2,
|
||||
Freeze = 3,
|
||||
Shock = 4,
|
||||
};
|
||||
|
||||
enum class EffectColourMode {
|
||||
Default = 0,
|
||||
Custom = 1,
|
||||
};
|
||||
|
||||
struct Weapon {
|
||||
Weapon() = default;
|
||||
|
||||
Weapon(const Weapon& other);
|
||||
Weapon& operator=(const Weapon& other);
|
||||
|
||||
Weapon(Weapon&& other) = default;
|
||||
Weapon& operator=(Weapon&& other) = default;
|
||||
|
||||
std::string name;
|
||||
WeaponType type = WeaponType::Melee;
|
||||
Containers::Array<WeaponPart> parts;
|
||||
Containers::StaticArray<16, CustomStyle> customStyles{ValueInit};
|
||||
bool attached = false;
|
||||
DamageType damageType = DamageType::Physical;
|
||||
bool dualWield = false;
|
||||
EffectColourMode effectColourMode = EffectColourMode::Default;
|
||||
Color4 effectColour{0.0f};
|
||||
};
|
66
src/Mass/WeaponPart.h
Normal file
66
src/Mass/WeaponPart.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
|
||||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <Corrade/Containers/Array.h>
|
||||
#include <Corrade/Containers/StaticArray.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
#include "Decal.h"
|
||||
#include "Accessory.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
struct WeaponPart {
|
||||
WeaponPart() = default;
|
||||
|
||||
WeaponPart(const WeaponPart& other) {
|
||||
id = other.id;
|
||||
styles = other.styles;
|
||||
decals = Containers::Array<Decal>{other.decals.size()};
|
||||
for(UnsignedInt i = 0; i < decals.size(); i++) {
|
||||
decals[i] = other.decals[i];
|
||||
}
|
||||
accessories = Containers::Array<Accessory>{other.accessories.size()};
|
||||
for(UnsignedInt i = 0; i < accessories.size(); i++) {
|
||||
accessories[i] = other.accessories[i];
|
||||
}
|
||||
}
|
||||
WeaponPart& operator=(const WeaponPart& other) {
|
||||
id = other.id;
|
||||
styles = other.styles;
|
||||
decals = Containers::Array<Decal>{other.decals.size()};
|
||||
for(UnsignedInt i = 0; i < decals.size(); i++) {
|
||||
decals[i] = other.decals[i];
|
||||
}
|
||||
accessories = Containers::Array<Accessory>{other.accessories.size()};
|
||||
for(UnsignedInt i = 0; i < accessories.size(); i++) {
|
||||
accessories[i] = other.accessories[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
WeaponPart(WeaponPart&& other) = default;
|
||||
WeaponPart& operator=(WeaponPart&& other) = default;
|
||||
|
||||
Int id = 0;
|
||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
||||
Containers::Array<Decal> decals{};
|
||||
Containers::Array<Accessory> accessories{};
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -49,11 +49,11 @@ auto MassManager::lastError() -> std::string const& {
|
|||
return _lastError;
|
||||
}
|
||||
|
||||
auto MassManager::hangar(int hangar) -> Mass& {
|
||||
auto MassManager::hangar(Int hangar) -> Mass& {
|
||||
return _hangars[hangar];
|
||||
}
|
||||
|
||||
void MassManager::refreshHangar(int hangar) {
|
||||
void MassManager::refreshHangar(Int hangar) {
|
||||
if(hangar < 0 || hangar >= 32) {
|
||||
return;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ void MassManager::refreshHangar(int hangar) {
|
|||
_hangars[hangar] = Mass{mass_filename};
|
||||
}
|
||||
|
||||
auto MassManager::importMass(const std::string& staged_fn, int hangar) -> bool {
|
||||
auto MassManager::importMass(const std::string& staged_fn, Int hangar) -> bool {
|
||||
if(hangar < 0 || hangar >= 32) {
|
||||
_lastError = "Hangar out of range in MassManager::importMass()";
|
||||
return false;
|
||||
|
@ -79,18 +79,22 @@ auto MassManager::importMass(const std::string& staged_fn, int hangar) -> bool {
|
|||
std::string source = Utility::Directory::join(_stagingAreaDirectory, staged_fn);
|
||||
Utility::Directory::copy(source, source + ".tmp");
|
||||
|
||||
if(!Mass{source + ".tmp"}.updateSteamId(_steamId))
|
||||
{
|
||||
_lastError = "The M.A.S.S. file at " + source + " seems to be corrupt.";
|
||||
Mass mass{source + ".tmp"};
|
||||
if(!mass.updateAccount(_steamId)) {
|
||||
_lastError = mass.lastError();
|
||||
Utility::Directory::rm(source + ".tmp");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Utility::Directory::exists(Utility::Directory::join(_saveDirectory, _hangars[hangar].filename()))) {
|
||||
Utility::Directory::rm(Utility::Directory::join(_saveDirectory, _hangars[hangar].filename()));
|
||||
}
|
||||
|
||||
if(!Utility::Directory::move(source + ".tmp", Utility::Directory::join(_saveDirectory, _hangars[hangar].filename()))) {
|
||||
std::string dest = Utility::Directory::join(_saveDirectory, _hangars[hangar].filename());
|
||||
|
||||
if(Utility::Directory::exists(dest)) {
|
||||
Utility::Directory::rm(dest);
|
||||
}
|
||||
|
||||
if(!Utility::Directory::move(source + ".tmp", dest)) {
|
||||
_lastError = Utility::formatString("Couldn't move {} to hangar {:.2d}", staged_fn, hangar + 1);
|
||||
return false;
|
||||
}
|
||||
|
@ -98,7 +102,7 @@ auto MassManager::importMass(const std::string& staged_fn, int hangar) -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto MassManager::exportMass(int hangar) -> bool {
|
||||
auto MassManager::exportMass(Int hangar) -> bool {
|
||||
if(hangar < 0 || hangar >= 32) {
|
||||
_lastError = "Hangar out of range in MassManager::exportMass()";
|
||||
return false;
|
||||
|
@ -121,7 +125,7 @@ auto MassManager::exportMass(int hangar) -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto MassManager::moveMass(int source, int destination) -> bool {
|
||||
auto MassManager::moveMass(Int source, Int destination) -> bool {
|
||||
if(source < 0 || source >= 32) {
|
||||
_lastError = "Source hangar out of range.";
|
||||
return false;
|
||||
|
@ -156,14 +160,14 @@ auto MassManager::moveMass(int source, int destination) -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto MassManager::deleteMass(int hangar) -> bool {
|
||||
auto MassManager::deleteMass(Int hangar) -> bool {
|
||||
if(hangar < 0 || hangar >= 32) {
|
||||
_lastError = "Hangar out of bounds";
|
||||
_lastError = "Hangar out of range.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!Utility::Directory::rm(Utility::Directory::join(_saveDirectory, _hangars[hangar].filename()))) {
|
||||
_lastError = "Deletion failed. Maybe the file was already deleted, or it's locked by another application.";
|
||||
_lastError = Utility::formatString("Deletion failed: {}", std::strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -202,7 +206,7 @@ auto MassManager::deleteStagedMass(const std::string& filename) -> bool {
|
|||
}
|
||||
|
||||
if(!Utility::Directory::rm(Utility::Directory::join(_stagingAreaDirectory, filename))) {
|
||||
_lastError = "The file " + filename + " couldn't be deleted for unknown reasons.";
|
||||
_lastError = Utility::formatString("{} couldn't be deleted: {}", filename, std::strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -27,8 +27,6 @@
|
|||
#include "../UESaveFile/Types/IntProperty.h"
|
||||
#include "../UESaveFile/Types/StringProperty.h"
|
||||
|
||||
#include "ResourceIDs.h"
|
||||
|
||||
#include "Profile.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
@ -36,7 +34,6 @@ using namespace Corrade;
|
|||
Profile::Profile(const std::string& path):
|
||||
_profile(path)
|
||||
{
|
||||
_profileDirectory = Utility::Directory::path(path);
|
||||
_filename = Utility::Directory::filename(path);
|
||||
|
||||
if(Utility::String::beginsWith(_filename, "Demo")) {
|
||||
|
@ -46,11 +43,22 @@ Profile::Profile(const std::string& path):
|
|||
_type = ProfileType::FullGame;
|
||||
}
|
||||
|
||||
_steamId = Utility::String::ltrim(Utility::String::rtrim(_filename, ".sav"), (_type == ProfileType::Demo ? "Demo" : "") + std::string{"Profile"});
|
||||
auto account_prop = _profile.at<StringProperty>("Account");
|
||||
if(!account_prop) {
|
||||
_lastError = "Couldn't find an account ID in " + _filename;
|
||||
_valid = false;
|
||||
return;
|
||||
}
|
||||
_account = account_prop->value;
|
||||
|
||||
if(Utility::String::beginsWith(_account, "PMCSlot")) {
|
||||
_version = ProfileVersion::Normal;
|
||||
}
|
||||
else {
|
||||
_version = ProfileVersion::Legacy;
|
||||
}
|
||||
|
||||
refreshValues();
|
||||
|
||||
_valid = _profile.valid();
|
||||
}
|
||||
|
||||
auto Profile::valid() const -> bool {
|
||||
|
@ -69,8 +77,12 @@ auto Profile::type() const -> ProfileType {
|
|||
return _type;
|
||||
}
|
||||
|
||||
auto Profile::steamId() const -> std::string const& {
|
||||
return _steamId;
|
||||
auto Profile::version() const -> ProfileVersion {
|
||||
return _version;
|
||||
}
|
||||
|
||||
auto Profile::account() const -> std::string const& {
|
||||
return _account;
|
||||
}
|
||||
|
||||
void Profile::refreshValues() {
|
||||
|
@ -80,7 +92,13 @@ void Profile::refreshValues() {
|
|||
return;
|
||||
}
|
||||
|
||||
_name = _profile.at<StringProperty>("CompanyName")->value;
|
||||
auto name_prop = _profile.at<StringProperty>("CompanyName");
|
||||
if(!name_prop) {
|
||||
_lastError = "No company name in " + _filename;
|
||||
_valid = false;
|
||||
return;
|
||||
}
|
||||
_name = name_prop->value;
|
||||
|
||||
auto prop = _profile.at<IntProperty>("ActiveFrameSlot");
|
||||
_activeFrameSlot = prop ? prop->value : 0;
|
||||
|
@ -117,6 +135,8 @@ void Profile::refreshValues() {
|
|||
_muscularConstruction = getResource("ResourceQuarkData", MuscularConstruction);
|
||||
_mineralExoskeletology = getResource("ResourceQuarkData", MineralExoskeletology);
|
||||
_carbonisedSkin = getResource("ResourceQuarkData", CarbonisedSkin);
|
||||
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
auto Profile::companyName() const -> std::string const& {
|
||||
|
@ -125,11 +145,16 @@ auto Profile::companyName() const -> std::string const& {
|
|||
|
||||
auto Profile::renameCompany(const std::string& new_name) -> bool {
|
||||
auto name_prop = _profile.at<StringProperty>("CompanyName");
|
||||
if(!name_prop) {
|
||||
_lastError = "No company name in " + _filename;
|
||||
_valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
name_prop->value = new_name;
|
||||
|
||||
if(!_profile.saveToFile()) {
|
||||
_lastError = "Couldn't save the profile.";
|
||||
_lastError = _profile.lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -149,13 +174,14 @@ auto Profile::setCredits(Int amount) -> bool {
|
|||
|
||||
if(!credits_prop) {
|
||||
credits_prop = new IntProperty;
|
||||
credits_prop->name.emplace("Credit");
|
||||
_profile.appendProperty(IntProperty::ptr{credits_prop});
|
||||
}
|
||||
|
||||
credits_prop->value = amount;
|
||||
|
||||
if(!_profile.saveToFile()) {
|
||||
_lastError = "Couldn't save the profile.";
|
||||
_lastError = _profile.lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -171,13 +197,14 @@ auto Profile::setStoryProgress(Int progress) -> bool {
|
|||
|
||||
if(!story_progress_prop) {
|
||||
story_progress_prop = new IntProperty;
|
||||
story_progress_prop->name.emplace("StoryProgress");
|
||||
_profile.appendProperty(IntProperty::ptr{story_progress_prop});
|
||||
}
|
||||
|
||||
story_progress_prop->value = progress;
|
||||
|
||||
if(!_profile.saveToFile()) {
|
||||
_lastError = "Couldn't save the profile.";
|
||||
_lastError = _profile.lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -348,7 +375,7 @@ auto Profile::setCarbonisedSkin(Int amount) -> bool {
|
|||
return setResource("ResourceQuarkData", CarbonisedSkin, amount);
|
||||
}
|
||||
|
||||
auto Profile::getResource(const char* container, Int id) -> Int {
|
||||
auto Profile::getResource(const char* container, MaterialID id) -> Int {
|
||||
auto mats_prop = _profile.at<ArrayProperty>(container);
|
||||
|
||||
if(!mats_prop) {
|
||||
|
@ -364,14 +391,16 @@ auto Profile::getResource(const char* container, Int id) -> Int {
|
|||
return it != mats_prop->items.end() ? static_cast<ResourceItemValue*>(it->get())->quantity : 0;
|
||||
}
|
||||
|
||||
auto Profile::setResource(const char* container, Int id, Int amount) -> bool {
|
||||
auto Profile::setResource(const char* container, MaterialID id, Int amount) -> bool {
|
||||
auto mats_prop = _profile.at<ArrayProperty>(container);
|
||||
|
||||
if(!mats_prop) {
|
||||
_lastError = "Couldn't find " + std::string{container} + " in " + _filename;
|
||||
_valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
static auto predicate = [&id](UnrealPropertyBase::ptr& prop){
|
||||
auto predicate = [&id](UnrealPropertyBase::ptr& prop){
|
||||
auto res_prop = static_cast<ResourceItemValue*>(prop.get());
|
||||
return res_prop->id == id;
|
||||
};
|
||||
|
@ -396,5 +425,5 @@ auto Profile::setResource(const char* container, Int id, Int amount) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
return _profile.saveToFile();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include "../UESaveFile/UESaveFile.h"
|
||||
|
||||
#include "ResourceIDs.h"
|
||||
|
||||
using namespace Magnum;
|
||||
|
||||
enum class ProfileType : UnsignedByte {
|
||||
|
@ -29,6 +31,11 @@ enum class ProfileType : UnsignedByte {
|
|||
FullGame
|
||||
};
|
||||
|
||||
enum class ProfileVersion : UnsignedByte {
|
||||
Legacy, // pre-0.8
|
||||
Normal // 0.8 and later
|
||||
};
|
||||
|
||||
class Profile {
|
||||
public:
|
||||
explicit Profile(const std::string& path);
|
||||
|
@ -41,7 +48,9 @@ class Profile {
|
|||
|
||||
auto type() const -> ProfileType;
|
||||
|
||||
auto steamId() const -> std::string const&;
|
||||
auto version() const -> ProfileVersion;
|
||||
|
||||
auto account() const -> std::string const&;
|
||||
|
||||
void refreshValues();
|
||||
|
||||
|
@ -119,13 +128,13 @@ class Profile {
|
|||
auto setCarbonisedSkin(Int amount) -> bool;
|
||||
|
||||
private:
|
||||
auto getResource(const char* container, Int id) -> Int;
|
||||
auto setResource(const char* container, Int id, Int amount) -> bool;
|
||||
auto getResource(const char* container, MaterialID id) -> Int;
|
||||
auto setResource(const char* container, MaterialID id, Int amount) -> bool;
|
||||
|
||||
std::string _profileDirectory;
|
||||
std::string _filename;
|
||||
|
||||
ProfileType _type;
|
||||
ProfileVersion _version;
|
||||
|
||||
UESaveFile _profile;
|
||||
|
||||
|
@ -159,7 +168,7 @@ class Profile {
|
|||
Int _mineralExoskeletology = 0;
|
||||
Int _carbonisedSkin = 0;
|
||||
|
||||
std::string _steamId;
|
||||
std::string _account;
|
||||
|
||||
bool _valid = false;
|
||||
std::string _lastError;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -76,7 +76,7 @@ auto ProfileManager::refreshProfiles() -> bool {
|
|||
}
|
||||
|
||||
if(_profiles.empty()) {
|
||||
_lastError = "No profiles were found.";
|
||||
_lastError = "No valid profiles were found.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ auto ProfileManager::deleteProfile(std::size_t index, bool delete_builds) -> boo
|
|||
for(UnsignedByte i = 0; i < 32; ++i) {
|
||||
std::string filename = Utility::formatString("{}Unit{:.2d}{}.sav",
|
||||
_profiles[index].type() == ProfileType::Demo ? "Demo": "",
|
||||
i, _profiles[index].steamId());
|
||||
i, _profiles[index].account());
|
||||
Utility::Directory::rm(Utility::Directory::join(_saveDirectory, filename));
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> boo
|
|||
for(UnsignedByte i = 0; i < 32; ++i) {
|
||||
std::string build_filename = Utility::formatString("{}Unit{:.2d}{}.sav",
|
||||
_profiles[index].type() == ProfileType::Demo ? "Demo": "",
|
||||
i, _profiles[index].steamId());
|
||||
i, _profiles[index].account());
|
||||
|
||||
if(!Utility::Directory::exists(Utility::Directory::join(_saveDirectory, build_filename))) {
|
||||
continue;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -62,7 +62,7 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
#endif
|
||||
|
||||
if(SDL_VERSION_ATLEAST(2, 0, 5)) {
|
||||
if(SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1") == SDL_TRUE) {
|
||||
if(SDL_SetHintWithPriority(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1", SDL_HINT_OVERRIDE) == SDL_TRUE) {
|
||||
Utility::Debug{} << "Clickthrough is available.";
|
||||
}
|
||||
else {
|
||||
|
@ -95,6 +95,10 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
|
||||
_backupsDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "backups");
|
||||
_stagingDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "staging");
|
||||
_armouryDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "armoury");
|
||||
_armoursDir = Utility::Directory::join(_armouryDir, "armours");
|
||||
_weaponsDir = Utility::Directory::join(_armouryDir, "weapons");
|
||||
_stylesDir = Utility::Directory::join(_armouryDir, "styles");
|
||||
|
||||
if(!Utility::Directory::exists(_backupsDir)) {
|
||||
Utility::Directory::mkpath(_backupsDir);
|
||||
|
@ -104,6 +108,22 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
Utility::Directory::mkpath(_stagingDir);
|
||||
}
|
||||
|
||||
if(!Utility::Directory::exists(_armouryDir)) {
|
||||
Utility::Directory::mkpath(_armouryDir);
|
||||
}
|
||||
|
||||
if(!Utility::Directory::exists(_armoursDir)) {
|
||||
Utility::Directory::mkpath(_armoursDir);
|
||||
}
|
||||
|
||||
if(!Utility::Directory::exists(_weaponsDir)) {
|
||||
Utility::Directory::mkpath(_weaponsDir);
|
||||
}
|
||||
|
||||
if(!Utility::Directory::exists(_stylesDir)) {
|
||||
Utility::Directory::mkpath(_stylesDir);
|
||||
}
|
||||
|
||||
if(!findGameDataDirectory()) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", _lastError.c_str(), window());
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -207,7 +227,7 @@ void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
|||
|
||||
switch(action) {
|
||||
case efsw::Actions::Add:
|
||||
if(Utility::String::endsWith(filename, _currentProfile->steamId() + ".sav")) {
|
||||
if(Utility::String::endsWith(filename, _currentProfile->account() + ".sav")) {
|
||||
if(Utility::String::beginsWith(filename, Utility::formatString("{}Unit", _currentProfile->type() == ProfileType::Demo ? "Demo" : ""))) {
|
||||
int index = ((filename[_currentProfile->type() == ProfileType::Demo ? 8 : 4] - 0x30) * 10) +
|
||||
(filename[_currentProfile->type() == ProfileType::Demo ? 9 : 5] - 0x30);
|
||||
|
@ -221,7 +241,7 @@ void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
|||
}
|
||||
break;
|
||||
case efsw::Actions::Delete:
|
||||
if(Utility::String::endsWith(filename, _currentProfile->steamId() + ".sav")) {
|
||||
if(Utility::String::endsWith(filename, _currentProfile->account() + ".sav")) {
|
||||
if(Utility::String::beginsWith(filename, Utility::formatString("{}Unit", _currentProfile->type() == ProfileType::Demo ? "Demo" : ""))) {
|
||||
int index = ((filename[_currentProfile->type() == ProfileType::Demo ? 8 : 4] - 0x30) * 10) +
|
||||
(filename[_currentProfile->type() == ProfileType::Demo ? 9 : 5] - 0x30);
|
||||
|
@ -235,7 +255,7 @@ void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
|||
if(filename == _currentProfile->filename()) {
|
||||
_currentProfile->refreshValues();
|
||||
}
|
||||
else if(Utility::String::endsWith(filename, _currentProfile->steamId() + ".sav")) {
|
||||
else if(Utility::String::endsWith(filename, _currentProfile->account() + ".sav")) {
|
||||
if(Utility::String::beginsWith(filename, Utility::formatString("{}Unit", _currentProfile->type() == ProfileType::Demo ? "Demo" : ""))) {
|
||||
int index = ((filename[_currentProfile->type() == ProfileType::Demo ? 8 : 4] - 0x30) * 10) +
|
||||
(filename[_currentProfile->type() == ProfileType::Demo ? 9 : 5] - 0x30);
|
||||
|
@ -253,7 +273,7 @@ void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
|||
}
|
||||
break;
|
||||
case efsw::Actions::Moved:
|
||||
if(Utility::String::endsWith(filename, _currentProfile->steamId() + ".sav")) {
|
||||
if(Utility::String::endsWith(filename, _currentProfile->account() + ".sav")) {
|
||||
if(Utility::String::endsWith(old_filename, ".tmp")) {
|
||||
is_moved_after_save = true;
|
||||
return;
|
||||
|
@ -399,6 +419,9 @@ void SaveTool::updateCheckEvent(SDL_Event& event) {
|
|||
return ( major * 10000 + minor * 100 + patch) >
|
||||
(other.major * 10000 + other.minor * 100 + other.patch);
|
||||
}
|
||||
operator std::string() const {
|
||||
return Utility::formatString("{}.{}.{}", major, minor, patch);
|
||||
}
|
||||
};
|
||||
|
||||
static const Version current_ver{SAVETOOL_VERSION};
|
||||
|
@ -414,11 +437,11 @@ void SaveTool::updateCheckEvent(SDL_Event& event) {
|
|||
_queue.addToast(Toast::Type::Warning, "Your version is out of date.\nCheck the settings for more information.",
|
||||
std::chrono::milliseconds{5000});
|
||||
_updateAvailable = true;
|
||||
_latestVersion = Utility::formatString("{}.{}.{}", latest_ver.major, latest_ver.minor, latest_ver.patch);
|
||||
_releaseLink = response[0]["html_url"];
|
||||
_downloadLink = response[0]["assets"][0]["browser_download_url"];
|
||||
_latestVersion = latest_ver;
|
||||
_releaseLink = release["html_url"];
|
||||
_downloadLink = release["assets"][0]["browser_download_url"];
|
||||
}
|
||||
else if(latest_ver == current_ver) {
|
||||
else if(latest_ver == current_ver || (current_ver > latest_ver && Utility::String::endsWith(SAVETOOL_VERSION, "-pre"))) {
|
||||
_queue.addToast(Toast::Type::Success, "The application is already up to date.");
|
||||
}
|
||||
else if(current_ver > latest_ver) {
|
||||
|
@ -427,7 +450,6 @@ void SaveTool::updateCheckEvent(SDL_Event& event) {
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SaveTool::initialiseConfiguration() {
|
||||
|
@ -560,7 +582,7 @@ auto SaveTool::findGameDataDirectory() -> bool {
|
|||
|
||||
void SaveTool::initialiseMassManager() {
|
||||
_massManager.emplace(_saveDir,
|
||||
_currentProfile->steamId(),
|
||||
_currentProfile->account(),
|
||||
_currentProfile->type() == ProfileType::Demo,
|
||||
_stagingDir);
|
||||
|
||||
|
@ -746,7 +768,7 @@ void SaveTool::drawTooltip(const char* text, Float wrap_pos) {
|
|||
}
|
||||
|
||||
void SaveTool::openUri(const std::string& uri) {
|
||||
ShellExecuteW(nullptr, nullptr, Utility::Unicode::widen(uri).c_str(), nullptr, nullptr, SW_SHOW);
|
||||
ShellExecuteW(nullptr, nullptr, Utility::Unicode::widen(uri).c_str(), nullptr, nullptr, SW_SHOWDEFAULT);
|
||||
}
|
||||
|
||||
void SaveTool::checkGameState() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -105,6 +105,9 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
auto drawRenamePopup(Containers::ArrayView<char> name_view) -> bool;
|
||||
void drawGeneralInfo();
|
||||
void drawResearchInventory();
|
||||
template<typename Getter, typename Setter>
|
||||
void drawMaterialRow(const char* name, Int tier, Getter getter, Setter setter);
|
||||
void drawUnavailableMaterialRow(const char* name, Int tier);
|
||||
void drawMassManager();
|
||||
auto drawDeleteMassPopup(int mass_index) -> ImGuiID;
|
||||
auto drawDeleteStagedMassPopup(const std::string& filename) -> ImGuiID;
|
||||
|
@ -118,6 +121,7 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
void drawArmour();
|
||||
void drawCustomArmourStyles();
|
||||
void drawWeapons();
|
||||
void drawWeaponCategory(const char* name, Containers::ArrayView<Weapon> weapons_view, bool& dirty, const char* payload_type, const char* payload_tooltip);
|
||||
void drawWeaponEditor(Weapon& weapon);
|
||||
void drawGlobalStyles();
|
||||
void drawTuning();
|
||||
|
@ -168,6 +172,12 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void drawAlignedText(const char* text, Args... args) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(text, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void openUri(const std::string& uri);
|
||||
|
||||
void checkGameState();
|
||||
|
@ -212,6 +222,10 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
|
||||
std::string _backupsDir;
|
||||
std::string _stagingDir;
|
||||
std::string _armouryDir;
|
||||
std::string _armoursDir;
|
||||
std::string _weaponsDir;
|
||||
std::string _stylesDir;
|
||||
|
||||
enum class GameState : UnsignedByte {
|
||||
Unknown, NotRunning, Running
|
||||
|
@ -225,6 +239,8 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
Containers::Pointer<MassManager> _massManager;
|
||||
Mass* _currentMass{nullptr};
|
||||
|
||||
Weapon* _currentWeapon = nullptr;
|
||||
|
||||
Containers::Pointer<efsw::FileWatcher> _fileWatcher;
|
||||
enum watchID {
|
||||
SaveDir = 0,
|
||||
|
@ -248,5 +264,20 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
std::string _releaseLink;
|
||||
std::string _downloadLink;
|
||||
|
||||
bool _jointsDirty{false};
|
||||
bool _stylesDirty{false};
|
||||
bool _eyeFlareDirty{false};
|
||||
Containers::StaticArray<38, Int> _selectedArmourDecals{ValueInit};
|
||||
Containers::StaticArray<38, Int> _selectedArmourAccessories{ValueInit};
|
||||
Int _selectedWeaponPart{0};
|
||||
Int _selectedWeaponDecal{0};
|
||||
Int _selectedWeaponAccessory{0};
|
||||
bool _meleeDirty{false};
|
||||
bool _shieldsDirty{false};
|
||||
bool _bShootersDirty{false};
|
||||
bool _eShootersDirty{false};
|
||||
bool _bLaunchersDirty{false};
|
||||
bool _eLaunchersDirty{false};
|
||||
|
||||
bool _cheatMode{false};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -42,8 +42,7 @@ void SaveTool::drawManager() {
|
|||
return;
|
||||
}
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Current profile: %s (%s)",
|
||||
drawAlignedText("Current profile: %s (%s)",
|
||||
_currentProfile->companyName().c_str(),
|
||||
_currentProfile->type() == ProfileType::Demo ? "demo" : "full game");
|
||||
ImGui::SameLine();
|
||||
|
@ -188,7 +187,7 @@ void SaveTool::drawGeneralInfo() {
|
|||
{
|
||||
ImGui::TextUnformatted("Story progress:");
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.x / 4.0f);
|
||||
if(std::strcmp(it->after, "") == 0) {
|
||||
if(!it->after) {
|
||||
ImGui::TextWrapped("%s - %s", it->chapter, it->point);
|
||||
}
|
||||
else {
|
||||
|
@ -226,8 +225,7 @@ void SaveTool::drawGeneralInfo() {
|
|||
}
|
||||
if(drawRenamePopup(name_buf)) {
|
||||
if(!_currentProfile->renameCompany(name_buf.data())) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_currentProfile->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _currentProfile->lastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,8 +242,7 @@ void SaveTool::drawGeneralInfo() {
|
|||
}
|
||||
if(drawIntEditPopup(&credits, 20000000)) {
|
||||
if(!_currentProfile->setCredits(credits)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_currentProfile->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _currentProfile->lastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,11 +258,10 @@ void SaveTool::drawGeneralInfo() {
|
|||
}
|
||||
for(const auto& sp : story_progress) {
|
||||
if(ImGui::BeginMenu(sp.chapter)) {
|
||||
if(std::strcmp(sp.after, "") == 0) {
|
||||
if(!sp.after) {
|
||||
if(ImGui::MenuItem(sp.point)) {
|
||||
if(!_currentProfile->setStoryProgress(sp.id)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_currentProfile->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _currentProfile->lastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -273,8 +269,7 @@ void SaveTool::drawGeneralInfo() {
|
|||
if(ImGui::BeginMenu(sp.after)) {
|
||||
if(ImGui::MenuItem(sp.point)) {
|
||||
if(!_currentProfile->setStoryProgress(sp.id)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_currentProfile->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _currentProfile->lastError());
|
||||
}
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
|
@ -292,45 +287,6 @@ void SaveTool::drawResearchInventory() {
|
|||
return;
|
||||
}
|
||||
|
||||
#define unavRow(name, tier) \
|
||||
ImGui::TableNextRow(); \
|
||||
ImGui::TableSetColumnIndex(0); \
|
||||
ImGui::TextUnformatted("T" #tier); \
|
||||
ImGui::TableSetColumnIndex(1); \
|
||||
ImGui::TextUnformatted(name); \
|
||||
ImGui::TableSetColumnIndex(2); \
|
||||
ImGui::TextDisabled("Unavailable as of game version " SUPPORTED_GAME_VERSION);
|
||||
|
||||
#define matRow(name, tier, var, getter, setter) \
|
||||
ImGui::TableNextRow(); \
|
||||
ImGui::TableSetColumnIndex(0); \
|
||||
ImGui::TextUnformatted("T" #tier); \
|
||||
ImGui::TableSetColumnIndex(1); \
|
||||
ImGui::TextUnformatted(name); \
|
||||
ImGui::TableSetColumnIndex(2); \
|
||||
if(_currentProfile->getter() != -1) { \
|
||||
ImGui::Text("%i", _currentProfile->getter()); \
|
||||
if(_cheatMode) { \
|
||||
ImGui::TableSetColumnIndex(3); \
|
||||
ImGui::PushID(#setter); \
|
||||
static Int var = _currentProfile->getter(); \
|
||||
if(drawUnsafeWidget([]{ return ImGui::SmallButton(ICON_FA_EDIT); })) { \
|
||||
(var) = _currentProfile->getter(); \
|
||||
ImGui::OpenPopup("int_edit"); \
|
||||
} \
|
||||
if(drawIntEditPopup(&(var), 9999)) { \
|
||||
if(!_currentProfile->set##setter((var))) { \
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", \
|
||||
_currentProfile->lastError().c_str(), window()); \
|
||||
} \
|
||||
} \
|
||||
ImGui::PopID(); \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
ImGui::TextDisabled("Not found in the save file"); \
|
||||
}
|
||||
|
||||
if(ImGui::BeginTable("##ResearchInventoryTable", 4,
|
||||
ImGuiTableFlags_BordersOuter|ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersInnerH))
|
||||
{
|
||||
|
@ -343,55 +299,136 @@ void SaveTool::drawResearchInventory() {
|
|||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::Text("Engine materials");
|
||||
|
||||
matRow("Verse steel", 1, verse_steel, verseSteel, VerseSteel)
|
||||
matRow("Undinium", 2, undinium, undinium, Undinium)
|
||||
matRow("Necrium alloy", 3, necrium_alloy, necriumAlloy, NecriumAlloy)
|
||||
matRow("Lunarite", 4, lunarite, lunarite, Lunarite)
|
||||
matRow("Asterite", 5, asterite, asterite, Asterite)
|
||||
unavRow("Hallite fragma", 6)
|
||||
unavRow("Unnoctinium", 7)
|
||||
drawMaterialRow("Verse steel", 1,
|
||||
[this]{ return _currentProfile->verseSteel(); },
|
||||
[this](Int amount){ return _currentProfile->setVerseSteel(amount); });
|
||||
drawMaterialRow("Undinium", 2,
|
||||
[this]{ return _currentProfile->undinium(); },
|
||||
[this](Int amount){ return _currentProfile->setUndinium(amount); });
|
||||
drawMaterialRow("Necrium alloy", 3,
|
||||
[this]{ return _currentProfile->necriumAlloy(); },
|
||||
[this](Int amount){ return _currentProfile->setNecriumAlloy(amount); });
|
||||
drawMaterialRow("Lunarite", 4,
|
||||
[this]{ return _currentProfile->lunarite(); },
|
||||
[this](Int amount){ return _currentProfile->setLunarite(amount); });
|
||||
drawMaterialRow("Asterite", 5,
|
||||
[this]{ return _currentProfile->asterite(); },
|
||||
[this](Int amount){ return _currentProfile->setAsterite(amount); });
|
||||
drawUnavailableMaterialRow("Hallite fragma", 6);
|
||||
drawUnavailableMaterialRow("Unnoctinium", 7);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::Text("OS materials");
|
||||
|
||||
matRow("Ednil", 1, ednil, ednil, Ednil)
|
||||
matRow("Nuflalt", 2, nuflalt, nuflalt, Nuflalt)
|
||||
matRow("Aurelene", 3, aurelene, aurelene, Aurelene)
|
||||
matRow("Soldus", 4, soldus, soldus, Soldus)
|
||||
matRow("Synthesized N", 5, synthesised_n, synthesisedN, SynthesisedN)
|
||||
unavRow("Nanoc", 6)
|
||||
unavRow("Abyssillite", 7)
|
||||
drawMaterialRow("Ednil", 1,
|
||||
[this]{ return _currentProfile->ednil(); },
|
||||
[this](Int amount){ return _currentProfile->setEdnil(amount); });
|
||||
drawMaterialRow("Nuflalt", 2,
|
||||
[this]{ return _currentProfile->nuflalt(); },
|
||||
[this](Int amount){ return _currentProfile->setNuflalt(amount); });
|
||||
drawMaterialRow("Aurelene", 3,
|
||||
[this]{ return _currentProfile->aurelene(); },
|
||||
[this](Int amount){ return _currentProfile->setAurelene(amount); });
|
||||
drawMaterialRow("Soldus", 4,
|
||||
[this]{ return _currentProfile->soldus(); },
|
||||
[this](Int amount){ return _currentProfile->setSoldus(amount); });
|
||||
drawMaterialRow("Synthesized N", 5,
|
||||
[this]{ return _currentProfile->synthesisedN(); },
|
||||
[this](Int amount){ return _currentProfile->setSynthesisedN(amount); });
|
||||
drawUnavailableMaterialRow("Nanoc", 6);
|
||||
drawUnavailableMaterialRow("Abyssillite", 7);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::Text("Architect materials");
|
||||
|
||||
matRow("Alcarbonite", 1, alcarbonite, alcarbonite, Alcarbonite)
|
||||
matRow("Keriphene", 2, keriphene, keriphene, Keriphene)
|
||||
matRow("Nitinol-CM", 3, nitinol_cm, nitinolCM, NitinolCM)
|
||||
matRow("Quarkium", 4, quarkium, quarkium, Quarkium)
|
||||
matRow("Alterene", 5, alterene, alterene, Alterene)
|
||||
unavRow("Cosmium", 6)
|
||||
unavRow("Purified quarkium", 7)
|
||||
drawMaterialRow("Alcarbonite", 1,
|
||||
[this]{ return _currentProfile->alcarbonite(); },
|
||||
[this](Int amount){ return _currentProfile->setAlcarbonite(amount); });
|
||||
drawMaterialRow("Keripehene", 2,
|
||||
[this]{ return _currentProfile->keriphene(); },
|
||||
[this](Int amount){ return _currentProfile->setKeriphene(amount); });
|
||||
drawMaterialRow("Nitinol-CM", 3,
|
||||
[this]{ return _currentProfile->nitinolCM(); },
|
||||
[this](Int amount){ return _currentProfile->setNitinolCM(amount); });
|
||||
drawMaterialRow("Quarkium", 4,
|
||||
[this]{ return _currentProfile->quarkium(); },
|
||||
[this](Int amount){ return _currentProfile->setQuarkium(amount); });
|
||||
drawMaterialRow("Alterene", 5,
|
||||
[this]{ return _currentProfile->alterene(); },
|
||||
[this](Int amount){ return _currentProfile->setAlterene(amount); });
|
||||
drawUnavailableMaterialRow("Cosmium", 6);
|
||||
drawUnavailableMaterialRow("Purified quarkium", 7);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::Text("Quark data");
|
||||
|
||||
matRow("Mixed composition", 1, mixed_composition, mixedComposition, MixedComposition)
|
||||
matRow("Void residue", 2, void_residue, voidResidue, VoidResidue)
|
||||
matRow("Muscular construction", 3, muscular_construction, muscularConstruction, MuscularConstruction)
|
||||
matRow("Mineral exoskeletology", 4, mineral_exoskeletology, mineralExoskeletology, MineralExoskeletology)
|
||||
matRow("Carbonized skin", 5, carbonised_skin, carbonisedSkin, CarbonisedSkin)
|
||||
unavRow("Isolated void particle", 6)
|
||||
unavRow("Weaponised physiology", 7)
|
||||
drawMaterialRow("Mixed composition", 1,
|
||||
[this]{ return _currentProfile->mixedComposition(); },
|
||||
[this](Int amount){ return _currentProfile->setMixedComposition(amount); });
|
||||
drawMaterialRow("Void residue", 2,
|
||||
[this]{ return _currentProfile->voidResidue(); },
|
||||
[this](Int amount){ return _currentProfile->setVoidResidue(amount); });
|
||||
drawMaterialRow("Muscular construction", 3,
|
||||
[this]{ return _currentProfile->muscularConstruction(); },
|
||||
[this](Int amount){ return _currentProfile->setMuscularConstruction(amount); });
|
||||
drawMaterialRow("Mineral exoskeletology", 4,
|
||||
[this]{ return _currentProfile->mineralExoskeletology(); },
|
||||
[this](Int amount){ return _currentProfile->setMineralExoskeletology(amount); });
|
||||
drawMaterialRow("Carbonized skin", 5,
|
||||
[this]{ return _currentProfile->carbonisedSkin(); },
|
||||
[this](Int amount){ return _currentProfile->setCarbonisedSkin(amount); });
|
||||
drawUnavailableMaterialRow("Isolated void particle", 6);
|
||||
drawUnavailableMaterialRow("Weaponised physiology", 7);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
#undef unavRow
|
||||
#undef matRow
|
||||
template<typename Getter, typename Setter>
|
||||
void SaveTool::drawMaterialRow(const char* name, Int tier, Getter getter, Setter setter) {
|
||||
static_assert(std::is_same<decltype(getter()), Int>::value, "getter doesn't return an Int, and/or doesn't take zero arguments.");
|
||||
static_assert(std::is_same<decltype(setter(0)), bool>::value, "setter doesn't return a bool, and/or doesn't take a single Int as an argument.");
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::Text("T%i", tier);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::TextUnformatted(name);
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
if(getter() != -1) {
|
||||
ImGui::Text("%i", getter());
|
||||
if(_cheatMode) {
|
||||
ImGui::TableSetColumnIndex(3);
|
||||
ImGui::PushID(name);
|
||||
static Int var = 0;
|
||||
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_EDIT)) {
|
||||
(var) = getter();
|
||||
ImGui::OpenPopup("int_edit");
|
||||
}
|
||||
if(drawIntEditPopup(&(var), 9999)) {
|
||||
if(!setter(var)) {
|
||||
_queue.addToast(Toast::Type::Error, _currentProfile->lastError());
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ImGui::TextDisabled("Not found in the save file");
|
||||
}
|
||||
}
|
||||
|
||||
void SaveTool::drawUnavailableMaterialRow(const char* name, Int tier) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::Text("T%i", tier);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::TextUnformatted(name);
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
ImGui::TextDisabled("Unavailable as of game version " SUPPORTED_GAME_VERSION);
|
||||
}
|
||||
|
||||
void SaveTool::drawMassManager() {
|
||||
|
@ -409,7 +446,7 @@ void SaveTool::drawMassManager() {
|
|||
ImGui::TableSetupColumn("##Hangar", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("##MASSName", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("##Active", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("##DeleteButton", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("##Buttons", ImGuiTableColumnFlags_WidthFixed);
|
||||
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
|
||||
|
@ -451,11 +488,10 @@ void SaveTool::drawMassManager() {
|
|||
std::string file = *(static_cast<std::string*>(payload->Data));
|
||||
|
||||
if(!_massManager->importMass(file, i)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error importing M.A.S.S.",
|
||||
_massManager->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
||||
}
|
||||
}
|
||||
else if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("Mass")) {
|
||||
else if((payload = ImGui::AcceptDragDropPayload("Mass"))) {
|
||||
if(payload->DataSize != sizeof(int)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
||||
"payload->DataSize != sizeof(int) in SaveTool::drawMassManager()",
|
||||
|
@ -466,9 +502,7 @@ void SaveTool::drawMassManager() {
|
|||
int index = *(static_cast<int*>(payload->Data));
|
||||
|
||||
if(!_massManager->moveMass(index, i)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_massManager->lastError().c_str(),
|
||||
window());
|
||||
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -504,6 +538,11 @@ void SaveTool::drawMassManager() {
|
|||
}
|
||||
ImGui::SameLine(0.0f, 2.0f);
|
||||
}
|
||||
else{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.0f);
|
||||
ImGui::SmallButton(ICON_FA_SEARCH);
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) {
|
||||
mass_to_delete = i;
|
||||
ImGui::OpenPopup(mass_deletion_popup_ID);
|
||||
|
@ -576,9 +615,7 @@ void SaveTool::drawMassManager() {
|
|||
int index = *(static_cast<int*>(payload->Data));
|
||||
|
||||
if(!_massManager->exportMass(index)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_massManager->lastError().c_str(),
|
||||
window());
|
||||
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -627,8 +664,7 @@ auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID {
|
|||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::Button("Yes")) {
|
||||
if(!_massManager->deleteMass(mass_index)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error when deleting M.A.S.S.",
|
||||
_massManager->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
@ -666,8 +702,7 @@ auto SaveTool::drawDeleteStagedMassPopup(const std::string& filename) -> ImGuiID
|
|||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::Button("Yes")) {
|
||||
if(!_massManager->deleteStagedMass(filename)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error when deleting M.A.S.S.",
|
||||
_massManager->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
198
src/SaveTool/SaveTool_MassViewer_Armour.cpp
Normal file
198
src/SaveTool/SaveTool_MassViewer_Armour.cpp
Normal file
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#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();
|
||||
}
|
307
src/SaveTool/SaveTool_MassViewer_Frame.cpp
Normal file
307
src/SaveTool/SaveTool_MassViewer_Frame.cpp
Normal file
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#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();
|
||||
}
|
475
src/SaveTool/SaveTool_MassViewer_Weapons.cpp
Normal file
475
src/SaveTool/SaveTool_MassViewer_Weapons.cpp
Normal file
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#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<Weapon> 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<int*>(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();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -90,7 +90,7 @@ void SaveTool::drawProfileManager() {
|
|||
}
|
||||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::TextUnformatted(_profileManager->profiles()[i].type() == ProfileType::Demo ? "Demo" : "Full");
|
||||
ImGui::TextUnformatted(_profileManager->profiles()[i].type() == ProfileType::Demo ? "Demo (legacy)" : "Full (legacy)");
|
||||
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
if(ImGui::SmallButton(ICON_FA_FILE_ARCHIVE)) {
|
||||
|
@ -150,8 +150,7 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
|||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::Button("Yes")) {
|
||||
if(!_profileManager->restoreBackup(backup_index)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error when restoring backup",
|
||||
_profileManager->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
||||
}
|
||||
_profileManager->refreshProfiles();
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
@ -190,8 +189,7 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
|||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::Button("Yes")) {
|
||||
if(!_profileManager->deleteBackup(backup_index)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error when deleting backup",
|
||||
_profileManager->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
@ -378,8 +376,7 @@ auto SaveTool::drawDeleteProfilePopup(std::size_t profile_index) -> ImGuiID {
|
|||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::Button("Yes")) {
|
||||
if(!_profileManager->deleteProfile(profile_index, delete_builds)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error when deleting profile",
|
||||
_profileManager->lastError().c_str(), window());
|
||||
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -57,9 +57,8 @@ void SaveTool::drawAbout() {
|
|||
ImGui::TextWrapped("This application, made for the M.A.S.S. Builder community by Guillaume Jacquemin (aka William JCM), "
|
||||
"is a rewrite of the wxWidgets-powered M.A.S.S. Builder Save Tool (formerly known as wxMASSManager).");
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* repo = "https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool";
|
||||
ImGui::Text(ICON_FA_GIT_ALT " %s", repo);
|
||||
drawAlignedText(ICON_FA_GIT_ALT " %s", repo);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(repo);
|
||||
|
@ -90,9 +89,8 @@ void SaveTool::drawAbout() {
|
|||
|
||||
if(ImGui::TreeNodeEx("Corrade", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::Text("Version used: %s", CORRADE_VERSION_STRING);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* corrade_website = "https://magnum.graphics/corrade";
|
||||
ImGui::Text(ICON_FA_GLOBE " %s", corrade_website);
|
||||
drawAlignedText(ICON_FA_GLOBE " %s", corrade_website);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(corrade_website);
|
||||
|
@ -119,9 +117,8 @@ void SaveTool::drawAbout() {
|
|||
ImGui::TextUnformatted("Versions used:");
|
||||
ImGui::BulletText("Magnum: %s", MAGNUM_VERSION_STRING);
|
||||
ImGui::BulletText("Integration: %s", MAGNUMINTEGRATION_VERSION_STRING);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* magnum_website = "https://magnum.graphics";
|
||||
ImGui::Text(ICON_FA_GLOBE " %s", magnum_website);
|
||||
drawAlignedText(ICON_FA_GLOBE " %s", magnum_website);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(magnum_website);
|
||||
|
@ -146,9 +143,8 @@ void SaveTool::drawAbout() {
|
|||
|
||||
if(ImGui::TreeNodeEx("Dear ImGui", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::Text("Version used: %s", IMGUI_VERSION);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* imgui_repo = "https://github.com/ocornut/imgui";
|
||||
ImGui::Text(ICON_FA_GITHUB " %s", imgui_repo);
|
||||
drawAlignedText(ICON_FA_GITHUB " %s", imgui_repo);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(imgui_repo);
|
||||
|
@ -173,9 +169,8 @@ void SaveTool::drawAbout() {
|
|||
|
||||
if(ImGui::TreeNodeEx("Simple DirectMedia Layer (SDL) 2", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::Text("Version used: %i.%i.%i", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* sdl_website = "https://www.libsdl.org/";
|
||||
ImGui::Text(ICON_FA_GLOBE " %s", sdl_website);
|
||||
drawAlignedText(ICON_FA_GLOBE " %s", sdl_website);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(sdl_website);
|
||||
|
@ -200,9 +195,8 @@ void SaveTool::drawAbout() {
|
|||
|
||||
if(ImGui::TreeNodeEx("libzip", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::Text("Version used: %s", LIBZIP_VERSION);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* libzip_website = "https://libzip.org/";
|
||||
ImGui::Text(ICON_FA_GLOBE " %s", libzip_website);
|
||||
drawAlignedText(ICON_FA_GLOBE " %s", libzip_website);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(libzip_website);
|
||||
|
@ -226,9 +220,8 @@ void SaveTool::drawAbout() {
|
|||
}
|
||||
|
||||
if(ImGui::TreeNodeEx("Entropia File System Watcher (efsw)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* efsw_repo = "https://github.com/SpartanJ/efsw";
|
||||
ImGui::Text(ICON_FA_GITHUB " %s", efsw_repo);
|
||||
drawAlignedText(ICON_FA_GITHUB " %s", efsw_repo);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(efsw_repo);
|
||||
|
@ -252,9 +245,8 @@ void SaveTool::drawAbout() {
|
|||
}
|
||||
|
||||
if(ImGui::TreeNodeEx("C++ Requests (cpr)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* cpr_website = "https://whoshuu.github.io/cpr/";
|
||||
ImGui::Text(ICON_FA_GLOBE " %s", cpr_website);
|
||||
drawAlignedText(ICON_FA_GLOBE " %s", cpr_website);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(cpr_website);
|
||||
|
@ -278,9 +270,8 @@ void SaveTool::drawAbout() {
|
|||
}
|
||||
|
||||
if(ImGui::TreeNodeEx("JSON for Modern C++ (aka json.hpp)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* json_website = "https://json.nlohmann.me/";
|
||||
ImGui::Text(ICON_FA_GLOBE " %s", json_website);
|
||||
drawAlignedText(ICON_FA_GLOBE " %s", json_website);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(json_website);
|
||||
|
@ -305,9 +296,8 @@ void SaveTool::drawAbout() {
|
|||
|
||||
if(ImGui::TreeNodeEx("Font Awesome", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::TextUnformatted("Version used: 5.15.3");
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* fa_website = "https://fontawesome.com/";
|
||||
ImGui::Text(ICON_FA_GLOBE " %s", fa_website);
|
||||
drawAlignedText(ICON_FA_GLOBE " %s", fa_website);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(fa_website);
|
||||
|
@ -323,9 +313,8 @@ void SaveTool::drawAbout() {
|
|||
}
|
||||
|
||||
if(ImGui::TreeNodeEx("IconFontCppHeaders", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
const char* icon_repo = "https://github.com/juliettef/IconFontCppHeaders";
|
||||
ImGui::Text(ICON_FA_GITHUB " %s", icon_repo);
|
||||
drawAlignedText(ICON_FA_GITHUB " %s", icon_repo);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(icon_repo);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -55,8 +55,7 @@ void SaveTool::drawMainMenu() {
|
|||
ImGui::Separator();
|
||||
|
||||
if(ImGui::BeginMenu(ICON_FA_COG " Settings")) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::TextUnformatted("Frame limiter:");
|
||||
drawAlignedText("Frame limiter:");
|
||||
ImGui::SameLine();
|
||||
|
||||
static UnsignedByte selection = static_cast<UnsignedByte>(_framelimit);
|
||||
|
@ -118,8 +117,7 @@ void SaveTool::drawMainMenu() {
|
|||
}
|
||||
|
||||
if(_updateAvailable) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Version %s is available.", _latestVersion.c_str());
|
||||
drawAlignedText("Version %s is available.", _latestVersion.c_str());
|
||||
if(ImGui::Button(ICON_FA_FILE_SIGNATURE " Release notes")) {
|
||||
openUri(_releaseLink);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -45,6 +45,10 @@ auto BinaryReader::position() -> Long {
|
|||
return _ftelli64(_file);
|
||||
}
|
||||
|
||||
auto BinaryReader::seek(Long position) -> bool {
|
||||
return _fseeki64(_file, position, SEEK_SET) == 0;
|
||||
}
|
||||
|
||||
void BinaryReader::closeFile() {
|
||||
std::fclose(_file);
|
||||
_file = nullptr;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -36,6 +36,8 @@ class BinaryReader {
|
|||
auto eof() -> bool;
|
||||
auto position() -> Long;
|
||||
|
||||
auto seek(Long position) -> bool;
|
||||
|
||||
void closeFile();
|
||||
|
||||
auto readChar(char& value) -> bool;
|
||||
|
@ -51,6 +53,11 @@ class BinaryReader {
|
|||
auto readDouble(Double& value) -> bool;
|
||||
auto readArray(Containers::Array<char>& array, std::size_t count) -> bool;
|
||||
|
||||
template<typename T>
|
||||
auto readValue(T& value) -> bool {
|
||||
return fread(&value, sizeof(T), 1, _file) == sizeof(T);
|
||||
}
|
||||
|
||||
template<std::size_t S>
|
||||
auto readStaticArray(Containers::StaticArray<S, char>& array) -> bool {
|
||||
return std::fread(array.data(), sizeof(char), S, _file) == S;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -46,6 +46,10 @@ auto BinaryWriter::position() -> Long {
|
|||
return _ftelli64(_file);
|
||||
}
|
||||
|
||||
auto BinaryWriter::array() const -> Containers::ArrayView<const char> {
|
||||
return _data;
|
||||
}
|
||||
|
||||
auto BinaryWriter::arrayPosition() const -> UnsignedLong {
|
||||
return _index;
|
||||
}
|
||||
|
@ -102,7 +106,7 @@ auto BinaryWriter::writeDouble(Double value) -> bool {
|
|||
return std::fwrite(&value, sizeof(Double), 1, _file) == 1;
|
||||
}
|
||||
|
||||
auto BinaryWriter::writeArray(Containers::ArrayView<char> array) -> bool {
|
||||
auto BinaryWriter::writeArray(Containers::ArrayView<const char> array) -> bool {
|
||||
if(array.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -33,12 +33,19 @@ class BinaryWriter {
|
|||
explicit BinaryWriter(const std::string& filename);
|
||||
~BinaryWriter();
|
||||
|
||||
BinaryWriter(const BinaryWriter& other) = delete;
|
||||
BinaryWriter& operator=(const BinaryWriter& other) = delete;
|
||||
|
||||
BinaryWriter(BinaryWriter&& other) = default;
|
||||
BinaryWriter& operator=(BinaryWriter&& other) = default;
|
||||
|
||||
auto open() -> bool;
|
||||
|
||||
void closeFile();
|
||||
|
||||
auto position() -> Long;
|
||||
|
||||
auto array() const -> Containers::ArrayView<const char>;
|
||||
auto arrayPosition() const -> UnsignedLong;
|
||||
auto flushToFile() -> bool;
|
||||
|
||||
|
@ -53,7 +60,11 @@ class BinaryWriter {
|
|||
auto writeUnsignedLong(UnsignedLong value) -> bool;
|
||||
auto writeFloat(Float value) -> bool;
|
||||
auto writeDouble(Double value) -> bool;
|
||||
auto writeArray(Containers::ArrayView<char> array) -> bool;
|
||||
auto writeArray(Containers::ArrayView<const char> array) -> bool;
|
||||
template<std::size_t size>
|
||||
auto writeString(const char(&str)[size]) -> bool {
|
||||
return writeArray({str, size - 1});
|
||||
}
|
||||
|
||||
template<std::size_t S>
|
||||
auto writeStaticArray(Containers::StaticArrayView<S, const char> array) -> bool {
|
||||
|
@ -64,7 +75,7 @@ class BinaryWriter {
|
|||
|
||||
template<typename T, typename U = std::conditional_t<std::is_trivially_copyable<T>::value, T, T&>>
|
||||
auto writeValueToArray(U value) -> UnsignedLong {
|
||||
Containers::ArrayView<U> view{&value, 1};
|
||||
Containers::ArrayView<T> view{&value, 1};
|
||||
return writeDataToArray(view);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 Guillaume Jacquemin
|
||||
// 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
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue