
- Fixed Super Novice explosion spirits triggering no matter what you said on the third line. It now triggers on the fourth line.... - Fixed GTB blocking targetted spells when gtb_pvp_only was set. - Merged the code of Ankle snare and Spider web. It no longer moves target if sc failed. - Players should stop walking as soon as they start vending or get into a chat. git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@5382 54d463be-8e91-2dee-dedb-b68131a5f0ec
268 lines
7.9 KiB
C
268 lines
7.9 KiB
C
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
|
|
// For more information, see LICENCE in the main folder
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "../common/nullpo.h"
|
|
#include "clif.h"
|
|
#include "itemdb.h"
|
|
#include "atcommand.h"
|
|
#include "map.h"
|
|
#include "chrif.h"
|
|
#include "vending.h"
|
|
#include "pc.h"
|
|
#include "skill.h"
|
|
#include "battle.h"
|
|
#include "log.h"
|
|
|
|
#include "irc.h"
|
|
|
|
/*==========================================
|
|
* 露店閉鎖
|
|
*------------------------------------------
|
|
*/
|
|
void vending_closevending(struct map_session_data *sd)
|
|
{
|
|
nullpo_retv(sd);
|
|
|
|
sd->vender_id=0;
|
|
clif_closevendingboard(&sd->bl,0);
|
|
if(use_irc && irc_announce_shop_flag)
|
|
irc_announce_shop(sd,0);
|
|
}
|
|
|
|
/*==========================================
|
|
* 露店アイテムリスト要求
|
|
*------------------------------------------
|
|
*/
|
|
void vending_vendinglistreq(struct map_session_data *sd,int id)
|
|
{
|
|
struct map_session_data *vsd;
|
|
|
|
nullpo_retv(sd);
|
|
|
|
if( (vsd=map_id2sd(id)) == NULL )
|
|
return;
|
|
if(vsd->vender_id==0)
|
|
return;
|
|
clif_vendinglist(sd,id,vsd->vending);
|
|
}
|
|
|
|
/*==========================================
|
|
* 露店アイテム購入
|
|
*------------------------------------------
|
|
*/
|
|
void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned char *p)
|
|
{
|
|
int i, j, w, new_ = 0, blank, vend_list[MAX_VENDING];
|
|
double z;
|
|
unsigned short amount;
|
|
short idx;
|
|
struct map_session_data *vsd = map_id2sd(id);
|
|
struct vending vending[MAX_VENDING]; // against duplicate packets
|
|
|
|
nullpo_retv(sd);
|
|
|
|
if (vsd == NULL)
|
|
return;
|
|
if (vsd->vender_id == 0)
|
|
return;
|
|
if (vsd->vender_id == sd->bl.id)
|
|
return;
|
|
|
|
// check number of buying items
|
|
if (len < 8 + 4 || len > 8 + 4 * MAX_VENDING) {
|
|
clif_buyvending(sd, 0, 32767, 4); // not enough quantity (index and amount are unknown)
|
|
return;
|
|
}
|
|
|
|
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(struct vending) * MAX_VENDING); // copy vending list
|
|
|
|
// some checks
|
|
z = 0.;
|
|
w = 0;
|
|
for(i = 0; 8 + 4 * i < len; i++) {
|
|
amount = *(unsigned short*)(p + 4 * i);
|
|
idx = *(short*)(p + 2 + 4 * i) - 2;
|
|
|
|
if (amount <= 0)
|
|
return;
|
|
|
|
// check of item index in the cart
|
|
if (idx < 0 || idx >= MAX_CART)
|
|
return;
|
|
|
|
for(j = 0; j < vsd->vend_num; j++) {
|
|
if (vsd->vending[j].index == idx) {
|
|
vend_list[i] = j;
|
|
break;
|
|
}
|
|
}
|
|
if (j == vsd->vend_num)
|
|
return; //picked non-existing item
|
|
|
|
z += ((double)vsd->vending[j].value * (double)amount);
|
|
if (z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY) { // fix positiv overflow (buyer)
|
|
clif_buyvending(sd, idx, amount, 1); // you don't have enough zeny
|
|
return; // zeny s'<
|
|
}
|
|
if (z + (double)vsd->status.zeny > (double)MAX_ZENY) { // fix positiv overflow (merchand)
|
|
clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // too much zeny = overflow
|
|
return; // zeny s'<
|
|
}
|
|
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;
|
|
}
|
|
|
|
if (vending[j].amount > vsd->status.cart[idx].amount) //Check to see if cart/vend info is in sync.
|
|
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 cumulativ 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;
|
|
} else
|
|
vending[j].amount -= amount;
|
|
|
|
switch(pc_checkadditem(sd, vsd->status.cart[idx].nameid, amount)) {
|
|
case ADDITEM_EXIST:
|
|
break; //We'd add this item to the existing one (in buyers inventory)
|
|
case ADDITEM_NEW:
|
|
new_++;
|
|
if (new_ > blank)
|
|
return; //Buyer has no space in his inventory
|
|
break;
|
|
case ADDITEM_OVERAMOUNT:
|
|
return; //too many items
|
|
}
|
|
}
|
|
|
|
//Logs (V)ending Zeny [Lupus]
|
|
if(log_config.zeny > 0 )
|
|
log_zeny(vsd, "V", sd, (int)z);
|
|
//Logs
|
|
|
|
pc_payzeny(sd, (int)z);
|
|
pc_getzeny(vsd, (int)z);
|
|
|
|
for(i = 0; 8 + 4 * i < len; i++) {
|
|
amount = *(short*)(p + 4 *i);
|
|
idx = *(short*)(p + 2 + 4 * i) - 2;
|
|
//if (amount < 0) break; // tested at start of the function
|
|
|
|
//Logs sold (V)ending items [Lupus]
|
|
if(log_config.pick > 0 ) {
|
|
log_pick(vsd, "V", 0, vsd->status.cart[idx].nameid, -amount, (struct item*)&vsd->status.cart[idx]);
|
|
log_pick( sd, "V", 0, vsd->status.cart[idx].nameid, amount, (struct item*)&vsd->status.cart[idx]);
|
|
}
|
|
//Logs
|
|
|
|
//Old VENDING log added by Lupus
|
|
if(log_config.vend > 0) {
|
|
log_vend(sd,vsd, idx, amount, (int)z); // for Item + Zeny. log.
|
|
//we log ZENY only with the 1st item. Then zero it for the rest items
|
|
z = 0;
|
|
}
|
|
|
|
// vending item
|
|
pc_additem(sd, &vsd->status.cart[idx], amount);
|
|
vsd->vending[vend_list[i]].amount -= amount;
|
|
pc_cart_delitem(vsd, idx, amount, 0);
|
|
clif_vendingreport(vsd, idx, amount);
|
|
|
|
//print buyer's name
|
|
if(battle_config.buyer_name) {
|
|
char temp[256];
|
|
sprintf(temp, msg_txt(265), sd->status.name);
|
|
clif_disp_onlyself(vsd,temp,strlen(temp));
|
|
}
|
|
}
|
|
|
|
//Always save BOTH: buyer and customer
|
|
chrif_save(sd,0);
|
|
chrif_save(vsd,0);
|
|
//check for @AUTOTRADE users [durf]
|
|
if (vsd->state.autotrade)
|
|
{
|
|
//Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex]
|
|
for(i = 0; i < vsd->vend_num && vsd->vending[i].amount < 1; i++);
|
|
if (i == vsd->vend_num)
|
|
{
|
|
vending_closevending(vsd);
|
|
map_quit(vsd); //They have no reason to stay around anymore, do they?
|
|
}
|
|
}
|
|
}
|
|
|
|
/*==========================================
|
|
* 露店開設
|
|
*------------------------------------------
|
|
*/
|
|
void vending_openvending(struct map_session_data *sd,int len,char *message,int flag,unsigned char *p)
|
|
{
|
|
int i, j;
|
|
int vending_skill_lvl;
|
|
nullpo_retv(sd);
|
|
|
|
//check shopname len
|
|
if(message[0] == '\0')
|
|
return;
|
|
|
|
vending_skill_lvl = pc_checkskill(sd, MC_VENDING);
|
|
if(!vending_skill_lvl || !pc_iscarton(sd)) { // cart skill and cart check [Valaris]
|
|
clif_skill_fail(sd,MC_VENDING,0,0);
|
|
return;
|
|
}
|
|
|
|
if (flag) {
|
|
// check number of items in shop
|
|
if (len < 85 + 8 || len > 85 + 8 * MAX_VENDING || len > 85 + 8 * (2 + vending_skill_lvl)) {
|
|
clif_skill_fail(sd, MC_VENDING, 0, 0);
|
|
return;
|
|
}
|
|
for(i = 0, j = 0; (85 + 8 * j < len) && (i < MAX_VENDING); i++, j++) {
|
|
sd->vending[i].index = *(short*)(p+8*j)-2;
|
|
if (sd->vending[i].index < 0 || sd->vending[i].index >= MAX_CART ||
|
|
!itemdb_cantrade(sd->status.cart[sd->vending[i].index].nameid, pc_isGM(sd), pc_isGM(sd)))
|
|
{
|
|
i--; //Preserve the vending index, skip to the next item.
|
|
continue;
|
|
}
|
|
sd->vending[i].amount = *(short*)(p+2+8*j);
|
|
sd->vending[i].value = *(int*)(p+4+8*j);
|
|
if(sd->vending[i].value > battle_config.vending_max_value)
|
|
sd->vending[i].value=battle_config.vending_max_value;
|
|
else if(sd->vending[i].value < 1)
|
|
sd->vending[i].value = 1000000; // auto set to 1 million [celest]
|
|
// カート内のアイテム数と販売するアイテム数に相違があったら中止
|
|
if(pc_cartitem_amount(sd, sd->vending[i].index, sd->vending[i].amount) < 0 || sd->vending[i].value < 0) { // fixes by Valaris and fritz
|
|
clif_skill_fail(sd, MC_VENDING, 0, 0);
|
|
return;
|
|
}
|
|
}
|
|
if (i != j)
|
|
{ //Some items were not vended. [Skotlex]
|
|
clif_displaymessage (sd->fd, msg_txt(266));
|
|
}
|
|
sd->vender_id = sd->bl.id;
|
|
sd->vend_num = i;
|
|
memcpy(sd->message,message, MESSAGE_SIZE-1);
|
|
if (clif_openvending(sd,sd->vender_id,sd->vending) > 0){
|
|
pc_stop_walking(sd,1);
|
|
clif_showvendingboard(&sd->bl,message,0);
|
|
if(use_irc && irc_announce_shop_flag)
|
|
irc_announce_shop(sd,1);
|
|
} else
|
|
sd->vender_id = 0;
|
|
}
|
|
}
|
|
|