WIP: Add a research tree view #1
9 changed files with 1397 additions and 0 deletions
|
@ -48,6 +48,9 @@ add_executable(MassBuilderSaveTool WIN32
|
||||||
Maps/StoryProgress.h
|
Maps/StoryProgress.h
|
||||||
ToastQueue/ToastQueue.h
|
ToastQueue/ToastQueue.h
|
||||||
ToastQueue/ToastQueue.cpp
|
ToastQueue/ToastQueue.cpp
|
||||||
|
ResearchTree/NodeIDs.h
|
||||||
|
ResearchTree/ResearchTree.h
|
||||||
|
ResearchTree/ResearchTree.cpp
|
||||||
FontAwesome/IconsFontAwesome5.h
|
FontAwesome/IconsFontAwesome5.h
|
||||||
FontAwesome/IconsFontAwesome5Brands.h
|
FontAwesome/IconsFontAwesome5Brands.h
|
||||||
resource.rc
|
resource.rc
|
||||||
|
|
|
@ -109,6 +109,10 @@ void Profile::refreshValues() {
|
||||||
getMuscularConstruction();
|
getMuscularConstruction();
|
||||||
getMineralExoskeletology();
|
getMineralExoskeletology();
|
||||||
getCarbonizedSkin();
|
getCarbonizedSkin();
|
||||||
|
|
||||||
|
getEngineUnlocks();
|
||||||
|
getOsUnlocks();
|
||||||
|
getArchUnlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::companyName() const -> std::string const& {
|
auto Profile::companyName() const -> std::string const& {
|
||||||
|
@ -1001,3 +1005,156 @@ auto Profile::setCarbonizedSkin(Int amount) -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Profile::engineInventory() -> Containers::ArrayView<Int> {
|
||||||
|
return _engineInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Profile::gearInventory() -> Containers::ArrayView<Int> {
|
||||||
|
return _gearInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profile::getEngineUnlocks() {
|
||||||
|
auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename));
|
||||||
|
|
||||||
|
auto iter = std::search(mmap.begin(), mmap.end(), &engine_inventory_locator[0], &engine_inventory_locator[33]);
|
||||||
|
|
||||||
|
if(iter != mmap.end()) {
|
||||||
|
Int* int_iter = reinterpret_cast<Int*>(iter + 0x3B);
|
||||||
|
Int size = *(int_iter++);
|
||||||
|
|
||||||
|
if(size > 0) {
|
||||||
|
_engineInventory = Containers::Array<Int>{DefaultInit, std::size_t(size)};
|
||||||
|
std::copy_n(int_iter, size, _engineInventory.data());
|
||||||
|
|
||||||
|
Utility::Debug{} << "_engineInventory:" << _engineInventory;
|
||||||
|
|
||||||
|
iter = std::search(mmap.begin(), mmap.end(), &gear_inventory_locator[0], &gear_inventory_locator[31]);
|
||||||
|
|
||||||
|
if(iter == mmap.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_iter = reinterpret_cast<Int*>(iter + 0x39);
|
||||||
|
size = *(int_iter++);
|
||||||
|
|
||||||
|
if(size <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_gearInventory = Containers::Array<Int>{DefaultInit, std::size_t(size)};
|
||||||
|
std::copy_n(int_iter, size, _gearInventory.data());
|
||||||
|
|
||||||
|
Utility::Debug{} << "_gearInventory:" << _gearInventory;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_lastError = "An array can't have a null or negative size.";
|
||||||
|
Utility::Fatal{EXIT_FAILURE} << _lastError.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Profile::osInventory() -> Containers::ArrayView<Int> {
|
||||||
|
return _osInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Profile::moduleInventory() -> Containers::ArrayView<Int> {
|
||||||
|
return _moduleInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profile::getOsUnlocks() {
|
||||||
|
auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename));
|
||||||
|
|
||||||
|
auto iter = std::search(mmap.begin(), mmap.end(), &os_inventory_locator[0], &os_inventory_locator[29]);
|
||||||
|
|
||||||
|
if(iter != mmap.end()) {
|
||||||
|
Int* int_iter = reinterpret_cast<Int*>(iter + 0x37);
|
||||||
|
Int size = *(int_iter++);
|
||||||
|
|
||||||
|
if(size > 0) {
|
||||||
|
_osInventory = Containers::Array<Int>{DefaultInit, std::size_t(size)};
|
||||||
|
std::copy_n(int_iter, size, _osInventory.data());
|
||||||
|
|
||||||
|
Utility::Debug{} << "_osInventory:" << _osInventory;
|
||||||
|
|
||||||
|
iter = std::search(mmap.begin(), mmap.end(), &module_inventory_locator[0], &module_inventory_locator[33]);
|
||||||
|
|
||||||
|
if(iter == mmap.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_iter = reinterpret_cast<Int*>(iter + 0x3B);
|
||||||
|
size = *(int_iter++);
|
||||||
|
|
||||||
|
if(size <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_moduleInventory = Containers::Array<Int>{DefaultInit, std::size_t(size)};
|
||||||
|
std::copy_n(int_iter, size, _moduleInventory.data());
|
||||||
|
|
||||||
|
Utility::Debug{} << "_moduleInventory:" << _moduleInventory;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_lastError = "An array can't have a null or negative size.";
|
||||||
|
Utility::Fatal{EXIT_FAILURE} << _lastError.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Profile::archInventory() -> Containers::ArrayView<Int> {
|
||||||
|
return _archInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Profile::techInventory() -> Containers::ArrayView<Int> {
|
||||||
|
return _techInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profile::getArchUnlocks() {
|
||||||
|
auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename));
|
||||||
|
|
||||||
|
auto iter = std::search(mmap.begin(), mmap.end(), &arch_inventory_locator[0], &arch_inventory_locator[36]);
|
||||||
|
|
||||||
|
if(iter != mmap.end()) {
|
||||||
|
Int* int_iter = reinterpret_cast<Int*>(iter + 0x3E);
|
||||||
|
Int size = *(int_iter++);
|
||||||
|
|
||||||
|
if(size > 0) {
|
||||||
|
_archInventory = Containers::Array<Int>{DefaultInit, std::size_t(size)};
|
||||||
|
std::copy_n(int_iter, size, _archInventory.data());
|
||||||
|
|
||||||
|
Utility::Debug{} << "_archInventory:" << _archInventory;
|
||||||
|
|
||||||
|
iter = std::search(mmap.begin(), mmap.end(), &tech_inventory_locator[0], &tech_inventory_locator[31]);
|
||||||
|
|
||||||
|
if(iter == mmap.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_iter = reinterpret_cast<Int*>(iter + 0x39);
|
||||||
|
size = *(int_iter++);
|
||||||
|
|
||||||
|
if(size <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_techInventory = Containers::Array<Int>{DefaultInit, std::size_t(size)};
|
||||||
|
std::copy_n(int_iter, size, _techInventory.data());
|
||||||
|
|
||||||
|
Utility::Debug{} << "_techInventory:" << _techInventory;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_lastError = "An array can't have a null or negative size.";
|
||||||
|
Utility::Fatal{EXIT_FAILURE} << _lastError.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/Array.h>
|
||||||
|
|
||||||
#include <Magnum/Magnum.h>
|
#include <Magnum/Magnum.h>
|
||||||
|
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
@ -141,6 +143,18 @@ class Profile {
|
||||||
auto getCarbonizedSkin() -> Int;
|
auto getCarbonizedSkin() -> Int;
|
||||||
auto setCarbonizedSkin(Int amount) -> bool;
|
auto setCarbonizedSkin(Int amount) -> bool;
|
||||||
|
|
||||||
|
auto engineInventory() -> Containers::ArrayView<Int>;
|
||||||
|
auto gearInventory() -> Containers::ArrayView<Int>;
|
||||||
|
void getEngineUnlocks();
|
||||||
|
|
||||||
|
auto osInventory() -> Containers::ArrayView<Int>;
|
||||||
|
auto moduleInventory() -> Containers::ArrayView<Int>;
|
||||||
|
void getOsUnlocks();
|
||||||
|
|
||||||
|
auto archInventory() -> Containers::ArrayView<Int>;
|
||||||
|
auto techInventory() -> Containers::ArrayView<Int>;
|
||||||
|
void getArchUnlocks();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _profileDirectory;
|
std::string _profileDirectory;
|
||||||
std::string _filename;
|
std::string _filename;
|
||||||
|
@ -183,4 +197,13 @@ class Profile {
|
||||||
Int _muscularConstruction;
|
Int _muscularConstruction;
|
||||||
Int _mineralExoskeletology;
|
Int _mineralExoskeletology;
|
||||||
Int _carbonizedSkin;
|
Int _carbonizedSkin;
|
||||||
|
|
||||||
|
Containers::Array<Int> _engineInventory;
|
||||||
|
Containers::Array<Int> _gearInventory;
|
||||||
|
|
||||||
|
Containers::Array<Int> _osInventory;
|
||||||
|
Containers::Array<Int> _moduleInventory;
|
||||||
|
|
||||||
|
Containers::Array<Int> _archInventory;
|
||||||
|
Containers::Array<Int> _techInventory;
|
||||||
};
|
};
|
||||||
|
|
360
src/ResearchTree/NodeIDs.h
Normal file
360
src/ResearchTree/NodeIDs.h
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
#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/>.
|
||||||
|
|
||||||
|
enum EngineIDs: Int {
|
||||||
|
// Tier 1
|
||||||
|
VerseEngine = 100000,
|
||||||
|
LoadedEngine = 100020,
|
||||||
|
MetalPlatings1 = 200000,
|
||||||
|
HeatTurbines1 = 200040,
|
||||||
|
Microcontroller1 = 200060,
|
||||||
|
CombustionController1 = 200020,
|
||||||
|
|
||||||
|
// Tier 2
|
||||||
|
ModAlloyEngine = 110000,
|
||||||
|
ChargedEngine = 110040,
|
||||||
|
ReinforcedLoadedEngine = 110020,
|
||||||
|
HeavyImpactsEnabler = 110100,
|
||||||
|
MetalPlatings2 = 210000,
|
||||||
|
HeatTurbines2 = 210040,
|
||||||
|
Microcontroller2 = 210060,
|
||||||
|
WeaponsCargo1 = 210061,
|
||||||
|
CombustionController2 = 210020,
|
||||||
|
PoweredRewiring1 = 210021,
|
||||||
|
|
||||||
|
// Tier 3
|
||||||
|
ModSteelEngine,
|
||||||
|
SuperchargedEngine,
|
||||||
|
NecriumAlloyEngine,
|
||||||
|
MetalPlatings3,
|
||||||
|
HeatTurbines3,
|
||||||
|
Microcontroller3,
|
||||||
|
WeaponsCargo2,
|
||||||
|
CombustionController3,
|
||||||
|
PoweredRewiring2,
|
||||||
|
|
||||||
|
// Tier 4
|
||||||
|
ModLunariteEngine,
|
||||||
|
ChargedLunariteEngine,
|
||||||
|
LunariteEngine,
|
||||||
|
InfusedEngine,
|
||||||
|
MetalPlatings4,
|
||||||
|
HeatTurbines4,
|
||||||
|
Microcontroller4,
|
||||||
|
WeaponsCargo3,
|
||||||
|
CombustionController4,
|
||||||
|
PoweredRewiring3,
|
||||||
|
ArmouredCargo1,
|
||||||
|
ArmouredFuelTank1,
|
||||||
|
ExtraCapacity1,
|
||||||
|
HighmetalEngine,
|
||||||
|
PowerRedirector1,
|
||||||
|
|
||||||
|
// Tier 5
|
||||||
|
AsteriteCarbonEngine,
|
||||||
|
ChargedAsteriteEngine,
|
||||||
|
AsteriteSteelEngine,
|
||||||
|
MeldedEngine,
|
||||||
|
MetalPlatings5,
|
||||||
|
HeatTurbines5,
|
||||||
|
Microcontroller5,
|
||||||
|
WeaponsCargo4,
|
||||||
|
CombustionController5,
|
||||||
|
PoweredRewiring4,
|
||||||
|
ArmouredCargo2,
|
||||||
|
ArmouredFuelTank2,
|
||||||
|
ExtraCapacity2,
|
||||||
|
CastHighmetalEngine,
|
||||||
|
PowerRedirector2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OSIDs: Int {
|
||||||
|
// Tier 1
|
||||||
|
NeuralOS = 300010,
|
||||||
|
ExoSkelOS = 300030,
|
||||||
|
Shields1 = 400010,
|
||||||
|
Enhancements1 = 400050,
|
||||||
|
FuelSave1 = 400051,
|
||||||
|
LongRange1 = 400030,
|
||||||
|
|
||||||
|
// Tier 2
|
||||||
|
SparkOS = 310010,
|
||||||
|
ImprovedNeuralOS = 310050,
|
||||||
|
EnhancedSkeletonOS = 310030,
|
||||||
|
ExtendedArtsLibrary = 310100,
|
||||||
|
SustainableShields1 = 410011,
|
||||||
|
Shields2 = 410010,
|
||||||
|
SustainableRecharger1 = 410052,
|
||||||
|
Enhancements2 = 410050,
|
||||||
|
FuelSave2 = 410051,
|
||||||
|
LongRange2 = 410030,
|
||||||
|
EmpoweredArtsLibrary = 310101,
|
||||||
|
|
||||||
|
//Tier 3
|
||||||
|
BlazeOS,
|
||||||
|
NeurolinkOS,
|
||||||
|
PoweredGuardianOS,
|
||||||
|
SustainableShields2,
|
||||||
|
Shields3,
|
||||||
|
SustainableRecharger2,
|
||||||
|
Enhancements3,
|
||||||
|
FuelSave3,
|
||||||
|
LongRange3,
|
||||||
|
|
||||||
|
// Tier 4
|
||||||
|
IgnitionOS,
|
||||||
|
AlteredFuelOS,
|
||||||
|
MindlinkOS,
|
||||||
|
FramelinkOS,
|
||||||
|
SlayerOS,
|
||||||
|
SustainableShields3,
|
||||||
|
Shields4,
|
||||||
|
SustainableRecharger3,
|
||||||
|
Enhancements4,
|
||||||
|
FuelSave4,
|
||||||
|
LongRange4,
|
||||||
|
CellburnOS,
|
||||||
|
StorageShielder1,
|
||||||
|
Realignment1,
|
||||||
|
AlphaAssault1,
|
||||||
|
BetaAssault1,
|
||||||
|
|
||||||
|
// Tier 5
|
||||||
|
BrightburnOS,
|
||||||
|
OmniaOS,
|
||||||
|
FullConnectOS,
|
||||||
|
FullDiveOS,
|
||||||
|
SpartoiOS,
|
||||||
|
SustainableShields4,
|
||||||
|
Shields5,
|
||||||
|
SustainableRecharger4,
|
||||||
|
Enhancements5,
|
||||||
|
FuelSave5,
|
||||||
|
LongRange5,
|
||||||
|
FirestormOS,
|
||||||
|
StorageShielder2,
|
||||||
|
Realignment2,
|
||||||
|
AlphaAssault2,
|
||||||
|
BetaAssault2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ArchIDs: Int { // That tree is a **fucking mess**, so this enum will be too.
|
||||||
|
// Left side T1
|
||||||
|
StandardFrame = 500099,
|
||||||
|
StrengthFrame,
|
||||||
|
BoostFrame,
|
||||||
|
SupportFrame,
|
||||||
|
CombatFrame,
|
||||||
|
DurableFibre1,
|
||||||
|
EfficientThrusters1,
|
||||||
|
MaterialsCollector1,
|
||||||
|
TempoPreserver,
|
||||||
|
|
||||||
|
// Left side T2
|
||||||
|
StopperFrame,
|
||||||
|
ReinforcedFrame,
|
||||||
|
Overtaker,
|
||||||
|
GeneratorFrame,
|
||||||
|
HeavyLoadFrame,
|
||||||
|
SiegeMechFrame,
|
||||||
|
SentryFrame,
|
||||||
|
MetalsReplacement,
|
||||||
|
ReactiveArmour1,
|
||||||
|
FrameBoostingSystemSType,
|
||||||
|
EnemyScanner1,
|
||||||
|
MaterialsCollector2,
|
||||||
|
CompositeNanorobotics,
|
||||||
|
PinpointReticle1,
|
||||||
|
|
||||||
|
// Left side T3
|
||||||
|
BlockerUnit,
|
||||||
|
Hillgard,
|
||||||
|
Atmosformer,
|
||||||
|
Revitaliser,
|
||||||
|
SupplyCarrier,
|
||||||
|
TheEnforcer,
|
||||||
|
Precelsior,
|
||||||
|
ForcefulTinkeringDType,
|
||||||
|
ReactiveArmour2,
|
||||||
|
EfficienttThrusters2,
|
||||||
|
EnemyScanner2,
|
||||||
|
MaterialsCollector3,
|
||||||
|
PressurisedGears1,
|
||||||
|
PinpointReticle2,
|
||||||
|
|
||||||
|
// Left side T4
|
||||||
|
Aurochs,
|
||||||
|
Pantheris,
|
||||||
|
Vulture,
|
||||||
|
Vitalcycler,
|
||||||
|
Amberjack,
|
||||||
|
Bloodhounds,
|
||||||
|
ManOWar,
|
||||||
|
Steelwall,
|
||||||
|
DurableFibre2,
|
||||||
|
Streamliner,
|
||||||
|
FortressConfigurations1,
|
||||||
|
Afterburners1,
|
||||||
|
PerpetualGenerator1,
|
||||||
|
DataAnalyser1,
|
||||||
|
VoidDestabiliser1,
|
||||||
|
Ragelock,
|
||||||
|
BinaryMonarchEType,
|
||||||
|
Stingray,
|
||||||
|
ShieldsformerSystem1,
|
||||||
|
ShieldsEnhancer1,
|
||||||
|
AcceleratedWalkers1,
|
||||||
|
BulletRecollector1,
|
||||||
|
EnemyScanner3,
|
||||||
|
ArmsSBattery1,
|
||||||
|
BinaryMonarchAType,
|
||||||
|
|
||||||
|
// Left side T5
|
||||||
|
Longhorn,
|
||||||
|
Lionel,
|
||||||
|
Stormbyrd,
|
||||||
|
Hydra,
|
||||||
|
Orca,
|
||||||
|
Felcaninus,
|
||||||
|
Anglerwasp,
|
||||||
|
Ramsgate,
|
||||||
|
DoomsdayCargo,
|
||||||
|
Ghostech,
|
||||||
|
ReactiveArmour3,
|
||||||
|
FrameBoostingSystemDType,
|
||||||
|
PerpetualGenerator2,
|
||||||
|
DataAnalyser2,
|
||||||
|
PoweredNanorobotics,
|
||||||
|
Styxgear,
|
||||||
|
FullMetalJacketAType,
|
||||||
|
Thornwhip,
|
||||||
|
ShieldsformerSystem2,
|
||||||
|
ShieldsRerouter,
|
||||||
|
AdditionalThrusters1,
|
||||||
|
BulletRecollector2,
|
||||||
|
EnemyInspector1,
|
||||||
|
ArmsSBattery2,
|
||||||
|
FullMetalJacketIType,
|
||||||
|
|
||||||
|
// Elemental T1/2 (there's a lone T1 node, so I won't make a separate group just for it)
|
||||||
|
EnemyObserverUnit,
|
||||||
|
BladeBlazeCanister,
|
||||||
|
BladeCryoCore,
|
||||||
|
BladeVoltAmplifier,
|
||||||
|
BlazeBulletsTech,
|
||||||
|
CryoBulletsTech,
|
||||||
|
VoltBulletsTech,
|
||||||
|
BlazePodsTech,
|
||||||
|
CryoPodsTech,
|
||||||
|
VoltPodsTech,
|
||||||
|
|
||||||
|
// Elemental T3
|
||||||
|
PowerTransferenceUnit1,
|
||||||
|
Adaptive,
|
||||||
|
BlazeArmsEnhancer,
|
||||||
|
CryoArmsEnhancer,
|
||||||
|
VoltArmsEnhancer,
|
||||||
|
|
||||||
|
// Elemental T4
|
||||||
|
PowerTransferenceUnit2,
|
||||||
|
Elemental,
|
||||||
|
BlazeTransferenceUnit,
|
||||||
|
CryoTransferenceUnit,
|
||||||
|
VoltTransferenceUnit,
|
||||||
|
QuickBurningChemicals,
|
||||||
|
CryoCoatedMetals,
|
||||||
|
VoltageOverclock,
|
||||||
|
|
||||||
|
// Elemental T5
|
||||||
|
PowerTransferenceUnit3,
|
||||||
|
Revenant,
|
||||||
|
ArmsConductionController,
|
||||||
|
TrinityCore1,
|
||||||
|
PodsConductionController,
|
||||||
|
MeltingChemicals,
|
||||||
|
LongLastingCryoChems,
|
||||||
|
VoltSplitters,
|
||||||
|
|
||||||
|
WeaponStanceControls, // This node is common to both the DW and shield sub-trees.
|
||||||
|
|
||||||
|
// Shield T2
|
||||||
|
ProtectiveCoating1,
|
||||||
|
MeteorShielder1,
|
||||||
|
|
||||||
|
// Shield T3
|
||||||
|
Retaliator,
|
||||||
|
Flagbearer1,
|
||||||
|
AegisReinforcements1,
|
||||||
|
|
||||||
|
// Shield T4
|
||||||
|
Flashspike,
|
||||||
|
ProtectiveCoating2,
|
||||||
|
MeteorShielder2,
|
||||||
|
IntegrityStrengthening1,
|
||||||
|
|
||||||
|
// Shield T5
|
||||||
|
Faithbinder,
|
||||||
|
SaintessBulwark,
|
||||||
|
MeteorShielder3,
|
||||||
|
BlizzardCore1,
|
||||||
|
|
||||||
|
// DW T2
|
||||||
|
GatheringStorm1,
|
||||||
|
WildfireStarter1,
|
||||||
|
|
||||||
|
// DW T3
|
||||||
|
MasterOfArms,
|
||||||
|
Stormwielder,
|
||||||
|
Suncaller,
|
||||||
|
|
||||||
|
// DW T4
|
||||||
|
Evoker,
|
||||||
|
GatheringStorm2,
|
||||||
|
WildfireStarter2,
|
||||||
|
GravitationDefier1,
|
||||||
|
|
||||||
|
// DW T5
|
||||||
|
Bladedancer,
|
||||||
|
Type3ArmsSBattery1,
|
||||||
|
ShieldsBatteryRegulator1,
|
||||||
|
GravitationDefier2,
|
||||||
|
|
||||||
|
// QB T2/3
|
||||||
|
// Okay, time to rant. The first node of the QB sub-tree is a tier 2 node. By itself, it's not that bad,
|
||||||
|
// except that... it's the child of Master of Arms, the first T3 node in the DW sub-tree. :DeadInside:
|
||||||
|
QuantumMechanicsResearch,
|
||||||
|
QuantumAccelerationResearch,
|
||||||
|
QuantumControlResearch,
|
||||||
|
QuantumCoatingResearch,
|
||||||
|
|
||||||
|
// QB T4
|
||||||
|
EnergyCollector1,
|
||||||
|
ParticleAccelerator1,
|
||||||
|
AmplificationModule1,
|
||||||
|
QAugmentedThrusters,
|
||||||
|
EssenceRedistributor1,
|
||||||
|
MomentumSpiker1,
|
||||||
|
|
||||||
|
// QB T5
|
||||||
|
EnergyCollector2,
|
||||||
|
ParticleAccelerator2,
|
||||||
|
AmplificationModule2,
|
||||||
|
QAugmentedShields,
|
||||||
|
EssenceRedistributor2,
|
||||||
|
MomentumSpiker2,
|
||||||
|
};
|
594
src/ResearchTree/ResearchTree.cpp
Normal file
594
src/ResearchTree/ResearchTree.cpp
Normal file
|
@ -0,0 +1,594 @@
|
||||||
|
// 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 "ResearchTree.h"
|
||||||
|
|
||||||
|
#include "NodeIDs.h"
|
||||||
|
|
||||||
|
//region Node
|
||||||
|
Node::Node(Node::Type type, const char* name, UnsignedByte tier, UnsignedByte slots,
|
||||||
|
const char* description, const char* active_effect, const char* passive_effect):
|
||||||
|
_type{type}, _state{State::Unavailable}, _name{name}, _tier{tier}, _slots{slots},
|
||||||
|
_description{description}, _activeEffect{active_effect}, _passiveEffect{passive_effect}
|
||||||
|
{
|
||||||
|
//ctor
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Node::type() const -> Node::Type {
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Node::state() const -> Node::State {
|
||||||
|
return _state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::setState(Node::State state) {
|
||||||
|
if(_state == state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_state = state;
|
||||||
|
|
||||||
|
if(_state == State::Available) {
|
||||||
|
for(Node* n : _children) {
|
||||||
|
n->setState(State::Unavailable, NotClicked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(_state == State::Unlocked) {
|
||||||
|
for(Node* n : _children) {
|
||||||
|
n->setState(State::Available, NotClicked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Node::name() const -> const char* {
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Node::tier() const -> UnsignedByte {
|
||||||
|
return _tier;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Node::slots() const -> UnsignedByte {
|
||||||
|
return _slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Node::description() const -> const char* {
|
||||||
|
return _description;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Node::activeEffect() const -> const char* {
|
||||||
|
return _activeEffect;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Node::passiveEffect() const -> const char* {
|
||||||
|
return _passiveEffect;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Node::children() -> Containers::ArrayView<Node*> {
|
||||||
|
return _children;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::addChild(Node& child) {
|
||||||
|
arrayAppend(_children, &child);
|
||||||
|
child.addParent(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::addParent(Node& parent) {
|
||||||
|
arrayAppend(_parents, &parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::setState(State state, NotClickedT) {
|
||||||
|
if(_state == state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(state == State::Unavailable) {
|
||||||
|
for(Node* node : _parents) {
|
||||||
|
if(node->state() == State::Unlocked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(state == State::Available && _state == State::Unlocked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_state = state;
|
||||||
|
|
||||||
|
if(_state != State::Unlocked) {
|
||||||
|
for(Node* node : _children) {
|
||||||
|
node->setState(State::Unavailable, NotClicked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(Node* node : _children) {
|
||||||
|
node->setState(State::Available, NotClicked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
void ResearchTree::generateEngineTree() {
|
||||||
|
if(!_engineNodes.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// T1
|
||||||
|
_engineNodes.emplace(VerseEngine, Node{Node::Type::Engine, "Verse Engine", 1, 3,
|
||||||
|
"A basic low-speed engine with great durability.",
|
||||||
|
"Durability +346, Power +60, Armour +22, Acceleration +75, Magazine load +35, Energy capacity +35",
|
||||||
|
"Durability +3%"});
|
||||||
|
|
||||||
|
_engineNodes.emplace(LoadedEngine, Node{Node::Type::Engine, "Loaded Engine", 1, 3,
|
||||||
|
"An alternate heavier model of engine used to operate a M.A.S.S.",
|
||||||
|
"Durability +288, Power +84, Armour +14, Acceleration +75, Magazine load +35, Energy capacity +35",
|
||||||
|
"Power +3%"});
|
||||||
|
|
||||||
|
_engineNodes.emplace(MetalPlatings1, Node{Node::Type::Gear, "Metal Platings 1", 1, 0,
|
||||||
|
"Level 1 metal plating that adds durability and armour to your engine.",
|
||||||
|
"Durability +60, Armour +5, Acceleration -15", ""});
|
||||||
|
_engineNodes.emplace(HeatTurbines1, Node{Node::Type::Gear, "Heat Turbines 1", 1, 0,
|
||||||
|
"Modified heat turbines to increase speed for a M.A.S.S.",
|
||||||
|
"Acceleration +75, Fuel capacity +5", ""});
|
||||||
|
_engineNodes.emplace(Microcontroller1, Node{Node::Type::Gear, "Microcontroller 1", 1, 0,
|
||||||
|
"A microchip that enhances various aspects of a M.A.S.S.",
|
||||||
|
"Durability +36, Power +1, Armour +11, Magazine load +5, Energy capacity +5, Fuel capacity +3", ""});
|
||||||
|
_engineNodes.emplace(CombustionController1, Node{Node::Type::Gear, "Combustion Controller 1", 1, 0,
|
||||||
|
"Controlled combustion allows increased power generation through specific ignition.",
|
||||||
|
"Power +2, Magazine load +10, Energy capacity +10, Acceleration -25", ""});
|
||||||
|
|
||||||
|
// T2
|
||||||
|
_engineNodes.emplace(ModAlloyEngine, Node{Node::Type::Engine, "Mod. Alloy Engine", 2, 3,
|
||||||
|
"Built with a modified alloy and able to sustain greater attacks from any enemy.",
|
||||||
|
"Durability +1152, Power +75, Armour +194, Acceleration +75, Magazine load +40, Energy capacity +40",
|
||||||
|
"Durability +3%"});
|
||||||
|
_engineNodes.emplace(ChargedEngine, Node{Node::Type::Engine, "Charged Engine", 2, 3,
|
||||||
|
"Remove most armours to attain more speed and power, and fuel.",
|
||||||
|
"Durability +960, Power +75, Acceleration +300, Magazine load +40, Energy capacity +40, Fuel capacity +52",
|
||||||
|
"Acceleration +5"});
|
||||||
|
_engineNodes.emplace(ReinforcedLoadedEngine, Node{Node::Type::Engine, "Reinforced Loaded Engine", 2, 3,
|
||||||
|
"An upgraded build of the basic model, with reinforced Verse Steel for more strength.",
|
||||||
|
"Durability +960, Power +105, Armour +130, Acceleration +75, Magazine load +40, Energy capacity +40",
|
||||||
|
"Power +3%"});
|
||||||
|
_engineNodes.emplace(HeavyImpactsEnabler, Node{Node::Type::Engine, "Heavy Impacts Enabler", 2, 0,
|
||||||
|
"Enable the usage of Heavy Combos in close combat attacks.", "", ""});
|
||||||
|
|
||||||
|
_engineNodes.emplace(MetalPlatings2, Node{Node::Type::Gear, "Metal Platings 2", 2, 0,
|
||||||
|
"Level 2 Metal plating that adds durability and armour to your engine.",
|
||||||
|
"Durability +180, Armour +41, Acceleration -15", ""});
|
||||||
|
_engineNodes.emplace(HeatTurbines2, Node{Node::Type::Gear, "Heat Turbines 2", 2, 0,
|
||||||
|
"Level 2 Modified heat turbines to increase speed for a M.A.S.S.",
|
||||||
|
"Acceleration +75, Fuel capacity +16", ""});
|
||||||
|
_engineNodes.emplace(Microcontroller2, Node{Node::Type::Gear, "Microcontroller 2", 2, 0,
|
||||||
|
"Level 2 Microchip that enhances various aspects of a M.A.S.S.",
|
||||||
|
"Durability +108, Power +3, Armour +17, Magazine load +6, Energy capacity +6, Fuel capacity +8", ""});
|
||||||
|
_engineNodes.emplace(WeaponsCargo1, Node{Node::Type::Gear, "Weapons Cargo 1", 2, 0,
|
||||||
|
"Added another cargo hold for ammo and energy recharger.",
|
||||||
|
"Magazine load +24, Energy capacity +24, Acceleration -40", ""});
|
||||||
|
_engineNodes.emplace(CombustionController2, Node{Node::Type::Gear, "Combustion Controller 2", 2, 0,
|
||||||
|
"Level 2 Controlled combustion allows increased power generation through specific ignition.",
|
||||||
|
"Power +5, Magazine load +12, Energy capacity +12, Acceleration -25", ""});
|
||||||
|
_engineNodes.emplace(PoweredRewiring1, Node{Node::Type::Gear, "Powered Rewiring 1", 2, 0,
|
||||||
|
"Rewiring that efficiently improves power and engine durability.",
|
||||||
|
"Durability +180, Power +5", ""});
|
||||||
|
|
||||||
|
// T3
|
||||||
|
_engineNodes.emplace(ModSteelEngine, Node{Node::Type::Engine, "Mod. Steel Engine", 3, 3,
|
||||||
|
"Low-speed engine that uses heavy materials for high durability.",
|
||||||
|
"Durability +2352, Power +90, Armour +311, Acceleration +75, Magazine load +47, Energy capacity +47",
|
||||||
|
"Durability +3%"});
|
||||||
|
_engineNodes.emplace(SuperchargedEngine, Node{Node::Type::Engine, "Supercharged Engine", 3, 3,
|
||||||
|
"An engine with more thermal efficiency that does not sacrifice much performance for speed.",
|
||||||
|
"Durability +1960, Power +90, Acceleration +300, Magazine load +47, Energy capacity +47, Fuel capacity +104",
|
||||||
|
"Acceleration +5"});
|
||||||
|
_engineNodes.emplace(NecriumAlloyEngine, Node{Node::Type::Engine, "Necrium Alloy Engine", 3, 3,
|
||||||
|
"Engine constructed of Necrium Alloy. Costly but with better performance.",
|
||||||
|
"Durability +1960, Power +126, Armour +207, Acceleration +75, Magazine load +47, Energy capacity +47",
|
||||||
|
"Power +3%"});
|
||||||
|
_engineNodes.emplace(MetalPlatings3, Node{Node::Type::Gear, "Metal Platings 3", 3, 0,
|
||||||
|
"Level 3 Metal plating that adds durability and armour to your engine.",
|
||||||
|
"Durability +360, Armour +57, Acceleration -15", ""});
|
||||||
|
_engineNodes.emplace(HeatTurbines3, Node{Node::Type::Gear, "Heat Turbines 3", 3, 0,
|
||||||
|
"Level 3 Modified heat turbines to increase speed for a M.A.S.S.",
|
||||||
|
"Acceleration +75, Fuel capacity +32", ""});
|
||||||
|
_engineNodes.emplace(Microcontroller3, Node{Node::Type::Gear, "Microcontroller 3", 3, 0,
|
||||||
|
"Level 3 Microchip that enhances various aspects of a M.A.S.S.",
|
||||||
|
"Durability +216, Power +5, Armour +24, Magazine load +7, Energy capacity +7, Fuel capacity +16", ""});
|
||||||
|
_engineNodes.emplace(WeaponsCargo2, Node{Node::Type::Gear, "Weapons Cargo 2", 3, 0,
|
||||||
|
"Level 2 Added another cargo hold for ammo and energy recharger.",
|
||||||
|
"Magazine load +28, Energy capacity +28, Acceleration -40", ""});
|
||||||
|
_engineNodes.emplace(CombustionController3, Node{Node::Type::Gear, "Combustion Controller 3", 3, 0,
|
||||||
|
"Level 3 Controlled combustion allows increased power generation through specific ignition.",
|
||||||
|
"Power +11, Magazine load +14, Energy capacity +14, Acceleration -25", ""});
|
||||||
|
_engineNodes.emplace(PoweredRewiring2, Node{Node::Type::Gear, "Powered Rewiring 2", 3, 0,
|
||||||
|
"Level 2 Rewiring that efficiently improves power and engine durability.",
|
||||||
|
"Durability +360, Power +11", ""});
|
||||||
|
|
||||||
|
// T4
|
||||||
|
_engineNodes.emplace(ModLunariteEngine, Node{Node::Type::Engine, "Mod. Lunarite Engine", 4, 4,
|
||||||
|
"Modified Durasteel that is heavier than normal durasteel, but even more durable",
|
||||||
|
"Durability +3744, Power +105, Armour +428, Acceleration +75, Magazine load +54, Energy capacity +54",
|
||||||
|
"Durability +3%"});
|
||||||
|
_engineNodes.emplace(ChargedLunariteEngine, Node{Node::Type::Engine, "Charged Lunarite Engine", 4, 4,
|
||||||
|
"Charged up Lunarite engine that compromises durability for more speed, then added with armour platings.",
|
||||||
|
"Durability +3120, Power +105, Acceleration +300, Magazine load +54, Energy capacity +54, Fuel capacity +157",
|
||||||
|
"Acceleration +5"});
|
||||||
|
_engineNodes.emplace(LunariteEngine, Node{Node::Type::Engine, "Lunarite Engine", 4, 4,
|
||||||
|
"Engine made of an alloy composed of Lunarite and various other metals.",
|
||||||
|
"Durability +3120, Power +147, Armour +285, Acceleration +75, Magazine load +54, Energy capacity +54",
|
||||||
|
"Power +3%"});
|
||||||
|
_engineNodes.emplace(InfusedEngine, Node{Node::Type::Engine, "Infused Engine", 4, 4,
|
||||||
|
"An engine with infused plating. Highly resistant to heat, allowing fuel to be burned at higher temperatures.",
|
||||||
|
"Durability +5460, Power +84, Armour +499, Acceleration -50, Magazine load +43, Energy capacity +43",
|
||||||
|
"Durability +3%"});
|
||||||
|
_engineNodes.emplace(MetalPlatings4, Node{Node::Type::Gear, "Metal Platings 4", 4, 0,
|
||||||
|
"Level 4 Metal plating that adds durability and armour to your engine.",
|
||||||
|
"Durability +540, Armour +73, Acceleration -15", ""});
|
||||||
|
_engineNodes.emplace(HeatTurbines4, Node{Node::Type::Gear, "Heat Turbines 4", 4, 0,
|
||||||
|
"Level 4 Modified heat turbines to increase speed for a M.A.S.S.",
|
||||||
|
"Acceleration +75, Fuel capacity +47", ""});
|
||||||
|
_engineNodes.emplace(Microcontroller4, Node{Node::Type::Gear, "Microcontroller 4", 4, 0,
|
||||||
|
"Level 4 Microchip that enhances various aspects of a M.A.S.S.",
|
||||||
|
"Durability +324, Power +8, Armour +30, Magazine load +8, Energy capacity +8, Fuel capacity +24", ""});
|
||||||
|
_engineNodes.emplace(WeaponsCargo3, Node{Node::Type::Gear, "Weapons Cargo 3", 4, 0,
|
||||||
|
"Level 3 Added another cargo hold for ammo and energy recharger.",
|
||||||
|
"Magazine load +32, Energy capacity +32, Acceleration -40", ""});
|
||||||
|
_engineNodes.emplace(CombustionController4, Node{Node::Type::Gear, "Combustion Controller 4", 4, 0,
|
||||||
|
"Level 4 Controlled combustion allows increased power generation through specific ignition.",
|
||||||
|
"Power +16, Magazine load +16, Energy capacity +16, Acceleration -25", ""});
|
||||||
|
_engineNodes.emplace(PoweredRewiring3, Node{Node::Type::Gear, "Powered Rewiring 3", 4, 0,
|
||||||
|
"Level 3 Rewiring that efficiently improves power and engine durability.",
|
||||||
|
"Durability +540, Power +16", ""});
|
||||||
|
_engineNodes.emplace(ArmouredCargo1, Node{Node::Type::Gear, "Armoured Cargo 1", 4, 0,
|
||||||
|
"Added armoured platings for large cargo holds.",
|
||||||
|
"Armour +61, Magazine load +16, Energy capacity +16, Acceleration -40", ""});
|
||||||
|
_engineNodes.emplace(ArmouredFuelTank1, Node{Node::Type::Gear, "Armoured Fuel Tank 1", 4, 0,
|
||||||
|
"Added armoured platings for a large fuel tank.",
|
||||||
|
"Armour +61, Fuel capacity +24, Acceleration -15", ""});
|
||||||
|
_engineNodes.emplace(ExtraCapacity1, Node{Node::Type::Gear, "Extra Capacity 1", 4, 0,
|
||||||
|
"Space management with added capacity for more cargo holds and fuel.",
|
||||||
|
"Magazine load +16, Energy capacity +16, Fuel capacity +47, Acceleration -40", ""});
|
||||||
|
_engineNodes.emplace(HighmetalEngine, Node{Node::Type::Engine, "Highmetal Engine", 4, 4,
|
||||||
|
"Made of highmetal, an alloy composed of Lunarite and other metals. Difficult to work into complex shapes, but high heat resistance.",
|
||||||
|
"Durability +2730, Power +189, Armour +249, Acceleration -50",
|
||||||
|
"Power +3%"});
|
||||||
|
_engineNodes.emplace(PowerRedirector1, Node{Node::Type::Gear, "Power Redirector 1", 4, 0,
|
||||||
|
"Redirection of power into fuel management for more power and acceleration.",
|
||||||
|
"Power +16, Acceleration +50", ""});
|
||||||
|
|
||||||
|
// T5
|
||||||
|
_engineNodes.emplace(AsteriteCarbonEngine, Node{Node::Type::Engine, "Asterite Carbon Engine", 5, 4,
|
||||||
|
"A modified version of carbon steel with additional metals alloyed into it. Surprisingly harder, but heavier.",
|
||||||
|
"Durability +5952, Power +130, Armour +544, Acceleration +75, Magazine load +62, Energy capacity +62",
|
||||||
|
"Durability +3%"});
|
||||||
|
_engineNodes.emplace(ChargedAsteriteEngine, Node{Node::Type::Engine, "Charged Asterite Engine", 5, 4,
|
||||||
|
"Charged-up Asterite steel. Extremely high resistance for better acceleration.",
|
||||||
|
"Durability +4960, Power +130, Acceleration +300, Magazine load +62, Energy capacity +62, Fuel capacity +244",
|
||||||
|
"Acceleration +5"});
|
||||||
|
_engineNodes.emplace(AsteriteSteelEngine, Node{Node::Type::Engine, "Asterite Steel Engine", 5, 4,
|
||||||
|
"Engine made of Asterite steel, a technology learnt from researching interstellar metals.",
|
||||||
|
"Durability +4960, Power +182, Armour +363, Acceleration +75, Magazine load +62, Energy capacity +62",
|
||||||
|
"Power +3%"});
|
||||||
|
_engineNodes.emplace(MeldedEngine, Node{Node::Type::Engine, "Melded Engine", 5, 4,
|
||||||
|
"Instead of infusing armour platings, they are melded to the engine itself for greater performance.",
|
||||||
|
"Durability +8680, Power +104, Armour +435, Acceleration -50, Magazine load +50, Energy capacity +50",
|
||||||
|
"Durability +3%"});
|
||||||
|
_engineNodes.emplace(MetalPlatings5, Node{Node::Type::Gear, "Metal Platings 5", 5, 0,
|
||||||
|
"Level 5 Metal plating that adds durability and armour to your engine.",
|
||||||
|
"Durability +840, Armour +91, Acceleration -15", ""});
|
||||||
|
_engineNodes.emplace(HeatTurbines5, Node{Node::Type::Gear, "Heat Turbines 5", 5, 0,
|
||||||
|
"Level 5 Modified heat turbines to increase speed for a M.A.S.S.",
|
||||||
|
"Acceleration +75, Fuel capacity +74", ""});
|
||||||
|
_engineNodes.emplace(Microcontroller5, Node{Node::Type::Gear, "Microcontroller 5", 5, 0,
|
||||||
|
"Level 5 Microchip that enhances various aspects of a M.A.S.S.",
|
||||||
|
"Durability +504, Power +13, Armour +38, Magazine load +9, Energy capacity +9, Fuel capacity +37", ""});
|
||||||
|
_engineNodes.emplace(WeaponsCargo4, Node{Node::Type::Gear, "Weapons Cargo 4", 5, 0,
|
||||||
|
"Level 4 Added another cargo hold for ammo and energy recharger.",
|
||||||
|
"Magazine load +36, Energy capacity +36, Acceleration -40", ""});
|
||||||
|
_engineNodes.emplace(CombustionController5, Node{Node::Type::Gear, "Combustion Controller 5", 5, 0,
|
||||||
|
"Level 5 Controlled combustion allows increased power generation through specific ignition.",
|
||||||
|
"Power +25, Magazine load +18, Energy capacity +18, Acceleration -25", ""});
|
||||||
|
_engineNodes.emplace(PoweredRewiring4, Node{Node::Type::Gear, "Powered Rewiring 4", 5, 0,
|
||||||
|
"Level 4 Rewiring that efficiently improves power and engine durability.",
|
||||||
|
"Durability +840, Power +25", ""});
|
||||||
|
_engineNodes.emplace(ArmouredCargo2, Node{Node::Type::Gear, "Armoured Cargo 2", 5, 0,
|
||||||
|
"Level 2 Added armoured platings for large cargo holds.",
|
||||||
|
"Armour +76, Magazine load +18, Energy capacity +18, Acceleration -40", ""});
|
||||||
|
_engineNodes.emplace(ArmouredFuelTank2, Node{Node::Type::Gear, "Armoured Fuel Tank 2", 5, 0,
|
||||||
|
"Level 2 Added armoured platings for a large fuel tank.",
|
||||||
|
"Armour +76, Fuel capacity +37, Acceleration -15", ""});
|
||||||
|
_engineNodes.emplace(ExtraCapacity2, Node{Node::Type::Gear, "Extra Capacity 2", 5, 0,
|
||||||
|
"Level 2 Space management with added capacity for more cargo holds and fuel.",
|
||||||
|
"Magazine load +18, Energy capacity +18, Fuel capacity +74, Acceleration -40", ""});
|
||||||
|
_engineNodes.emplace(CastHighmetalEngine, Node{Node::Type::Engine, "Cast Highmetal Engine", 5, 4,
|
||||||
|
"An upgraded version of the highmetal material, casted into a complex mold for better performance.",
|
||||||
|
"Durability +4340, Power +234, Armour +318, Acceleration -50",
|
||||||
|
"Power +3%"});
|
||||||
|
_engineNodes.emplace(PowerRedirector2, Node{Node::Type::Gear, "Power Redirector 2", 5, 0,
|
||||||
|
"Level 2 Redirection of power into fuel management for more power and acceleration.",
|
||||||
|
"Power +25, Acceleration +50", ""});
|
||||||
|
|
||||||
|
#define engineAddChild(parent, child) _engineNodes.at(parent).addChild(_engineNodes.at(child));
|
||||||
|
engineAddChild(VerseEngine, MetalPlatings1)
|
||||||
|
engineAddChild(VerseEngine, HeatTurbines1)
|
||||||
|
engineAddChild(VerseEngine, LoadedEngine)
|
||||||
|
engineAddChild(LoadedEngine, Microcontroller1)
|
||||||
|
engineAddChild(LoadedEngine, CombustionController1)
|
||||||
|
engineAddChild(MetalPlatings1, ModAlloyEngine)
|
||||||
|
engineAddChild(HeatTurbines1, ChargedEngine)
|
||||||
|
engineAddChild(Microcontroller1, ChargedEngine)
|
||||||
|
engineAddChild(CombustionController1, ReinforcedLoadedEngine)
|
||||||
|
engineAddChild(ModAlloyEngine, MetalPlatings2)
|
||||||
|
engineAddChild(ModAlloyEngine, HeatTurbines2)
|
||||||
|
engineAddChild(ChargedEngine, HeatTurbines2)
|
||||||
|
engineAddChild(ChargedEngine, Microcontroller2)
|
||||||
|
engineAddChild(ChargedEngine, WeaponsCargo1)
|
||||||
|
engineAddChild(ReinforcedLoadedEngine, CombustionController2)
|
||||||
|
engineAddChild(ReinforcedLoadedEngine, PoweredRewiring1)
|
||||||
|
engineAddChild(ReinforcedLoadedEngine, HeavyImpactsEnabler)
|
||||||
|
engineAddChild(MetalPlatings2, ModSteelEngine)
|
||||||
|
engineAddChild(HeatTurbines2, SuperchargedEngine)
|
||||||
|
engineAddChild(Microcontroller2, SuperchargedEngine)
|
||||||
|
engineAddChild(WeaponsCargo1, SuperchargedEngine)
|
||||||
|
engineAddChild(CombustionController2, NecriumAlloyEngine)
|
||||||
|
engineAddChild(PoweredRewiring1, NecriumAlloyEngine)
|
||||||
|
engineAddChild(ModSteelEngine, MetalPlatings3)
|
||||||
|
engineAddChild(ModSteelEngine, HeatTurbines3)
|
||||||
|
engineAddChild(SuperchargedEngine, HeatTurbines3)
|
||||||
|
engineAddChild(SuperchargedEngine, Microcontroller3)
|
||||||
|
engineAddChild(SuperchargedEngine, WeaponsCargo2)
|
||||||
|
engineAddChild(NecriumAlloyEngine, WeaponsCargo2)
|
||||||
|
engineAddChild(NecriumAlloyEngine, CombustionController3)
|
||||||
|
engineAddChild(NecriumAlloyEngine, PoweredRewiring2)
|
||||||
|
engineAddChild(MetalPlatings3, ModLunariteEngine)
|
||||||
|
engineAddChild(HeatTurbines3, ChargedLunariteEngine)
|
||||||
|
engineAddChild(Microcontroller3, ChargedLunariteEngine)
|
||||||
|
engineAddChild(WeaponsCargo2, ChargedLunariteEngine)
|
||||||
|
engineAddChild(CombustionController3, LunariteEngine)
|
||||||
|
engineAddChild(PoweredRewiring2, LunariteEngine)
|
||||||
|
engineAddChild(ModLunariteEngine, InfusedEngine)
|
||||||
|
engineAddChild(ModLunariteEngine, MetalPlatings4)
|
||||||
|
engineAddChild(ChargedLunariteEngine, HeatTurbines4)
|
||||||
|
engineAddChild(ChargedLunariteEngine, Microcontroller4)
|
||||||
|
engineAddChild(ChargedLunariteEngine, WeaponsCargo3)
|
||||||
|
engineAddChild(LunariteEngine, CombustionController4)
|
||||||
|
engineAddChild(LunariteEngine, PoweredRewiring3)
|
||||||
|
engineAddChild(InfusedEngine, ArmouredCargo1)
|
||||||
|
engineAddChild(InfusedEngine, ArmouredFuelTank1)
|
||||||
|
engineAddChild(MetalPlatings4, ArmouredCargo1)
|
||||||
|
engineAddChild(MetalPlatings4, ArmouredFuelTank1)
|
||||||
|
engineAddChild(HeatTurbines4, ExtraCapacity1)
|
||||||
|
engineAddChild(Microcontroller4, ExtraCapacity1)
|
||||||
|
engineAddChild(WeaponsCargo3, ExtraCapacity1)
|
||||||
|
engineAddChild(CombustionController4, HighmetalEngine)
|
||||||
|
engineAddChild(CombustionController4, PowerRedirector1)
|
||||||
|
engineAddChild(PoweredRewiring3, HighmetalEngine)
|
||||||
|
engineAddChild(PoweredRewiring3, PowerRedirector1)
|
||||||
|
engineAddChild(ArmouredCargo1, AsteriteCarbonEngine)
|
||||||
|
engineAddChild(ArmouredFuelTank1, AsteriteCarbonEngine)
|
||||||
|
engineAddChild(ExtraCapacity1, ChargedAsteriteEngine)
|
||||||
|
engineAddChild(HighmetalEngine, AsteriteSteelEngine)
|
||||||
|
engineAddChild(PowerRedirector1, AsteriteSteelEngine)
|
||||||
|
engineAddChild(AsteriteCarbonEngine, MeldedEngine)
|
||||||
|
engineAddChild(AsteriteCarbonEngine, MetalPlatings5)
|
||||||
|
engineAddChild(ChargedAsteriteEngine, HeatTurbines5)
|
||||||
|
engineAddChild(ChargedAsteriteEngine, Microcontroller5)
|
||||||
|
engineAddChild(ChargedAsteriteEngine, WeaponsCargo4)
|
||||||
|
engineAddChild(AsteriteSteelEngine, CombustionController5)
|
||||||
|
engineAddChild(AsteriteSteelEngine, PoweredRewiring4)
|
||||||
|
engineAddChild(MeldedEngine, ArmouredCargo2)
|
||||||
|
engineAddChild(MeldedEngine, ArmouredFuelTank2)
|
||||||
|
engineAddChild(MetalPlatings5, ArmouredCargo2)
|
||||||
|
engineAddChild(MetalPlatings5, ArmouredFuelTank2)
|
||||||
|
engineAddChild(HeatTurbines5, ExtraCapacity2)
|
||||||
|
engineAddChild(Microcontroller5, ExtraCapacity2)
|
||||||
|
engineAddChild(WeaponsCargo4, ExtraCapacity2)
|
||||||
|
engineAddChild(CombustionController5, CastHighmetalEngine)
|
||||||
|
engineAddChild(CombustionController5, PowerRedirector2)
|
||||||
|
engineAddChild(PoweredRewiring4, CastHighmetalEngine)
|
||||||
|
engineAddChild(PoweredRewiring4, PowerRedirector2)
|
||||||
|
#undef engineAddChild
|
||||||
|
|
||||||
|
_engineNodes.at(VerseEngine).setState(Node::State::Unlocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResearchTree::generateOSTree() {
|
||||||
|
if(!_osNodes.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// T1
|
||||||
|
_osNodes.emplace(NeuralOS, Node{Node::Type::OS, "Neural OS", 1, 3,
|
||||||
|
"Synchronise the links between your nervous system and the M.A.S.S. perfectly.",
|
||||||
|
"Accuracy +24, Shield +624, Fuel burn rate +200, Magazine reload +24, Energy recharge +66, Shield recover +1620",
|
||||||
|
"Shield +3%"});
|
||||||
|
_osNodes.emplace(ExoSkelOS, Node{Node::Type::OS, "ExoSkel OS", 1, 3,
|
||||||
|
"An OS that simulates the M.A.S.S. as your exoskeleton.",
|
||||||
|
"Accuracy +45, Shield +360, Fuel burn rate +300, Magazine reload +30, Energy recharge +83, Shield recover +608",
|
||||||
|
"Accuracy +3%"});
|
||||||
|
_osNodes.emplace(Shields1, Node{Node::Type::Module, "Shields 1", 1, 0,
|
||||||
|
"Module that helps in optimising shield usage.",
|
||||||
|
"Shield +60, Fuel burn rate +25, Shield recover +506", ""});
|
||||||
|
_osNodes.emplace(Enhancements1, Node{Node::Type::Module, "Enhancements 1", 1, 0,
|
||||||
|
"An overall enhancement module.",
|
||||||
|
"Accuracy +1, Shield +36, Magazine reload +13, Energy recharge +16, Fuel burn rate -3, Shield recover +169", ""});
|
||||||
|
_osNodes.emplace(FuelSave1, Node{Node::Type::Module, "Fuel Save 1", 1, 0,
|
||||||
|
"Optimisation module for energy usage of the M.A.S.S. frame.",
|
||||||
|
"Fuel burn rate -5, Fuel recharge +2", ""});
|
||||||
|
_osNodes.emplace(LongRange1, Node{Node::Type::Module, "Long Range 1", 1, 0,
|
||||||
|
"Controlling module that helps in stabilisation for higher accuracy and reload speed.",
|
||||||
|
"Accuracy +2, Fuel burn rate +50, Magazine reload +25, Energy recharge +33", ""});
|
||||||
|
|
||||||
|
// T2
|
||||||
|
_osNodes.emplace(SparkOS, Node{Node::Type::OS, "Spark OS", 2, 3,
|
||||||
|
"An OS equipped with an enhanced AI for M.A.S.S. control called \"Spark\".",
|
||||||
|
"Accuracy +31, Shield +1872, Fuel burn rate +200, Magazine reload +54, Energy recharge +93, Shield recover +2040",
|
||||||
|
"Shield +3%"});
|
||||||
|
_osNodes.emplace(ImprovedNeuralOS, Node{Node::Type::OS, "Improved Neural OS", 2, 3,
|
||||||
|
"An improved version of the Neural OS that improves synchronisation.",
|
||||||
|
"Accuracy +14, Shield +1296, Fuel burn rate +50, Magazine reload +68, Energy recharge +117, Shield recover +3230",
|
||||||
|
"Magazine reload +3%, Energy recharge +3%"});
|
||||||
|
_osNodes.emplace(EnhancedSkeletonOS, Node{Node::Type::OS, "Enhanced Skeleton OS", 2, 3,
|
||||||
|
"An updated version of the ExoSkel OS that improves weight simulation.",
|
||||||
|
"Accuracy +59, Shield +1080, Fuel burn rate +300, Magazine reload +68, Energy recharge +117, Shield recover +765",
|
||||||
|
"Accuracy +3%"});
|
||||||
|
_osNodes.emplace(ExtendedArtsLibrary, Node{Node::Type::OS, "Extended Arts Library", 2, 0,
|
||||||
|
"Enable the usage of Extended Combos in close combat attacks.",
|
||||||
|
"", ""});
|
||||||
|
_osNodes.emplace(SustainableShields1, Node{Node::Type::Module, "Sustainable Shields 1", 2, 0,
|
||||||
|
"A module that efficiently converts energy into shields.",
|
||||||
|
"Shields +216", ""});
|
||||||
|
_osNodes.emplace(Shields2, Node{Node::Type::Module, "Shields 2", 2, 0,
|
||||||
|
"Level 2 Module that helps in optimising shield usage.",
|
||||||
|
"Shield +180, Fuel burn rate +25, Shield recover +675", ""});
|
||||||
|
_osNodes.emplace(SustainableRecharger1, Node{Node::Type::Module, "Sustainable Recharger 1", 2, 0,
|
||||||
|
"Energy-saving shield recharging module.",
|
||||||
|
"Shield recover +1350", ""});
|
||||||
|
_osNodes.emplace(Enhancements2, Node{Node::Type::Module, "Enhancements 2", 2, 0,
|
||||||
|
"Level 2 Overall enhancement module.",
|
||||||
|
"Accuracy +3, Shield +108, Magazine reload +15, Energy recharge +19, Fuel burn rate -6, Shield recover +225", ""});
|
||||||
|
_osNodes.emplace(FuelSave2, Node{Node::Type::Module, "Fuel Save 2", 2, 0,
|
||||||
|
"Level 2 Optimisation module for energy usage of the M.A.S.S. frame.",
|
||||||
|
"Fuel burn rate -12, Fuel recharge +7", ""});
|
||||||
|
_osNodes.emplace(LongRange2, Node{Node::Type::Module, "Long Range 2", 2, 0,
|
||||||
|
"Level 2 Controlling module that helps in stabilisation for higher accuracy and reload speed.",
|
||||||
|
"Accuracy +5, Fuel burn rate +50, Magazine reload +31, Energy recharge +38", ""});
|
||||||
|
_osNodes.emplace(EmpoweredArtsLibrary, Node{Node::Type::OS, "Empowered Arts Library", 2, 0,
|
||||||
|
"Enable the usage of Empowered Combos in close combat attacks.",
|
||||||
|
"", ""});
|
||||||
|
|
||||||
|
#define osAddChild(parent, child) _osNodes.at(parent).addChild(_osNodes.at(child));
|
||||||
|
osAddChild(NeuralOS, Shields1)
|
||||||
|
osAddChild(NeuralOS, Enhancements1)
|
||||||
|
osAddChild(NeuralOS, ExoSkelOS)
|
||||||
|
osAddChild(ExoSkelOS, FuelSave1)
|
||||||
|
osAddChild(ExoSkelOS, LongRange1)
|
||||||
|
osAddChild(Shields1, SparkOS)
|
||||||
|
osAddChild(Enhancements1, ImprovedNeuralOS)
|
||||||
|
osAddChild(FuelSave1, ImprovedNeuralOS)
|
||||||
|
osAddChild(LongRange1, EnhancedSkeletonOS)
|
||||||
|
osAddChild(SparkOS, SustainableShields1)
|
||||||
|
osAddChild(SparkOS, Shields2)
|
||||||
|
osAddChild(SparkOS, SustainableRecharger1)
|
||||||
|
osAddChild(ImprovedNeuralOS, SustainableRecharger1)
|
||||||
|
osAddChild(ImprovedNeuralOS, Enhancements2)
|
||||||
|
osAddChild(ImprovedNeuralOS, FuelSave2)
|
||||||
|
osAddChild(EnhancedSkeletonOS, FuelSave2)
|
||||||
|
osAddChild(EnhancedSkeletonOS, LongRange2)
|
||||||
|
osAddChild(EnhancedSkeletonOS, ExtendedArtsLibrary)
|
||||||
|
osAddChild(ExtendedArtsLibrary, EmpoweredArtsLibrary)
|
||||||
|
#undef osAddChild
|
||||||
|
|
||||||
|
_osNodes.at(NeuralOS).setState(Node::State::Unlocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResearchTree::generateArchTree() {
|
||||||
|
if(!_archNodes.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_archNodes.emplace(StandardFrame, Node{Node::Type::Architect, "Standard Frame", 1, 2,
|
||||||
|
"The standard frame architecture for mass-produced humanoid robots. It uses the most common technologies and materials.",
|
||||||
|
"Durability +300, Shield +200, Physical damage +600, Piercing damage +300, Plasma damage +300",
|
||||||
|
""});
|
||||||
|
|
||||||
|
#define archAddChild(parent, child) _archNodes.at(parent).addChild(_archNodes.at(child));
|
||||||
|
#undef archAddChild
|
||||||
|
|
||||||
|
_archNodes.at(StandardFrame).setState(Node::State::Unlocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResearchTree::readEngineUnlocks(Containers::ArrayView<Int> engines, Containers::ArrayView<Int> gears) {
|
||||||
|
if(engines == nullptr || engines.size() == 0) {
|
||||||
|
Utility::Error{} << "Engines can't be empty";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Int engine : engines) {
|
||||||
|
if(_engineNodes.find(engine) != _engineNodes.end()) {
|
||||||
|
_engineNodes.at(engine).setState(Node::State::Unlocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gears == nullptr || gears.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Int gear : gears) {
|
||||||
|
if(_engineNodes.find(gear) != _engineNodes.end()) {
|
||||||
|
_engineNodes.at(gear).setState(Node::State::Unlocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResearchTree::readOSUnlocks(Containers::ArrayView<Int> os, Containers::ArrayView<Int> modules) {
|
||||||
|
if(os == nullptr || os.size() == 0) {
|
||||||
|
Utility::Error{} << "OSes can't be empty";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Int os_id : os) {
|
||||||
|
if(_osNodes.find(os_id) != _osNodes.end()) {
|
||||||
|
_osNodes.at(os_id).setState(Node::State::Unlocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(modules == nullptr || modules.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Int module : modules) {
|
||||||
|
if(_osNodes.find(module) != _osNodes.end()) {
|
||||||
|
_osNodes.at(module).setState(Node::State::Unlocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResearchTree::readArchUnlocks(Containers::ArrayView<Int> archs, Containers::ArrayView<Int> techs) {
|
||||||
|
if(archs == nullptr || archs.size() == 0) {
|
||||||
|
Utility::Error{} << "Archs can't be empty";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Int arch : archs) {
|
||||||
|
if(_archNodes.find(arch) != _archNodes.end()) {
|
||||||
|
_archNodes.at(arch).setState(Node::State::Unlocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(techs == nullptr || techs.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Int tech : techs) {
|
||||||
|
if(_archNodes.find(tech) != _archNodes.end()) {
|
||||||
|
_archNodes.at(tech).setState(Node::State::Unlocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ResearchTree::getEngineRootNode() -> Node& {
|
||||||
|
return _engineNodes.at(VerseEngine);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ResearchTree::getOSRootNode() -> Node& {
|
||||||
|
return _osNodes.at(NeuralOS);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ResearchTree::getArchRootNode() -> Node& {
|
||||||
|
return _archNodes.at(StandardFrame);
|
||||||
|
}
|
114
src/ResearchTree/ResearchTree.h
Normal file
114
src/ResearchTree/ResearchTree.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#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 <unordered_map>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
|
#include <Corrade/Containers/GrowableArray.h>
|
||||||
|
|
||||||
|
#include <Magnum/Magnum.h>
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
using namespace Magnum;
|
||||||
|
|
||||||
|
class Node {
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
Engine,
|
||||||
|
Gear,
|
||||||
|
OS,
|
||||||
|
Module,
|
||||||
|
Architect,
|
||||||
|
Tech
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
Unavailable,
|
||||||
|
Available,
|
||||||
|
Unlocked
|
||||||
|
};
|
||||||
|
|
||||||
|
Node(Type type, const char* name, UnsignedByte tier, UnsignedByte slots,
|
||||||
|
const char* description, const char* active_effect, const char* passive_effect);
|
||||||
|
|
||||||
|
Node(const Node& other) = delete;
|
||||||
|
Node& operator=(const Node& other) = delete;
|
||||||
|
|
||||||
|
Node(Node&& other) = default;
|
||||||
|
Node& operator=(Node&& other) = default;
|
||||||
|
|
||||||
|
auto type() const -> Type;
|
||||||
|
|
||||||
|
auto state() const -> State;
|
||||||
|
void setState(State state);
|
||||||
|
|
||||||
|
auto name() const -> const char*;
|
||||||
|
|
||||||
|
auto tier() const -> UnsignedByte;
|
||||||
|
|
||||||
|
auto slots() const -> UnsignedByte;
|
||||||
|
|
||||||
|
auto description() const -> const char*;
|
||||||
|
|
||||||
|
auto activeEffect() const -> const char*;
|
||||||
|
|
||||||
|
auto passiveEffect() const -> const char*;
|
||||||
|
|
||||||
|
auto children() -> Containers::ArrayView<Node*>;
|
||||||
|
void addChild(Node& child);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addParent(Node& parent);
|
||||||
|
|
||||||
|
struct NotClickedT {} NotClicked;
|
||||||
|
void setState(State state, NotClickedT);
|
||||||
|
|
||||||
|
Type _type;
|
||||||
|
State _state;
|
||||||
|
|
||||||
|
const char* _name;
|
||||||
|
UnsignedByte _tier;
|
||||||
|
UnsignedByte _slots;
|
||||||
|
const char* _description;
|
||||||
|
const char* _activeEffect;
|
||||||
|
const char* _passiveEffect;
|
||||||
|
|
||||||
|
Containers::Array<Node*> _parents;
|
||||||
|
Containers::Array<Node*> _children;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ResearchTree {
|
||||||
|
public:
|
||||||
|
void generateEngineTree();
|
||||||
|
void generateOSTree();
|
||||||
|
void generateArchTree();
|
||||||
|
|
||||||
|
void readEngineUnlocks(Containers::ArrayView<Int> engines, Containers::ArrayView<Int> gears = nullptr);
|
||||||
|
void readOSUnlocks(Containers::ArrayView<Int> os, Containers::ArrayView<Int> modules = nullptr);
|
||||||
|
void readArchUnlocks(Containers::ArrayView<Int> archs, Containers::ArrayView<Int> techs = nullptr);
|
||||||
|
|
||||||
|
auto getEngineRootNode() -> Node&;
|
||||||
|
auto getOSRootNode() -> Node&;
|
||||||
|
auto getArchRootNode() -> Node&;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Tree = std::unordered_map<Int, Node>;
|
||||||
|
Tree _engineNodes;
|
||||||
|
Tree _osNodes;
|
||||||
|
Tree _archNodes;
|
||||||
|
};
|
|
@ -188,6 +188,11 @@ void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
||||||
case efsw::Actions::Modified:
|
case efsw::Actions::Modified:
|
||||||
if(filename == _currentProfile->filename()) {
|
if(filename == _currentProfile->filename()) {
|
||||||
_currentProfile->refreshValues();
|
_currentProfile->refreshValues();
|
||||||
|
if(_tree) {
|
||||||
|
_tree->readEngineUnlocks(_currentProfile->engineInventory(), _currentProfile->gearInventory());
|
||||||
|
_tree->readOSUnlocks(_currentProfile->osInventory(), _currentProfile->moduleInventory());
|
||||||
|
_tree->readArchUnlocks(_currentProfile->archInventory(), _currentProfile->techInventory());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(Utility::String::endsWith(filename, _currentProfile->steamId() + ".sav")) {
|
else if(Utility::String::endsWith(filename, _currentProfile->steamId() + ".sav")) {
|
||||||
if(Utility::String::beginsWith(filename, Utility::formatString("{}Unit", _currentProfile->type() == ProfileType::Demo ? "Demo" : ""))) {
|
if(Utility::String::beginsWith(filename, Utility::formatString("{}Unit", _currentProfile->type() == ProfileType::Demo ? "Demo" : ""))) {
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
#include "../ProfileManager/ProfileManager.h"
|
#include "../ProfileManager/ProfileManager.h"
|
||||||
#include "../MassManager/MassManager.h"
|
#include "../MassManager/MassManager.h"
|
||||||
#include "../ToastQueue/ToastQueue.h"
|
#include "../ToastQueue/ToastQueue.h"
|
||||||
|
#include "../ResearchTree/ResearchTree.h"
|
||||||
|
|
||||||
|
class Node;
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
@ -97,6 +100,8 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
auto drawRenamePopup(Containers::ArrayView<char> name_view) -> bool;
|
auto drawRenamePopup(Containers::ArrayView<char> name_view) -> bool;
|
||||||
void drawGeneralInfo();
|
void drawGeneralInfo();
|
||||||
void drawResearchInventory();
|
void drawResearchInventory();
|
||||||
|
void drawResearchTree();
|
||||||
|
void drawNode(Node& node);
|
||||||
void drawMassManager();
|
void drawMassManager();
|
||||||
auto drawDeleteMassPopup(int mass_index) -> ImGuiID;
|
auto drawDeleteMassPopup(int mass_index) -> ImGuiID;
|
||||||
auto drawDeleteStagedMassPopup(const std::string& filename) -> ImGuiID;
|
auto drawDeleteStagedMassPopup(const std::string& filename) -> ImGuiID;
|
||||||
|
@ -197,6 +202,8 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
};
|
};
|
||||||
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
||||||
|
|
||||||
|
Containers::Pointer<ResearchTree> _tree;
|
||||||
|
|
||||||
bool _checkUpdatesOnStartup{true};
|
bool _checkUpdatesOnStartup{true};
|
||||||
bool _unsafeMode{false};
|
bool _unsafeMode{false};
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,11 @@ void SaveTool::drawManager() {
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginTabItem("Research tree")) {
|
||||||
|
drawResearchTree();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::EndTabBar();
|
ImGui::EndTabBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,6 +394,135 @@ void SaveTool::drawResearchInventory() {
|
||||||
#undef matRow
|
#undef matRow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SaveTool::drawResearchTree() {
|
||||||
|
if(!_tree) {
|
||||||
|
_tree.emplace();
|
||||||
|
|
||||||
|
_tree->generateEngineTree();
|
||||||
|
_tree->readEngineUnlocks(_currentProfile->engineInventory(), _currentProfile->gearInventory());
|
||||||
|
|
||||||
|
_tree->generateOSTree();
|
||||||
|
_tree->readOSUnlocks(_currentProfile->osInventory(), _currentProfile->moduleInventory());
|
||||||
|
|
||||||
|
_tree->generateArchTree();
|
||||||
|
_tree->readArchUnlocks(_currentProfile->archInventory(), _currentProfile->techInventory());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginTabBar("##TreeTabBar")) {
|
||||||
|
if(ImGui::BeginTabItem("Engine")) {
|
||||||
|
if(ImGui::BeginTable("##EngineTable", 1, ImGuiTableFlags_RowBg)) {
|
||||||
|
ImGui::TableSetupColumn("##Column", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
|
||||||
|
drawNode(_tree->getEngineRootNode());
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginTabItem("OS")) {
|
||||||
|
if(ImGui::BeginTable("##OSTable", 1, ImGuiTableFlags_RowBg)) {
|
||||||
|
ImGui::TableSetupColumn("##Column", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
|
||||||
|
drawNode(_tree->getOSRootNode());
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginTabItem("Architect")) {
|
||||||
|
if(ImGui::BeginTable("##ArchTable", 1, ImGuiTableFlags_RowBg)) {
|
||||||
|
ImGui::TableSetupColumn("##Column", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
|
||||||
|
drawNode(_tree->getArchRootNode());
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabBar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveTool::drawNode(Node& node) {
|
||||||
|
auto nodeTooltip = [this, &node]{
|
||||||
|
if(ImGui::IsItemHovered()) {
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("Tier %u", node.tier());
|
||||||
|
|
||||||
|
if(node.type() == Node::Type::Engine ||
|
||||||
|
node.type() == Node::Type::OS ||
|
||||||
|
node.type() == Node::Type::Architect)
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
switch(node.type()) {
|
||||||
|
case Node::Type::Engine:
|
||||||
|
ImGui::Text("%u gear slots", node.slots());
|
||||||
|
break;
|
||||||
|
case Node::Type::OS:
|
||||||
|
ImGui::Text("%u module slots", node.slots());
|
||||||
|
break;
|
||||||
|
case Node::Type::Architect:
|
||||||
|
ImGui::Text("%u tech slots", node.slots());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
|
||||||
|
ImGui::TextUnformatted(node.description());
|
||||||
|
if(std::strncmp("", node.activeEffect(), 3) != 0) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Active effect: %s", node.activeEffect());
|
||||||
|
}
|
||||||
|
if(std::strncmp("", node.passiveEffect(), 3) != 0) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Passive effect: %s", node.passiveEffect());
|
||||||
|
}
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
bool has_children = (node.children().size() > 0);
|
||||||
|
if(node.state() == Node::State::Unavailable) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
|
||||||
|
}
|
||||||
|
if(has_children) {
|
||||||
|
bool open = ImGui::TreeNodeEx(node.name(), ImGuiTreeNodeFlags_SpanAvailWidth|(node.state() == Node::State::Unlocked ? ImGuiTreeNodeFlags_Selected : 0));
|
||||||
|
if(node.state() == Node::State::Unavailable) {
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
nodeTooltip();
|
||||||
|
if(open) {
|
||||||
|
for(Node* child : node.children()) {
|
||||||
|
drawNode(*child);
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImGui::TreeNodeEx(node.name(), ImGuiTreeNodeFlags_SpanAvailWidth|ImGuiTreeNodeFlags_Leaf|ImGuiTreeNodeFlags_NoTreePushOnOpen|
|
||||||
|
ImGuiTreeNodeFlags_Bullet|(node.state() == Node::State::Unlocked ? ImGuiTreeNodeFlags_Selected : 0));
|
||||||
|
if(node.state() == Node::State::Unavailable) {
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
nodeTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SaveTool::drawMassManager() {
|
void SaveTool::drawMassManager() {
|
||||||
if(!_massManager) {
|
if(!_massManager) {
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue