Jump to content

rmon008

Members
  • Posts

    80
  • Joined

  • Last visited

Everything posted by rmon008

  1. i've checked the application.php but i can't see the Download Rules Features here's my application.php 'MenuItems' => array( 'Main Menu' => array( 'Home' => array('module' => 'main'), //'Forums' => array('exturl' => 'http://www.fluxro.com/community'), ),
  2. Guide Here: http://rathena.org/wiki/Custom_Items tried all (2^10) 1024 = Costume Upper headgear(2^11) 2048 = Costume Middle headgear(2^12) 4096 = Costume Lower headgear(2^13) 8192 = Costume Garment/Robe still same appearance
  3. why the item id is still unknown item(apple) [inside data folder] idnum2itemdisplaynametable.txt 30147#MVP Ticket# idnum2itemresnametable.txt 30147#¿µÁÖÀÇÅëÇàÁõ# idnum2itemdesctable.txt 30147# ^000088MVP Ticket^000000 # [inside System folder] iteminfo.lub [30147] = { unidentifiedDisplayName = "MVP Ticket", unidentifiedResourceName = "¿µÁÖÀÇÅëÇàÁõ", unidentifiedDescriptionName = { "^000088MVP Ticket^000000", "^000088[MVP Ladder Warper]^000000", }, identifiedDisplayName = "MVP Ticket", identifiedResourceName = "¿µÁÖÀÇÅëÇàÁõ", identifiedDescriptionName = { "^000088MVP Ticket^000000", "^000088[MVP Ladder Warper]^000000", }, slotCount = 0, ClassNum = 0 }, [ in my sql file ( item_db2 ) ] '30147', 'MVP Ticket', 'MVP Ticket', '3', '0', NULL, '0', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
  4. MGA BRO ! why the item id is still unknown item(apple) [inside data folder] idnum2itemdisplaynametable.txt 30147#MVP Ticket# idnum2itemresnametable.txt 30147#¿µÁÖÀÇÅëÇàÁõ# idnum2itemdesctable.txt 30147# ^000088MVP Ticket^000000 # [inside System folder] iteminfo.lub [30147] = { unidentifiedDisplayName = "MVP Ticket", unidentifiedResourceName = "¿µÁÖÀÇÅëÇàÁõ", unidentifiedDescriptionName = { "^000088MVP Ticket^000000", "^000088[MVP Ladder Warper]^000000", }, identifiedDisplayName = "MVP Ticket", identifiedResourceName = "¿µÁÖÀÇÅëÇàÁõ", identifiedDescriptionName = { "^000088MVP Ticket^000000", "^000088[MVP Ladder Warper]^000000", }, slotCount = 0, ClassNum = 0 }, [ in my sql file ( item_db2 ) ] '30147', 'MVP Ticket', 'MVP Ticket', '3', '0', NULL, '0', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
  5. I found exploit on refine_master https://github.com/rathena/rathena/blob/master/npc/re/merchants/ticket_refiner.txt if i already have +4 weapon then i use +9 refine ticket in refine master refine will be +13 any fix for it ?
  6. i want to delete for example all yggdrasil berry in all the monster ( all monster thats normally dropping yggdrasil berry will no longer drop ygg drasil berry ) any sql command i can use ?
  7. can this work with latest rathena git ? 12108?
  8. if( #HuntRoomDelay > gettimetick(2) ){ set .last,#HuntRoomDelay - gettimetick(2); set .@min, .last % ( 24 * 3600 ) % 3600 / (60); mes "Wait for ^FF0000"+.@min+" Minutes^000000."; close; // Adding X Minutes of Delay before can go in again. set .DelayMin,1080; how to change the minutes display , because it only until 59 then will go back to 59
  9. i tried to apply this patch on FRESH COPY rev12108 but still id on item_vending.txt is not showing anyone please ?
  10. if( #HuntRoomDelay > gettimetick(2) ){ set .last,#HuntRoomDelay - gettimetick(2); set .@min, .last % ( 24 * 3600 ) % 3600 / (60); mes "Wait for ^FF0000"+.@min+" Minutes^000000."; close; // Adding X Minutes of Delay before can go in again. set .DelayMin,1080; how to change the minutes display , because it only until 59 then will go back to 59
  11. i made a script for rune boots because i want this to release on my server but the problem is the matk +% is not working When pure STR is 90 or higher, ATK + 10. When pure STR is 120 or higher, ATK + 10 additionally. When pure INT is 90 or higher, MATK + 3%. When pure INT is 120 or higher, MATK + 2% additionally. bonus bUnbreakableShoes,0; if(readparam(bStr)>=90){ bonus bBaseAtk,10; }; if(readparam(bStr)>=120){ bonus bBaseAtk,10; }; if(readparam(bInt)>=90){ bonus bMatkRate,3; }; if(readparam(bInt)>=120){ bonus bMatkRate,2; }; anyone please ? thank you ...
  12. i found some error on my vending.c vending.c: In function \u2018vending_purchasereq\u2019: vending.c:313: warning: \u2018item_name\u2019 may be used uninitialized in this function here's my vending.c // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder #include "../common/nullpo.h" #include "../common/malloc.h" // aMalloc, aFree #include "../common/showmsg.h" // ShowInfo #include "../common/strlib.h" #include "../common/utils.h" #include "clif.h" #include "itemdb.h" #include "atcommand.h" #include "map.h" #include "path.h" #include "chrif.h" #include "vending.h" #include "pc.h" #include "npc.h" #include "skill.h" #include "battle.h" #include "log.h" #include <stdio.h> #include <stdlib.h> // atoi #include <string.h> /// Struct for vending entry of autotrader struct s_autotrade_entry { int cartinventory_id; uint16 amount; int price; uint16 index; }; /// Struct of autotrader struct s_autotrade { int account_id; int char_id; int vendor_id; int m; uint16 x, y; unsigned char sex; char title[MESSAGE_SIZE]; uint16 count; struct s_autotrade_entry **entries; struct map_session_data *sd; }; static int vending_nextid = 0; ///Vending_id counter static DBMap *vending_db; ///Db holder the vender : charid -> map_session_data //Autotrader static struct s_autotrade **autotraders; ///Autotraders Storage static uint16 autotrader_count; ///Autotrader count static void do_final_vending_autotrade(void); /** * Lookup to get the vending_db outside module * @return the vending_db */ DBMap * vending_getdb(){ return vending_db; } /** * Create an unique vending shop id. * @return the next vending_id */ static int vending_getuid(void){ return ++vending_nextid; } /** * Make a player close his shop * @param sd : player session */ void vending_closevending(struct map_session_data* sd) { nullpo_retv(sd); if( sd->state.vending ) { if( Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE vending_id = %d;", vending_items_db, sd->vender_id ) != SQL_SUCCESS || Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE `id` = %d;", vendings_db, sd->vender_id ) != SQL_SUCCESS ){ Sql_ShowDebug(mmysql_handle); } sd->state.vending = false; clif_closevendingboard(&sd->bl, 0); idb_remove(vending_db, sd->status.char_id); } } /** * Player request a shop's item list (a player shop) * @param sd : player requestion the list * @param id : vender account id (gid) */ void vending_vendinglistreq(struct map_session_data* sd, int id) { struct map_session_data* vsd; char output[1024]; // Extended Vending system [Lilith] nullpo_retv(sd); if( (vsd = map_id2sd(id)) == NULL ) return; if( !vsd->state.vending ) return; // not vending if (!pc_can_give_items(sd) || !pc_can_give_items(vsd)) //check if both GMs are allowed to trade { // GM is not allowed to trade clif_displaymessage(sd->fd, msg_txt(sd,246)); return; } /** * Extended Vending system [Lilith] **/ if(battle_config.extended_vending && vsd->vend_loot){ sprintf(output,msg_txt(sd,805),vsd->status.name, itemdb_jname(vsd->vend_loot)); clif_displaymessagecolor(sd,output,VEND_COLOR); } sd->vended_id = vsd->vender_id; // register vending uid clif_vendinglist(sd, id, vsd->vending); } /** * Purchase item(s) from a shop * @param sd : buyer player session * @param aid : account id of vender * @param uid : shop unique id * @param data : items data who would like to purchase \n * data := {<index>.w <amount>.w }[count] * @param count : number of different items he's trying to buy */ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const uint8* data, int count) { int i, j, cursor, w, new_ = 0, blank, vend_list[MAX_VENDING]; double z; struct s_vending vending[MAX_VENDING]; // against duplicate packets struct map_session_data* vsd = map_id2sd(aid); nullpo_retv(sd); if( vsd == NULL || !vsd->state.vending || vsd->bl.id == sd->bl.id ) return; // invalid shop if( vsd->vender_id != uid ) { // shop has changed clif_buyvending(sd, 0, 0, 6); // store information was incorrect return; } if( !searchstore_queryremote(sd, aid) && ( sd->bl.m != vsd->bl.m || !check_distance_bl(&sd->bl, &vsd->bl, AREA_SIZE) ) ) return; // shop too far away searchstore_clearremote(sd); if( count < 1 || count > MAX_VENDING || count > vsd->vend_num ) return; // invalid amount of purchased items blank = pc_inventoryblank(sd); //number of free cells in the buyer's inventory // duplicate item in vending to check hacker with multiple packets memcpy(&vending, &vsd->vending, sizeof(vsd->vending)); // copy vending list // some checks z = 0.; // zeny counter w = 0; // weight counter for( i = 0; i < count; i++ ) { short amount = *(uint16*)(data + 4*i + 0); short idx = *(uint16*)(data + 4*i + 2); idx -= 2; if( amount <= 0 ) return; // check of item index in the cart if( idx < 0 || idx >= MAX_CART ) return; ARR_FIND( 0, vsd->vend_num, j, vsd->vending[j].index == idx ); if( j == vsd->vend_num ) return; //picked non-existing item else vend_list[i] = j; z += ((double)vsd->vending[j].value * (double)amount); /** * Extended Vending system [Lilith] **/ if(battle_config.extended_vending){ if(vsd->vend_loot == ITEMID_ZENY || !vsd->vend_loot) { if( z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY ) { //clif_buyvending(sd, idx, amount, 1); // you don't have enough zeny return; } if( z + (double)vsd->status.zeny > (double)MAX_ZENY && !battle_config.vending_over_max ) { clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // too much zeny = overflow return; } } else if(vsd->vend_loot == ITEMID_CASH){ if(z > sd->cashPoints || z < 0. || z > (double)MAX_ZENY ) { clif_displaymessagecolor(sd,msg_txt(sd,800),VEND_COLOR); return; } } else { int k, loot_count = 0, vsd_w = 0; for(k = 0; k < MAX_INVENTORY; k++) if(sd->status.inventory[k].nameid == vsd->vend_loot) loot_count += sd->status.inventory[k].amount; if( z > loot_count || z < 0) { clif_displaymessagecolor(sd,msg_txt(sd,801),VEND_COLOR); return; } if(pc_inventoryblank(vsd) <= 0) { clif_displaymessagecolor(sd,msg_txt(sd,802),VEND_COLOR); return; } vsd_w += itemdb_weight(vsd->vend_loot) * (int)z; if(vsd_w + vsd->weight > vsd->max_weight) { clif_displaymessagecolor(sd,msg_txt(sd,803),VEND_COLOR); return; } } } else { if( z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY ) { clif_buyvending(sd, idx, amount, 1); // you don't have enough zeny return; } if( z + (double)vsd->status.zeny > (double)MAX_ZENY && !battle_config.vending_over_max ) { clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // too much zeny = overflow return; } } w += itemdb_weight(vsd->status.cart[idx].nameid) * amount; if( w + sd->weight > sd->max_weight ) { clif_buyvending(sd, idx, amount, 2); // you can not buy, because overweight return; } //Check to see if cart/vend info is in sync. if( vending[j].amount > vsd->status.cart[idx].amount ) vending[j].amount = vsd->status.cart[idx].amount; // if they try to add packets (example: get twice or more 2 apples if marchand has only 3 apples). // here, we check cumulative amounts if( vending[j].amount < amount ) { // send more quantity is not a hack (an other player can have buy items just before) clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // not enough quantity return; } vending[j].amount -= amount; switch( pc_checkadditem(sd, vsd->status.cart[idx].nameid, amount) ) { case CHKADDITEM_EXIST: break; //We'd add this item to the existing one (in buyers inventory) case CHKADDITEM_NEW: new_++; if (new_ > blank) return; //Buyer has no space in his inventory break; case CHKADDITEM_OVERAMOUNT: return; //too many items } } /** * Extended Vending system [Lilith] **/ if(battle_config.extended_vending){ if(vsd->vend_loot == ITEMID_ZENY || !vsd->vend_loot) { //Logs (V)ending Zeny [Lupus] log_zeny(vsd, LOG_TYPE_VENDING, sd, (int)z); pc_payzeny(sd, (int)z, LOG_TYPE_VENDING, vsd); if( battle_config.vending_tax ) z -= z * (battle_config.vending_tax/10000.); pc_getzeny(vsd, (int)z, LOG_TYPE_VENDING, sd); } else if(vsd->vend_loot == ITEMID_CASH) { pc_paycash(sd,(int)z,0,LOG_TYPE_VENDING); pc_getcash(vsd,(int)z,0,LOG_TYPE_VENDING); } else { for( i = 0; i < MAX_INVENTORY; i++) if(sd->status.inventory[i].nameid == vsd->vend_loot) { struct item *item; item = &sd->status.inventory[i]; pc_additem(vsd,item,(int)z, LOG_TYPE_VENDING); } pc_delitem(sd,pc_search_inventory(sd, vsd->vend_loot),(int)z,0,6, LOG_TYPE_VENDING); } }else{ pc_payzeny(sd, (int)z, LOG_TYPE_VENDING, vsd); if( battle_config.vending_tax ) z -= z * (battle_config.vending_tax/10000.); pc_getzeny(vsd, (int)z, LOG_TYPE_VENDING, sd); } for( i = 0; i < count; i++ ) { short amount = *(uint16*)(data + 4*i + 0); short idx = *(uint16*)(data + 4*i + 2); const char *item_name; double rev = 0.; idx -= 2; if(battle_config.ex_vending_info){ // Extended Vending system [Lilith] item_name = itemdb_jname(vsd->status.cart[idx].nameid); rev = ((double)vsd->vending[vend_list[i]].value * (double)amount); } // vending item pc_additem(sd, &vsd->status.cart[idx], amount, LOG_TYPE_VENDING); vsd->vending[vend_list[i]].amount -= amount; if( vsd->vending[vend_list[i]].amount ){ if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `amount` = %d WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_db, vsd->vending[vend_list[i]].amount, vsd->vender_id, vsd->status.cart[idx].id ) != SQL_SUCCESS ){ Sql_ShowDebug( mmysql_handle ); } }else{ if( Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_db, vsd->vender_id, vsd->status.cart[idx].id ) != SQL_SUCCESS ){ Sql_ShowDebug( mmysql_handle ); } } pc_cart_delitem(vsd, idx, amount, 0, LOG_TYPE_VENDING); clif_vendingreport(vsd, idx, amount); //print buyer's name if( battle_config.buyer_name ) { char temp[256]; if(battle_config.ex_vending_info) // Extended Vending system [Lilith] sprintf(temp, msg_txt(sd,807), sd->status.name, item_name, amount, (int)(rev -= rev * (battle_config.vending_tax/10000.)), vsd->vend_loot?itemdb_jname(vsd->vend_loot):"Zeny"); else sprintf(temp, msg_txt(sd,265), sd->status.name); clif_disp_onlyself(vsd,temp,strlen(temp)); } } if(battle_config.ex_vending_info){ // Extended Vending system [Lilith] char temp[256]; sprintf(temp, msg_txt(sd,808), sd->status.name, (int)z, vsd->vend_loot?itemdb_jname(vsd->vend_loot):"Zeny"); clif_disp_onlyself(vsd,temp,strlen(temp)); } // compact the vending list for( i = 0, cursor = 0; i < vsd->vend_num; i++ ) { if( vsd->vending[i].amount == 0 ) continue; if( cursor != i ) { // speedup vsd->vending[cursor].index = vsd->vending[i].index; vsd->vending[cursor].amount = vsd->vending[i].amount; vsd->vending[cursor].value = vsd->vending[i].value; } cursor++; } vsd->vend_num = cursor; //Always save BOTH: buyer and customer if( save_settings&2 ) { chrif_save(sd,0); chrif_save(vsd,0); } //check for @AUTOTRADE users [durf] if( vsd->state.autotrade ) { //see if there is anything left in the shop ARR_FIND( 0, vsd->vend_num, i, vsd->vending[i].amount > 0 ); if( i == vsd->vend_num ) { //Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex] vending_closevending(vsd); map_quit(vsd); //They have no reason to stay around anymore, do they? } } } /** * Player setup a new shop * @param sd : player opening the shop * @param message : shop title * @param data : itemlist data \n * data := {<index>.w <amount>.w <value>.l}[count] * @param count : number of different items */ bool vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count) { int i, j; int vending_skill_lvl; char message_sql[MESSAGE_SIZE*2]; nullpo_retr(false,sd); if ( pc_isdead(sd) || !sd->state.prevend || pc_istrading(sd)) return false; // can't open vendings lying dead || didn't use via the skill (wpe/hack) || can't have 2 shops at once vending_skill_lvl = pc_checkskill(sd, MC_VENDING); // skill level and cart check if( !vending_skill_lvl || !pc_iscarton(sd) ) { clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); return false; } // check number of items in shop if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl ) { // invalid item count clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); return false; } // filter out invalid items i = 0; for( j = 0; j < count; j++ ) { short index = *(uint16*)(data + 8*j + 0); short amount = *(uint16*)(data + 8*j + 2); unsigned int value = *(uint32*)(data + 8*j + 4); index -= 2; // offset adjustment (client says that the first cart position is 2) if( index < 0 || index >= MAX_CART // invalid position || pc_cartitem_amount(sd, index, amount) < 0 // invalid item or insufficient quantity //NOTE: official server does not do any of the following checks! || !sd->status.cart[index].identify // unidentified item || sd->status.cart[index].attribute == 1 // broken item || sd->status.cart[index].expire_time // It should not be in the cart but just in case || (sd->status.cart[index].bound && !pc_can_give_bounded_items(sd)) // can't trade account bound items and has no permission || !itemdb_cantrade(&sd->status.cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // untradeable item continue; sd->vending[i].index = index; sd->vending[i].amount = amount; sd->vending[i].value = min(value, (unsigned int)battle_config.vending_max_value); i++; // item successfully added } if( i != j ) clif_displaymessage (sd->fd, msg_txt(sd,266)); //"Some of your items cannot be vended and were removed from the shop." if( i == 0 ) { // no valid item found clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); // custom reply packet return false; } sd->state.prevend = 0; sd->state.vending = true; sd->vender_id = vending_getuid(); sd->vend_num = i; safestrncpy(sd->message, message, MESSAGE_SIZE); Sql_EscapeString( mmysql_handle, message_sql, sd->message ); if( Sql_Query( mmysql_handle, "INSERT INTO `%s`(`id`,`account_id`,`char_id`,`sex`,`map`,`x`,`y`,`title`,`autotrade`) VALUES( %d, %d, %d, '%c', '%s', %d, %d, '%s', %d );", vendings_db, sd->vender_id, sd->status.account_id, sd->status.char_id, sd->status.sex == 0 ? 'F' : 'M', map[sd->bl.m].name, sd->bl.x, sd->bl.y, message_sql, sd->state.autotrade ) != SQL_SUCCESS ){ Sql_ShowDebug(mmysql_handle); } for( i = 0; i < count; i++ ){ if( Sql_Query( mmysql_handle, "INSERT INTO `%s`(`vending_id`,`index`,`cartinventory_id`,`amount`,`price`) VALUES( %d, %d, %d, %d, %d );", vending_items_db, sd->vender_id, i, sd->status.cart[sd->vending[i].index].id, sd->vending[i].amount, sd->vending[i].value ) != SQL_SUCCESS ){ Sql_ShowDebug(mmysql_handle); } } clif_openvending(sd,sd->bl.id,sd->vending); clif_showvendingboard(&sd->bl,message,0); idb_put(vending_db, sd->status.char_id, sd); return true; } /** * Checks if an item is being sold in given player's vending. * @param sd : vender session (player) * @param nameid : item id * @return 0:not selling it, 1: yes */ bool vending_search(struct map_session_data* sd, unsigned short nameid) { int i; if( !sd->state.vending ) { // not vending return false; } ARR_FIND( 0, sd->vend_num, i, sd->status.cart[sd->vending[i].index].nameid == (short)nameid ); if( i == sd->vend_num ) { // not found return false; } return true; } /** * Searches for all items in a vending, that match given ids, price and possible cards. * @param sd : The vender session to search into * @param s : parameter of the search (see s_search_store_search) * @return Whether or not the search should be continued. */ bool vending_searchall(struct map_session_data* sd, const struct s_search_store_search* s) { int i, c, slot; unsigned int idx, cidx; struct item* it; if( !sd->state.vending ) // not vending return true; for( idx = 0; idx < s->item_count; idx++ ) { ARR_FIND( 0, sd->vend_num, i, sd->status.cart[sd->vending[i].index].nameid == (short)s->itemlist[idx] ); if( i == sd->vend_num ) {// not found continue; } it = &sd->status.cart[sd->vending[i].index]; if( s->min_price && s->min_price > sd->vending[i].value ) {// too low price continue; } if( s->max_price && s->max_price < sd->vending[i].value ) {// too high price continue; } if( s->card_count ) {// check cards if( itemdb_isspecial(it->card[0]) ) {// something, that is not a carded continue; } slot = itemdb_slot(it->nameid); for( c = 0; c < slot && it->card[c]; c ++ ) { ARR_FIND( 0, s->card_count, cidx, s->cardlist[cidx] == it->card[c] ); if( cidx != s->card_count ) {// found break; } } if( c == slot || !it->card[c] ) {// no card match continue; } } if( !searchstore_result(s->search_sd, sd->vender_id, sd->status.account_id, sd->message, it->nameid, sd->vending[i].amount, sd->vending[i].value, it->card, it->refine) ) {// result set full return false; } } return true; } /** Open vending for Autotrader * @param sd Player as autotrader */ void vending_reopen( struct map_session_data* sd ){ // Ready to open vending for this char if ( sd && autotrader_count > 0 && autotraders){ uint16 i; uint8 *data, *p; uint16 j, count; ARR_FIND(0,autotrader_count,i,autotraders[i] && autotraders[i]->char_id == sd->status.char_id); if (i >= autotrader_count) { return; } // Init vending data for autotrader CREATE(data, uint8, autotraders[i]->count * 8); for (j = 0, p = data, count = autotraders[i]->count; j < autotraders[i]->count; j++) { struct s_autotrade_entry *entry = autotraders[i]->entries[j]; uint16 *index = (uint16*)(p + 0); uint16 *amount = (uint16*)(p + 2); uint32 *value = (uint32*)(p + 4); // Find item position in cart ARR_FIND(0, MAX_CART, entry->index, sd->status.cart[entry->index].id == entry->cartinventory_id); if (entry->index == MAX_CART) { count--; continue; } *index = entry->index + 2; *amount = entry->amount; *value = entry->price; p += 8; } // Set him into a hacked prevend state sd->state.prevend = 1; // Open the vending again if( vending_openvending(sd, autotraders[i]->title, data, count) ){ // Set him to autotrade if (Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", vendings_db, sd->vender_id ) != SQL_SUCCESS ) { Sql_ShowDebug( mmysql_handle ); } // Make him look perfect unit_setdir(&sd->bl,battle_config.feature_autotrade_direction); if( battle_config.feature_autotrade_sit ) pc_setsit(sd); ShowInfo("Loaded autotrade vending data for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items at "CL_WHITE"%s (%d,%d)"CL_RESET"\n", sd->status.name,count,mapindex_id2name(sd->mapindex),sd->bl.x,sd->bl.y); }else{ // Failed to open the vending, set him offline ShowWarning("Failed to load autotrade vending data for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items\n", sd->status.name, count ); map_quit( sd ); } aFree(data); //If the last autotrade is loaded, clear autotraders [Cydh] if (i+1 >= autotrader_count) do_final_vending_autotrade(); } } /** * Initializing autotraders from table */ void do_init_vending_autotrade( void ) { if (battle_config.feature_autotrade) { uint16 i, items = 0; autotrader_count = 0; // Get autotrader from table. `map`, `x`, and `y`, aren't used here // Just read player that has data at vending_items [Cydh] if (Sql_Query(mmysql_handle, "SELECT `id`, `account_id`, `char_id`, `sex`, `title` " "FROM `%s` " "WHERE `autotrade` = 1 AND (SELECT COUNT(`vending_id`) FROM `%s` WHERE `vending_id` = `id`) > 0;", vendings_db, vending_items_db ) != SQL_SUCCESS ) { Sql_ShowDebug(mmysql_handle); return; } if( (autotrader_count = (uint32)Sql_NumRows(mmysql_handle)) > 0 ){ // Init autotraders CREATE(autotraders, struct s_autotrade *, autotrader_count); if (autotraders == NULL) { //This is shouldn't happen [Cydh] ShowError("Failed to initialize vending autotraders!\n"); Sql_FreeResult(mmysql_handle); return; } // Init each autotrader data i = 0; while (SQL_SUCCESS == Sql_NextRow(mmysql_handle) && i < autotrader_count) { size_t len; char* data; CREATE(autotraders[i], struct s_autotrade, 1); Sql_GetData(mmysql_handle, 0, &data, NULL); autotraders[i]->vendor_id = atoi(data); Sql_GetData(mmysql_handle, 1, &data, NULL); autotraders[i]->account_id = atoi(data); Sql_GetData(mmysql_handle, 2, &data, NULL); autotraders[i]->char_id = atoi(data); Sql_GetData(mmysql_handle, 3, &data, NULL); autotraders[i]->sex = (data[0] == 'F') ? 0 : 1; Sql_GetData(mmysql_handle, 4, &data, &len); safestrncpy(autotraders[i]->title, data, min(len + 1, MESSAGE_SIZE)); autotraders[i]->count = 0; // initialize player CREATE(autotraders[i]->sd, struct map_session_data, 1); pc_setnewpc(autotraders[i]->sd, autotraders[i]->account_id, autotraders[i]->char_id, 0, gettick(), autotraders[i]->sex, 0); autotraders[i]->sd->state.autotrade = 1; chrif_authreq(autotraders[i]->sd, true); i++; } Sql_FreeResult(mmysql_handle); //Init items on vending list each autotrader for (i = 0; i < autotrader_count; i++){ struct s_autotrade *at = NULL; uint16 j; if (autotraders[i] == NULL) continue; at = autotraders[i]; if (SQL_ERROR == Sql_Query(mmysql_handle, "SELECT `cartinventory_id`, `amount`, `price` " "FROM `%s` " "WHERE `vending_id` = %d " "ORDER BY `index` ASC;", vending_items_db, at->vendor_id ) ) { Sql_ShowDebug(mmysql_handle); continue; } if (!(at->count = (uint32)Sql_NumRows(mmysql_handle))) { map_quit(at->sd); continue; } //Init the list CREATE(at->entries, struct s_autotrade_entry *,at->count); //Add the item into list j = 0; while (SQL_SUCCESS == Sql_NextRow(mmysql_handle) && j < at->count) { char* data; CREATE(at->entries[j], struct s_autotrade_entry, 1); Sql_GetData(mmysql_handle, 0, &data, NULL); at->entries[j]->cartinventory_id = atoi(data); Sql_GetData(mmysql_handle, 1, &data, NULL); at->entries[j]->amount = atoi(data); Sql_GetData(mmysql_handle, 2, &data, NULL); at->entries[j]->price = atoi(data); j++; } items += j; Sql_FreeResult(mmysql_handle); } ShowStatus("Done loading '"CL_WHITE"%d"CL_RESET"' autotraders with '"CL_WHITE"%d"CL_RESET"' items.\n", autotrader_count, items); } } // Everything is loaded fine, their entries will be reinserted once they are loaded if (Sql_Query( mmysql_handle, "DELETE FROM `%s`;", vendings_db ) != SQL_SUCCESS || Sql_Query( mmysql_handle, "DELETE FROM `%s`;", vending_items_db ) != SQL_SUCCESS) { Sql_ShowDebug(mmysql_handle); } } /** * Clear all autotraders * @author [Cydh] */ void do_final_vending_autotrade(void) { if (autotrader_count && autotraders){ uint16 i = 0; while (i < autotrader_count) { //Free the autotrader if (autotraders[i] == NULL) continue; if (autotraders[i]->count) { uint16 j = 0; while (j < autotraders[i]->count) { //Free the autotrade entries if (autotraders[i]->entries == NULL) continue; if (autotraders[i]->entries[j]) aFree(autotraders[i]->entries[j]); j++; } aFree(autotraders[i]->entries); } aFree(autotraders[i]); i++; } aFree(autotraders); autotrader_count = 0; } } /** * Initialise the vending module * called in map::do_init */ void do_final_vending(void) { db_destroy(vending_db); do_final_vending_autotrade(); //Make sure everything is cleared [Cydh] } /** * Destory the vending module * called in map::do_final */ void do_init_vending(void) { vending_db = idb_alloc(DB_OPT_BASE); vending_nextid = 0; } I have all that code in my item_db.c but still the item id's in my item_vending.txt is not showing Here's my item_db.c // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder #include "../common/nullpo.h" #include "../common/malloc.h" #include "../common/random.h" #include "../common/showmsg.h" #include "../common/strlib.h" #include "../common/utils.h" #include "itemdb.h" #include "map.h" #include "battle.h" // struct battle_config #include "cashshop.h" #include "script.h" // item script processing #include "pc.h" // W_MUSICAL, W_WHIP #include <stdio.h> #include <stdlib.h> #include <string.h> static struct item_data* itemdb_array[MAX_ITEMDB]; static DBMap* itemdb_other;// int nameid -> struct item_data* static struct s_item_group_db itemgroup_db[MAX_ITEMGROUP]; struct item_data dummy_item; //This is the default dummy item used for non-existant items. [Skotlex] static DBMap *itemdb_combo; DBMap * itemdb_get_combodb(){ return itemdb_combo; } /** * Search for item name * name = item alias, so we should find items aliases first. if not found then look for "jname" (full name) * @see DBApply */ static int itemdb_searchname_sub(DBKey key, DBData *data, va_list ap) { struct item_data *item = db_data2ptr(data), **dst, **dst2; char *str; str=va_arg(ap,char *); dst=va_arg(ap,struct item_data **); dst2=va_arg(ap,struct item_data **); if(item == &dummy_item) return 0; //Absolute priority to Aegis code name. if (*dst != NULL) return 0; if( strcmpi(item->name,str)==0 ) *dst=item; //Second priority to Client displayed name. if (*dst2 != NULL) return 0; if( strcmpi(item->jname,str)==0 ) *dst2=item; return 0; } /*========================================== * Return item data from item name. (lookup) *------------------------------------------*/ struct item_data* itemdb_searchname(const char *str) { struct item_data* item; struct item_data* item2=NULL; int i; for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i ) { item = itemdb_array[i]; if( item == NULL ) continue; // Absolute priority to Aegis code name. if( strcasecmp(item->name,str) == 0 ) return item; //Second priority to Client displayed name. if( strcasecmp(item->jname,str) == 0 ) item2 = item; } item = NULL; itemdb_other->foreach(itemdb_other,itemdb_searchname_sub,str,&item,&item2); return item?item:item2; } /** * @see DBMatcher */ static int itemdb_searchname_array_sub(DBKey key, DBData data, va_list ap) { struct item_data *item = db_data2ptr(&data); char *str; str=va_arg(ap,char *); if (item == &dummy_item) return 1; //Invalid item. if(stristr(item->jname,str)) return 0; if(stristr(item->name,str)) return 0; return strcmpi(item->jname,str); } /*========================================== * Founds up to N matches. Returns number of matches [Skotlex] *------------------------------------------*/ int itemdb_searchname_array(struct item_data** data, int size, const char *str) { struct item_data* item; int i; int count=0; // Search in the array for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i ) { item = itemdb_array[i]; if( item == NULL ) continue; if( stristr(item->jname,str) || stristr(item->name,str) ) { if( count < size ) data[count] = item; ++count; } } // search in the db if( count < size ) { DBData *db_data[MAX_SEARCH]; int db_count = 0; size -= count; db_count = itemdb_other->getall(itemdb_other, (DBData**)&db_data, size, itemdb_searchname_array_sub, str); for (i = 0; i < db_count; i++) data[count++] = db_data2ptr(db_data[i]); count += db_count; } return count; } /** * Return a random item id from group. (takes into account % chance giving/tot group) * NOTE: Sub group 0 will be set to default 1, since 0 isn't random group * @param group_id * @param sub_group: Default is 1 * @return nameid */ unsigned short itemdb_searchrandomid(uint16 group_id, uint8 sub_group) { if (sub_group) sub_group -= 1; if (!group_id || group_id >= MAX_ITEMGROUP || !&itemgroup_db[group_id]) { ShowError("itemdb_searchrandomid: Invalid group id %d\n", group_id); return UNKNOWN_ITEM_ID; } if (sub_group > MAX_ITEMGROUP_RANDGROUP) { ShowError("itemdb_searchrandomid: Invalid sub_group %d\n", sub_group+1); return UNKNOWN_ITEM_ID; } if (&itemgroup_db[group_id].random[sub_group] && itemgroup_db[group_id].random[sub_group].data_qty) return itemgroup_db[group_id].random[sub_group].data[rand()%itemgroup_db[group_id].random[sub_group].data_qty].nameid; ShowError("itemdb_searchrandomid: No item entries for group id %d and sub group %d\n", group_id, sub_group+1); return UNKNOWN_ITEM_ID; } /** [Cydh] * Return a number of item's amount that will be obtained for 'getrandgroupitem id,1;' * NOTE: Sub group 0 will be set to default 1, since 0 isn't random group * @param group_id * @param sub_group * @param nameid: The target item will be found * @return amount */ uint16 itemdb_get_randgroupitem_count(uint16 group_id, uint8 sub_group, uint16 nameid) { uint16 i, amt = 1; if (sub_group) sub_group -= 1; if (!group_id || group_id >= MAX_ITEMGROUP || !&itemgroup_db[group_id]) { ShowError("itemdb_get_randgroupitem_count: Invalid group id %d\n", group_id); return amt; } if (sub_group > MAX_ITEMGROUP_RANDGROUP) { ShowError("itemdb_get_randgroupitem_count: Invalid sub_group id %d\n", group_id+1); return amt; } if (!(&itemgroup_db[group_id].random[sub_group]) || !itemgroup_db[group_id].random[sub_group].data_qty) return amt; ARR_FIND(0,itemgroup_db[group_id].random[sub_group].data_qty,i,itemgroup_db[group_id].random[sub_group].data[i].nameid == nameid); if (i < itemgroup_db[group_id].random[sub_group].data_qty) amt = itemgroup_db[group_id].random[sub_group].data[i].amount; return amt; } /** [Cydh] * Gives item(s) to the player based on item group * @param sd: Player that obtains item from item group * @param group_id: The group ID of item that obtained by player * @param *group: struct s_item_group from itemgroup_db[group_id].random[idx] or itemgroup_db[group_id].must[sub_group][idx] */ static void itemdb_pc_get_itemgroup_sub(struct map_session_data *sd, uint16 group_id, struct s_item_group *group) { uint16 i; struct item tmp; nullpo_retv(group); memset(&tmp,0,sizeof(tmp)); tmp.nameid = group->nameid; tmp.amount = (itemdb_isstackable(group->nameid)) ? group->amount : 1; tmp.bound = group->bound; tmp.identify = 1; tmp.expire_time = (group->duration) ? (unsigned int)(time(NULL) + group->duration*60) : 0; if (group->isNamed) { tmp.card[0] = itemdb_isequip(group->nameid) ? CARD0_FORGE : CARD0_CREATE; tmp.card[1] = 0; tmp.card[2] = GetWord(sd->status.char_id, 0); tmp.card[3] = GetWord(sd->status.char_id, 1); } //Do loop for non-stackable item for (i = 0; i < group->amount; i++) { int flag; if ((flag = pc_additem(sd,&tmp,tmp.amount,LOG_TYPE_SCRIPT))) clif_additem(sd,0,0,flag); else if (!flag && group->isAnnounced) { ///TODO: Move this broadcast to proper behavior (it should on at different packet) char output[CHAT_SIZE_MAX]; sprintf(output,msg_txt(NULL,717),sd->status.name,itemdb_jname(group->nameid),itemdb_jname(sd->itemid)); clif_broadcast(&sd->bl,output,strlen(output),0,ALL_CLIENT); //clif_broadcast_obtain_special_item(); } if (itemdb_isstackable(group->nameid)) break; } } /** [Cydh] * Find item(s) that will be obtained by player based on Item Group * @param group_id: The group ID that will be gained by player * @param nameid: The item that trigger this item group * @return val: 0:success, 1:no sd, 2:invalid item group */ char itemdb_pc_get_itemgroup(uint16 group_id, struct map_session_data *sd) { uint16 i = 0; nullpo_retr(1,sd); if (!group_id || group_id >= MAX_ITEMGROUP) { ShowError("itemdb_pc_get_itemgroup: Invalid group id '%d' specified.",group_id); return 2; } //Get the 'must' item(s) if (itemgroup_db[group_id].must_qty) for (i = 0; i < itemgroup_db[group_id].must_qty; i++) if (&itemgroup_db[group_id].must[i] && itemdb_exists(itemgroup_db[group_id].must[i].nameid)) itemdb_pc_get_itemgroup_sub(sd,group_id,&itemgroup_db[group_id].must[i]); //Get the 'random' item each random group for (i = 0; i < MAX_ITEMGROUP_RANDGROUP; i++) { uint16 rand; if (!(&itemgroup_db[group_id].random[i]) || !itemgroup_db[group_id].random[i].data_qty) //Skip empty random group continue; rand = rnd()%itemgroup_db[group_id].random[i].data_qty; //Woops, why is the data empty? Every check should be done when load the item group! So this is bad day for the player if (!&itemgroup_db[group_id].random[i].data[rand] || !itemgroup_db[group_id].random[i].data[rand].nameid) { continue; } if (itemdb_exists(itemgroup_db[group_id].random[i].data[rand].nameid)) itemdb_pc_get_itemgroup_sub(sd,group_id,&itemgroup_db[group_id].random[i].data[rand]); } return 0; } /*========================================== * Calculates total item-group related bonuses for the given item *------------------------------------------*/ int itemdb_group_bonus(struct map_session_data* sd, int itemid) { int bonus = 0, i, j; for (i=0; i < MAX_ITEMGROUP; i++) { if (!sd->itemgrouphealrate[i]) continue; ARR_FIND(0,itemgroup_db[i].random[0].data_qty,j,itemgroup_db[i].random[0].data[j].nameid == itemid ); if( j < itemgroup_db[i].random[0].data_qty ) bonus += sd->itemgrouphealrate[i]; } return bonus; } /// Searches for the item_data. /// Returns the item_data or NULL if it does not exist. struct item_data* itemdb_exists(int nameid) { struct item_data* item; if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) ) return itemdb_array[nameid]; item = (struct item_data*)idb_get(itemdb_other,nameid); if( item == &dummy_item ) return NULL;// dummy data, doesn't exist return item; } /// Returns name type of ammunition [Cydh] const char *itemdb_typename_ammo (enum e_item_ammo ammo) { switch (ammo) { case AMMO_ARROW: return "Arrow"; case AMMO_THROWABLE_DAGGER: return "Throwable Dagger"; case AMMO_BULLET: return "Bullet"; case AMMO_SHELL: return "Shell"; case AMMO_GRENADE: return "Grenade"; case AMMO_SHURIKEN: return "Shuriken"; case AMMO_KUNAI: return "Kunai"; case AMMO_CANNONBALL: return "Cannonball"; case AMMO_THROWABLE_ITEM: return "Throwable Item/Sling Item"; } return "Ammunition"; } /// Returns human readable name for given item type. /// @param type Type id to retrieve name for ( IT_* ). const char* itemdb_typename(enum item_types type) { switch(type) { case IT_HEALING: return "Potion/Food"; case IT_USABLE: return "Usable"; case IT_ETC: return "Etc."; case IT_WEAPON: return "Weapon"; case IT_ARMOR: return "Armor"; case IT_CARD: return "Card"; case IT_PETEGG: return "Pet Egg"; case IT_PETARMOR: return "Pet Accessory"; case IT_AMMO: return "Arrow/Ammunition"; case IT_DELAYCONSUME: return "Delay-Consume Usable"; case IT_SHADOWGEAR: return "Shadow Equipment"; case IT_CASH: return "Cash Usable"; } return "Unknown Type"; } /*========================================== * Converts the jobid from the format in itemdb * to the format used by the map server. [Skotlex] *------------------------------------------*/ static void itemdb_jobid2mapid(unsigned int *bclass, unsigned int jobmask) { int i; bclass[0]= bclass[1]= bclass[2]= 0; //Base classes if (jobmask & 1<<JOB_NOVICE) { //Both Novice/Super-Novice are counted with the same ID bclass[0] |= 1<<MAPID_NOVICE; bclass[1] |= 1<<MAPID_NOVICE; } for (i = JOB_NOVICE+1; i <= JOB_THIEF; i++) { if (jobmask & 1<<i) bclass[0] |= 1<<(MAPID_NOVICE+i); } //2-1 classes if (jobmask & 1<<JOB_KNIGHT) bclass[1] |= 1<<MAPID_SWORDMAN; if (jobmask & 1<<JOB_PRIEST) bclass[1] |= 1<<MAPID_ACOLYTE; if (jobmask & 1<<JOB_WIZARD) bclass[1] |= 1<<MAPID_MAGE; if (jobmask & 1<<JOB_BLACKSMITH) bclass[1] |= 1<<MAPID_MERCHANT; if (jobmask & 1<<JOB_HUNTER) bclass[1] |= 1<<MAPID_ARCHER; if (jobmask & 1<<JOB_ASSASSIN) bclass[1] |= 1<<MAPID_THIEF; //2-2 classes if (jobmask & 1<<JOB_CRUSADER) bclass[2] |= 1<<MAPID_SWORDMAN; if (jobmask & 1<<JOB_MONK) bclass[2] |= 1<<MAPID_ACOLYTE; if (jobmask & 1<<JOB_SAGE) bclass[2] |= 1<<MAPID_MAGE; if (jobmask & 1<<JOB_ALCHEMIST) bclass[2] |= 1<<MAPID_MERCHANT; if (jobmask & 1<<JOB_BARD) bclass[2] |= 1<<MAPID_ARCHER; // Bard/Dancer share the same slot now. // if (jobmask & 1<<JOB_DANCER) // bclass[2] |= 1<<MAPID_ARCHER; if (jobmask & 1<<JOB_ROGUE) bclass[2] |= 1<<MAPID_THIEF; //Special classes that don't fit above. if (jobmask & 1<<21) //Taekwon boy bclass[0] |= 1<<MAPID_TAEKWON; if (jobmask & 1<<22) //Star Gladiator bclass[1] |= 1<<MAPID_TAEKWON; if (jobmask & 1<<23) //Soul Linker bclass[2] |= 1<<MAPID_TAEKWON; if (jobmask & 1<<JOB_GUNSLINGER) bclass[0] |= 1<<MAPID_GUNSLINGER; if (jobmask & 1<<JOB_NINJA) { //Kagerou/Oboro jobs can equip Ninja equips. [Rytech] bclass[0] |= 1<<MAPID_NINJA; bclass[1] |= 1<<MAPID_NINJA; } if (jobmask & 1<<26) //Bongun/Munak bclass[0] |= 1<<MAPID_GANGSI; if (jobmask & 1<<27) //Death Knight bclass[1] |= 1<<MAPID_GANGSI; if (jobmask & 1<<28) //Dark Collector bclass[2] |= 1<<MAPID_GANGSI; if (jobmask & 1<<29) //Kagerou / Oboro bclass[1] |= 1<<MAPID_NINJA; if (jobmask & 1<<30) //Rebellion bclass[1] |= 1<<MAPID_GUNSLINGER; } static void create_dummy_data(void) { memset(&dummy_item, 0, sizeof(struct item_data)); dummy_item.nameid=500; dummy_item.weight=1; dummy_item.value_sell=1; dummy_item.type=IT_ETC; //Etc item safestrncpy(dummy_item.name,"UNKNOWN_ITEM",sizeof(dummy_item.name)); safestrncpy(dummy_item.jname,"UNKNOWN_ITEM",sizeof(dummy_item.jname)); dummy_item.view_id=UNKNOWN_ITEM_ID; } static struct item_data* create_item_data(int nameid) { struct item_data *id; CREATE(id, struct item_data, 1); id->nameid = nameid; id->weight = 1; id->type = IT_ETC; return id; } /*========================================== * Loads (and creates if not found) an item from the db. *------------------------------------------*/ struct item_data* itemdb_load(int nameid) { struct item_data *id; if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) ) { id = itemdb_array[nameid]; if( id == NULL || id == &dummy_item ) id = itemdb_array[nameid] = create_item_data(nameid); return id; } id = (struct item_data*)idb_get(itemdb_other, nameid); if( id == NULL || id == &dummy_item ) { id = create_item_data(nameid); idb_put(itemdb_other, nameid, id); } return id; } /*========================================== * Loads an item from the db. If not found, it will return the dummy item. *------------------------------------------*/ struct item_data* itemdb_search(int nameid) { struct item_data* id; if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) ) id = itemdb_array[nameid]; else id = (struct item_data*)idb_get(itemdb_other, nameid); if( id == NULL ) { ShowWarning("itemdb_search: Item ID %d does not exists in the item_db. Using dummy data.\n", nameid); id = &dummy_item; dummy_item.nameid = nameid; } return id; } /*========================================== * Returns if given item is a player-equippable piece. *------------------------------------------*/ bool itemdb_isequip(int nameid) { int type=itemdb_type(nameid); switch (type) { case IT_WEAPON: case IT_ARMOR: case IT_AMMO: case IT_SHADOWGEAR: return true; default: return false; } } /*========================================== * Alternate version of itemdb_isequip *------------------------------------------*/ bool itemdb_isequip2(struct item_data *data) { nullpo_ret(data); switch(data->type) { case IT_WEAPON: case IT_ARMOR: case IT_AMMO: case IT_SHADOWGEAR: return true; default: return false; } } /*========================================== * Returns if given item's type is stackable. *------------------------------------------*/ bool itemdb_isstackable(uint16 nameid) { uint8 type = itemdb_type(nameid); switch(type) { case IT_WEAPON: case IT_ARMOR: case IT_PETEGG: case IT_PETARMOR: case IT_SHADOWGEAR: return false; default: return true; } } /*========================================== * Alternate version of itemdb_isstackable *------------------------------------------*/ bool itemdb_isstackable2(struct item_data *data) { nullpo_ret(data); switch(data->type) { case IT_WEAPON: case IT_ARMOR: case IT_PETEGG: case IT_PETARMOR: case IT_SHADOWGEAR: return false; default: return true; } } /*========================================== * Trade Restriction functions [Skotlex] *------------------------------------------*/ int itemdb_isdropable_sub(struct item_data *item, int gmlv, int unused) { return (item && (!(item->flag.trade_restriction&1) || gmlv >= item->gm_lv_trade_override)); } int itemdb_cantrade_sub(struct item_data* item, int gmlv, int gmlv2) { return (item && (!(item->flag.trade_restriction&2) || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override)); } int itemdb_canpartnertrade_sub(struct item_data* item, int gmlv, int gmlv2) { return (item && (item->flag.trade_restriction&4 || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override)); } int itemdb_cansell_sub(struct item_data* item, int gmlv, int unused) { return (item && (!(item->flag.trade_restriction&8) || gmlv >= item->gm_lv_trade_override)); } int itemdb_cancartstore_sub(struct item_data* item, int gmlv, int unused) { return (item && (!(item->flag.trade_restriction&16) || gmlv >= item->gm_lv_trade_override)); } int itemdb_canstore_sub(struct item_data* item, int gmlv, int unused) { return (item && (!(item->flag.trade_restriction&32) || gmlv >= item->gm_lv_trade_override)); } int itemdb_canguildstore_sub(struct item_data* item, int gmlv, int unused) { return (item && (!(item->flag.trade_restriction&64) || gmlv >= item->gm_lv_trade_override)); } int itemdb_canmail_sub(struct item_data* item, int gmlv, int unused) { return (item && (!(item->flag.trade_restriction&128) || gmlv >= item->gm_lv_trade_override)); } int itemdb_canauction_sub(struct item_data* item, int gmlv, int unused) { return (item && (!(item->flag.trade_restriction&256) || gmlv >= item->gm_lv_trade_override)); } bool itemdb_isrestricted(struct item* item, int gmlv, int gmlv2, int (*func)(struct item_data*, int, int)) { struct item_data* item_data = itemdb_search(item->nameid); int i; if (!func(item_data, gmlv, gmlv2)) return false; if(item_data->slot == 0 || itemdb_isspecial(item->card[0])) return true; for(i = 0; i < item_data->slot; i++) { if (!item->card[i]) continue; if (!func(itemdb_search(item->card[i]), gmlv, gmlv2)) return false; } return true; } /** Specifies if item-type should drop unidentified. * @param nameid ID of item */ char itemdb_isidentified(int nameid) { int type=itemdb_type(nameid); switch (type) { case IT_WEAPON: case IT_ARMOR: case IT_PETARMOR: case IT_SHADOWGEAR: return 0; default: return 1; } } /** Search by name for the override flags available items (Give item another sprite) * Structure: <nameid>,<sprite> */ static bool itemdb_read_itemavail(char* str[], int columns, int current) { int nameid, sprite; struct item_data *id; nameid = atoi(str[0]); if( ( id = itemdb_exists(nameid) ) == NULL ) { ShowWarning("itemdb_read_itemavail: Invalid item id %d.\n", nameid); return false; } sprite = atoi(str[1]); if( sprite > 0 ) { id->flag.available = 1; id->view_id = sprite; } else { id->flag.available = 0; } return true; } /** Read item group data * Structure: GroupID,ItemID,Rate{,Amount,isMust,isAnnounced,Duration,isNamed,isBound} */ static void itemdb_read_itemgroup_sub(const char* filename, bool silent) { FILE *fp; int ln=0, entries=0; char line[1024]; if ((fp=fopen(filename,"r")) == NULL) { if(silent == 0) ShowError("Can't read %s\n", filename); return; } while (fgets(line,sizeof(line),fp)) { uint16 nameid; int j, group_id, prob = 1, amt = 1, rand_group = 1, announced = 0, dur = 0, named = 0, bound = 0; char *str[3], *p; bool found = false; struct s_item_group_random *random; ln++; if (line[0] == '/' && line[1] == '/') continue; if (strstr(line,"import")) { char w1[1024], w2[1024]; if (sscanf(line,"%[^:]: %[^\r\n]",w1,w2) == 2 && strcmpi(w1,"import") == 0) { itemdb_read_itemgroup_sub(w2, 0); continue; } } memset(str,0,sizeof(str)); for (j = 0, p = line; j < 3 && p;j++) { str[j] = p; if (j == 2) sscanf(str[j],"%d,%d,%d,%d,%d,%d,%d",&prob,&amt,&rand_group,&announced,&dur,&named,&bound); p = strchr(p,','); if (p) *p++=0; } if (str[0] == NULL) continue; if (j < 3) { if (j > 1) //Or else it barks on blank lines... ShowWarning("itemdb_read_itemgroup: Insufficient fields for entry at %s:%d\n", filename, ln); continue; } //Checking group_id trim(str[0]); if (ISDIGIT(str[0][0])) group_id = atoi(str[0]); else //Try reads group id by const script_get_constant(trim(str[0]),&group_id); if (!group_id || group_id >= MAX_ITEMGROUP) { ShowWarning("itemdb_read_itemgroup: Cannot save '%s' because invalid group id or group db is overflow in %s:%d\n", str[0], filename, ln); continue; } //Checking sub group if (rand_group < 0 || rand_group > MAX_ITEMGROUP_RANDGROUP) { ShowWarning("itemdb_read_itemgroup: Invalid sub group %d for group '%s' in %s:%d\n", rand_group, str[0], filename, ln); continue; } if (rand_group && prob < 1) { ShowWarning("itemdb_read_itemgroup: Invalid probaility for group '%s' sub: %d in %s:%d\n", str[0], rand_group, filename, ln); continue; } //Checking item trim(str[1]); if (ISDIGIT(str[1][0]) && itemdb_exists((nameid = atoi(str[1])))) found = true; else if (itemdb_searchname(str[1])) { found = true; nameid = itemdb_searchname(str[1])->nameid; } if (!found) { ShowWarning("itemdb_read_itemgroup: Non-existant item '%s' in %s:%d\n", str[1], filename, ln); continue; } amt = cap_value(amt,1,MAX_AMOUNT); dur = cap_value(dur,0,UINT16_MAX); bound = cap_value(bound,0,4); //Must item (rand_group == 0), place it here if (!rand_group) { uint16 idx = itemgroup_db[group_id].must_qty; if (!idx) CREATE(itemgroup_db[group_id].must,struct s_item_group,1); else RECREATE(itemgroup_db[group_id].must,struct s_item_group,idx+1); itemgroup_db[group_id].must[idx].nameid = nameid; itemgroup_db[group_id].must[idx].amount = amt; itemgroup_db[group_id].must[idx].isAnnounced = announced; itemgroup_db[group_id].must[idx].duration = dur; itemgroup_db[group_id].must[idx].isNamed = named; itemgroup_db[group_id].must[idx].bound = bound; itemgroup_db[group_id].must_qty++; //If 'must' item isn't set as random item, skip the next process if (!prob) { entries++; continue; } rand_group = 0; } else rand_group -= 1; random = &itemgroup_db[group_id].random[rand_group]; //Check, if the entry for this random group already created or not if (!random->data_qty) { CREATE(random->data,struct s_item_group,prob); random->data_qty = 0; } else RECREATE(random->data,struct s_item_group,random->data_qty+prob); //Now put the entry to its rand_group for (j = random->data_qty; j < random->data_qty+prob; j++) { random->data[j].nameid = nameid; random->data[j].amount = amt; random->data[j].isAnnounced = announced; random->data[j].duration = dur; random->data[j].isNamed = named; random->data[j].bound = bound; } random->data_qty += prob; entries++; } fclose(fp); ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, filename); return; } static void itemdb_read_itemgroup(const char* basedir, bool silent) { char filepath[256]; sprintf(filepath, "%s/%s", basedir, "item_group_db.txt"); itemdb_read_itemgroup_sub(filepath, silent); return; } /** Read item forbidden by mapflag (can't equip item) * Structure: <nameid>,<mode> */ static bool itemdb_read_noequip(char* str[], int columns, int current) { int nameid; struct item_data *id; nameid = atoi(str[0]); if( ( id = itemdb_exists(nameid) ) == NULL ) { ShowWarning("itemdb_read_noequip: Invalid item id %d.\n", nameid); return false; } id->flag.no_equip |= atoi(str[1]); return true; } /** Reads item trade restrictions [Skotlex] * Structure: <nameid>,<mask>,<gm level> */ static bool itemdb_read_itemtrade(char* str[], int columns, int current) { int nameid, flag, gmlv; struct item_data *id; nameid = atoi(str[0]); if( ( id = itemdb_exists(nameid) ) == NULL ) { //ShowWarning("itemdb_read_itemtrade: Invalid item id %d.\n", nameid); //return false; // FIXME: item_trade.txt contains items, which are commented in item database. return true; } flag = atoi(str[1]); gmlv = atoi(str[2]); if( flag < 0 || flag > 511 ) {//Check range ShowWarning("itemdb_read_itemtrade: Invalid trading mask %d for item id %d.\n", flag, nameid); return false; } if( gmlv < 1 ) { ShowWarning("itemdb_read_itemtrade: Invalid override GM level %d for item id %d.\n", gmlv, nameid); return false; } id->flag.trade_restriction = flag; id->gm_lv_trade_override = gmlv; return true; } /** Reads item delay amounts [Paradox924X] * Structure: <nameid>,<delay> */ static bool itemdb_read_itemdelay(char* str[], int columns, int current) { int nameid, delay; struct item_data *id; nameid = atoi(str[0]); if( ( id = itemdb_exists(nameid) ) == NULL ) { ShowWarning("itemdb_read_itemdelay: Invalid item id %d.\n", nameid); return false; } delay = atoi(str[1]); if( delay < 0 ) { ShowWarning("itemdb_read_itemdelay: Invalid delay %d for item id %d.\n", id->delay, nameid); return false; } id->delay = delay; return true; } /** Reads item stacking restrictions * Structure: <item id>,<stack limit amount>,<type> */ static bool itemdb_read_stack(char* fields[], int columns, int current) { unsigned short nameid, amount; unsigned int type; struct item_data* id; nameid = (unsigned short)strtoul(fields[0], NULL, 10); if( ( id = itemdb_exists(nameid) ) == NULL ) { ShowWarning("itemdb_read_stack: Unknown item id '%hu'.\n", nameid); return false; } if( !itemdb_isstackable2(id) ) { ShowWarning("itemdb_read_stack: Item id '%hu' is not stackable.\n", nameid); return false; } amount = (unsigned short)strtoul(fields[1], NULL, 10); type = strtoul(fields[2], NULL, 10); if( !amount ) {// ignore return true; } id->stack.amount = amount; id->stack.inventory = (type&1)!=0; id->stack.cart = (type&2)!=0; id->stack.storage = (type&4)!=0; id->stack.guildstorage = (type&8)!=0; return true; } /** Reads items allowed to be sold in buying stores * <nameid> */ static bool itemdb_read_buyingstore(char* fields[], int columns, int current) { int nameid; struct item_data* id; nameid = atoi(fields[0]); if( ( id = itemdb_exists(nameid) ) == NULL ) { ShowWarning("itemdb_read_buyingstore: Invalid item id %d.\n", nameid); return false; } if( !itemdb_isstackable2(id) ) { ShowWarning("itemdb_read_buyingstore: Non-stackable item id %d cannot be enabled for buying store.\n", nameid); return false; } id->flag.buyingstore = true; return true; } /** Item usage restriction (item_nouse.txt) * <nameid>,<flag>,<override> */ static bool itemdb_read_nouse(char* fields[], int columns, int current) { int nameid, flag, override; struct item_data* id; nameid = atoi(fields[0]); if( ( id = itemdb_exists(nameid) ) == NULL ) { ShowWarning("itemdb_read_nouse: Invalid item id %d.\n", nameid); return false; } flag = atoi(fields[1]); override = atoi(fields[2]); id->item_usage.flag = flag; id->item_usage.override = override; return true; } /** * @return: amount of retrieved entries. **/ static int itemdb_combo_split_atoi (char *str, int *val) { int i; for (i=0; i<MAX_ITEMS_PER_COMBO; i++) { if (!str) break; val[i] = atoi(str); str = strchr(str,':'); if (str) *str++=0; } if( i == 0 ) //No data found. return 0; return i; } /** * <combo{:combo{:combo:{..}}}>,<{ script }> **/ static void itemdb_read_combos(const char* basedir, bool silent) { uint32 lines = 0, count = 0; char line[1024]; char path[256]; FILE* fp; sprintf(path, "%s/%s", basedir, "item_combo_db.txt"); if ((fp = fopen(path, "r")) == NULL) { if(silent==0) ShowError("itemdb_read_combos: File not found \"%s\".\n", path); return; } // process rows one by one while(fgets(line, sizeof(line), fp)) { char *str[2], *p; lines++; if (line[0] == '/' && line[1] == '/') continue; memset(str, 0, sizeof(str)); p = line; p = trim(p); if (*p == '\0') continue;// empty line if (!strchr(p,',')) { /* is there even a single column? */ ShowError("itemdb_read_combos: Insufficient columns in line %d of \"%s\", skipping.\n", lines, path); continue; } str[0] = p; p = strchr(p,','); *p = '\0'; p++; str[1] = p; p = strchr(p,','); p++; if (str[1][0] != '{') { ShowError("itemdb_read_combos(#1): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path); continue; } /* no ending key anywhere (missing \}\) */ if ( str[1][strlen(str[1])-1] != '}' ) { ShowError("itemdb_read_combos(#2): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path); continue; } else { int items[MAX_ITEMS_PER_COMBO]; int v = 0, retcount = 0; struct item_data * id = NULL; int idx = 0; if((retcount = itemdb_combo_split_atoi(str[0], items)) < 2) { ShowError("itemdb_read_combos: line %d of \"%s\" doesn't have enough items to make for a combo (min:2), skipping.\n", lines, path); continue; } /* validate */ for(v = 0; v < retcount; v++) { if( !itemdb_exists(items[v]) ) { ShowError("itemdb_read_combos: line %d of \"%s\" contains unknown item ID %d, skipping.\n", lines, path,items[v]); break; } } /* failed at some item */ if( v < retcount ) continue; id = itemdb_exists(items[0]); idx = id->combos_count; /* first entry, create */ if( id->combos == NULL ) { CREATE(id->combos, struct item_combo*, 1); id->combos_count = 1; } else { RECREATE(id->combos, struct item_combo*, ++id->combos_count); } CREATE(id->combos[idx],struct item_combo,1); id->combos[idx]->nameid = aMalloc( retcount * sizeof(unsigned short) ); id->combos[idx]->count = retcount; id->combos[idx]->script = parse_script(str[1], path, lines, 0); id->combos[idx]->id = count; id->combos[idx]->isRef = false; /* populate ->nameid field */ for( v = 0; v < retcount; v++ ) { id->combos[idx]->nameid[v] = items[v]; } /* populate the children to refer to this combo */ for( v = 1; v < retcount; v++ ) { struct item_data * it; int index; it = itemdb_exists(items[v]); index = it->combos_count; if( it->combos == NULL ) { CREATE(it->combos, struct item_combo*, 1); it->combos_count = 1; } else { RECREATE(it->combos, struct item_combo*, ++it->combos_count); } CREATE(it->combos[index],struct item_combo,1); /* we copy previously alloc'd pointers and just set it to reference */ memcpy(it->combos[index],id->combos[idx],sizeof(struct item_combo)); /* we flag this way to ensure we don't double-dealloc same data */ it->combos[index]->isRef = true; } idb_put(itemdb_combo,id->combos[idx]->id,id->combos[idx]); } count++; } fclose(fp); ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",count,path); return; } /*====================================== * Extended Vending system [Lilith] *======================================*/ static bool itemdb_read_vending(char* fields[], int columns, int current) { struct item_data* id; int nameid; nameid = atoi(fields[0]); if( ( id = itemdb_exists(nameid) ) == NULL ) { ShowWarning("itemdb_read_vending: Invalid item id %d.\n", nameid); return false; } if( id->type == IT_ARMOR || id->type == IT_WEAPON ) { ShowWarning("itemdb_read_vending: item id %d cannot be equipment or weapon.\n", nameid); return false; } item_vend[current].itemid = nameid; return true; } /*====================================== * Applies gender restrictions according to settings. [Skotlex] *======================================*/ static char itemdb_gendercheck(struct item_data *id) { if (id->nameid == WEDDING_RING_M) //Grom Ring return 1; if (id->nameid == WEDDING_RING_F) //Bride Ring return 0; if (id->look == W_MUSICAL && id->type == IT_WEAPON) //Musical instruments are always male-only return 1; if (id->look == W_WHIP && id->type == IT_WEAPON) //Whips are always female-only return 0; return (battle_config.ignore_items_gender) ? 2 : id->sex; } /** * [RRInd] * For backwards compatibility, in Renewal mode, MATK from weapons comes from the atk slot * We use a ':' delimiter which, if not found, assumes the weapon does not provide any matk. **/ #ifdef RENEWAL static void itemdb_re_split_atoi(char *str, int *atk, int *matk) { int i, val[2]; for (i=0; i<2; i++) { if (!str) break; val[i] = atoi(str); str = strchr(str,':'); if (str) *str++=0; } if( i == 0 ) { *atk = *matk = 0; return;//no data found } if( i == 1 ) {//Single Value, we assume it's the ATK *atk = val[0]; *matk = 0; return; } //We assume we have 2 values. *atk = val[0]; *matk = val[1]; return; } #endif /** * 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_SHADOWGEAR && id->type < IT_CASH ) || 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]); #ifdef RENEWAL 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; } if( id->type != IT_SHADOWGEAR && id->equip&EQP_SHADOW_GEAR ) { ShowWarning("Item %d (%s) have invalid equipment slot! Making it an etc item.\n", nameid, id->jname); id->type = IT_ETC; } id->wlv = cap_value(atoi(str[15]), REFINE_TYPE_ARMOR, REFINE_TYPE_MAX); #ifdef RENEWAL itemdb_re_split_atoi(str[16],&id->elv,&id->elvmax); #else id->elv = atoi(str[16]); #endif 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; } /** * Read item from item db * item_db2 overwriting item_db */ static int itemdb_readdb(void){ const char* filename[] = { DBPATH"item_db.txt", DBIMPORT"/item_db.txt" }; int fi; for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) { uint32 lines = 0, count = 0; char line[1024]; char path[256]; FILE* fp; sprintf(path, "%s/%s", db_path, filename[fi]); fp = fopen(path, "r"); if( fp == NULL ) { ShowWarning("itemdb_readdb: File not found \"%s\", skipping.\n", path); continue; } // process rows one by one while(fgets(line, sizeof(line), fp)) { char *str[32], *p; int i; lines++; if(line[0] == '/' && line[1] == '/') continue; memset(str, 0, sizeof(str)); p = line; while( ISSPACE(*p) ) ++p; if( *p == '\0' ) continue;// empty line for( i = 0; i < 19; ++i ) { str[i] = p; p = strchr(p,','); if( p == NULL ) break;// comma not found *p = '\0'; ++p; } if( p == NULL ) { ShowError("itemdb_readdb: Insufficient columns in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); continue; } // Script if( *p != '{' ) { ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); continue; } str[19] = p; p = strstr(p+1,"},"); if( p == NULL ) { ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); continue; } p[1] = '\0'; p += 2; // OnEquip_Script if( *p != '{' ) { ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); continue; } str[20] = p; p = strstr(p+1,"},"); if( p == NULL ) { ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); continue; } p[1] = '\0'; p += 2; // OnUnequip_Script (last column) if( *p != '{' ) { ShowError("itemdb_readdb: Invalid format (OnUnequip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); continue; } str[21] = p; if ( str[21][strlen(str[21])-2] != '}' ) { /* lets count to ensure it's not something silly e.g. a extra space at line ending */ int v, lcurly = 0, rcurly = 0; for( v = 0; v < strlen(str[21]); v++ ) { if( str[21][v] == '{' ) lcurly++; else if ( str[21][v] == '}' ) rcurly++; } if( lcurly != rcurly ) { ShowError("itemdb_readdb: Mismatching curly braces in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); continue; } } if (!itemdb_parse_dbrow(str, path, lines, 0)) continue; count++; } fclose(fp); ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, path); } return 0; } /** * Read item_db table */ static int itemdb_read_sqldb(void) { const char* item_db_name[] = { #ifdef RENEWAL item_db_re_db, #else item_db_db, #endif item_db2_db }; int fi; for( fi = 0; fi < ARRAYLENGTH(item_db_name); ++fi ) { uint32 lines = 0, count = 0; // retrieve all rows from the item database if( SQL_ERROR == Sql_Query(mmysql_handle, "SELECT * FROM `%s`", item_db_name[fi]) ) { Sql_ShowDebug(mmysql_handle); continue; } // process rows one by one while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) ) {// wrap the result into a TXT-compatible format char* str[22]; char* dummy = ""; int i; ++lines; for( i = 0; i < 22; ++i ) { Sql_GetData(mmysql_handle, i, &str[i], NULL); if( str[i] == NULL ) str[i] = dummy; // get rid of NULL columns } if (!itemdb_parse_dbrow(str, item_db_name[fi], lines, SCRIPT_IGNORE_EXTERNAL_BRACKETS)) continue; ++count; } // free the query result Sql_FreeResult(mmysql_handle); ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, item_db_name[fi]); } return 0; } /** Unique item ID function * Only one operation by once * @param flag * 0 return new id * 1 set new value, checked with current value * 2 set new value bypassing anything * 3/other * @param value * @return last value *------------------------------------------*/ uint64 itemdb_unique_id(int8 flag, int64 value) { static uint64 item_uid = 0; if(flag) { if(flag == 1) { if(item_uid < value) return (item_uid = value); }else if(flag == 2) return (item_uid = value); return item_uid; } return ++item_uid; } /** * Load Unique ID for Item */ static void itemdb_uid_load(void){ char * uid; if (SQL_ERROR == Sql_Query(mmysql_handle, "SELECT `value` FROM `interreg` WHERE `varname`='unique_id'")) Sql_ShowDebug(mmysql_handle); if( SQL_SUCCESS != Sql_NextRow(mmysql_handle) ) { ShowError("itemdb_uid_load: Unable to fetch unique_id data\n"); Sql_FreeResult(mmysql_handle); return; } Sql_GetData(mmysql_handle, 0, &uid, NULL); itemdb_unique_id(1, (uint64)strtoull(uid, NULL, 10)); Sql_FreeResult(mmysql_handle); } /** Check if the item is restricted by item_noequip.txt * @param id Item that will be checked * @param m Map ID * @return true: can't be used; false: can be used */ bool itemdb_isNoEquip(struct item_data *id, uint16 m) { if (!id->flag.no_equip) return false; /* on restricted maps the item is consumed but the effect is not used */ if ((!map_flag_vs(m) && id->flag.no_equip&1) || // Normal (map[m].flag.pvp && id->flag.no_equip&2) || // PVP (map_flag_gvg(m) && id->flag.no_equip&4) || // GVG (map[m].flag.battleground && id->flag.no_equip&8) || // Battleground (map[m].flag.restricted && id->flag.no_equip&(8*map[m].zone)) // Zone restriction ) return true; return false; } /** * Read all item-related databases */ static void itemdb_read(void) { int i; const char* dbsubpath[] = { "", "/"DBIMPORT, }; if (db_use_sqldbs) itemdb_read_sqldb(); else itemdb_readdb(); memset(&itemgroup_db, 0, sizeof(itemgroup_db)); for(i=0; i<ARRAYLENGTH(dbsubpath); i++){ uint8 n1 = strlen(db_path)+strlen(dbsubpath[i])+1; uint8 n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1; char* dbsubpath1 = (char*)aMalloc(n1+1); char* dbsubpath2 = (char*)aMalloc(n2+1); if(i==0) { safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]); safesnprintf(dbsubpath2,n2,"%s/%s%s",db_path,DBPATH,dbsubpath[i]); } else { safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]); safesnprintf(dbsubpath2,n1,"%s%s",db_path,dbsubpath[i]); } sv_readdb(dbsubpath1, "item_avail.txt", ',', 2, 2, -1, &itemdb_read_itemavail, i); sv_readdb(dbsubpath1, "item_stack.txt", ',', 3, 3, -1, &itemdb_read_stack, i); sv_readdb(dbsubpath1, "item_nouse.txt", ',', 3, 3, -1, &itemdb_read_nouse, i); sv_readdb(dbsubpath1, "item_vending.txt", ',', 1, 1, ARRAYLENGTH(item_vend), &itemdb_read_vending, i); // Extended Vending system [Lilith] itemdb_read_itemgroup(dbsubpath2, i); itemdb_read_combos(dbsubpath2,i); //TODO change this to sv_read ? id#script ? sv_readdb(dbsubpath2, "item_noequip.txt", ',', 2, 2, -1, &itemdb_read_noequip, i); sv_readdb(dbsubpath2, "item_trade.txt", ',', 3, 3, -1, &itemdb_read_itemtrade, i); sv_readdb(dbsubpath2, "item_delay.txt", ',', 2, 2, -1, &itemdb_read_itemdelay, i); sv_readdb(dbsubpath2, "item_buyingstore.txt", ',', 1, 1, -1, &itemdb_read_buyingstore, i); sv_readdb(db_path, "item_vending.txt", ',', 1, 1, ARRAYLENGTH(item_vend), &itemdb_read_vending, i); // Extended Vending system [Lilith] aFree(dbsubpath1); aFree(dbsubpath2); } itemdb_uid_load(); memset(item_vend, 0, sizeof(item_vend)); // Extended Vending system [Lilith] } /*========================================== * Initialize / Finalize *------------------------------------------*/ /** * Destroys the item_data. */ static void destroy_item_data(struct item_data* self, bool 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( self->combos_count ) { int i; for( i = 0; i < self->combos_count; i++ ) { if( !self->combos[i]->isRef ) { aFree(self->combos[i]->nameid); script_free_code(self->combos[i]->script); } aFree(self->combos[i]); } aFree(self->combos); } #if defined(DEBUG) // trash item memset(self, 0xDD, sizeof(struct item_data)); #endif // free self if( free_self ) aFree(self); } /** * @see DBApply */ static int itemdb_final_sub(DBKey key, DBData *data, va_list ap) { struct item_data *id = db_data2ptr(data); if( id != &dummy_item ) destroy_item_data(id, true); return 0; } /** * Reload Item DB */ void itemdb_reload(void) { struct s_mapiterator* iter; struct map_session_data* sd; int i,d,k; // clear the previous itemdb data for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i ) if( itemdb_array[i] ) destroy_item_data(itemdb_array[i], true); for (i = 0; i < MAX_ITEMGROUP; i++) { uint8 j; if (!(&itemgroup_db[i])) continue; if (itemgroup_db[i].must_qty) aFree(itemgroup_db[i].must); for (j = 0; j < MAX_ITEMGROUP_RANDGROUP; j++) { if (!(&itemgroup_db[i].random[j]) || !itemgroup_db[i].random[j].data_qty) continue; aFree(itemgroup_db[i].random[j].data); } } itemdb_other->clear(itemdb_other, itemdb_final_sub); db_clear(itemdb_combo); memset(itemdb_array, 0, sizeof(itemdb_array)); // read new data itemdb_read(); cashshop_reloaddb(); //Epoque's awesome @reloaditemdb fix - thanks! [Ind] //- Fixes the need of a @reloadmobdb after a @reloaditemdb to re-link monster drop data for( i = 0; i < MAX_MOB_DB; i++ ) { struct mob_db *entry; if( !((i < 1324 || i > 1363) && (i < 1938 || i > 1946)) ) continue; entry = mob_db(i); for(d = 0; d < MAX_MOB_DROP; d++) { struct item_data *id; if( !entry->dropitem[d].nameid ) continue; id = itemdb_search(entry->dropitem[d].nameid); for (k = 0; k < MAX_SEARCH; k++) { if (id->mob[k].chance <= entry->dropitem[d].p) break; } if (k == MAX_SEARCH) continue; if (id->mob[k].id != i) memmove(&id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0])); id->mob[k].chance = entry->dropitem[d].p; id->mob[k].id = i; } } // readjust itemdb pointer cache for each player iter = mapit_geteachpc(); for( sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) ) { memset(sd->item_delay, 0, sizeof(sd->item_delay)); // reset item delays pc_setinventorydata(sd); pc_check_available_item(sd); // Check for invalid(ated) items. /* clear combo bonuses */ if( sd->combos.count ) { aFree(sd->combos.bonus); aFree(sd->combos.id); sd->combos.bonus = NULL; sd->combos.id = NULL; sd->combos.count = 0; if( pc_load_combo(sd) > 0 ) status_calc_pc(sd,0); } } mapit_free(iter); } /** * Finalizing Item DB */ void do_final_itemdb(void) { int i; for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i ) if( itemdb_array[i] ) destroy_item_data(itemdb_array[i], true); for (i = 0; i < MAX_ITEMGROUP; i++) { uint8 j; if (!(&itemgroup_db[i])) continue; if (itemgroup_db[i].must_qty) aFree(itemgroup_db[i].must); for (j = 0; j < MAX_ITEMGROUP_RANDGROUP; j++) { if (!(&itemgroup_db[i].random[j]) || !itemgroup_db[i].random[j].data_qty) continue; aFree(itemgroup_db[i].random[j].data); } } itemdb_other->destroy(itemdb_other, itemdb_final_sub); destroy_item_data(&dummy_item, false); db_destroy(itemdb_combo); } /** * Initializing Item DB */ void do_init_itemdb(void) { memset(itemdb_array, 0, sizeof(itemdb_array)); itemdb_other = idb_alloc(DB_OPT_BASE); itemdb_combo = idb_alloc(DB_OPT_BASE); create_dummy_data(); //Dummy data item. itemdb_read(); }
  13. no error appear , but still the scripts still not working - script DiceTrigger -1,{ OnMinute00: if(OnHour10 || OnHour12 || OnHour14 || OnHour16 || OnHour18 || OnHour20 || OnHour22 || OnHour24 || OnHour2 || OnHour4 || OnHour6) donpcevent "DiceTrigger::OnDiceETrigger"; end; OnInit: disablenpc "Dice Event Warper#dice"; disablenpc "Claim Your Prize!#dice"; end; OnDiceETrigger: if(agitcheck() == 1) end; enablenpc "Dice Event Warper#dice"; announce "Dice Event: We are going to have a Dice Event",bc_all,0x8A2BE2; sleep2 1000; announce "Dice Event: For those who want to join, please go to CloneRO Main Town ( lunette 118 97) !",bc_all,0x8A2BE2; sleep2 1000; announce "Dice Event: The Warper would be open for 1 minute",bc_all,0x8A2BE2; sleep2 30000; announce "Dice Event: Last 30 Seconds.",bc_all,0x8A2BE2; sleep2 30000; announce "Dice Event: Warper Closed.",bc_all,0x8A2BE2; disablenpc "Dice Event Warper#dice"; areawarp "ra_temsky",86,149,113,134,"ra_temsky",99,114; donpcevent "DiceEvent::OnDiceStart"; end; }
  14. How to add new .txt file in "db folder " and read it automatically each time the emulator starts i trying the extended vending system to work , http://rathena.org/board/topic/60817-extended-vending-system-18/page-17 while i was editing my files, i figure out that item_vending.txt is missing in my db folder , so i manually create a new .txt file named item_vending.txt but i think each time the emulator starts, i doesnt read the item_vending.txt that i made in db folder. is there anything i need to edit in src ? or other .... Thanks in advance
  15. - script pcetrigger -1,{ OnMinute00: if(gettime(3) == 9 || gettime(3) == 11 || gettime(3) == 13 || gettime(3) == 15 || gettime(3) == 17 || gettime(3) == 19 || gettime(3) == 21 || gettime(3) == 23 || gettime(3) == 1 || gettime(3) == 3 || gettime(3) == 5) donpcevent "pcetrigger::OnCatcherTrigger"; end; OnInit: disablenpc "Poring Catcher Warper"; end; OnCatcherTrigger: if(agitcheck() == 1) end; enablenpc "Poring Catcher Warper"; announce "Clone™: We are going to have a Poring Catcher Event",bc_all,0xFF7F50; sleep2 1000; announce "Clone™: For those who want to join, please go to CloneRO Main Town (lunette 56 94)!",bc_all,0xFF7F50; //Edit to where would you place the warper sleep2 1000; announce "Clone™: The Warper would be open for 1 minute",bc_all,0xFF7F50; sleep2 30000; announce "Clone™: Last 30 Seconds.",bc_all,0xFF7F50; sleep2 30000; announce "Clone™: Warper Closed.",bc_all,0xFF7F50; disablenpc "Poring Catcher Warper"; donpcevent "Poring Catcher Event::OnPoringCatcherStart"; end; } @sandbox the time is not triggering ex.i want the poring catcher to execute on 9am , 11am 1pm etc. any thing i need to change ?
  16. Hi guys , i manage to make zeny and cash work, but my problem is : I manually add item_vending.txt in my db folder because it doesnt exist in revision " 12094 " svn i'm using is https://github.com/rathena/rathena.git is this the reason why the Item(your desired item) - purchase item using your desired items..(Example: TCG-7227) is not showing on my list ??? Please help ....
  17. i saw only private server which has 2 iteminfo.lub can anyone teach me how this possible happen
  18. did you put this in your item_db2.txt? // Vending system 30000,Zeny,Zeny,3,,10,10,,,,,,,,,,,,,{},{},{} 30001,Cash,Cash,3,,10,10,,,,,,,,,,,,,{},{},{} no , because i'm using sql for item_db2 it even says " Conflicting item/script var 'Zeny', prioritising the script var "
  19. Guys, when i'm trying to use the Zeny and Cash for vending the vend says " Sales carrie out : Zeny when i try to buy it says "you don't have enough items" *i guess its detecting that zeny and cash i an item* but i have zeny in my char i'm using item_db2 on sql '30000', 'Zeny', 'Zeny', '3', '0', '10', '10', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', NULL, NULL, NULL '30001', 'Cash', 'Cash', '3', '0', '10', '10', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', NULL, NULL, NULL
  20. @Bump i even format my desktop already .... but this had the same problem ....
×
×
  • Create New...