1 // This file is part of GtkEveMon.
2 //
3 // GtkEveMon is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // You should have received a copy of the GNU General Public License
9 // along with GtkEveMon. If not, see <http://www.gnu.org/licenses/>.
10
11 #include <iostream>
12
13 #include <gtkmm.h>
14
15 #include "util/helpers.h"
16 #include "bits/config.h"
17 #include "imagestore.h"
18 #include "gtkhelpers.h"
19 #include "gtkdefines.h"
20 #include "gtkitembrowser.h"
21
ItemBrowserBase(void)22 ItemBrowserBase::ItemBrowserBase (void)
23 : store(Gtk::TreeStore::create(cols)),
24 view(store)
25 {
26 Gtk::TreeViewColumn* col_name = Gtk::manage(new Gtk::TreeViewColumn);
27 col_name->set_title("Name");
28 col_name->pack_start(this->cols.icon, false);
29 #ifdef GLIBMM_PROPERTIES_ENABLED
30 Gtk::CellRendererText* name_renderer = Gtk::manage(new Gtk::CellRendererText);
31 col_name->pack_start(*name_renderer, true);
32 col_name->add_attribute(name_renderer->property_markup(),
33 this->cols.name);
34 #else
35 /* FIXME: Activate markup here. */
36 col_name->pack_start(this->cols.name);
37 #endif
38 this->view.append_column(*col_name);
39 this->view.set_headers_visible(false);
40 this->view.get_selection()->set_mode(Gtk::SELECTION_SINGLE);
41
42 this->view.get_selection()->signal_changed().connect
43 (sigc::mem_fun(*this, &ItemBrowserBase::on_selection_changed));
44 this->view.signal_row_activated().connect(sigc::mem_fun
45 (*this, &ItemBrowserBase::on_row_activated));
46 this->view.signal_button_press_myevent().connect(sigc::mem_fun
47 (*this, &ItemBrowserBase::on_view_button_pressed));
48 this->view.signal_query_tooltip().connect(sigc::mem_fun
49 (*this, &ItemBrowserBase::on_query_element_tooltip));
50 this->view.set_has_tooltip(true);
51 }
52
53 /* ---------------------------------------------------------------- */
54
55 void
on_selection_changed(void)56 ItemBrowserBase::on_selection_changed (void)
57 {
58 if (this->view.get_selection()->get_selected_rows().empty())
59 return;
60
61 Gtk::TreeModel::iterator iter = this->view.get_selection()->get_selected();
62
63 ApiElement const* elem = (*iter)[this->cols.data];
64 if (elem == 0)
65 return;
66
67 this->sig_element_selected.emit(elem);
68 }
69
70 /* ---------------------------------------------------------------- */
71
72 void
on_row_activated(Gtk::TreeModel::Path const & path,Gtk::TreeViewColumn *)73 ItemBrowserBase::on_row_activated (Gtk::TreeModel::Path const& path,
74 Gtk::TreeViewColumn* /*col*/)
75 {
76 Gtk::TreeModel::iterator iter = this->store->get_iter(path);
77 ApiElement const* elem = (*iter)[this->cols.data];
78
79 if (elem != 0)
80 {
81 this->sig_element_activated.emit(elem);
82 }
83 else
84 {
85 if (this->view.row_expanded(path))
86 this->view.collapse_row(path);
87 else
88 this->view.expand_row(path, true);
89 }
90 }
91
92 /* ---------------------------------------------------------------- */
93
94 void
on_view_button_pressed(GdkEventButton * event)95 ItemBrowserBase::on_view_button_pressed (GdkEventButton* event)
96 {
97 if (event->type != GDK_BUTTON_PRESS || event->button != 3)
98 return;
99
100 Glib::RefPtr<Gtk::TreeView::Selection> selection
101 = this->view.get_selection();
102
103 if (selection->count_selected_rows() != 1)
104 return;
105
106 Gtk::TreeModel::iterator iter = selection->get_selected();
107 ApiElement const* elem = (*iter)[this->cols.data];
108 if (elem == 0)
109 return;
110
111 /* Skills and certs have context menus. */
112 switch (elem->get_type())
113 {
114 case API_ELEM_SKILL:
115 {
116 ApiSkill const* skill = (ApiSkill const*)elem;
117
118 GtkSkillContextMenu* menu = Gtk::manage(new GtkSkillContextMenu);
119 menu->set_skill(skill, this->charsheet->get_level_for_skill(skill->id));
120 menu->popup(event->button, event->time);
121 menu->signal_planning_requested().connect(sigc::mem_fun
122 (*this, &ItemBrowserBase::on_planning_requested));
123 break;
124 }
125
126 case API_ELEM_CERT:
127 {
128 ApiCert const* cert = (ApiCert const*)elem;
129 GtkCertContextMenu* menu = Gtk::manage(new GtkCertContextMenu);
130 menu->set_cert(cert);
131 menu->popup(event->button, event->time);
132 menu->signal_planning_requested().connect(sigc::mem_fun
133 (*this, &ItemBrowserBase::on_planning_requested));
134 break;
135 }
136
137 default:
138 break;
139 }
140
141 return;
142 }
143
144 /* ---------------------------------------------------------------- */
145
146 bool
on_query_element_tooltip(int x,int y,bool,Glib::RefPtr<Gtk::Tooltip> const & tooltip)147 ItemBrowserBase::on_query_element_tooltip (int x, int y,
148 bool /* key */, Glib::RefPtr<Gtk::Tooltip> const& tooltip)
149 {
150 return GtkHelpers::create_tooltip_from_view(x, y, tooltip,
151 this->view, this->store, this->cols.data);
152 }
153
154 /* ================================================================ */
155
156 enum ComboBoxSkillFilter
157 {
158 CB_FILTER_SKILL_ALL,
159 CB_FILTER_SKILL_UNKNOWN,
160 CB_FILTER_SKILL_PARTIAL,
161 CB_FILTER_SKILL_ENABLED,
162 CB_FILTER_SKILL_KNOWN,
163 CB_FILTER_SKILL_KNOWN_BUT_V
164 };
165
166 enum ComboBoxSkillFilterAttribute
167 {
168 CB_FILTER_ATTRIBUTE_ANY,
169 CB_FILTER_ATTRIBUTE_INTELLIGENCE,
170 CB_FILTER_ATTRIBUTE_MEMORY,
171 CB_FILTER_ATTRIBUTE_CHARISMA,
172 CB_FILTER_ATTRIBUTE_PERCEPTION,
173 CB_FILTER_ATTRIBUTE_WILLPOWER
174 };
175
GtkSkillBrowser(void)176 GtkSkillBrowser::GtkSkillBrowser (void)
177 : Gtk::Box(Gtk::ORIENTATION_VERTICAL, 5)
178 {
179 this->store->set_sort_column(this->cols.name, Gtk::SORT_ASCENDING);
180
181 this->filter_cb.append("Show all skills");
182 this->filter_cb.append("Only show unknown skills");
183 this->filter_cb.append("Only show partial skills");
184 this->filter_cb.append("Only show enabled skills");
185 this->filter_cb.append("Only show known skills");
186 this->filter_cb.append("Only show known skills not at V");
187 this->filter_cb.set_active(0);
188
189 this->primary_cb.append("Any");
190 this->primary_cb.append("Intelligence");
191 this->primary_cb.append("Memory");
192 this->primary_cb.append("Charisma");
193 this->primary_cb.append("Perception");
194 this->primary_cb.append("Willpower");
195 this->primary_cb.set_active(0);
196
197 this->secondary_cb.append("Any");
198 this->secondary_cb.append("Intelligence");
199 this->secondary_cb.append("Memory");
200 this->secondary_cb.append("Charisma");
201 this->secondary_cb.append("Perception");
202 this->secondary_cb.append("Willpower");
203 this->secondary_cb.set_active(0);
204
205 Gtk::ScrolledWindow* scwin = MK_SCWIN;
206 scwin->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
207 scwin->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
208 scwin->add(this->view);
209
210 Gtk::Button* clear_filter_but = MK_BUT0;
211 clear_filter_but->set_image_from_icon_name("edit-clear", Gtk::ICON_SIZE_MENU);
212 clear_filter_but->set_relief(Gtk::RELIEF_NONE);
213 clear_filter_but->set_tooltip_text("Clear filter");
214
215 Gtk::Box* filter_box = MK_HBOX(5);
216 filter_box->pack_start(*MK_LABEL("Filter:"), false, false, 0);
217 filter_box->pack_start(this->filter_entry, true, true, 0);
218 filter_box->pack_start(*clear_filter_but, false, false, 0);
219
220 Gtk::Box* attributes_box = MK_HBOX(5);
221 Gtk::Box* attributes_label_box = MK_HBOX(5);
222 attributes_label_box->pack_start(*MK_LABEL("Primary Attribute"), true, true, 0);
223 attributes_label_box->pack_start(*MK_LABEL("Secondary Attribute"), true, true, 0);
224 attributes_box->pack_start(this->primary_cb, true, true, 0);
225 attributes_box->pack_start(this->secondary_cb, true, true, 0);
226
227 this->pack_start(*filter_box, false, false, 0);
228 this->pack_start(this->filter_cb, false, false, 0);
229 this->pack_start(*attributes_label_box, false, false, 0);
230 this->pack_start(*attributes_box, false, false, 0);
231 this->pack_start(*scwin, true, true, 0);
232
233 this->filter_entry.signal_activate().connect(sigc::mem_fun
234 (*this, &GtkSkillBrowser::fill_store));
235 this->filter_cb.signal_changed().connect(sigc::mem_fun
236 (*this, &GtkSkillBrowser::fill_store));
237 this->primary_cb.signal_changed().connect(sigc::mem_fun
238 (*this, &GtkSkillBrowser::fill_store));
239 this->secondary_cb.signal_changed().connect(sigc::mem_fun
240 (*this, &GtkSkillBrowser::fill_store));
241 clear_filter_but->signal_clicked().connect(sigc::mem_fun
242 (*this, &GtkSkillBrowser::clear_filter));
243 }
244
245 /* ---------------------------------------------------------------- */
246
247 void
fill_store(void)248 GtkSkillBrowser::fill_store (void)
249 {
250 this->store->clear();
251 Glib::ustring filter = this->filter_entry.get_text();
252
253 ApiSkillTreePtr tree = ApiSkillTree::request();
254 ApiSkillMap& skills = tree->skills;
255 ApiSkillGroupMap& groups = tree->groups;
256
257 typedef Gtk::TreeModel::iterator GtkTreeModelIter;
258 typedef std::map<int, std::pair<GtkTreeModelIter, int> > SkillGroupsMap;
259 SkillGroupsMap skill_group_iters;
260
261 /* Append all skill groups to the store. */
262 for (ApiSkillGroupMap::iterator iter = groups.begin();
263 iter != groups.end(); iter++)
264 {
265 Gtk::TreeModel::iterator siter = this->store->append();
266 (*siter)[this->cols.name] = iter->second.name;
267 (*siter)[this->cols.icon] = ImageStore::skillicons[0];
268 (*siter)[this->cols.data] = 0;
269 skill_group_iters.insert(std::make_pair
270 (iter->first, std::make_pair(siter, 0)));
271 }
272
273 /* Prepare some short hands .*/
274 int active_row_num = this->filter_cb.get_active_row_number();
275 int primary_active_row_num = this->primary_cb.get_active_row_number();
276 int secondary_active_row_num = this->secondary_cb.get_active_row_number();
277 bool only_unknown = (active_row_num == CB_FILTER_SKILL_UNKNOWN);
278 bool only_partial = (active_row_num == CB_FILTER_SKILL_PARTIAL);
279 bool only_enabled = (active_row_num == CB_FILTER_SKILL_ENABLED);
280 bool only_known = (active_row_num == CB_FILTER_SKILL_KNOWN) || (active_row_num == CB_FILTER_SKILL_KNOWN_BUT_V);
281 bool only_known_but_v = (active_row_num == CB_FILTER_SKILL_KNOWN_BUT_V);
282 ApiAttrib primary = primary_active_row_num == CB_FILTER_ATTRIBUTE_ANY ? API_ATTRIB_UNKNOWN : (ApiAttrib)(primary_active_row_num-CB_FILTER_ATTRIBUTE_INTELLIGENCE);
283 ApiAttrib secondary = secondary_active_row_num == CB_FILTER_ATTRIBUTE_ANY ? API_ATTRIB_UNKNOWN : (ApiAttrib)(secondary_active_row_num-CB_FILTER_ATTRIBUTE_INTELLIGENCE);
284 std::string unpublished_cfg("planner.show_unpublished_skills");
285 bool only_published = !Config::conf.get_value(unpublished_cfg)->get_bool();
286
287 /* Append all skills to the skill groups. */
288 for (ApiSkillMap::iterator iter = skills.begin();
289 iter != skills.end(); iter++)
290 {
291 ApiSkill& skill = iter->second;
292
293 /* Filter non-public skills if so requested */
294 if (only_published && !skill.published)
295 continue;
296
297 /* Apply string filter. */
298 if (Glib::ustring(skill.name).casefold()
299 .find(filter.casefold()) == Glib::ustring::npos)
300 continue;
301
302 SkillGroupsMap::iterator giter = skill_group_iters.find(skill.group);
303 if (giter == skill_group_iters.end())
304 {
305 std::cout << "Error appending skill, unknown group!" << std::endl;
306 continue;
307 }
308
309 ApiCharSheetSkill* cskill = this->charsheet->get_skill_for_id(skill.id);
310 Glib::RefPtr<Gdk::Pixbuf> skill_icon;
311
312 if (cskill == 0)
313 {
314 if (primary!=API_ATTRIB_UNKNOWN)
315 if (skill.primary != primary)
316 continue;
317
318 if (secondary!=API_ATTRIB_UNKNOWN)
319 if (skill.secondary != secondary)
320 continue;
321
322 /* The skill is unknown. */
323 if (only_known || only_partial)
324 continue;
325
326 if (this->have_prerequisites_for_skill(&skill))
327 {
328 /* The skill is unknown but prequisites are there. */
329 skill_icon = ImageStore::skillstatus[1];
330 }
331 else
332 {
333 /* The skill is unknown and no prequisites. */
334 if (only_enabled)
335 continue;
336 skill_icon = ImageStore::skillstatus[0];
337 }
338
339 }
340 else
341 {
342 if (primary!=API_ATTRIB_UNKNOWN)
343 if (skill.primary != primary)
344 continue;
345
346 if (secondary!=API_ATTRIB_UNKNOWN)
347 if (skill.secondary != secondary)
348 continue;
349
350 /* The skill is known. */
351 if (only_unknown || only_enabled)
352 continue;
353
354 /* Check if the skill is partially trained. */
355 if (only_partial && cskill->points == cskill->points_start)
356 continue;
357
358 /* The skill is known and already trained to level v */
359 if (only_known_but_v && cskill->level == 5)
360 continue;
361
362 switch (cskill->level)
363 {
364 case 0: skill_icon = ImageStore::skillstatus[2]; break;
365 case 1: skill_icon = ImageStore::skillstatus[3]; break;
366 case 2: skill_icon = ImageStore::skillstatus[4]; break;
367 case 3: skill_icon = ImageStore::skillstatus[5]; break;
368 case 4: skill_icon = ImageStore::skillstatus[6]; break;
369 case 5: skill_icon = ImageStore::skillstatus[7]; break;
370 default: skill_icon = ImageStore::skillstatus[0]; break;
371 }
372 }
373
374 /* Finally append the skill. */
375 Gtk::TreeModel::iterator siter = this->store->append
376 (giter->second.first->children());
377 char const *primary_name = ApiSkillTree::get_attrib_short_name(skill.primary);
378 char const *secondary_name = ApiSkillTree::get_attrib_short_name(skill.secondary);
379 (*siter)[this->cols.name] = skill.name + " ("
380 + Helpers::get_string_from_int(skill.rank)
381 + ") <span size=\"small\" foreground=\"grey\">" + primary_name + "/"
382 + secondary_name + "</span>";
383 (*siter)[this->cols.data] = &skill;
384
385 (*siter)[this->cols.icon] = skill_icon;
386
387 giter->second.second += 1;
388 }
389
390 /* Remove empty groups (due to filtering). */
391 for (SkillGroupsMap::iterator iter = skill_group_iters.begin();
392 iter != skill_group_iters.end(); iter++)
393 {
394 if (iter->second.second == 0)
395 this->store->erase(iter->second.first);
396 }
397
398 if (!filter.empty() || primary != API_ATTRIB_UNKNOWN
399 || secondary != API_ATTRIB_UNKNOWN || active_row_num != 0)
400 this->view.expand_all();
401 }
402
403 /* ---------------------------------------------------------------- */
404
405 void
clear_filter(void)406 GtkSkillBrowser::clear_filter (void)
407 {
408 this->filter_entry.set_text("");
409 this->fill_store();
410 }
411
412 /* ---------------------------------------------------------------- */
413
414 bool
have_prerequisites_for_skill(ApiSkill const * skill)415 GtkSkillBrowser::have_prerequisites_for_skill (ApiSkill const* skill)
416 {
417 ApiSkillTreePtr tree = ApiSkillTree::request();
418 for (unsigned int i = 0; i < skill->deps.size(); ++i)
419 {
420 int depskill_id = skill->deps[i].first;
421 int depskill_level = skill->deps[i].second;
422
423 int charlevel = this->charsheet->get_level_for_skill(depskill_id);
424 if (charlevel < depskill_level)
425 return false;
426 }
427
428 return true;
429 }
430
431 /* ================================================================ */
432
433 enum ComboBoxCertFilter
434 {
435 CB_FILTER_CERT_ALL,
436 CB_FILTER_CERT_CLAIMED,
437 CB_FILTER_CERT_CLAIMABLE,
438 CB_FILTER_CERT_PARTIAL,
439 CB_FILTER_CERT_NOPRE
440 };
441
GtkCertBrowser(void)442 GtkCertBrowser::GtkCertBrowser (void)
443 : Gtk::Box(Gtk::ORIENTATION_VERTICAL, 5)
444 {
445 this->filter_cb.append("Show all certificates");
446 this->filter_cb.append("Only show claimed certs");
447 this->filter_cb.append("Only show claimable certs");
448 this->filter_cb.append("Only show partial certs");
449 this->filter_cb.append("Only show unknown certs");
450 this->filter_cb.set_active(0);
451
452 Gtk::ScrolledWindow* scwin = MK_SCWIN;
453 scwin->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
454 scwin->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
455 scwin->add(this->view);
456
457 Gtk::Button* clear_filter_but = MK_BUT0;
458 clear_filter_but->set_image_from_icon_name("edit-clear", Gtk::ICON_SIZE_MENU);
459 clear_filter_but->set_relief(Gtk::RELIEF_NONE);
460 clear_filter_but->set_tooltip_text("Clear filter");
461
462 Gtk::Box* filter_box = MK_HBOX(5);
463 filter_box->pack_start(*MK_LABEL("Filter:"), false, false, 0);
464 filter_box->pack_start(this->filter_entry, true, true, 0);
465 filter_box->pack_start(*clear_filter_but, false, false, 0);
466
467 this->pack_start(*filter_box, false, false, 0);
468 this->pack_start(this->filter_cb, false, false, 0);
469 this->pack_start(*scwin, true, true, 0);
470
471 this->filter_entry.signal_activate().connect(sigc::mem_fun
472 (*this, &GtkCertBrowser::fill_store));
473 this->filter_cb.signal_changed().connect(sigc::mem_fun
474 (*this, &GtkCertBrowser::fill_store));
475 clear_filter_but->signal_clicked().connect(sigc::mem_fun
476 (*this, &GtkCertBrowser::clear_filter));
477 }
478
479 /* ---------------------------------------------------------------- */
480
481 void
fill_store(void)482 GtkCertBrowser::fill_store (void)
483 {
484 this->store->clear();
485 Glib::ustring filter = this->filter_entry.get_text();
486
487 ApiCertTreePtr tree = ApiCertTree::request();
488 ApiCertMap& certs = tree->certificates;
489
490 /* Prepare some short hands .*/
491 int active_row_num = this->filter_cb.get_active_row_number();
492 bool only_claimed = (active_row_num == CB_FILTER_CERT_CLAIMED);
493 bool only_claimable = (active_row_num == CB_FILTER_CERT_CLAIMABLE);
494 bool only_partial = (active_row_num == CB_FILTER_CERT_PARTIAL);
495 bool only_unknown = (active_row_num == CB_FILTER_CERT_NOPRE);
496
497 typedef std::pair<int, ApiCert const*> CertShowInfo;
498 typedef std::map<Glib::ustring, CertShowInfo> CertClassMap;
499 typedef std::map<int, CertClassMap> CertGradeMap;
500 typedef std::map<Glib::ustring, CertGradeMap> CertCatMap;
501 CertCatMap show_mapping;
502
503 /* Iterate over all certificates, check character status and add to maps. */
504 for (ApiCertMap::iterator iter = certs.begin(); iter != certs.end(); iter++)
505 {
506 ApiCert const* cert = &iter->second;
507 ApiCertClass const* cclass = cert->class_details;
508 ApiCertCategory const* cat = cclass->cat_details;
509
510 /* Check if cert matches the filter. */
511 if (!filter.empty() && Glib::ustring(cclass->name)
512 .casefold().find(filter.casefold()) == Glib::ustring::npos)
513 continue;
514
515 CertShowInfo csi;
516 csi.second = cert;
517 int cgrade = this->charsheet->get_grade_for_class(cclass->id);
518 if (cgrade < cert->grade)
519 {
520 if (only_claimed)
521 continue;
522
523 switch (this->check_prerequisites_for_cert(cert))
524 {
525 default:
526 case CERT_PRE_HAVE_NONE:
527 if (only_claimable || only_partial)
528 continue;
529 csi.first = 3;
530 break;
531
532 case CERT_PRE_HAVE_SOME:
533 if (only_claimable || only_unknown)
534 continue;
535 csi.first = 2;
536 break;
537
538 case CERT_PRE_HAVE_ALL:
539 if (only_partial || only_unknown)
540 continue;
541 csi.first = 1;
542 break;
543 }
544 }
545 else
546 {
547 if (only_claimable || only_partial || only_unknown)
548 continue;
549
550 csi.first = 0;
551 }
552
553 /* Certificate matched filters. Add to sets. */
554 show_mapping[cat->name][cert->grade][cclass->name] = csi;
555 }
556
557 /* Fill the certificate store. */
558 for (CertCatMap::iterator i = show_mapping.begin();
559 i != show_mapping.end(); i++)
560 {
561 Gtk::TreeModel::iterator siter = this->store->append();
562 (*siter)[this->cols.name] = i->first;
563 (*siter)[this->cols.icon] = ImageStore::certificate_small;
564 (*siter)[this->cols.data] = 0;
565
566 for (CertGradeMap::iterator j = i->second.begin();
567 j != i->second.end(); j++)
568 {
569 Gtk::TreeModel::iterator siter2 = this->store->append(siter->children());
570 int grade_idx = ApiCertTree::get_grade_index(j->first);
571 (*siter2)[this->cols.name] = ApiCertTree::get_name_for_grade(j->first);
572 (*siter2)[this->cols.icon] = ImageStore::certgrades[grade_idx];
573 (*siter2)[this->cols.data] = 0;
574
575 for (CertClassMap::iterator k = j->second.begin();
576 k != j->second.end(); k++)
577 {
578 Gtk::TreeModel::iterator row = this->store->append(siter2->children());
579 (*row)[this->cols.name] = k->second.second->class_details->name;
580 (*row)[this->cols.icon] = ImageStore::certstatus[k->second.first];
581 (*row)[this->cols.data] = k->second.second;
582 }
583 }
584 }
585
586 if (!filter.empty() || active_row_num != 0)
587 this->view.expand_all();
588 }
589
590 /* ---------------------------------------------------------------- */
591
592 void
clear_filter(void)593 GtkCertBrowser::clear_filter (void)
594 {
595 this->filter_entry.set_text("");
596 this->fill_store();
597 }
598
599 /* ---------------------------------------------------------------- */
600
601 GtkCertBrowser::CertPrerequisite
check_prerequisites_for_cert(ApiCert const * cert)602 GtkCertBrowser::check_prerequisites_for_cert (ApiCert const* cert)
603 {
604 unsigned int deps_amount = 0;
605 unsigned int have_amount = 0;
606
607 for (unsigned int i = 0; i < cert->skilldeps.size(); ++i)
608 {
609 int skill_id = cert->skilldeps[i].first;
610 int skill_level = cert->skilldeps[i].second;
611
612 if (this->charsheet->get_level_for_skill(skill_id) >= skill_level)
613 have_amount += 1;
614 deps_amount += 1;
615 }
616
617 ApiCertTreePtr tree = ApiCertTree::request();
618 for (unsigned int i = 0; i < cert->certdeps.size(); ++i)
619 {
620 int cert_id = cert->certdeps[i].first;
621 ApiCert const* rcert = tree->get_certificate_for_id(cert_id);
622 int rcert_class_id = rcert->class_details->id;
623
624 if (this->charsheet->get_grade_for_class(rcert_class_id) >= rcert->grade)
625 have_amount += 1;
626 deps_amount += 1;
627 }
628
629 if (have_amount == deps_amount)
630 return CERT_PRE_HAVE_ALL;
631 else if (have_amount == 0)
632 return CERT_PRE_HAVE_NONE;
633 else
634 return CERT_PRE_HAVE_SOME;
635 }
636