@ -34,6 +34,11 @@ using namespace rathena;
using json = nlohmann : : json ;
/// global defines
// Global cache for item AegisName-to-ID mapping
static json cached_itemdb_aegisname_to_id ;
static json cached_itemdb_id_to_aegisname ;
static json cached_itemdb_id_to_name ;
static bool itemdbs_loaded = false ; // Flag to track if data is loaded
/// internal structure
typedef struct InventoryDB_SQL {
@ -286,23 +291,7 @@ static bool bot_inv_item_db_sql_create(InventoryDB* self, struct bot_inv_item* i
* @ param char_id : id of char , the item belongs to
* @ param inventory_id : if of item to delete
* @ return true if successful , false if something has failed
static bool bot_inv_item_db_sql_remove ( InventoryDB * self , const uint32 char_id , const uint32 inventory_id ) {
InventoryDB_SQL * db = ( InventoryDB_SQL * ) self ;
Sql * sql_handle = db - > bot_inventory ;
bool result = false ;
if ( SQL_SUCCESS ! = Sql_QueryStr ( sql_handle , " START TRANSACTION " )
| | SQL_SUCCESS ! = Sql_Query ( sql_handle , " DELETE FROM `%s` WHERE `char_id` = %d AND `id` = %d " , db - > inventory_db , char_id , inventory_id )
)
Sql_ShowDebug ( sql_handle ) ;
else
result = true ;
result & = ( SQL_SUCCESS = = Sql_QueryStr ( sql_handle , ( result = = true ) ? " COMMIT " : " ROLLBACK " ) ) ;
return result ;
} */
*/
static bool bot_inv_item_db_sql_remove ( InventoryDB * self , const uint32 char_id , const uint32 inventory_id ) {
InventoryDB_SQL * db = ( InventoryDB_SQL * ) self ;
Sql * sql_handle = db - > bot_inventory ;
@ -395,27 +384,49 @@ void dump_item_bundle(const bot_item_bundle& item_bundle) {
ShowDebug ( " End of item bundle dump. \n " ) ;
}
/*
* Weapon Types
*/
enum weapon_type : uint8 {
W_FIST , //Bare hands
W_DAGGER , //1
W_1HSWORD , //2
W_2HSWORD , //3
W_1HSPEAR , //4
W_2HSPEAR , //5
W_1HAXE , //6
W_2HAXE , //7
W_MACE , //8
W_2HMACE , //9 (unused)
W_STAFF , //10
W_BOW , //11
W_KNUCKLE , //12
W_MUSICAL , //13
W_WHIP , //14
W_BOOK , //15
W_KATAR , //16
W_REVOLVER , //17
W_RIFLE , //18
W_GATLING , //19
W_SHOTGUN , //20
W_GRENADE , //21
W_HUUMA , //22
W_2HSTAFF , //23
MAX_WEAPON_TYPE ,
// dual-wield constants
W_DOUBLE_DD , // 2 daggers
W_DOUBLE_SS , // 2 swords
W_DOUBLE_AA , // 2 axes
W_DOUBLE_DS , // dagger + sword
W_DOUBLE_DA , // dagger + axe
W_DOUBLE_SA , // sword + axe
MAX_WEAPON_TYPE_ALL ,
W_SHIELD = MAX_WEAPON_TYPE ,
} ;
/**
* Create a new forward iterator .
* @ param self : pointer to db iterator
* @ return a new db iterator
static InventoryDBIterator * bot_inv_item_db_sql_iterator ( InventoryDB * self , const uint32 char_id ) {
InventoryDB_SQL * db = ( InventoryDB_SQL * ) self ;
InventoryDBIterator_SQL * iter = ( InventoryDBIterator_SQL * ) aCalloc ( 1 , sizeof ( InventoryDBIterator_SQL ) ) ;
// set up the vtable
iter - > vtable . destroy = & bot_inv_item_db_sql_iter_destroy ;
iter - > vtable . next = & bot_inv_item_db_sql_iter_next ;
# define WEAPON_TYPE_ALL ((1<<MAX_WEAPON_TYPE)-1)
// fill data
iter - > db = db ;
iter - > char_id = char_id ;
iter - > last_inv_item_id = - 1 ;
return & iter - > vtable ;
} */
static InventoryDBIterator * bot_inv_item_db_sql_iterator ( InventoryDB * self , const uint32 char_id ) {
InventoryDB_SQL * db = ( InventoryDB_SQL * ) self ;
@ -458,43 +469,6 @@ static void bot_inv_item_db_sql_iter_destroy(InventoryDBIterator* self) {
aFree ( iter ) ;
}
/**
* Fetches the next inv item entry in the database .
* @ param self : pointer to db iterator
* @ param inventory_id : id of the inventory table the item belongs to
* @ return true if next inventory entry found and filled , false if something has failed
static bool bot_inv_item_db_sql_iter_next ( InventoryDBIterator * self , struct bot_inv_item * item ) {
InventoryDBIterator_SQL * iter = ( InventoryDBIterator_SQL * ) self ;
InventoryDB_SQL * db = iter - > db ;
Sql * sql_handle = db - > bot_inventory ;
char * data ;
// get next inventory ID
if ( SQL_ERROR = = Sql_Query ( sql_handle , " SELECT `id` FROM `%s` WHERE `char_id` = %d AND `id` > '%d' ORDER BY `id` ASC LIMIT 1 " ,
db - > inventory_db , iter - > char_id , iter - > last_inv_item_id ) )
{
Sql_ShowDebug ( sql_handle ) ;
return false ;
}
if ( SQL_SUCCESS = = Sql_NextRow ( sql_handle ) & &
SQL_SUCCESS = = Sql_GetData ( sql_handle , 0 , & data , nullptr ) & &
data ! = nullptr )
{ // get item data
uint32 inventory_id = atoi ( data ) ;
item - > inventory_id = inventory_id ;
if ( bot_inv_item_db_fromsql ( db , item ) )
{
iter - > last_inv_item_id = inventory_id ;
Sql_FreeResult ( sql_handle ) ;
return true ;
}
}
Sql_FreeResult ( sql_handle ) ;
return false ;
} */
static bool bot_inv_item_db_sql_iter_next ( InventoryDBIterator * self , struct bot_inv_item * item ) {
InventoryDBIterator_SQL * iter = ( InventoryDBIterator_SQL * ) self ;
InventoryDB_SQL * db = iter - > db ;
@ -549,80 +523,6 @@ static bool bot_inv_item_db_sql_iter_next(InventoryDBIterator* self, struct bot_
return false ;
}
/**
* Fetch a struct bot_inv_item from sql .
* @ param db : pointer to db
* @ param item : pointer of bot_inv_item to fill
* @ param char_id : id of character , item belong to
* @ param item_id : id of item to take data from
* @ return true if successful , false if something has failed
static bool bot_inv_item_db_fromsql ( InventoryDB_SQL * db , struct bot_inv_item * item ) {
Sql * sql_handle = db - > bot_inventory ;
char * data ;
// retrieve login entry for the specified account
if ( SQL_ERROR = = Sql_Query ( sql_handle ,
# ifdef VIP_ENABLE
" SELECT `id`, `char_id`, `nameid`, `amount`, `equip`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `enchantgrade` FROM `%s` WHERE `id` = %d " ,
# else
" SELECT `id`, `char_id`, `nameid`, `amount`, `equip`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `enchantgrade` FROM `%s` WHERE `id` = %d " ,
# endif
db - > inventory_db , item - > inventory_id )
) {
Sql_ShowDebug ( sql_handle ) ;
return false ;
}
if ( SQL_SUCCESS ! = Sql_NextRow ( sql_handle ) )
{ // no such entry
Sql_FreeResult ( sql_handle ) ;
return false ;
}
Sql_GetData ( sql_handle , 0 , & data , nullptr ) ; item - > inventory_id = atoi ( data ) ;
Sql_GetData ( sql_handle , 1 , & data , nullptr ) ; item - > char_id = atoi ( data ) ;
Sql_GetData ( sql_handle , 2 , & data , nullptr ) ; item - > item_id = atoi ( data ) ;
Sql_GetData ( sql_handle , 3 , & data , nullptr ) ; item - > amount = atoi ( data ) ;
Sql_GetData ( sql_handle , 4 , & data , nullptr ) ; item - > equip = atoi ( data ) ;
Sql_GetData ( sql_handle , 5 , & data , nullptr ) ; item - > refine = atoi ( data ) ;
Sql_GetData ( sql_handle , 6 , & data , nullptr ) ; item - > attribute = atoi ( data ) ;
Sql_GetData ( sql_handle , 7 , & data , nullptr ) ; item - > card0 = atoi ( data ) ;
Sql_GetData ( sql_handle , 8 , & data , nullptr ) ; item - > card1 = atoi ( data ) ;
Sql_GetData ( sql_handle , 9 , & data , nullptr ) ; item - > card2 = atoi ( data ) ;
Sql_GetData ( sql_handle , 10 , & data , nullptr ) ; item - > card3 = atoi ( data ) ;
Sql_GetData ( sql_handle , 11 , & data , nullptr ) ; item - > enchantgrade = atoi ( data ) ;
//endif
Sql_FreeResult ( sql_handle ) ;
//Other fields are more or less irrelevant for bot purposes -> therefor they are pre-filled with default values
item - > identify = 1 ; //identify = 1 means is successfully identified
item - > expire_time = 0 ; //Dont expire
item - > favorite = 0 ;
item - > bound = 0 ;
item - > unique_id = 0 ;
item - > equip_switch = 0 ;
item - > option_id0 = 0 ;
item - > option_parm0 = 0 ;
item - > option_val0 = 0 ;
item - > option_id1 = 0 ;
item - > option_parm1 = 0 ;
item - > option_val1 = 0 ;
item - > option_id2 = 0 ;
item - > option_parm2 = 0 ;
item - > option_val2 = 0 ;
item - > option_id3 = 0 ;
item - > option_parm3 = 0 ;
item - > option_val3 = 0 ;
item - > option_id4 = 0 ;
item - > option_parm4 = 0 ;
item - > option_val4 = 0 ;
return true ;
} */
static bool bot_inv_item_db_fromsql ( InventoryDB_SQL * db , struct bot_inv_item * item ) {
Sql * sql_handle = db - > bot_inventory ;
char * data ;
@ -826,125 +726,80 @@ void set_bot_inv_item_defaults(bot_inv_item& item) {
item . enchantgrade = 0 ;
}
uint32 convert_item_aegisname_to_id ( const char * aegisname )
void set_bot_equip_item_defaults ( bot_inv_item & item )
{
// Open the mapping JSON file
std : : ifstream bot_itemdb_aegisname_to_id_file ( " conf/bot_helper_jsons/itemdb_converter_aegisname_to_id.json " ) ;
if ( ! bot_itemdb_aegisname_to_id_file . is_open ( ) ) {
ShowError ( " Failed to open itemdb_converter_aegisname_to_id.json \n " ) ;
return 0 ;
}
// Parse the JSON file
json json_itemdb_aegisname_to_id ;
try {
bot_itemdb_aegisname_to_id_file > > json_itemdb_aegisname_to_id ;
}
catch ( json : : parse_error & e ) {
ShowError ( " Error parsing bot_accounts.json: %s \n " , e . what ( ) ) ;
return false ;
}
// Close file after done with it
bot_itemdb_aegisname_to_id_file . close ( ) ;
//ShowStatus("Mapping aegisname to id...\n");
if ( ! json_itemdb_aegisname_to_id . contains ( aegisname ) ) {
// Error: aegisname is not inside json file
ShowWarning ( " Aegisname \" %s \" was not found inside the itemdb. Skipped... " , aegisname ) ;
return 0 ;
}
item . inventory_id = - 1 ;
item . char_id = 0 ;
item . item_id = 512 ; // Default apple
item . amount = 1 ;
item . equip = 0 ; // is Overriden by value
const uint32 item_id = json_itemdb_aegisname_to_id [ aegisname ] ;
//ShowStatus("aegisname found for Item_id %d\n",item_id);
item . identify = 1 ; // Default indentified
item . refine = 0 ;
item . attribute = 0 ;
return item_id ;
}
item . card0 = 0 ;
item . card1 = 0 ;
item . card2 = 0 ;
item . card3 = 0 ;
std : : string convert_item_id_to_name ( uint32 item_id )
{
// Open the mapping JSON file
std : : ifstream bot_itemdb_item_id_to_name_file ( " conf/bot_helper_jsons/itemdb_converter_id_to_name.json " ) ;
if ( ! bot_itemdb_item_id_to_name_file . is_open ( ) ) {
ShowError ( " Failed to open itemdb_converter_id_to_name.json \n " ) ;
return " UNKNOWN " ;
}
item . option_id0 = 0 ;
item . option_val0 = 0 ;
item . option_parm0 = 0 ;
// Parse the JSON file
json json_itemdb_id_to_name ;
item . option_id1 = 0 ;
item . option_val1 = 0 ;
item . option_parm1 = 0 ;
try {
//bot_itemdb_item_id_to_name_file >> json_itemdb_id_to_name;
json test_json = json : : parse ( bot_itemdb_item_id_to_name_file ) ;
//ShowDebug("Test parse successful: %s\n", test_json.dump().c_str());
}
catch ( const json : : parse_error & e ) {
ShowError ( " JSON parse error: %s \n " , e . what ( ) ) ;
}
catch ( const std : : exception & e ) {
ShowError ( " General exception: %s \n " , e . what ( ) ) ;
}
catch ( . . . ) {
ShowError ( " Unknown error occurred during JSON parsing. \n " ) ;
}
// Close file after done with it
item . option_id2 = 0 ;
item . option_val2 = 0 ;
item . option_parm2 = 0 ;
bot_itemdb_item_id_to_name_file . close ( ) ;
item . option_id3 = 0 ;
item . option_val3 = 0 ;
item . option_parm3 = 0 ;
//ShowStatus("Mapping item_id to item_name...\n");
std : : string id_str = std : : to_string ( item_id ) ;
item . option_id4 = 0 ;
item . option_val4 = 0 ;
item . option_parm4 = 0 ;
//ShowStatus("id=%s\n", id_str.c_str());
if ( ! json_itemdb_id_to_name . contains ( id_str ) ) {
// Error: item_id is not inside json file
ShowWarning ( " Item_id \" %d \" was not found inside the itemdb. Skipped... \n " , item_id ) ;
return " UNKNOWN " ;
item . expire_time = 0 ;
item . favorite = 0 ;
item . bound = 0 ;
item . unique_id = 0 ;
item . equip_switch = 0 ;
item . enchantgrade = 0 ;
}
const std : : string item_name = json_itemdb_id_to_name [ id_str ] ;
// ShowStatus("Entry found. Item Name: %s\n", item_name.c_str());
return item_name ;
void generate_crafted_item_attributes ( bot_inv_item & item , uint32 creator_char_id , int element , int cnt_star_crumbs ) {
// Ensure valid input
if ( element < 1 | | element > 4 ) {
ShowError ( " Invalid element type for crafted item. Valid range is 1-4. \n " ) ;
return ;
}
std : : string convert_item_id_to_aegisname ( uint32 item_id ) {
static json json_itemdb_id_to_aegisname ;
static bool id_to_aegisname_is_loaded = false ;
// Load the JSON file only once
if ( ! id_to_aegisname_is_loaded ) {
std : : ifstream bot_itemdb_item_id_to_aegisname_file ( " conf/bot_helper_jsons/itemdb_converter_id_to_aegisname.json " ) ;
if ( ! bot_itemdb_item_id_to_aegisname_file . is_open ( ) ) {
ShowError ( " Failed to open itemdb_converter_id_to_aegisname.json \n " ) ;
return " UNKNOWN " ;
if ( cnt_star_crumbs < 0 ) {
ShowError ( " Invalid number of Star Crumbs. Must be non-negative. \n " ) ;
return ;
}
try {
bot_itemdb_item_id_to_aegisname_file > > json_itemdb_id_to_aegisname ;
id_to_aegisname_is_loaded = true ;
}
catch ( json : : parse_error & e ) {
ShowError ( " Error parsing itemdb_converter_id_to_aegisname.json: %s \n " , e . what ( ) ) ;
return " UNKNOWN " ;
}
// Assign crafted item flag to card1
item . card0 = 255 ; // Indicates inscribed equipment
bot_itemdb_item_id_to_aegisname_file . close ( ) ;
}
// Compute card2 using the formula
item . card1 = element + ( ( cnt_star_crumbs * 5 ) < < 8 ) ;
// Lookup the item ID in the JSON data
std : : string id_str = std : : to_string ( item_id ) ;
if ( ! json_itemdb_id_to_aegisname . contains ( id_str ) ) {
ShowWarning ( " Item_id \" %u \" was not found inside the itemdb. Skipped... " , item_id ) ;
return " UNKNOWN " ;
}
// Split inscriber ID into card3 and card4
item . card2 = creator_char_id & 65535 ; // Lower 16 bits of inscriber_id
item . card3 = creator_char_id > > 16 ; // Upper 16 bits of inscriber_id
return json_itemdb_id_to_aegisname [ id_str ] ;
ShowDebug ( " Crafted item attributes generated: \n " ) ;
ShowDebug ( " - Element: %d \n " , element ) ;
ShowDebug ( " - Star Crumbs: %d \n " , cnt_star_crumbs ) ;
ShowDebug ( " - Inscriber ID: %u (card2: %u, card3: %u) \n " , creator_char_id , item . card2 , item . card3 ) ;
}
/*
* Tool Functions for item name parsing
* Tool Functions for item preparation
*/
void prepare_item_bundle ( bot_item_bundle & bundle , uint32 char_id , const nlohmann : : json & character ) {
@ -1041,5 +896,519 @@ void prepare_item_bundle(bot_item_bundle& bundle, uint32 char_id, const nlohmann
bundle . items . push_back ( new_item ) ;
}
}
}
void prepare_equipment_bundle ( bot_item_bundle & bundle , uint32 char_id , const nlohmann : : json & character ) {
//Select for the used profile
std : : string equipment_profile = character [ " char_equip_profile " ] ;
if ( equipment_profile = = " CUSTOM " ) {
if ( ! character . contains ( " equip " ) ) {
throw std : : runtime_error ( " equip data is missing for CUSTOM equip profile. " ) ;
}
const auto & equip_items = character [ " equip " ] ;
//Initialize the items bundle
bundle . items . clear ( ) ;
// Iterate over the items in the JSON
for ( const auto & equip_item : equip_items . items ( ) ) {
std : : string equip_pos_str = equip_item . key ( ) ;
const auto & equip_item_data = equip_item . value ( ) ;
std : : string equip_item_name ;
//Einbauen: Check für crafted item
//generate_crafted_item_attributes(item, char_id, int element, int cnt_star_crumbs
uint32 equip_item_id = convert_item_aegisname_to_id ( equip_item_name . c_str ( ) ) ;
// Convert item name to item ID
uint32 equip_pos_id = convert_equipslot_id_to_number ( equip_pos_str . c_str ( ) ) ;
if ( equip_pos_id < = 0 ) { // Invalid Equip slot ID
ShowWarning ( " Equip slot ID %s is Invalid. Skipping... \n " , equip_pos_str . c_str ( ) ) ;
continue ; // Skip invalid item
}
const std : : string & equip_slot = equip_item . key ( ) ;
bot_inv_item new_item { } ;
set_bot_inv_item_defaults ( new_item ) ;
// Convert item aegisname to item ID
// Read item information
if ( equip_item_data . contains ( " AEGISNAME " ) ) {
std : : string aegisname = equip_item_data [ " AEGISNAME " ] ;
new_item . item_id = convert_item_aegisname_to_id ( aegisname . c_str ( ) ) ;
if ( new_item . item_id < = 0 ) {
ShowWarning ( " Invalid AEGISNAME %s for slot %s. Skipping... \n " , aegisname . c_str ( ) , equip_slot . c_str ( ) ) ;
continue ;
}
}
else {
ShowWarning ( " Missing AEGISNAME for slot %s. Skipping... \n " , equip_slot . c_str ( ) ) ;
continue ;
}
new_item . char_id = char_id ;
new_item . equip = equip_pos_id ;
// Read refine level
if ( equip_item_data . contains ( " REFINELVL " ) ) {
new_item . refine = equip_item_data [ " REFINELVL " ] ;
}
else {
new_item . refine = 0 ; // Default refine level
}
// Read card fields
if ( equip_item_data . contains ( " CARD0 " ) ) {
new_item . card0 = convert_item_aegisname_to_id ( equip_item_data [ " CARD0 " ] . get < std : : string > ( ) . c_str ( ) ) ;
}
if ( equip_item_data . contains ( " CARD1 " ) ) {
new_item . card1 = convert_item_aegisname_to_id ( equip_item_data [ " CARD1 " ] . get < std : : string > ( ) . c_str ( ) ) ;
}
if ( equip_item_data . contains ( " CARD2 " ) ) {
new_item . card2 = convert_item_aegisname_to_id ( equip_item_data [ " CARD2 " ] . get < std : : string > ( ) . c_str ( ) ) ;
}
if ( equip_item_data . contains ( " CARD3 " ) ) {
new_item . card3 = convert_item_aegisname_to_id ( equip_item_data [ " CARD3 " ] . get < std : : string > ( ) . c_str ( ) ) ;
}
// Handle crafted items
if ( equip_item_data . contains ( " CRAFTED " ) ) {
const nlohmann : : json & crafted_data = equip_item_data [ " CRAFTED " ] ;
new_item . card0 = 255 ; // Crafted equipment flag
if ( crafted_data . contains ( " CREATOR " ) ) {
std : : string creator = crafted_data [ " CREATOR " ] ;
//uint32 inscriber_id = (creator == "SELF") ? char_id : get_char_id_by_name(creator.c_str());
uint32 inscriber_id = ( creator = = " SELF " ) ? char_id : 0 ; // If creator is not self by default creator is "Nameless"
new_item . card2 = inscriber_id & 65535 ;
new_item . card3 = inscriber_id > > 16 ;
}
if ( crafted_data . contains ( " STAR_CRUMBS " ) & & crafted_data . contains ( " ELEMENT " ) ) {
int star_crumbs = crafted_data [ " STAR_CRUMBS " ] ;
std : : string element = crafted_data [ " ELEMENT " ] ;
int element_id = convert_element_id_to_number ( element ) ;
new_item . card1 = element_id + ( ( star_crumbs * 5 ) < < 8 ) ;
}
}
bundle . items . push_back ( new_item ) ;
}
}
else {
// Load item loadout Profile
std : : string job_str = character [ " start_job " ] ;
int job_id = convert_jobid_to_number ( job_str . c_str ( ) ) ;
std : : string job_profile_file_path = " conf/bot_profiles/equip_profiles/ " + job_str + " _equip_profile.json " ;
nlohmann : : json json_equip_profiles ;
// Try to Open iten Profile
std : : ifstream equip_profile_file ( job_profile_file_path ) ;
if ( ! equip_profile_file . is_open ( ) ) {
ShowWarning ( " Failed to open equip_profile_file %s. Trying to load DEFAULT instead. \n " , job_profile_file_path . c_str ( ) ) ;
job_profile_file_path = " conf/bot_profiles/equip_profiles/DEFAULT_equip_profile.json " ;
equip_profile_file . open ( job_profile_file_path ) ;
if ( ! equip_profile_file . is_open ( ) ) {
throw std : : runtime_error ( " Failed to open both job and default profiles. " ) ;
}
}
// Parse Profile Data
try {
equip_profile_file > > json_equip_profiles ;
}
catch ( const nlohmann : : json : : parse_error & e ) {
throw std : : runtime_error ( " Error parsing equip profile JSON: " + std : : string ( e . what ( ) ) ) ;
}
if ( ! json_equip_profiles . contains ( equipment_profile ) ) {
// If equipment profile is not found, default to INIT
equipment_profile = " INIT " ;
}
const auto & equip_profile = json_equip_profiles [ equipment_profile ] ;
//Initialize the item bundle
bundle . items . clear ( ) ;
// Iterate through each equipment slot
for ( auto & equip_entry : equip_profile . items ( ) ) {
std : : string equip_slot = equip_entry . key ( ) ;
uint32 equip_pos_id = convert_equipslot_id_to_number ( equip_slot . c_str ( ) ) ;
const auto & equip_item_data = equip_entry . value ( ) ;
bot_inv_item new_item { } ;
set_bot_inv_item_defaults ( new_item ) ;
// Convert item aegisname to item ID
// Read item information
if ( equip_item_data . contains ( " AEGISNAME " ) ) {
std : : string aegisname = equip_item_data [ " AEGISNAME " ] ;
new_item . item_id = convert_item_aegisname_to_id ( aegisname . c_str ( ) ) ;
if ( new_item . item_id < = 0 ) {
ShowWarning ( " Invalid AEGISNAME %s for slot %s. Skipping... \n " , aegisname . c_str ( ) , equip_slot . c_str ( ) ) ;
continue ;
}
}
else {
ShowWarning ( " Missing AEGISNAME for slot %s. Skipping... \n " , equip_slot . c_str ( ) ) ;
continue ;
}
new_item . char_id = char_id ;
new_item . equip = equip_pos_id ;
// Read refine level
if ( equip_item_data . contains ( " REFINELVL " ) ) {
new_item . refine = equip_item_data [ " REFINELVL " ] ;
}
else {
new_item . refine = 0 ; // Default refine level
}
// Read card fields
if ( equip_item_data . contains ( " CARD0 " ) ) {
new_item . card0 = convert_item_aegisname_to_id ( equip_item_data [ " CARD0 " ] . get < std : : string > ( ) . c_str ( ) ) ;
}
if ( equip_item_data . contains ( " CARD1 " ) ) {
new_item . card1 = convert_item_aegisname_to_id ( equip_item_data [ " CARD1 " ] . get < std : : string > ( ) . c_str ( ) ) ;
}
if ( equip_item_data . contains ( " CARD2 " ) ) {
new_item . card2 = convert_item_aegisname_to_id ( equip_item_data [ " CARD2 " ] . get < std : : string > ( ) . c_str ( ) ) ;
}
if ( equip_item_data . contains ( " CARD3 " ) ) {
new_item . card3 = convert_item_aegisname_to_id ( equip_item_data [ " CARD3 " ] . get < std : : string > ( ) . c_str ( ) ) ;
}
// Handle crafted items
if ( equip_item_data . contains ( " CRAFTED " ) ) {
const nlohmann : : json & crafted_data = equip_item_data [ " CRAFTED " ] ;
new_item . card0 = 255 ; // Crafted equipment flag
if ( crafted_data . contains ( " CREATOR " ) ) {
std : : string creator = crafted_data [ " CREATOR " ] ;
//uint32 inscriber_id = (creator == "SELF") ? char_id : get_char_id_by_name(creator.c_str());
uint32 inscriber_id = ( creator = = " SELF " ) ? char_id : 0 ; // If creator is not self by default creator is "Nameless"
new_item . card2 = inscriber_id & 65535 ;
new_item . card3 = inscriber_id > > 16 ;
}
if ( crafted_data . contains ( " STAR_CRUMBS " ) & & crafted_data . contains ( " ELEMENT " ) ) {
int star_crumbs = crafted_data [ " STAR_CRUMBS " ] ;
std : : string element = crafted_data [ " ELEMENT " ] ;
int element_id = convert_element_id_to_number ( element ) ;
new_item . card1 = element_id + ( ( star_crumbs * 5 ) < < 8 ) ;
}
}
bundle . items . push_back ( new_item ) ;
}
}
}
/*
* Converter Functions for item parsing
*/
uint32 convert_item_aegisname_to_id ( const char * aegisname ) {
if ( ! itemdbs_loaded ) {
load_itemdbs ( ) ;
}
if ( ! cached_itemdb_aegisname_to_id . contains ( aegisname ) ) {
ShowWarning ( " Aegisname \" %s \" was not found inside the itemdb. Skipped... \n " , aegisname ) ;
return 0 ;
}
const uint32 item_id = cached_itemdb_aegisname_to_id [ aegisname ] ;
//ShowStatus("aegisname found for Item_id %d\n",item_id);
return item_id ;
}
void load_itemdb_aegisname_to_id ( ) {
if ( itemdbs_loaded ) return ; // Already loaded, skip
std : : ifstream bot_itemdb_aegisname_to_id_file ( " conf/bot_helper_jsons/itemdb_converter_aegisname_to_id.json " ) ;
if ( ! bot_itemdb_aegisname_to_id_file . is_open ( ) ) {
ShowError ( " Failed to open itemdb_converter_aegisname_to_id.json \n " ) ;
return ;
}
try {
bot_itemdb_aegisname_to_id_file > > cached_itemdb_aegisname_to_id ;
}
catch ( json : : parse_error & e ) {
ShowError ( " Error parsing itemdb_converter_aegisname_to_id.json: %s \n " , e . what ( ) ) ;
throw e ;
}
bot_itemdb_aegisname_to_id_file . close ( ) ;
}
std : : string convert_item_id_to_name ( uint32 item_id )
{
if ( ! itemdbs_loaded ) {
load_itemdbs ( ) ;
}
//ShowStatus("Mapping item_id to item_name...\n");
std : : string id_str = std : : to_string ( item_id ) ;
if ( ! cached_itemdb_id_to_name . contains ( id_str ) ) {
ShowWarning ( " id_str \" %s \" was not found inside the itemdb. Skipped... \n " , id_str . c_str ( ) ) ;
return 0 ;
}
std : : string item_name = cached_itemdb_id_to_name [ id_str ] ;
//ShowStatus("item id found %d\n",item_name.c_str());
return item_name ;
}
void load_itemdb_id_to_name ( ) {
if ( itemdbs_loaded ) return ; // Already loaded, skip
std : : ifstream bot_itemdb_id_to_name_file ( " conf/bot_helper_jsons/itemdb_converter_id_to_name.json " ) ;
if ( ! bot_itemdb_id_to_name_file . is_open ( ) ) {
ShowError ( " Failed to open itemdb_converter_id_to_name.json \n " ) ;
return ;
}
try {
bot_itemdb_id_to_name_file > > cached_itemdb_id_to_name ;
}
catch ( json : : parse_error & e ) {
ShowError ( " Error parsing itemdb_converter_id_to_name.json: %s \n " , e . what ( ) ) ;
throw e ;
}
bot_itemdb_id_to_name_file . close ( ) ;
}
std : : string convert_item_id_to_aegisname ( uint32 item_id ) {
if ( ! itemdbs_loaded ) {
load_itemdbs ( ) ;
}
//ShowStatus("Mapping item_id to item_name...\n");
std : : string id_str = std : : to_string ( item_id ) ;
if ( ! cached_itemdb_id_to_aegisname . contains ( id_str ) ) {
ShowWarning ( " id_str \" %s \" was not found inside the itemdb. Skipped... \n " , id_str . c_str ( ) ) ;
return 0 ;
}
std : : string item_aegisname = cached_itemdb_id_to_aegisname [ id_str ] ;
//ShowStatus("item id found %d\n",item_name.c_str());
return item_aegisname ;
}
void load_itemdb_id_to_aegisname ( ) {
if ( itemdbs_loaded ) return ; // Already loaded, skip
std : : ifstream bot_itemdb_id_to_aegisname_file ( " conf/bot_helper_jsons/itemdb_converter_id_to_aegisname.json " ) ;
if ( ! bot_itemdb_id_to_aegisname_file . is_open ( ) ) {
ShowError ( " Failed to open itemdb_converter_id_to_aegisname.json \n " ) ;
return ;
}
try {
bot_itemdb_id_to_aegisname_file > > cached_itemdb_id_to_aegisname ;
}
catch ( json : : parse_error & e ) {
ShowError ( " Error parsing itemdb_converter_id_to_aegisname.json: %s \n " , e . what ( ) ) ;
throw e ;
}
bot_itemdb_id_to_aegisname_file . close ( ) ;
}
uint32 convert_equipslot_id_to_number ( const char * equipslot_id )
{
static const std : : unordered_map < std : : string , uint32 > equipslot_map = {
{ " EQP_HEAD_LOW " , EQP_HEAD_LOW } ,
{ " EQP_HEAD_MID " , EQP_HEAD_MID } ,
{ " EQP_HEAD_TOP " , EQP_HEAD_TOP } ,
{ " EQP_HEAD_LOWMID " , EQP_HEAD_LOW + EQP_HEAD_MID } ,
{ " EQP_HEAD_LOWTOP " , EQP_HEAD_LOW + EQP_HEAD_TOP } ,
{ " EQP_HEAD_MIDTOP " , EQP_HEAD_MID + EQP_HEAD_TOP } ,
{ " EQP_HEAD_ALL " , EQP_HEAD_LOW + EQP_HEAD_MID + EQP_HEAD_TOP } ,
{ " EQP_HAND_R " , EQP_HAND_R } ,
{ " EQP_HAND_L " , EQP_HAND_L } ,
{ " EQP_HAND_BOTH " , EQP_HAND_R + EQP_HAND_L } ,
{ " EQP_ARMOR " , EQP_ARMOR } ,
{ " EQP_SHOES " , EQP_SHOES } ,
{ " EQP_GARMENT " , EQP_GARMENT } ,
{ " EQP_ACC_R " , EQP_ACC_R } ,
{ " EQP_ACC_L " , EQP_ACC_L } ,
{ " EQP_COSTUME_HEAD_TOP " , EQP_COSTUME_HEAD_TOP } ,
{ " EQP_COSTUME_HEAD_MID " , EQP_COSTUME_HEAD_MID } ,
{ " EQP_COSTUME_HEAD_LOW " , EQP_COSTUME_HEAD_LOW } ,
{ " EQP_COSTUME_HEAD_LOWMID " , EQP_COSTUME_HEAD_LOW + EQP_COSTUME_HEAD_MID } ,
{ " EQP_COSTUME_HEAD_LOWTOP " , EQP_COSTUME_HEAD_LOW + EQP_COSTUME_HEAD_TOP } ,
{ " EQP_COSTUME_HEAD_MIDTOP " , EQP_COSTUME_HEAD_MID + EQP_COSTUME_HEAD_TOP } ,
{ " EQP_COSTUME_HEAD_ALL " , EQP_COSTUME_HEAD_LOW + EQP_COSTUME_HEAD_MID + EQP_COSTUME_HEAD_TOP } ,
{ " EQP_COSTUME_GARMENT " , EQP_COSTUME_GARMENT } ,
{ " EQP_AMMO " , EQP_AMMO } ,
{ " EQP_SHADOW_ARMOR " , EQP_SHADOW_ARMOR } ,
{ " EQP_SHADOW_WEAPON " , EQP_SHADOW_WEAPON } ,
{ " EQP_SHADOW_SHIELD " , EQP_SHADOW_SHIELD } ,
{ " EQP_SHADOW_SHOES " , EQP_SHADOW_SHOES } ,
{ " EQP_SHADOW_ACC_R " , EQP_SHADOW_ACC_R } ,
{ " EQP_SHADOW_ACC_L " , EQP_SHADOW_ACC_L }
} ;
// Look up the skill_id in the map
std : : string equipslot = equipslot_id ;
auto it = equipslot_map . find ( equipslot ) ;
if ( it ! = equipslot_map . end ( ) ) {
return it - > second ; // Return the corresponding str value
}
else {
ShowError ( " Unknown equipslot ID: %s \n " , equipslot_id ) ;
return 0 ; // Return an error value if the equipslot ID is unknown
}
}
const char * convert_equipslot_id_to_str ( uint32 equipslot_id )
{
static const std : : unordered_map < uint32 , std : : string > equipslot_map = {
{ EQP_HEAD_LOW , " EQP_HEAD_LOW " } ,
{ EQP_HEAD_MID , " EQP_HEAD_MID " } ,
{ EQP_HEAD_TOP , " EQP_HEAD_TOP " } ,
{ EQP_HEAD_LOW + EQP_HEAD_MID , " EQP_HEAD_LOWMID " } ,
{ EQP_HEAD_LOW + EQP_HEAD_TOP , " EQP_HEAD_LOWTOP " } ,
{ EQP_HEAD_MID + EQP_HEAD_TOP , " EQP_HEAD_MIDTOP " } ,
{ EQP_HEAD_LOW + EQP_HEAD_MID + EQP_HEAD_TOP , " EQP_HEAD_ALL " } ,
{ EQP_HAND_R , " EQP_HAND_R " } ,
{ EQP_HAND_L , " EQP_HAND_L " } ,
{ EQP_HAND_R + EQP_HAND_L , " EQP_HAND_BOTH " } ,
{ EQP_ARMOR , " EQP_ARMOR " } ,
{ EQP_SHOES , " EQP_SHOES " } ,
{ EQP_GARMENT , " EQP_GARMENT " } ,
{ EQP_ACC_R , " EQP_ACC_R " } ,
{ EQP_ACC_L , " EQP_ACC_L " } ,
{ EQP_COSTUME_HEAD_TOP , " EQP_COSTUME_HEAD_TOP " } ,
{ EQP_COSTUME_HEAD_MID , " EQP_COSTUME_HEAD_MID " } ,
{ EQP_COSTUME_HEAD_LOW , " EQP_COSTUME_HEAD_LOW " } ,
{ EQP_COSTUME_HEAD_LOW + EQP_COSTUME_HEAD_MID , " EQP_COSTUME_HEAD_LOWMID " } ,
{ EQP_COSTUME_HEAD_LOW + EQP_COSTUME_HEAD_TOP , " EQP_COSTUME_HEAD_LOWTOP " } ,
{ EQP_COSTUME_HEAD_MID + EQP_COSTUME_HEAD_TOP , " EQP_COSTUME_HEAD_MIDTOP " } ,
{ EQP_COSTUME_HEAD_LOW + EQP_COSTUME_HEAD_MID + EQP_COSTUME_HEAD_TOP , " EQP_COSTUME_HEAD_ALL " } ,
{ EQP_COSTUME_GARMENT , " EQP_COSTUME_GARMENT " } ,
{ EQP_AMMO , " EQP_AMMO " } ,
{ EQP_SHADOW_ARMOR , " EQP_SHADOW_ARMOR " } ,
{ EQP_SHADOW_WEAPON , " EQP_SHADOW_WEAPON " } ,
{ EQP_SHADOW_SHIELD , " EQP_SHADOW_SHIELD " } ,
{ EQP_SHADOW_SHOES , " EQP_SHADOW_SHOES " } ,
{ EQP_SHADOW_ACC_R , " EQP_SHADOW_ACC_R " } ,
{ EQP_SHADOW_ACC_L , " EQP_SHADOW_ACC_L " }
} ;
// Look up the equip_id in the map
uint32 equip_item = ( uint32 ) equipslot_id ;
auto it = equipslot_map . find ( equipslot_id ) ;
if ( it ! = equipslot_map . end ( ) ) {
return it - > second . c_str ( ) ; // Return the corresponding str value
}
else {
ShowError ( " Unknown equipslot_id ID: %s \n " , equipslot_id ) ;
return " UNKNOWN " ; // Return an error value if the equip ID is unknown
}
}
int convert_element_id_to_number ( const std : : string & element_name ) {
static const std : : unordered_map < std : : string , int > element_map = {
{ " ICE " , 1 } ,
{ " EARTH " , 2 } ,
{ " FIRE " , 3 } ,
{ " WIND " , 4 } ,
} ;
auto it = element_map . find ( element_name ) ;
return ( it ! = element_map . end ( ) ) ? it - > second : 0 ;
}
const char * convert_element_id_to_str ( uint8 element_id ) {
static const std : : unordered_map < uint8 , std : : string > element_map = {
{ 1 , " ICE " } ,
{ 2 , " EARTH " } ,
{ 3 , " FIRE " } ,
{ 4 , " WIND " } ,
} ;
auto it = element_map . find ( element_id ) ;
if ( it ! = element_map . end ( ) ) {
return it - > second . c_str ( ) ; // Return the corresponding str value
}
else {
ShowError ( " Unknown element_id ID: %s \n " , element_id ) ;
return " UNKNOWN " ; // Return an error value if the element ID is unknown
}
}
// Function to convert job_id string to job number
int convert_weaponid_to_number ( const char * weapon_id ) {
// Create a map for the job ID strings to the corresponding e_job enum values
static const std : : unordered_map < std : : string , int > weapon_map = {
{ " W_FIST " , W_FIST } , //Bare hands
{ " W_DAGGER " , W_DAGGER } , //1
{ " W_1HSWORD " , W_1HSWORD } , //2
{ " W_2HSWORD " , W_2HSWORD } , //3
{ " W_1HSPEAR " , W_1HSPEAR } , //4
{ " W_2HSPEAR " , W_2HSPEAR } , //5
{ " W_1HAXE " , W_1HAXE } , //6
{ " W_2HAXE " , W_2HAXE } , //7
{ " W_MACE " , W_MACE } , //8
{ " W_2HMACE " , W_2HMACE } , //9 (unused)
{ " W_STAFF " , W_STAFF } , //10
{ " W_BOW " , W_BOW } , //11
{ " W_KNUCKLE " , W_KNUCKLE } , //12
{ " W_MUSICAL " , W_MUSICAL } , //13
{ " W_WHIP " , W_WHIP } , //14
{ " W_BOOK " , W_BOOK } , //15
{ " W_KATAR " , W_KATAR } , //16
{ " W_REVOLVER " , W_REVOLVER } , //17
{ " W_RIFLE " , W_RIFLE } , //18
{ " W_GATLING " , W_GATLING } , //19
{ " W_SHOTGUN " , W_SHOTGUN } , //20
{ " W_GRENADE " , W_GRENADE } , //21
{ " W_HUUMA " , W_HUUMA } , //22
{ " W_2HSTAFF " , W_2HSTAFF } , //23
{ " MAX_WEAPON_TYPE " , MAX_WEAPON_TYPE } ,
// dual-wield constants
{ " W_DOUBLE_DD " , W_DOUBLE_DD } , // 2 daggers
{ " W_DOUBLE_SS " , W_DOUBLE_SS } , // 2 swords
{ " W_DOUBLE_AA " , W_DOUBLE_AA } , // 2 axes
{ " W_DOUBLE_DS " , W_DOUBLE_DS } , // dagger + sword
{ " W_DOUBLE_DA " , W_DOUBLE_DA } , // dagger + axe
{ " W_DOUBLE_SA " , W_DOUBLE_SA } , // sword + axe
{ " MAX_WEAPON_TYPE_ALL " , MAX_WEAPON_TYPE_ALL } ,
{ " W_SHIELD " , W_SHIELD } ,
// Add other job mappings here as needed
} ;
// Look up the job_id in the map
std : : string weapon_str = weapon_id ;
// Convert to upper case
for ( int index = 0 ; index < weapon_str . size ( ) ; index + + ) {
weapon_str . at ( index ) = toupper ( weapon_str . at ( index ) ) ;
}
auto it = weapon_map . find ( weapon_str ) ;
if ( it ! = weapon_map . end ( ) ) {
return it - > second ; // Return the corresponding enum value
}
else {
ShowError ( " Unknown weapon ID: %s \n " , weapon_id ) ;
return - 1 ; // Return an error value if the weapon ID is unknown
}
}
void load_itemdbs ( )
{
try {
load_itemdb_id_to_aegisname ( ) ;
load_itemdb_id_to_name ( ) ;
load_itemdb_aegisname_to_id ( ) ;
itemdbs_loaded = true ;
ShowInfo ( " ItemDbs loaded successfully into cache... \n " ) ;
}
catch ( json : : parse_error & e ) {
ShowError ( " Error parsing itemdbs: %s \n " , e . what ( ) ) ;
itemdbs_loaded = false ;
}
}