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