354{
355 int entry = 0;
356 item_tbl.for_each([this, &entry, &file_path](sol::object const &key, sol::object const &value) {
357 uint32_t t_int = 0;
358 sol::table tbl = value.as<sol::table>();
359 std::string t_str;
361
362 entry++;
363
364 if (key.get_type() != sol::type::string)
365 return;
366
367 id.
key_name = key.as<std::string>();
368
369 if (id.key_name.length() < 1) {
370 HLog(error) <<
"ItemDB::load_items: Invalid or non-existent mandatory field 'AegisName' for entry " <<
id.item_id <<
" in '" << file_path <<
"'. Skipping...";
371 return;
372 }
373
374 id.item_id = tbl.get_or("Id", 0);
375 if (id.item_id == 0) {
376 HLog(error) <<
"ItemDB::load_items: Invalid or non-existent mandatory field 'Id' for item '" <<
id.key_name <<
"' in '" << file_path <<
"'. Skipping...";
377 return;
378 }
379
380 id.name = tbl.get_or("Name", std::string(""));
381 if (id.name.empty()) {
382 HLog(error) <<
"ItemDB::load_items: Invalid or non-existent mandatory field 'Name' for entry " <<
id.item_id <<
" in '" << file_path <<
"'. Skipping...";
383 return;
384 }
385
387
392
393 id.value_buy = tbl.get_or("Buy", -1);
394 id.value_sell = tbl.get_or("Sell", -1);
395
396 if (id.value_buy == -1 && id.value_sell == -1)
397 id.value_buy = id.value_sell = 0;
398 else if (id.value_buy == -1)
399 id.value_buy = id.value_sell * 2;
400 else if (id.value_sell == -1)
401 id.value_sell = id.value_buy / 2;
402
403
404 if (id.value_buy / 124.0 < id.value_sell / 75.0) {
405 HLog(warning) <<
"Buying/Selling [" <<
id.value_buy <<
"/" <<
id.value_sell <<
"] price of item " <<
id.item_id <<
" (" <<
id.name <<
") "
406 "allows Zeny making exploit through buying/selling at discounted/overcharged prices! File '" << file_path << "'.\n";
407 }
408
409 id.weight = tbl.get_or("Weight", 0);
410 id.attack = tbl.get_or("Atk", 0);
411 id.magic_atk = tbl.get_or("Matk", 0);
412 id.defense = tbl.get_or("Def", 0);
413 id.attack_range = tbl.get_or("Range", 0);
414 id.card_slot_count = tbl.get_or("Slots", 0);
415 t_int = tbl.get_or("WeaponLv", 1);
416
418 id.level.weapon = t_int;
419 else
420 id.level.armor = t_int;
421
422 sol::optional<sol::object> maybe_job_tbl = tbl.get<sol::optional<sol::object>>("Job");
423 if (maybe_job_tbl && maybe_job_tbl.value().get_type() == sol::type::table) {
424 sol::table job_tbl = maybe_job_tbl.value().as<sol::table>();
425 job_tbl.for_each([this, &id, &file_path] (sol::object const &key, sol::object const &value)
426 {
427 bool enable = value.as<bool>();
428
429 if (key.get_type() == sol::type::string) {
430 std::string job_name = key.as<std::string>();
432 return;
433 } else if (key.get_type() == sol::type::number) {
434 int job_id = key.as<int>();
435
436 if (enable) {
437 id.requirements.job_ids.push_back(job_id);
438 } else {
439 std::remove_if(id.requirements.job_ids.begin(), id.requirements.job_ids.end(), [job_id] (uint32_t id) { return job_id == id; });
440 }
442 return;
443 }
444 });
445 } else if (maybe_job_tbl && maybe_job_tbl.value().get_type() == sol::type::string) {
446 std::string job_name = maybe_job_tbl.value().as<std::string>();
448 return;
449 } else if (maybe_job_tbl && maybe_job_tbl.value().get_type() == sol::type::number) {
450 id.requirements.job_ids.push_back(maybe_job_tbl.value().as<uint32_t>());
452 return;
453 }
454
456
457 sol::optional<sol::object> location = tbl.get<sol::optional<sol::object>>("Loc");
458
459 if (location) {
460 sol::object loc = location.value();
461
462 if (loc.get_type() == sol::type::table) {
463 loc.as<sol::table>().for_each([&id, &file_path] (sol::object const &key, sol::object const &value) {
464 if (value.get_type() != sol::type::number) {
465 HLog(warning) <<
"Invalid type for 'Loc' in entry '" <<
id.key_name <<
"' in file '" << file_path <<
"'";
466 return;
467 }
468
469 id.equip_location_mask |= value.as<int>();
470 });
471 } else if (loc.get_type() == sol::type::number) {
472 id.equip_location_mask |= loc.as<int>();
473 }
474 }
475
476 sol::optional<sol::object> maybe_elv = tbl.get<sol::optional<sol::object>>("EquipLv");
477
478 if (maybe_elv) {
479 if (maybe_elv.value().get_type() == sol::type::table) {
480 sol::table elv = maybe_elv.value();
481 id.requirements.min_lv = elv.get_or(0, 0);
482 id.requirements.max_lv = elv.get_or(1, 0);
483 } else if (maybe_elv.value().get_type() == sol::type::number) {
484 id.requirements.min_lv = maybe_elv.value().as<int32_t>();
485 } else {
486 id.requirements.min_lv = id.requirements.max_lv = 0;
487 }
488 } else {
489 id.requirements.min_lv = id.requirements.max_lv = 0;
490 }
491
492 id.config.refineable = tbl.get_or("Refine", false);
493 id.config.allow_item_options = tbl.get_or("EnableOptions", true);
494
495 id.config.bind_on_equip = tbl.get_or("BindOnEquip", false);
496 id.config.force_serial = tbl.get_or("ForceSerial", false);
497 id.config.keep_after_use = tbl.get_or("KeepAfterUse", false);
498 id.config.drop_announce = tbl.get_or("DropAnnounce", false);
499
500 id.config.show_drop_effect = tbl.get_or("ShowDropEffect", false);
501 id.drop_effect_mode = tbl.get_or("DropEffectMode", 0);
502
503 sol::optional<sol::object> no_trade = tbl.get<sol::optional<sol::object>>("NoTrade");
504
505 if (no_trade) {
506 sol::object nt = no_trade.value();
507
508 if (nt.get_type() == sol::type::table) {
509 nt.as<sol::table>().for_each([&id, &file_path] (sol::object const &key, sol::object const &value) {
510 if (value.get_type() != sol::type::number && value.get_type() != sol::type::boolean) {
511 HLog(warning) <<
"Invalid type for 'NoTrade' in entry '" <<
id.key_name <<
"' in file '" << file_path <<
"'";
512 return;
513 }
514
515 if (key.get_type() != sol::type::number) {
516 if (key.as<std::string>().compare("override") == 0) {
517 id.trade_restriction_group_override_id = value.as<int>();
518 return;
519 } else if (key.as<std::string>().compare("partneroverride") == 0) {
520 id.trade_restriction_partner_override = value.as<bool>();
521 return;
522 }
523 }
524
525 id.trade_restriction_mask |= value.as<int>();
526 });
527 } else if (nt.get_type() == sol::type::number) {
528 id.trade_restriction_mask |= nt.as<int>();
529 }
530 }
531
532 sol::optional<sol::object> no_use = tbl.get<sol::optional<sol::object>>("RestrictUsage");
533
534 if (no_use) {
535 sol::object nu = no_use.value();
536
537 if (nu.get_type() == sol::type::table) {
538 nu.as<sol::table>().for_each([&id, &file_path] (sol::object const &key, sol::object const &value) {
539 if (value.get_type() != sol::type::number) {
540 HLog(warning) <<
"Invalid type for 'RestrictUsage' in entry '" <<
id.key_name <<
"' in file '" << file_path <<
"'";
541 return;
542 }
543
544 if (key.get_type() != sol::type::number) {
545 if (key.as<std::string>().compare("override") == 0) {
546 id.usage_restriction_group_override_id = value.as<int>();
547 return;
548 }
549 }
550
551 id.usage_restriction_mask |= value.as<int>();
552 });
553 } else if (nu.get_type() == sol::type::number) {
554 id.usage_restriction_mask |= nu.as<int>();
555 }
556 }
557
558 sol::optional<sol::object> stack = tbl.get<sol::optional<sol::object>>("Stack");
559
560 if (stack) {
561 sol::object s = stack.value();
562
563 if (s.get_type() == sol::type::table) {
564 s.as<sol::table>().for_each([&id, &file_path] (sol::object const &key, sol::object const &value) {
565 if (value.get_type() != sol::type::number) {
566 HLog(warning) <<
"Invalid type for 'Stack' in entry '" <<
id.key_name <<
"' in file '" << file_path <<
"'";
567 return;
568 }
569
570 if (key.as<std::string>().compare("Inventory") == 0) {
571 id.stack.inventory = value.as<int>();
572 } else if (key.as<std::string>().compare("Cart") == 0) {
573 id.stack.cart = value.as<int>();
574 } else if (key.as<std::string>().compare("Storage") == 0) {
575 id.stack.storage = value.as<int>();
576 } else if (key.as<std::string>().compare("GuildStorage") == 0) {
577 id.stack.guild_storage = value.as<int>();
578 } else {
579 HLog(warning) <<
"Invalid type '" << key.as<std::string>() <<
"' for 'Stack' in entry '" <<
id.key_name <<
"' in file '" << file_path <<
"', skipping...";
580 }
581 });
582 } else {
587
588 HLog(warning) <<
"Invalid value type for 'Stack' in entry '" <<
id.key_name <<
"' in file '" << file_path <<
"', defaulting to max stack limits...";
589 }
590 } else {
595 }
596
597 id.delay = tbl.get_or("Delay", 0);
598
599 id.sprite_id = tbl.get_or("SpriteId", 0);
600
601 id.default_script = tbl.get_or("Script", std::string(""));
602 id.equip_script = tbl.get_or("OnEquipScript", std::string(""));
603 id.unequip_script = tbl.get_or("OnUnequipScript", std::string(""));
604
605 _item_db.
insert(
id.item_id, std::make_shared<item_config_data>(
id));
607 });
608
610}
#define MAX_INVENTORY_STACK_LIMIT
Definition: ItemDefinitions.hpp:65
item_ammunition_type
Definition: ItemDefinitions.hpp:271
@ IT_AT_NONE
Definition: ItemDefinitions.hpp:272
#define MAX_CART_STACK_LIMIT
Definition: ItemDefinitions.hpp:66
#define MAX_STORAGE_STACK_LIMIT
Definition: ItemDefinitions.hpp:67
item_type
Definition: ItemDefinitions.hpp:253
@ IT_TYPE_ETC
Definition: ItemDefinitions.hpp:257
@ IT_TYPE_WEAPON
Definition: ItemDefinitions.hpp:258
@ IT_TYPE_AMMO
Definition: ItemDefinitions.hpp:264
#define MAX_GSTORAGE_STACK_LIMIT
Definition: ItemDefinitions.hpp:68
item_weapon_type
Definition: ItemDefinitions.hpp:99
item_gender_type
Definition: ItemDefinitions.hpp:159
@ IT_GENDER_ANY
Definition: ItemDefinitions.hpp:162
bool add_job_group_to_item(std::string const &group, item_config_data &id, bool enable, std::string const &file_path)
Definition: ItemDB.cpp:104
void insert(const Key &key, const Value &value)
Definition: LockedLookupTable.hpp:68
std::size_t size()
Definition: LockedLookupTable.hpp:96
Definition: ItemDefinitions.hpp:334
std::string key_name
Definition: ItemDefinitions.hpp:336