/*========================================== * Initialize / Finalize *------------------------------------------ */ static int itemdb_final_sub (DBKey key,void *data,va_list ap) { int flag; struct item_data *id = (struct item_data *)data; flag = va_arg(ap, int); if (id->script) { script_free_code(id->script); id->script = NULL; } if (id->equip_script) { script_free_code(id->equip_script); id->equip_script = NULL; } if (id->unequip_script) { script_free_code(id->unequip_script); id->unequip_script = NULL; } // Whether to clear the item data (exception: do not clear the dummy item data if (flag && id != &dummy_item) aFree(id); return 0; }
/*========================================== * *------------------------------------------ */ static int itemdb_final(void *key,void *data,va_list ap) { struct item_data *id; nullpo_retr(0, id = (struct item_data *)data); if(id->use_script) script_free_code(id->use_script); if(id->equip_script) script_free_code(id->equip_script); aFree(id); return 0; }
void do_final_itemdb(void) { item_db->destroy(item_db, itemdb_final_sub, 1); if (dummy_item.script) { script_free_code(dummy_item.script); dummy_item.script = NULL; } if (dummy_item.equip_script) { script_free_code(dummy_item.equip_script); dummy_item.equip_script = NULL; } if (dummy_item.unequip_script) { script_free_code(dummy_item.unequip_script); dummy_item.unequip_script = NULL; } }
/// Destroys the item_data. static void destroy_item_data(struct item_data* self, int free_self) { if( self == NULL ) return; // free scripts if( self->script ) script_free_code(self->script); if( self->equip_script ) script_free_code(self->equip_script); if( self->unequip_script ) script_free_code(self->unequip_script); #if defined(DEBUG) // trash item memset(self, 0xDD, sizeof(struct item_data)); #endif // free self if( free_self ) aFree(self); }
/*========================================== * アイテムデータベースの読み込み *------------------------------------------ */ static int itemdb_readdb(void) { FILE *fp; char line[1024]; int ln=0,lines=0; int nameid,j; char *str[32],*p,*np; struct item_data *id; int i=0; char *filename[]={ "item_db.txt","item_db2.txt" }; for(i=0;i<2;i++){ sprintf(line, "%s/%s", db_path, filename[i]); fp=fopen(line,"r"); if(fp==NULL){ if(i>0) continue; ShowFatalError("can't read %s\n",line); exit(1); } lines=0; while(fgets(line,1020,fp)){ lines++; if(line[0]=='/' && line[1]=='/') continue; memset(str,0,sizeof(str)); for(j=0,np=p=line;j<19 && p;j++){ str[j]=p; p=strchr(p,','); if(p){ *p++=0; np=p; } } if(str[0]==NULL) continue; nameid=atoi(str[0]); if(nameid<=0) continue; if (j < 19) { //Crash-fix on broken item lines. [Skotlex] ShowWarning("Reading %s: Insufficient fields for item with id %d, skipping.\n", filename[i], nameid); continue; } ln++; //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Job Upper,Gender,Loc,wLV,eLV,refineable,View id=itemdb_load(nameid); strncpy(id->name, str[1], ITEM_NAME_LENGTH-1); strncpy(id->jname, str[2], ITEM_NAME_LENGTH-1); id->type=atoi(str[3]); if (id->type == IT_DELAYCONSUME) { //Items that are consumed upon target confirmation //(yggdrasil leaf, spells & pet lures) [Skotlex] id->type = IT_USABLE; id->flag.delay_consume=1; } { int buy = atoi(str[4]), sell = atoi(str[5]); // if buying price > selling price * 2 consider it valid and don't change it [celest] if (buy && sell && buy > sell*2){ id->value_buy = buy; id->value_sell = sell; } else { // buy≠sell*2 は item_value_db.txt で指定してください。 if (sell) { // sell値を優先とする id->value_buy = sell*2; id->value_sell = sell; } else { id->value_buy = buy; id->value_sell = buy/2; } } // check for bad prices that can possibly cause exploits if (id->value_buy*75/100 < id->value_sell*124/100) { ShowWarning ("Item %s [%d] buying:%d < selling:%d\n", id->name, id->nameid, id->value_buy*75/100, id->value_sell*124/100); } } id->weight=atoi(str[6]); id->atk=atoi(str[7]); id->def=atoi(str[8]); id->range=atoi(str[9]); id->slot=atoi(str[10]); if (id->slot > MAX_SLOTS) { ShowWarning("itemdb_readdb: Item %d (%s) specifies %d slots, but the server only supports up to %d\n", nameid, id->jname, id->slot, MAX_SLOTS); id->slot = MAX_SLOTS; } itemdb_jobid2mapid(id->class_base, (unsigned int)strtoul(str[11],NULL,0)); id->class_upper = atoi(str[12]); id->sex = atoi(str[13]); if(id->equip != atoi(str[14])){ id->equip=atoi(str[14]); } if (!id->equip && itemdb_isequip2(id)) { ShowWarning("Item %d (%s) is an equipment with no equip-field! Making it an etc item.\n", nameid, id->jname); id->type = 3; } id->wlv=atoi(str[15]); id->elv=atoi(str[16]); id->flag.no_refine = atoi(str[17])?0:1; //If the refine column is 1, no_refine is 0 id->look=atoi(str[18]); id->flag.available=1; id->flag.value_notdc=0; id->flag.value_notoc=0; id->view_id=0; id->sex = itemdb_gendercheck(id); //Apply gender filtering. if (id->script) { script_free_code(id->script); id->script=NULL; } if (id->equip_script) { script_free_code(id->equip_script); id->equip_script=NULL; } if (id->unequip_script) { script_free_code(id->unequip_script); id->unequip_script=NULL; } if((p=strchr(np,'{'))==NULL) continue; str[19] = p; //Script np = strchr(p,'}'); while (np && np[1] && np[1] != ',') np = strchr(np+1,'}'); //Jump close brackets until the next field is found. if (!np || !np[1]) { //Couldn't find the end of the script field. id->script = parse_script(str[19],filename[i],lines,0); continue; } np[1] = '\0'; //Set end of script id->script = parse_script(str[19],filename[i],lines,0); np+=2; //Skip to next field if(!np || (p=strchr(np,'{'))==NULL) continue; str[20] = p; //Equip Script np = strchr(p,'}'); while (np && np[1] && np[1] != ',') np = strchr(np+1,'}'); //Jump close brackets until the next field is found. if (!np || !np[1]) { //Couldn't find the end of the script field. id->equip_script = parse_script(str[20],filename[i],lines,0); continue; } np[1] = '\0'; //Set end of script id->equip_script = parse_script(str[20],filename[i],lines,0); np+=2; //Skip comma, to next field if(!np || (p=strchr(np,'{'))==NULL) continue; //Unequip script, last column. id->unequip_script = parse_script(p,filename[i],lines,0); } fclose(fp); if (ln > 0) { ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,filename[i]); } ln=0; // reset to 0 } return 0; }
/*====================================== * SQL *=================================== */ static int itemdb_read_sqldb(void) { unsigned short nameid; struct item_data *id; char script[65535 + 2 + 1]; // Maximum length of MySQL TEXT type (65535) + 2 bytes for curly brackets + 1 byte for terminator char *item_db_name[] = { item_db_db, item_db2_db }; long unsigned int ln = 0; int i; // ---------- for (i = 0; i < 2; i++) { sprintf(tmp_sql, "SELECT * FROM `%s`", item_db_name[i]); // Execute the query; if the query execution succeeded... if (mysql_query(&mmysql_handle, tmp_sql) == 0) { sql_res = mysql_store_result(&mmysql_handle); // If the storage of the query result succeeded... if (sql_res) { // Parse each row in the query result into sql_row while ((sql_row = mysql_fetch_row(sql_res))) { /*Table structure is: 00 id 01 name_english 02 name_japanese 03 type 04 price_buy 05 price_sell 06 weight 07 attack 08 defence 09 range 10 slots 11 equip_jobs 12 equip_upper 13 equip_genders 14 equip_locations 15 weapon_level 16 equip_level 17 refineable 18 view 19 script 20 equip_script 21 unequip_script */ nameid = atoi(sql_row[0]); // If the identifier is not within the valid range, process the next row if (nameid == 0) continue; ln++; // ---------- id = itemdb_load(nameid); strncpy(id->name, sql_row[1], ITEM_NAME_LENGTH-1); strncpy(id->jname, sql_row[2], ITEM_NAME_LENGTH-1); id->type = atoi(sql_row[3]); if (id->type == IT_DELAYCONSUME) { //Items that are consumed upon target confirmation //(yggdrasil leaf, spells & pet lures) [Skotlex] id->type = IT_USABLE; id->flag.delay_consume=1; } else //In case of an itemdb reload and the item type changed. id->flag.delay_consume=0; // If price_buy is not NULL and price_sell is not NULL... if ((sql_row[4] != NULL) && (sql_row[5] != NULL)) { id->value_buy = atoi(sql_row[4]); id->value_sell = atoi(sql_row[5]); } // If price_buy is not NULL and price_sell is NULL... else if ((sql_row[4] != NULL) && (sql_row[5] == NULL)) { id->value_buy = atoi(sql_row[4]); id->value_sell = atoi(sql_row[4]) / 2; } // If price_buy is NULL and price_sell is not NULL... else if ((sql_row[4] == NULL) && (sql_row[5] != NULL)) { id->value_buy = atoi(sql_row[5]) * 2; id->value_sell = atoi(sql_row[5]); } // If price_buy is NULL and price_sell is NULL... if ((sql_row[4] == NULL) && (sql_row[5] == NULL)) { id->value_buy = 0; id->value_sell = 0; } id->weight = atoi(sql_row[6]); id->atk = (sql_row[7] != NULL) ? atoi(sql_row[7]) : 0; id->def = (sql_row[8] != NULL) ? atoi(sql_row[8]) : 0; id->range = (sql_row[9] != NULL) ? atoi(sql_row[9]) : 0; id->slot = (sql_row[10] != NULL) ? atoi(sql_row[10]) : 0; if (id->slot > MAX_SLOTS) { ShowWarning("itemdb_read_sqldb: Item %d (%s) specifies %d slots, but the server only supports up to %d\n", nameid, id->jname, id->slot, MAX_SLOTS); id->slot = MAX_SLOTS; } itemdb_jobid2mapid(id->class_base, (sql_row[11] != NULL) ? (unsigned int)strtoul(sql_row[11], NULL, 0) : 0); id->class_upper= (sql_row[12] != NULL) ? atoi(sql_row[12]) : 0; id->sex = (sql_row[13] != NULL) ? atoi(sql_row[13]) : 0; id->equip = (sql_row[14] != NULL) ? atoi(sql_row[14]) : 0; if (!id->equip && itemdb_isequip2(id)) { ShowWarning("Item %d (%s) is an equipment with no equip-field! Making it an etc item.\n", nameid, id->jname); id->type = 3; } id->wlv = (sql_row[15] != NULL) ? atoi(sql_row[15]) : 0; id->elv = (sql_row[16] != NULL) ? atoi(sql_row[16]) : 0; id->flag.no_refine = (sql_row[17] == NULL || atoi(sql_row[17]) == 1)?0:1; id->look = (sql_row[18] != NULL) ? atoi(sql_row[18]) : 0; id->view_id = 0; id->sex = itemdb_gendercheck(id); //Apply gender filtering. // ---------- if (id->script) script_free_code(id->script); if (sql_row[19] != NULL) { if (sql_row[19][0] == '{') id->script = parse_script(sql_row[19],item_db_name[i], ln, 0); else { sprintf(script, "{%s}", sql_row[19]); id->script = parse_script(script, item_db_name[i], ln, 0); } } else id->script = NULL; if (id->equip_script) script_free_code(id->equip_script); if (sql_row[20] != NULL) { if (sql_row[20][0] == '{') id->equip_script = parse_script(sql_row[20], item_db_name[i], ln, 0); else { sprintf(script, "{%s}", sql_row[20]); id->equip_script = parse_script(script, item_db_name[i], ln, 0); } } else id->equip_script = NULL; if (id->unequip_script) script_free_code(id->unequip_script); if (sql_row[21] != NULL) { if (sql_row[21][0] == '{') id->unequip_script = parse_script(sql_row[21],item_db_name[i], ln, 0); else { sprintf(script, "{%s}", sql_row[21]); id->unequip_script = parse_script(script, item_db_name[i], ln, 0); } } else id->unequip_script = NULL; // ---------- id->flag.available = 1; id->flag.value_notdc = 0; id->flag.value_notoc = 0; } ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", ln, item_db_name[i]); ln = 0; } else { ShowSQL("DB error (%s) - %s\n",item_db_name[i], mysql_error(&mmysql_handle)); ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql); } // Free the query result mysql_free_result(sql_res); } else { ShowSQL("DB error (%s) - %s\n",item_db_name[i], mysql_error(&mmysql_handle)); ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql); } } return 0; }
/*========================================== * processes one itemdb entry *------------------------------------------*/ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt) { /* +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ | id | name_english | name_japanese | type | price_buy | price_sell | weight | attack | defence | range | slots | equip_jobs | equip_upper | equip_genders | equip_locations | weapon_level | equip_level | refineable | view | script | equip_script | unequip_script | +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ */ int nameid; struct item_data* id; nameid = atoi(str[0]); if( nameid <= 0 ) { ShowWarning("itemdb_parse_dbrow: Invalid id %d in line %d of \"%s\", skipping.\n", nameid, line, source); return false; } //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Job Upper,Gender,Loc,wLV,eLV,refineable,View id = itemdb_load(nameid); safestrncpy(id->name, str[1], sizeof(id->name)); safestrncpy(id->jname, str[2], sizeof(id->jname)); id->type = atoi(str[3]); if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_DELAYCONSUME && id->type < IT_THROWWEAPON ) || id->type >= IT_MAX ) {// catch invalid item types ShowWarning("itemdb_parse_dbrow: Invalid item type %d for item %d. IT_ETC will be used.\n", id->type, nameid); id->type = IT_ETC; } if (id->type == IT_DELAYCONSUME) { //Items that are consumed only after target confirmation id->type = IT_USABLE; id->flag.delay_consume = 1; } else //In case of an itemdb reload and the item type changed. id->flag.delay_consume = 0; //When a particular price is not given, we should base it off the other one //(it is important to make a distinction between 'no price' and 0z) if ( str[4][0] ) id->value_buy = atoi(str[4]); else id->value_buy = atoi(str[5]) * 2; if ( str[5][0] ) id->value_sell = atoi(str[5]); else id->value_sell = id->value_buy / 2; /* if ( !str[4][0] && !str[5][0]) { ShowWarning("itemdb_parse_dbrow: No buying/selling price defined for item %d (%s), using 20/10z\n", nameid, id->jname); id->value_buy = 20; id->value_sell = 10; } else */ if (id->value_buy/124. < id->value_sell/75.) ShowWarning("itemdb_parse_dbrow: Buying/Selling [%d/%d] price of item %d (%s) allows Zeny making exploit through buying/selling at discounted/overcharged prices!\n", id->value_buy, id->value_sell, nameid, id->jname); id->weight = atoi(str[6]); #if REMODE itemdb_re_split_atoi(str[7],&id->atk,&id->matk); #else id->atk = atoi(str[7]); #endif id->def = atoi(str[8]); id->range = atoi(str[9]); id->slot = atoi(str[10]); if (id->slot > MAX_SLOTS) { ShowWarning("itemdb_parse_dbrow: Item %d (%s) specifies %d slots, but the server only supports up to %d. Using %d slots.\n", nameid, id->jname, id->slot, MAX_SLOTS, MAX_SLOTS); id->slot = MAX_SLOTS; } itemdb_jobid2mapid(id->class_base, (unsigned int)strtoul(str[11],NULL,0)); id->class_upper = atoi(str[12]); id->sex = atoi(str[13]); id->equip = atoi(str[14]); if (!id->equip && itemdb_isequip2(id)) { ShowWarning("Item %d (%s) is an equipment with no equip-field! Making it an etc item.\n", nameid, id->jname); id->type = IT_ETC; } id->wlv = atoi(str[15]); id->elv = atoi(str[16]); id->flag.no_refine = atoi(str[17]) ? 0 : 1; //FIXME: verify this id->look = atoi(str[18]); id->flag.available = 1; id->view_id = 0; id->sex = itemdb_gendercheck(id); //Apply gender filtering. if (id->script) { script_free_code(id->script); id->script = NULL; } if (id->equip_script) { script_free_code(id->equip_script); id->equip_script = NULL; } if (id->unequip_script) { script_free_code(id->unequip_script); id->unequip_script = NULL; } if (*str[19]) id->script = parse_script(str[19], source, line, scriptopt); if (*str[20]) id->equip_script = parse_script(str[20], source, line, scriptopt); if (*str[21]) id->unequip_script = parse_script(str[21], source, line, scriptopt); return true; }
/*========================================== * アイテムデータベースの読み込み *------------------------------------------ */ static int itemdb_read_itemdb(void) { FILE *fp; char line[4096]; int ln=0,lines=0; int nameid,j; char *str[32],*p,*np; struct item_data *id; struct script_code *script = NULL; int i=0; const char *filename[] = { "db/item_db.txt", #ifdef PRE_RENEWAL "db/pre/item_db_pre.txt", #endif "db/addon/item_db_add.txt" }; const char *filename2; for(i = 0; i < sizeof(filename)/sizeof(filename[0]); i++) { fp = fopen(filename[i], "r"); if(fp == NULL) { if(i > 0) continue; printf("itemdb_read_itemdb: open [%s] failed !\n", filename[i]); continue; } lines=ln=0; while(fgets(line,sizeof(line),fp)){ lines++; if(line[0] == '\0' || line[0] == '\r' || line[0] == '\n') continue; if(line[0]=='/' && line[1]=='/') continue; memset(str,0,sizeof(str)); for(j=0,np=p=line;j<18 && p;j++){ str[j]=p; p=strchr(p,','); if(p){ *p++=0; np=p; } } if(str[0] == NULL) continue; nameid = atoi(str[0]); if(nameid <= 0) continue; ln++; //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Gender,Loc,wLV,eLV,View,Refine id = itemdb_search(nameid); strncpy(id->name,str[1],48); strncpy(id->jname,str[2],48); id->type = atoi(str[3]); // buy≠sell*2 は item_value_db.txt で指定してください。 if(atoi(str[5])) { // sell値を優先とする id->value_buy = atoi(str[5])*2; id->value_sell = atoi(str[5]); } else { id->value_buy = atoi(str[4]); id->value_sell = atoi(str[4])/2; } id->weight = atoi(str[6]); itemdb_split_atoi(str[7],&id->atk,&id->matk); itemdb_split_atoi(str[8],&id->def,&id->mdef); id->range = atoi(str[9]); id->slot = atoi(str[10]); if(id->slot < 0 || id->slot > 4) { id->slot = 0; } id->class_ = (unsigned int)strtoul(str[11],NULL,0); id->sex = atoi(str[12]); if(id->equip != atoi(str[13])) { id->equip = atoi(str[13]); } id->wlv = atoi(str[14]); if(id->wlv < 0 || id->wlv > MAX_WEAPON_LEVEL) { id->wlv = 0; } id->elv = atoi(str[15]); id->look = atoi(str[16]); id->refine = atoi(str[17]); id->flag.available = 1; id->flag.value_notdc = 0; id->flag.value_notoc = 0; id->flag.pet_egg = 0; id->flag.pet_acce = 0; id->view_id = 0; id->group = 0; id->delay = 0; id->upper = 0; id->zone = 0; // force \0 terminal id->name[47] = '\0'; id->jname[47] = '\0'; if((p = strchr(np, '{')) == NULL) continue; np = parse_script_line_end(p, filename[i], lines); if(!np) continue; if(id->use_script) { script_free_code(id->use_script); } script = parse_script(p, filename[i], lines); id->use_script = (script_is_error(script))? NULL: script; np++; if(*np != ',') continue; if((p = strchr(np + 1, '{')) == NULL) continue; np = parse_script_line_end(p, filename[i], lines); if(!np) continue; if(id->equip_script) { script_free_code(id->equip_script); } script = parse_script(p, filename[i], lines); id->equip_script = (script_is_error(script))? NULL: script; } fclose(fp); printf("read %s done (count=%d)\n",filename[i],ln); } filename2 = "db/item_db2.txt"; fp = fopen(filename2, "r"); if(fp == NULL) { printf("itemdb_read_itemdb: open [%s] failed !\n", filename2); return 0; } ln=0; while(fgets(line,sizeof(line),fp)){ if(line[0] == '\0' || line[0] == '\r' || line[0] == '\n') continue; if(line[0]=='/' && line[1]=='/') continue; memset(str,0,sizeof(str)); for(j=0,np=p=line;j<11 && p;j++){ str[j]=p; p=strchr(p,','); if(p){ *p++=0; np=p; } } if(str[0] == NULL) continue; nameid = atoi(str[0]); if(nameid <= 0 || !(id = itemdb_exists(nameid))) continue; ln++; id->upper = atoi(str[1]); id->zone = atoi(str[2]); id->flag.dropable = (atoi(str[3]) == 0)? 0: 1; id->flag.sellable = (atoi(str[4]) == 0)? 0: 1; id->flag.storageable = (atoi(str[5]) == 0)? 0: 1; id->flag.guildstorageable = (atoi(str[6]) == 0)? 0: 1; id->flag.cartable = (atoi(str[7]) == 0)? 0: 1; id->delay = atoi(str[8]); id->flag.buyingable = (atoi(str[9]) == 0)? 0: 1; id->flag.nonconsume = (atoi(str[10]) == 0)? 0: 1; } fclose(fp); printf("read %s (count=%d)\n", filename2, ln); filename2 = "db/item_arrowtype.txt", fp = fopen(filename2, "r"); if(fp == NULL){ printf("itemdb_read_itemdb: open [%s] failed !\n", filename2); return 0; } while(fgets(line,sizeof(line),fp)){ if(line[0] == '\0' || line[0] == '\r' || line[0] == '\n') continue; if(line[0]=='/' && line[1]=='/') continue; memset(str,0,sizeof(str)); for(j=0,np=p=line;j<4 && p;j++){ str[j]=p; p=strchr(p,','); if(p){ *p++=0; np=p; } } if(str[0] == NULL || str[3] == NULL) continue; nameid = atoi(str[0]); if(nameid <= 0 || !(id = itemdb_exists(nameid))) continue; //ID,Name,Jname,type id->arrow_type = atoi(str[3]); } fclose(fp); printf("read %s done\n", filename2); filename2 = "db/item_cardtype.txt"; fp = fopen(filename2, "r"); if(fp == NULL) { printf("itemdb_read_itemdb: open [%s] failed !\n", filename2); return 0; } while(fgets(line,sizeof(line),fp)){ if(line[0] == '\0' || line[0] == '\r' || line[0] == '\n') continue; if(line[0]=='/' && line[1]=='/') continue; memset(str,0,sizeof(str)); for(j=0,np=p=line;j<4 && p;j++){ str[j]=p; p=strchr(p,','); if(p){ *p++=0; np=p; } } if(str[0] == NULL || str[3] == NULL) continue; nameid = atoi(str[0]); if(nameid <= 0 || !(id = itemdb_exists(nameid))) continue; //ID,Name,Jname,type id->card_type = atoi(str[3]); } fclose(fp); printf("read %s done\n", filename2); filename2 = "db/item_group_db.txt"; fp = fopen(filename2, "r"); if(fp == NULL) { printf("itemdb_read_itemdb: open [%s] failed !\n", filename2); return 0; } while(fgets(line,sizeof(line),fp)) { int group_id; if(line[0] == '\0' || line[0] == '\r' || line[0] == '\n') continue; if(line[0]=='/' && line[1]=='/') continue; memset(str,0,sizeof(str)); for(j=0,np=p=line;j<4 && p;j++){ str[j]=p; p=strchr(p,','); if(p){ *p++=0; np=p; } } if(str[0] == NULL || str[3] == NULL) continue; nameid = atoi(str[0]); if(nameid <= 0 || !(id = itemdb_exists(nameid))) continue; //ID,Name,Jname,Group group_id = atoi(str[3]); if(group_id >= MAX_ITEMGROUP) { printf("item_group: invalid group id(%d) ID %d\n", group_id, nameid); continue; } id->group = group_id; } fclose(fp); printf("read %s done\n", filename2); return 0; }