Index: conf/battle/feature.conf =================================================================== --- conf/battle/feature.conf (revision 17133) +++ conf/battle/feature.conf (working copy) @@ -17,4 +17,16 @@ // Atcommand suggestions (Note 1) // If one type incomplete atcommand, it will suggest the complete ones. -feature.atcommand_suggestions: off \ No newline at end of file +feature.atcommand_suggestions: off + +// Extended Vending System [Lilith] +// Enable or disable extended vending system? (Note 1) +extended_vending: yes +// Show currency's name in vending board? (Note 1) +show_item_vending: yes +// Show more info about buying? (Note 1) +ex_vending_info: yes +// Item ID for Zeny. Set to 0 if you don't want use Zeny. +item_zeny: 30000 +// Item ID for Cash. Set to 0 if you don't want use Cash. +item_cash: 30001 \ No newline at end of file Index: conf/msg_athena.conf =================================================================== --- conf/msg_athena.conf (revision 17133) +++ conf/msg_athena.conf (working copy) @@ -1406,5 +1406,17 @@ 1396: You do not have a cart to be cleaned. 1397: Your cart was cleaned. +// Extended Vending system [Lilith] +700: You do not have enough CashPoint +701: You do not have enough items +702: Seller has not enough space in your inventory +703: Seller can not take all the item +704: You have selected: %s +705: You've opened %s's shop. Sale is carried out: %s +706: Current Currency: %s +707: %s has bought '%s' in the amount of %d. Revenue: %d %s +708: Full revenue from %s is %d %s + + //Custom translations import: conf/import/msg_conf.txt Index: db/item_db2.txt =================================================================== --- db/item_db2.txt (revision 17133) +++ db/item_db2.txt (working copy) @@ -61,3 +61,7 @@ //================================================================== //2338,Wedding_Dress,Wedding Dress,5,43000,,500,,0,,0,0xFFFFFFFE,7,0,16,,0,1,0,{},{ setoption Option_Wedding,1; },{ setoption Option_Wedding,0; } //7170,Tuxedo,Tuxedo,5,43000,,10,,0,,0,0xFFFFFFFE,7,1,16,,0,1,0,{},{ setoption Option_Wedding,1; },{ setoption Option_Wedding,0; } + +// Vending system +30000,Zeny,Zeny,3,,10,10,,,,,,,,,,,,,{},{},{} +30001,Cash,Cash,3,,10,10,,,,,,,,,,,,,{},{},{} Index: db/item_vending.txt =================================================================== --- db/item_vending.txt (revision 0) +++ db/item_vending.txt (revision 0) @@ -0,0 +1,12 @@ +// Specific items for Vending System +// Format: ItemID +// Max items is equal MAX_INVENTORY ( 100 by default ) + +// TCG Card +7227 +// Mithril Coin +674 +// Silver Coin +675 +// Bronze Coin +673 \ No newline at end of file Index: src/map/battle.c =================================================================== --- src/map/battle.c (revision 17133) +++ src/map/battle.c (working copy) @@ -5870,6 +5870,14 @@ { "atcommand_max_stat_bypass", &battle_config.atcommand_max_stat_bypass, 0, 0, 100, }, { "skill_amotion_leniency", &battle_config.skill_amotion_leniency, 90, 0, 300 }, { "mvp_tomb_enabled", &battle_config.mvp_tomb_enabled, 1, 0, 1 }, + /** + * Extended Vending system [Lilith] + **/ + { "extended_vending", &battle_config.extended_vending, 1, 0, 1, }, + { "show_item_vending", &battle_config.show_item_vending, 1, 0, 1, }, + { "ex_vending_info", &battle_config.ex_vending_info, 1, 0, 1, }, + { "item_zeny", &battle_config.item_zeny, 0, 0, MAX_ITEMDB, }, + { "item_cash", &battle_config.item_cash, 0, 0, MAX_ITEMDB, }, { "feature.atcommand_suggestions", &battle_config.atcommand_suggestions_enabled, 0, 0, 1 }, { "min_npc_vending_distance", &battle_config.min_npc_vending_distance, 3, 0, 100 }, { "atcommand_mobinfo_type", &battle_config.atcommand_mobinfo_type, 0, 0, 1 }, Index: src/map/battle.h =================================================================== --- src/map/battle.h (revision 17133) +++ src/map/battle.h (working copy) @@ -483,6 +483,15 @@ int atcommand_mobinfo_type; int mob_size_influence; // Enable modifications on earned experience, drop rates and monster status depending on monster size. [mkbu95] + /** + * Extended Vending system [Lilith] + **/ + int extended_vending; + int show_item_vending; + int ex_vending_info; + int item_zeny; + int item_cash; + int skill_trap_type; int item_restricted_consumption_type; int max_walk_path; Index: src/map/clif.c =================================================================== --- src/map/clif.c (revision 17133) +++ src/map/clif.c (working copy) @@ -5415,6 +5415,25 @@ } } +void clif_displaymessagecolor(struct map_session_data *sd, const char* msg, unsigned long color) +{ + int fd; + unsigned short len = strlen(msg) + 1; + + nullpo_retv(sd); + + color = (color & 0x0000FF) << 16 | (color & 0x00FF00) | (color & 0xFF0000) >> 16; // RGB to BGR + + fd = sd->fd; + WFIFOHEAD(fd, len+12); + WFIFOW(fd,0) = 0x2C1; + WFIFOW(fd,2) = len+12; + WFIFOL(fd,4) = 0; + WFIFOL(fd,8) = color; + memcpy(WFIFOP(fd,12), msg, len); + WFIFOSET(fd, WFIFOW(fd,2)); +} + /// Send broadcast message in yellow or blue without font formatting (ZC_BROADCAST). /// 009a .W .?B void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target) @@ -11228,6 +11247,9 @@ case GC_POISONINGWEAPON: skill_poisoningweapon(sd,RFIFOW(fd,2)); break; + case MC_VENDING: // Extended Vending system [Lilith] + skill_vending(sd,RFIFOW(fd,2)); + break; case NC_MAGICDECOY: skill_magicdecoy(sd,RFIFOW(fd,2)); break; @@ -11897,11 +11919,17 @@ /// 1 = open void clif_parse_OpenVending(int fd, struct map_session_data* sd) { + struct item_data *item = itemdb_exists(sd->vend_loot); short len = (short)RFIFOW(fd,2) - 85; const char* message = (char*)RFIFOP(fd,4); bool flag = (bool)RFIFOB(fd,84); const uint8* data = (uint8*)RFIFOP(fd,85); - + char out_msg[1024]; + + if(battle_config.extended_vending && battle_config.show_item_vending && sd->vend_loot){ + memset(out_msg, '\0', sizeof(out_msg)); + strcat(strcat(strcat(strcat(out_msg,"["),item->jname),"] "),message); + } if( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM ) return; if( map[sd->bl.m].flag.novending ) { @@ -11924,7 +11952,10 @@ if( message[0] == '\0' ) // invalid input return; - vending_openvending(sd, message, flag, data, len/8); + if(battle_config.extended_vending && battle_config.show_item_vending && sd->vend_loot) + vending_openvending(sd, out_msg, flag, data, len/8); + else + vending_openvending(sd, message, flag, data, len/8); } @@ -16261,6 +16292,49 @@ WFIFOSET(fd, packet_len(0x7e2)); #endif } + +/** + * Extended Vending system [Lilith] + **/ +int clif_vend(struct map_session_data *sd, int skill_lv) { + + struct item_data *item; + int c, i, d = 0; + int fd; + + nullpo_ret(sd); + + fd = sd->fd; + WFIFOHEAD(fd, 8 * 8 + 8); + WFIFOW(fd,0) = 0x1ad; + if(battle_config.item_zeny){ + WFIFOW(fd, d * 2 + 4) = ITEMID_ZENY; + d++; + } + if(battle_config.item_cash){ + WFIFOW(fd, d * 2 + 4) = ITEMID_CASH; + d++; + } + for( c = d, i = 0; i < ARRAYLENGTH(item_vend); i ++ ) { + if((item = itemdb_exists(item_vend[i].itemid)) != NULL && + item->nameid != ITEMID_ZENY && item->nameid != ITEMID_CASH){ + WFIFOW(fd, c * 2 + 4) = item->nameid; + c++; + } + } + if( c > 0 ) { + sd->menuskill_id = MC_VENDING; + sd->menuskill_val = skill_lv; + WFIFOW(fd,2) = c * 2 + 4; + WFIFOSET(fd, WFIFOW(fd, 2)); + } else { + clif_skill_fail(sd,MC_VENDING,USESKILL_FAIL_LEVEL,0); + return 0; + } + + return 1; +} + /*========================================== * used by SC_AUTOSHADOWSPELL * RFIFOL(fd,2) - flag (currently not used) Index: src/map/clif.h =================================================================== --- src/map/clif.h (revision 17133) +++ src/map/clif.h (working copy) @@ -570,6 +570,7 @@ // atcommand void clif_displaymessage(const int fd, const char* mes); +void clif_displaymessagecolor(struct map_session_data *sd, const char* msg, unsigned long color); void clif_disp_onlyself(struct map_session_data *sd, const char *mes, int len); void clif_disp_message(struct block_list* src, const char* mes, int len, enum send_target target); void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target); @@ -768,5 +769,10 @@ int clif_colormes(struct map_session_data * sd, enum clif_colors color, const char* msg); #define clif_menuskill_clear(sd) (sd)->menuskill_id = (sd)->menuskill_val = (sd)->menuskill_val2 = 0; +/** + * Extended Vending system [Lilith] + **/ +int clif_vend(struct map_session_data *sd, int skill_lv); +#define VEND_COLOR 0x00FFFF // Cyan #endif /* _CLIF_H_ */ Index: src/map/itemdb.c =================================================================== --- src/map/itemdb.c (revision 17133) +++ src/map/itemdb.c (working copy) @@ -902,7 +902,33 @@ } +/** + * 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] *======================================*/ @@ -1315,6 +1341,7 @@ sv_readdb(db_path, "item_delay.txt", ',', 2, 2, -1, &itemdb_read_itemdelay); sv_readdb(db_path, "item_stack.txt", ',', 3, 3, -1, &itemdb_read_stack); sv_readdb(db_path, DBPATH"item_buyingstore.txt", ',', 1, 1, -1, &itemdb_read_buyingstore); + sv_readdb(db_path, "item_vending.txt", ',', 1, 1, ARRAYLENGTH(item_vend), &itemdb_read_vending); // Extended Vending system [Lilith] itemdb_uid_load(); } @@ -1383,6 +1410,7 @@ itemdb_other->clear(itemdb_other, itemdb_final_sub); memset(itemdb_array, 0, sizeof(itemdb_array)); + memset(item_vend,0,sizeof(item_vend)); // Extended Vending system [Lilith] // read new data itemdb_read(); Index: src/map/itemdb.h =================================================================== --- src/map/itemdb.h (revision 17133) +++ src/map/itemdb.h (working copy) @@ -156,6 +156,11 @@ bool isRef;/* whether this struct is a reference or the master */ }; +struct s_item_vend{ + int itemid; +}; + +struct s_item_vend item_vend[MAX_INVENTORY]; struct item_data* itemdb_searchname(const char *name); int itemdb_searchname_array(struct item_data** data, int size, const char *str); struct item_data* itemdb_load(int nameid); @@ -226,4 +231,10 @@ void do_final_itemdb(void); int do_init_itemdb(void); +/** + * Extended Vending system [Lilith] + **/ +#define ITEMID_ZENY battle_config.item_zeny +#define ITEMID_CASH battle_config.item_cash + #endif /* _ITEMDB_H_ */ Index: src/map/pc.h =================================================================== --- src/map/pc.h (revision 17133) +++ src/map/pc.h (working copy) @@ -478,6 +478,11 @@ // temporary debugging of bug #3504 const char* delunit_prevfile; int delunit_prevline; + /** + * Extended Vending system [Lilith] + **/ + int vend_loot; + int vend_lvl; }; Index: src/map/skill.c =================================================================== --- src/map/skill.c (revision 17133) +++ src/map/skill.c (working copy) @@ -6037,12 +6037,46 @@ case MC_VENDING: if(sd) - { //Prevent vending of GMs with unnecessary Level to trade/drop. [Skotlex] - if ( !pc_can_give_items(sd) ) - clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - else { - sd->state.prevend = 1; - clif_openvendingreq(sd,2+skill_lv); + { + if ( !pc_can_give_items(sd) ) //Prevent vending of GMs with unnecessary Level to trade/drop. [Skotlex] + clif_skill_fail(sd,MC_VENDING,USESKILL_FAIL_LEVEL,0); + else { // Extended Vending system [Lilith] + if(battle_config.extended_vending){ + struct item_data *item; + char output[1024]; + int c = 0, i, d = 0; + + sd->vend_lvl = skill_lv; + if(battle_config.item_zeny) + d++; + if(battle_config.item_cash) + d++; + for( c = d, i = 0; i < ARRAYLENGTH(item_vend); i ++ ) { + if((item = itemdb_exists(item_vend[i].itemid)) != NULL && + item->nameid != ITEMID_ZENY && item->nameid != ITEMID_CASH) + c++; + } + + if(c > 1) + clif_vend(sd,sd->vend_lvl); + else { + sd->state.prevend = 1; + if(c) { + item = itemdb_exists(battle_config.item_zeny?battle_config.item_zeny:battle_config.item_cash?battle_config.item_cash:item_vend[0].itemid); + sd->vend_loot = item->nameid; + sprintf(output,msg_txt(706),itemdb_jname(sd->vend_loot)); + clif_displaymessagecolor(sd,output,VEND_COLOR); + clif_openvendingreq(sd,2+sd->vend_lvl); + } else { + sd->vend_loot = 0; + clif_openvendingreq(sd,2+sd->vend_lvl); + } + } + } else { + sd->vend_loot = 0; + sd->state.prevend = 1; + clif_openvendingreq(sd,2+skill_lv); + } } } break; @@ -15429,6 +15463,40 @@ } /** + * Extended Vending system [Lilith] + **/ +int skill_vending( struct map_session_data *sd, int nameid) { + + struct item_data *item; + char output[1024]; + + nullpo_ret(sd); + + if( nameid <= 0) { + clif_skill_fail(sd,MC_VENDING,USESKILL_FAIL_LEVEL,0); + return 0; + } + + if( nameid > MAX_ITEMDB ) + return 0; + + sd->vend_loot = nameid; + item = itemdb_exists(nameid); + + sprintf(output,msg_txt(704),item->jname); + clif_displaymessagecolor(sd,output,VEND_COLOR); + + if ( !pc_can_give_items(sd) ) + clif_skill_fail(sd,MC_VENDING,USESKILL_FAIL_LEVEL,0); + else { + sd->state.prevend = 1; + clif_openvendingreq(sd,2+sd->vend_lvl); + } + + return 0; +} + +/** * @see DBApply */ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) Index: src/map/skill.h =================================================================== --- src/map/skill.h (revision 17133) +++ src/map/skill.h (working copy) @@ -1857,5 +1857,9 @@ int skill_elementalanalysis(struct map_session_data *sd, int n, uint16 skill_lv, unsigned short *item_list); // Sorcerer Four Elemental Analisys. int skill_changematerial(struct map_session_data *sd, int n, unsigned short *item_list); // Genetic Change Material. int skill_get_elemental_type(uint16 skill_id, uint16 skill_lv); +/** + * Extended Vending system [Lilith] + **/ +int skill_vending( struct map_session_data *sd, int nameid); #endif /* _SKILL_H_ */ Index: src/map/vending.c =================================================================== --- src/map/vending.c (revision 17133) +++ src/map/vending.c (working copy) @@ -48,6 +48,7 @@ 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 ) @@ -60,7 +61,13 @@ clif_displaymessage(sd->fd, msg_txt(246)); return; } - + /** + * Extended Vending system [Lilith] + **/ + if(battle_config.extended_vending && vsd->vend_loot){ + sprintf(output,msg_txt(705),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); @@ -122,16 +129,64 @@ vend_list[i] = j; z += ((double)vsd->vending[j].value * (double)amount); - 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; + /** + * 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(700),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(701),VEND_COLOR); + return; + } + if(pc_inventoryblank(vsd) <= 0) + { + clif_displaymessagecolor(sd,msg_txt(702),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(703),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 ) @@ -168,17 +223,57 @@ } } - 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); + /** + * Extended Vending system [Lilith] + **/ + if(battle_config.extended_vending){ + if(vsd->vend_loot == ITEMID_ZENY || !vsd->vend_loot) { + + + 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); + pc_getcash(vsd,(int)z,0); + } 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 { + + 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); + } 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; @@ -189,11 +284,20 @@ if( battle_config.buyer_name ) { char temp[256]; - sprintf(temp, msg_txt(265), sd->status.name); + if(battle_config.ex_vending_info) // Extended Vending system [Lilith] + sprintf(temp, msg_txt(707), 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(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(708), 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++ ) {