1 #include <iostream>
2
3 #include "util/helpers.h"
4 #include "api/evetime.h"
5
6 #include "character.h"
7
Character(EveApiAuth const & auth)8 Character::Character (EveApiAuth const& auth)
9 {
10 this->auth = auth;
11
12 this->cs_fetcher.set_auth(auth);
13 this->sq_fetcher.set_auth(auth);
14
15 this->cs_fetcher.set_doctype(API_DOCTYPE_CHARSHEET);
16 this->sq_fetcher.set_doctype(API_DOCTYPE_SKILLQUEUE);
17
18 this->cs = ApiCharSheet::create();
19 this->sq = ApiSkillQueue::create();
20
21 this->cs_fetcher.signal_done().connect(sigc::mem_fun
22 (*this, &Character::on_cs_available));
23 this->sq_fetcher.signal_done().connect(sigc::mem_fun
24 (*this, &Character::on_sq_available));
25
26 this->process_api_data();
27 }
28
29 /* ---------------------------------------------------------------- */
30
~Character(void)31 Character::~Character (void)
32 {
33 //std::cout << "Removing character" << std::endl;
34 }
35
36 /* ---------------------------------------------------------------- */
37
38 void
on_cs_available(EveApiData data)39 Character::on_cs_available (EveApiData data)
40 {
41 if (data.data.get() == 0)
42 {
43 this->sig_request_error.emit(API_DOCTYPE_CHARSHEET, data.exception);
44 return;
45 }
46
47 bool yet_unnamed = this->cs->name.empty();
48
49 try
50 {
51 this->cs->set_api_data(data);
52 if (data.locally_cached)
53 this->sig_cached_warning.emit(API_DOCTYPE_CHARSHEET, data.exception);
54 }
55 catch (Exception& e)
56 {
57 this->sig_request_error.emit(API_DOCTYPE_CHARSHEET, e);
58 return;
59 }
60
61 if (yet_unnamed && !this->cs->name.empty())
62 this->sig_name_available.emit(this->auth.char_id);
63
64 this->process_api_data();
65 this->sig_char_sheet_updated.emit();
66 this->sig_api_info_changed.emit();
67 }
68
69 /* ---------------------------------------------------------------- */
70
71 void
on_sq_available(EveApiData data)72 Character::on_sq_available (EveApiData data)
73 {
74 if (data.data.get() == 0)
75 {
76 this->sig_request_error.emit(API_DOCTYPE_SKILLQUEUE, data.exception);
77 return;
78 }
79
80 try
81 {
82 this->sq->set_api_data(data);
83 if (data.locally_cached)
84 this->sig_cached_warning.emit(API_DOCTYPE_SKILLQUEUE, data.exception);
85 }
86 catch (Exception& e)
87 {
88 this->sig_request_error.emit(API_DOCTYPE_SKILLQUEUE, e);
89 return;
90 }
91
92 this->process_api_data();
93 this->sig_skill_queue_updated.emit();
94 this->sig_api_info_changed.emit();
95 }
96
97 /* ---------------------------------------------------------------- */
98
99 void
process_api_data(void)100 Character::process_api_data (void)
101 {
102 this->training_skill = 0;
103 this->training_spph = 0;
104 this->training_level_sp = 0;
105 this->training_skill_sp = 0;
106 this->training_level_done = 0.0;
107 this->training_remaining = 0;
108 this->training_info.queue_pos = -1;
109
110 this->char_base_sp = 0;
111 this->char_live_sp = 0;
112 this->char_group_base_sp = 0;
113
114 /* Update information related to the character sheet. */
115 if (this->cs->valid)
116 {
117 this->char_base_sp = this->cs->total_sp;
118 this->char_live_sp = this->cs->total_sp;
119 }
120
121 /* Update information related to the skill queue. */
122 if (this->is_training())
123 {
124 ApiSkillTreePtr tree = ApiSkillTree::request();
125 this->training_info = *this->sq->get_training_skill();
126 this->training_skill = tree->get_skill_for_id(this->training_info.skill_id);
127 this->training_spph = this->sq->get_spph_for_current();
128
129 if (this->training_skill == 0)
130 {
131 std::cout << "Warning: Skill in training (ID "
132 << this->training_info.skill_id << ") not found. "
133 << "Skill tree out of date?" << std::endl;
134 }
135 }
136
137 /* Update information related to both sheets. */
138 if (this->cs->valid && this->sq->valid)
139 {
140 this->training_cskill = 0;
141 if (this->is_training())
142 {
143 /* Get the character skill in training. */
144 this->training_cskill = this->cs->get_skill_for_id
145 (this->training_info.skill_id);
146
147 if (this->training_cskill != 0)
148 {
149 /* Cache the amount of SP in the active skill group. */
150 int group_id = this->training_cskill->details->group;
151 for (std::size_t i = 0; i < this->cs->skills.size(); ++i)
152 {
153 ApiCharSheetSkill& cskill = this->cs->skills[i];
154 if (cskill.details->group == group_id)
155 this->char_group_base_sp += cskill.points;
156 }
157 }
158 else
159 {
160 std::cout << "Warning: Skill in training (ID "
161 << this->training_info.skill_id
162 << ") is unknown to " << this->cs->name
163 << "!" << std::endl;
164 }
165 }
166
167 /* Update the character from skill queue information. */
168 this->update_from_queue();
169 }
170
171 /* Update the live info. */
172 this->update_live_info();
173 }
174
175 /* ---------------------------------------------------------------- */
176
177 void
update_live_info(void)178 Character::update_live_info (void)
179 {
180 if (this->training_info.queue_pos < 0)
181 return;
182
183 time_t evetime = EveTime::get_eve_time();
184 time_t finish = this->training_info.end_time_t;
185 time_t diff = finish - evetime;
186
187 //std::cout << "** Evetime: " << evetime << ", Finish: " << finish
188 // << ", time diff: " << diff << std::endl;
189
190 /* Check if the skill is finished. */
191 if (diff < 0)
192 {
193 this->training_info.queue_pos = -1;
194 this->skill_completed();
195 return;
196 }
197
198 /* Update easy values first to get useful results even in case of errors. */
199 unsigned int level_dest_sp = this->training_info.end_sp;
200 double spps = (double)this->training_spph / 3600.0;
201
202 this->training_remaining = diff;
203 this->training_skill_sp = level_dest_sp - (unsigned int)((double)diff * spps);
204
205 /* Check if the skill in training could be determined.
206 * This may be NULL if the skill was not available in the skill tree. */
207 if (this->training_skill == 0)
208 return;
209
210 /* Update training live values. */
211 unsigned int level_start_sp = ApiCharSheet::calc_start_sp
212 (this->training_info.to_level - 1, this->training_skill->rank);
213 unsigned int level_total_sp = level_dest_sp - level_start_sp;
214
215 this->training_level_sp = this->training_skill_sp - level_start_sp;
216 this->training_level_done = (double)this->training_level_sp
217 / (double)level_total_sp;
218
219 //std::cout << "** Start SP: " << level_start_sp << ", Dest SP: "
220 // << level_dest_sp << ", Level SP: " << level_total_sp << ", SP/s: "
221 // << spps << std::endl;
222
223 /* Check if the skill in training is available in the character.
224 * This may be NULL if the skill was not available in the skill tree. */
225 if (!this->cs->valid || this->training_cskill == 0)
226 return;
227
228 /* Update character live values. */
229 unsigned int basediff_sp = this->training_skill_sp
230 - this->training_cskill->points;
231 this->char_live_sp = this->char_base_sp + basediff_sp;
232 this->char_group_live_sp = this->char_group_base_sp + basediff_sp;
233 }
234
235 /* ---------------------------------------------------------------- */
236
237 void
update_from_queue(void)238 Character::update_from_queue (void)
239 {
240 if (!this->sq->valid || !this->cs->valid)
241 return;
242
243 /* Walk through the skill queue and update the character with already
244 * finished skills and the previous level of the skill in training.
245 */
246 time_t eve_time = EveTime::get_eve_time();
247 for (std::size_t i = 0; i < this->sq->queue.size(); ++i)
248 {
249 ApiSkillQueueItem const& item(this->sq->queue[i]);
250 if (item.start_time_t > eve_time)
251 break;
252 if (item.end_time_t < eve_time)
253 this->cs->add_char_skill(item.skill_id, item.to_level);
254 else
255 this->cs->add_char_skill(item.skill_id, item.to_level - 1);
256 }
257 this->char_base_sp = this->cs->total_sp;
258 }
259
260 /* ---------------------------------------------------------------- */
261
262 void
skill_completed(void)263 Character::skill_completed (void)
264 {
265 /* Update the character by registering completed skills. */
266 this->update_from_queue();
267
268 /* Emit the completed signal to notify listeners. */
269 this->sig_skill_completed.emit();
270
271 /* Clear old skill info and reprocess API data to update. */
272 this->training_cskill = 0;
273 this->training_skill = 0;
274 this->process_api_data();
275
276 /* Emit signal to notify about changed skill in training. */
277 this->sig_training_changed.emit();
278 }
279
280 /* ---------------------------------------------------------------- */
281
282 std::string
get_char_name(void) const283 Character::get_char_name (void) const
284 {
285 if (this->cs->valid)
286 return this->cs->name;
287 else
288 return this->auth.char_id;
289 }
290
291 /* ---------------------------------------------------------------- */
292
293 std::string
get_training_text(void) const294 Character::get_training_text (void) const
295 {
296 if (this->is_training())
297 {
298 int skill_id = this->training_info.skill_id;
299 int to_level = this->training_info.to_level;
300
301 std::string to_level_str = Helpers::get_roman_from_int(to_level);
302 std::string skill_str;
303 try
304 {
305 ApiSkillTreePtr tree = ApiSkillTree::request();
306 ApiSkill const* skill = tree->get_skill_for_id(skill_id);
307 if (skill == 0)
308 throw Exception();
309 skill_str = skill->name;
310 }
311 catch (Exception& e)
312 {
313 /* This happens if the ID is not found. */
314 skill_str = Helpers::get_string_from_int(skill_id);
315 }
316
317 return skill_str + " " + to_level_str;
318 }
319 else
320 {
321 return "No skill in training!";
322 }
323 }
324
325 /* ---------------------------------------------------------------- */
326
327 std::string
get_remaining_text(bool slim) const328 Character::get_remaining_text (bool slim) const
329 {
330 if (!this->sq->valid)
331 return "No training information!";
332
333 if (this->sq->is_paused())
334 return "Training is paused!";
335
336 if (!this->is_training())
337 return "No skill in training!";
338
339 return EveTime::get_string_for_timediff(this->training_remaining, slim);
340 }
341
342 /* ---------------------------------------------------------------- */
343
344 std::string
get_summary_text(bool detailed)345 Character::get_summary_text (bool detailed)
346 {
347 std::string ret;
348 ret += this->get_char_name();
349 ret += " - ";
350
351 if (this->is_training())
352 {
353 ret += this->get_remaining_text(true);
354 if (detailed)
355 {
356 ret += " - ";
357 ret += this->get_training_text();
358 }
359 }
360 else
361 ret += "Not training!";
362
363 return ret;
364 }
365