// 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 . #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 { 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", ""}); _engineNodes.at(VerseEngine).addChild(_engineNodes.at(MetalPlatings1)); _engineNodes.at(VerseEngine).addChild(_engineNodes.at(HeatTurbines1)); _engineNodes.at(VerseEngine).addChild(_engineNodes.at(LoadedEngine)); _engineNodes.at(LoadedEngine).addChild(_engineNodes.at(Microcontroller1)); _engineNodes.at(LoadedEngine).addChild(_engineNodes.at(CombustionController1)); _engineNodes.at(MetalPlatings1).addChild(_engineNodes.at(ModAlloyEngine)); _engineNodes.at(HeatTurbines1).addChild(_engineNodes.at(ChargedEngine)); _engineNodes.at(Microcontroller1).addChild(_engineNodes.at(ChargedEngine)); _engineNodes.at(CombustionController1).addChild(_engineNodes.at(ReinforcedLoadedEngine)); _engineNodes.at(ModAlloyEngine).addChild(_engineNodes.at(MetalPlatings2)); _engineNodes.at(ModAlloyEngine).addChild(_engineNodes.at(HeatTurbines2)); _engineNodes.at(ChargedEngine).addChild(_engineNodes.at(HeatTurbines2)); _engineNodes.at(ChargedEngine).addChild(_engineNodes.at(Microcontroller2)); _engineNodes.at(ChargedEngine).addChild(_engineNodes.at(WeaponsCargo1)); _engineNodes.at(ReinforcedLoadedEngine).addChild(_engineNodes.at(CombustionController2)); _engineNodes.at(ReinforcedLoadedEngine).addChild(_engineNodes.at(PoweredRewiring1)); _engineNodes.at(ReinforcedLoadedEngine).addChild(_engineNodes.at(HeavyImpactsEnabler)); _engineNodes.at(MetalPlatings2).addChild(_engineNodes.at(ModSteelEngine)); _engineNodes.at(HeatTurbines2).addChild(_engineNodes.at(SuperchargedEngine)); _engineNodes.at(Microcontroller2).addChild(_engineNodes.at(SuperchargedEngine)); _engineNodes.at(WeaponsCargo1).addChild(_engineNodes.at(SuperchargedEngine)); _engineNodes.at(CombustionController2).addChild(_engineNodes.at(NecriumAlloyEngine)); _engineNodes.at(PoweredRewiring1).addChild(_engineNodes.at(NecriumAlloyEngine)); _engineNodes.at(ModSteelEngine).addChild(_engineNodes.at(MetalPlatings3)); _engineNodes.at(ModSteelEngine).addChild(_engineNodes.at(HeatTurbines3)); _engineNodes.at(SuperchargedEngine).addChild(_engineNodes.at(HeatTurbines3)); _engineNodes.at(SuperchargedEngine).addChild(_engineNodes.at(Microcontroller3)); _engineNodes.at(SuperchargedEngine).addChild(_engineNodes.at(WeaponsCargo2)); _engineNodes.at(NecriumAlloyEngine).addChild(_engineNodes.at(WeaponsCargo2)); _engineNodes.at(NecriumAlloyEngine).addChild(_engineNodes.at(CombustionController3)); _engineNodes.at(NecriumAlloyEngine).addChild(_engineNodes.at(PoweredRewiring2)); _engineNodes.at(MetalPlatings3).addChild(_engineNodes.at(ModLunariteEngine)); _engineNodes.at(HeatTurbines3).addChild(_engineNodes.at(ChargedLunariteEngine)); _engineNodes.at(Microcontroller3).addChild(_engineNodes.at(ChargedLunariteEngine)); _engineNodes.at(WeaponsCargo2).addChild(_engineNodes.at(ChargedLunariteEngine)); _engineNodes.at(CombustionController3).addChild(_engineNodes.at(LunariteEngine)); _engineNodes.at(PoweredRewiring2).addChild(_engineNodes.at(LunariteEngine)); _engineNodes.at(ModLunariteEngine).addChild(_engineNodes.at(InfusedEngine)); _engineNodes.at(ModLunariteEngine).addChild(_engineNodes.at(MetalPlatings4)); _engineNodes.at(ChargedLunariteEngine).addChild(_engineNodes.at(HeatTurbines4)); _engineNodes.at(ChargedLunariteEngine).addChild(_engineNodes.at(Microcontroller4)); _engineNodes.at(ChargedLunariteEngine).addChild(_engineNodes.at(WeaponsCargo3)); _engineNodes.at(LunariteEngine).addChild(_engineNodes.at(CombustionController4)); _engineNodes.at(LunariteEngine).addChild(_engineNodes.at(PoweredRewiring3)); _engineNodes.at(InfusedEngine).addChild(_engineNodes.at(ArmouredCargo1)); _engineNodes.at(InfusedEngine).addChild(_engineNodes.at(ArmouredFuelTank1)); _engineNodes.at(MetalPlatings4).addChild(_engineNodes.at(ArmouredCargo1)); _engineNodes.at(MetalPlatings4).addChild(_engineNodes.at(ArmouredFuelTank1)); _engineNodes.at(HeatTurbines4).addChild(_engineNodes.at(ExtraCapacity1)); _engineNodes.at(Microcontroller4).addChild(_engineNodes.at(ExtraCapacity1)); _engineNodes.at(WeaponsCargo3).addChild(_engineNodes.at(ExtraCapacity1)); _engineNodes.at(CombustionController4).addChild(_engineNodes.at(HighmetalEngine)); _engineNodes.at(CombustionController4).addChild(_engineNodes.at(PowerRedirector1)); _engineNodes.at(PoweredRewiring3).addChild(_engineNodes.at(HighmetalEngine)); _engineNodes.at(PoweredRewiring3).addChild(_engineNodes.at(PowerRedirector1)); _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", ""}); _osNodes.at(NeuralOS).addChild(_osNodes.at(Shields1)); _osNodes.at(NeuralOS).addChild(_osNodes.at(Enhancements1)); _osNodes.at(NeuralOS).addChild(_osNodes.at(ExoSkelOS)); _osNodes.at(ExoSkelOS).addChild(_osNodes.at(FuelSave1)); _osNodes.at(ExoSkelOS).addChild(_osNodes.at(LongRange1)); _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", ""}); _archNodes.at(StandardFrame).setState(Node::State::Unlocked); } void ResearchTree::readEngineUnlocks(Containers::ArrayView engines, Containers::ArrayView 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 os, Containers::ArrayView 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 archs, Containers::ArrayView 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); }