1 ////////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2017 by Bertram (Valyria Tear)
3 //                         All Rights Reserved
4 //
5 // This code is licensed under the GNU GPL version 2. It is free software
6 // and you may modify it and/or redistribute it under the terms of this license.
7 // See http://www.gnu.org/copyleft/gpl.html for details.
8 ////////////////////////////////////////////////////////////////////////////////
9 
10 #include "skill_graph.h"
11 
12 namespace vt_global {
13 
Initialize(const std::string & skill_graph_file)14 bool SkillGraph::Initialize(const std::string& skill_graph_file)
15 {
16     vt_script::ReadScriptDescriptor script;
17     if (!script.OpenFile(skill_graph_file)) {
18         PRINT_WARNING << "Couldn't open file: " << skill_graph_file << std::endl;
19         return false;
20     }
21 
22     // Load skill tree data
23     std::vector<uint32_t> nodes_ids;
24     script.ReadTableKeys("skill_graph", nodes_ids);
25     if (nodes_ids.empty()) {
26         PRINT_WARNING << "Empty 'skill_graph' table in " << skill_graph_file << std::endl;
27         return false;
28     }
29 
30     if (!script.OpenTable("skill_graph")) {
31         PRINT_WARNING << "Couldn't open table 'skill_graph' in " << skill_graph_file << std::endl;
32         return false;
33     }
34 
35     _skill_graph_data.clear();
36 
37     // Read each node data
38     for (uint32_t node_id : nodes_ids) {
39         if (!script.OpenTable(node_id)) {
40             PRINT_WARNING << "Couldn't open table '" << node_id
41                           << "' in " << skill_graph_file << std::endl;
42             return false;
43         }
44 
45         // Read base data
46         float x_location = script.ReadFloat("x_location");
47         float y_location = script.ReadFloat("y_location");
48         std::string icon_file = script.ReadString("icon_file");
49         uint32_t experience_points_needed = script.ReadUInt("experience_points_needed");
50         int32_t skill_id_learned = script.ReadInt("skill_id_learned", -1);
51 
52         SkillNode* skill_node = new SkillNode(node_id,
53                                               x_location,
54                                               y_location,
55                                               icon_file,
56                                               experience_points_needed,
57                                               skill_id_learned);
58 
59         // Read potential other data
60         _ReadItemsNeeded(script, skill_node);
61         _ReadStatsUpgrades(script, skill_node);
62         _ReadChildrenNodeLinks(script, skill_node);
63 
64         // Add the node to the graph
65         _skill_graph_data.emplace_back(skill_node);
66 
67         script.CloseTable(); // node_id
68     }
69 
70     script.CloseTable(); // skill_graph
71 
72     // Costy
73     _ComputeNodeParentLinks();
74 
75     return true;
76 }
77 
GetSkillNode(uint32_t skill_node_id)78 SkillNode* SkillGraph::GetSkillNode(uint32_t skill_node_id)
79 {
80     for (SkillNode* skill_node : _skill_graph_data) {
81         if (skill_node->GetId() == skill_node_id)
82             return skill_node;
83     }
84     return nullptr;
85 }
86 
_ReadItemsNeeded(vt_script::ReadScriptDescriptor & script,SkillNode * skill_node)87 void SkillGraph::_ReadItemsNeeded(vt_script::ReadScriptDescriptor& script,
88                                  SkillNode* skill_node)
89 {
90     std::vector<uint32_t> item_ids;
91     script.ReadTableKeys("items_needed", item_ids);
92 
93     // No needed items can happen
94     if (item_ids.empty() || !script.OpenTable("items_needed"))
95         return;
96 
97     for (uint32_t item_id : item_ids) {
98         uint32_t item_number = script.ReadUInt(item_id);
99         skill_node->AddNeededItem(item_id, item_number);
100     }
101 
102     script.CloseTable(); // items_needed
103 }
104 
_ReadStatsUpgrades(vt_script::ReadScriptDescriptor & script,SkillNode * skill_node)105 void SkillGraph::_ReadStatsUpgrades(vt_script::ReadScriptDescriptor& script,
106                                    SkillNode* skill_node)
107 {
108     std::vector<uint32_t> stat_ids;
109     script.ReadTableKeys("stats", stat_ids);
110 
111     // No stats upgrades can happen
112     if (stat_ids.empty() || !script.OpenTable("stats"))
113         return;
114 
115     for (uint32_t stat_id: stat_ids) {
116         uint32_t upgrade = script.ReadUInt(stat_id);
117         skill_node->AddStatUpgrade(stat_id, upgrade);
118     }
119 
120     script.CloseTable(); // stat
121 }
122 
_ReadChildrenNodeLinks(vt_script::ReadScriptDescriptor & script,SkillNode * skill_node)123 void SkillGraph::_ReadChildrenNodeLinks(vt_script::ReadScriptDescriptor& script,
124                                         SkillNode* skill_node)
125 {
126     std::vector<uint32_t> node_ids;
127     script.ReadUIntVector("links", node_ids);
128 
129     // No node ids can happen for end of tree.
130     if (node_ids.empty() || !script.OpenTable("links"))
131         return;
132 
133     for (uint32_t node_id: node_ids) {
134         skill_node->AddChildNodeLink(node_id);
135     }
136 
137     script.CloseTable(); // links
138 }
139 
_ComputeNodeParentLinks()140 void SkillGraph::_ComputeNodeParentLinks()
141 {
142     for (SkillNode* current_node : _skill_graph_data) {
143         // If parent nodes were already added, skip it.
144         if (!current_node->GetParentNodeLinks().empty())
145             continue;
146         // Reparse every node and add the nodes as parent
147         // when they are listing the current one as a child.
148         for (SkillNode* parent_node : _skill_graph_data) {
149             // Don't check self
150             if (current_node == parent_node)
151                 continue;
152 
153             auto children_node_links = parent_node->GetChildrenNodeLinks();
154             for (uint32_t child_link : children_node_links) {
155                 if (current_node->GetId() == child_link)
156                     current_node->AddParentNodeLink(parent_node->GetId());
157             }
158         }
159     }
160 }
161 
162 } // namespace vt_global
163