Skip to content
Permalink
Browse files

Additional fixes for cart exploit (#4148)

* Fixes #4146.
* Reverted some of 7f772c3 as this falls into a larger refactor scope.
* Resolved an issue where items could not be picked up from the cart when the overweight message was sent to the player.
* Added missing e_additem_result constants.
Thanks to @secretdataz, @Normynator, and @cydh!
  • Loading branch information...
secretdataz authored and aleos89 committed May 14, 2019
1 parent 3ad276c commit 7ad1b32d7d44fd1c5d927228528cc607f61da001
Showing with 56 additions and 49 deletions.
  1. +29 −32 src/map/pc.cpp
  2. +19 −17 src/map/pc.hpp
  3. +8 −0 src/map/storage.cpp
@@ -4806,13 +4806,13 @@ short pc_search_inventory(struct map_session_data *sd, unsigned short nameid) {
* 6 = ?
* 7 = stack limitation
*/
char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_pick_type log_type) {
enum e_additem_result pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_pick_type log_type) {
struct item_data *id;
int16 i;
unsigned int w;

nullpo_retr(1, sd);
nullpo_retr(1, item);
nullpo_retr(ADDITEM_INVALID, sd);
nullpo_retr(ADDITEM_INVALID, item);

if( item->nameid == 0 || amount <= 0 )
return ADDITEM_INVALID;
@@ -5342,33 +5342,33 @@ int pc_useitem(struct map_session_data *sd,int n)
* @param item
* @param amount
* @param log_type
* @return 0 = success; 1 = fail; 2 = no slot
* @return See pc.hpp::e_additem_result
*/
unsigned char pc_cart_additem(struct map_session_data *sd,struct item *item,int amount,e_log_pick_type log_type)
enum e_additem_result pc_cart_additem(struct map_session_data *sd,struct item *item,int amount,e_log_pick_type log_type)
{
struct item_data *data;
int i,w;

nullpo_retr(1, sd);
nullpo_retr(1, item);
nullpo_retr(ADDITEM_INVALID, sd);
nullpo_retr(ADDITEM_INVALID, item);

if(item->nameid == 0 || amount <= 0)
return 1;
return ADDITEM_INVALID;
data = itemdb_search(item->nameid);

if( data->stack.cart && amount > data->stack.amount )
{// item stack limitation
return 1;
return ADDITEM_STACKLIMIT;
}

if( !itemdb_cancartstore(item, pc_get_group_level(sd)) || (item->bound > BOUND_ACCOUNT && !pc_can_give_bounded_items(sd)))
{ // Check item trade restrictions [Skotlex]
clif_displaymessage (sd->fd, msg_txt(sd,264));
return 1;
return ADDITEM_INVALID;
}

if( (w = data->weight*amount) + sd->cart_weight > sd->cart_weight_max )
return 1;
return ADDITEM_OVERWEIGHT;

i = MAX_CART;
if( itemdb_isstackable2(data) && !item->expire_time )
@@ -5386,7 +5386,7 @@ unsigned char pc_cart_additem(struct map_session_data *sd,struct item *item,int
if( i < MAX_CART )
{// item already in cart, stack it
if( amount > MAX_AMOUNT - sd->cart.u.items_cart[i].amount || ( data->stack.cart && amount > data->stack.amount - sd->cart.u.items_cart[i].amount ) )
return 2; // no slot
return ADDITEM_OVERAMOUNT; // no slot

sd->cart.u.items_cart[i].amount += amount;
clif_cart_additem(sd,i,amount,0);
@@ -5395,7 +5395,7 @@ unsigned char pc_cart_additem(struct map_session_data *sd,struct item *item,int
{// item not stackable or not present, add it
ARR_FIND( 0, MAX_CART, i, sd->cart.u.items_cart[i].nameid == 0 );
if( i == MAX_CART )
return 2; // no slot
return ADDITEM_OVERAMOUNT; // no slot

memcpy(&sd->cart.u.items_cart[i],item,sizeof(sd->cart.u.items_cart[0]));
sd->cart.u.items_cart[i].id = 0;
@@ -5410,7 +5410,7 @@ unsigned char pc_cart_additem(struct map_session_data *sd,struct item *item,int
sd->cart_weight += w;
clif_updatestatus(sd,SP_CARTINFO);

return 0;
return ADDITEM_SUCCESS;
}

/*==========================================
@@ -5443,15 +5443,12 @@ void pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log
*------------------------------------------*/
void pc_putitemtocart(struct map_session_data *sd,int idx,int amount)
{
struct item *item_data;
char flag;

nullpo_retv(sd);

if (idx < 0 || idx >= MAX_INVENTORY) //Invalid index check [Skotlex]
return;

item_data = &sd->inventory.u.items_inventory[idx];
struct item *item_data = &sd->inventory.u.items_inventory[idx];

if( item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending || sd->state.prevend )
return;
@@ -5461,11 +5458,14 @@ void pc_putitemtocart(struct map_session_data *sd,int idx,int amount)
return;
}

if( (flag = pc_cart_additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0 )
enum e_additem_result flag = pc_cart_additem(sd,item_data,amount,LOG_TYPE_NONE);

if (flag == ADDITEM_SUCCESS)
pc_delitem(sd,idx,amount,0,5,LOG_TYPE_NONE);
else {
clif_dropitem(sd,idx,0);
clif_cart_additem_ack(sd,(flag==1)?ADDITEM_TO_CART_FAIL_WEIGHT:ADDITEM_TO_CART_FAIL_COUNT);
clif_delitem(sd, idx, amount, flag);
clif_cart_additem_ack(sd, (flag == ADDITEM_OVERAMOUNT) ? ADDITEM_TO_CART_FAIL_COUNT : ADDITEM_TO_CART_FAIL_WEIGHT);
clif_additem(sd, idx, amount, flag);
}
}

@@ -5498,22 +5498,19 @@ void pc_getitemfromcart(struct map_session_data *sd,int idx,int amount)
if (idx < 0 || idx >= MAX_CART) //Invalid index check [Skotlex]
return;

item* item_data=&sd->cart.u.items_cart[idx];
struct item *item_data=&sd->cart.u.items_cart[idx];

if (item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending || sd->state.prevend)
return;

if (pc_checkadditem(sd, item_data->nameid, amount) == CHKADDITEM_OVERAMOUNT) {
return;
}

item item_copy = *item_data;
enum e_additem_result flag = pc_additem(sd, item_data, amount, LOG_TYPE_NONE);

pc_cart_delitem(sd, idx, amount, 0, LOG_TYPE_NONE);
char flag = pc_additem(sd, &item_copy, amount, LOG_TYPE_NONE);
if(flag != ADDITEM_SUCCESS) {
clif_dropitem(sd,idx,0);
clif_additem(sd,0,0,flag);
if (flag == ADDITEM_SUCCESS)
pc_cart_delitem(sd, idx, amount, 0, LOG_TYPE_NONE);
else {
clif_cart_delitem(sd, idx, amount);
clif_additem(sd, idx, amount, flag);
clif_cart_additem(sd, idx, amount, 0);
}
}

@@ -92,6 +92,23 @@ enum prevent_logout_trigger {
PLT_DAMAGE = 8
};

enum e_chkitem_result : uint8 {
CHKADDITEM_EXIST,
CHKADDITEM_NEW,
CHKADDITEM_OVERAMOUNT
};

enum e_additem_result : uint8 {
ADDITEM_SUCCESS,
ADDITEM_INVALID,
ADDITEM_OVERWEIGHT,
ADDITEM_ITEM,
ADDITEM_OVERITEM,
ADDITEM_OVERAMOUNT,
ADDITEM_REFUSED_TIME,
ADDITEM_STACKLIMIT
};

struct skill_cooldown_entry {
unsigned short skill_id;
int timer;
@@ -1049,7 +1066,7 @@ char pc_checkadditem(struct map_session_data *sd, unsigned short nameid, int amo
uint8 pc_inventoryblank(struct map_session_data *sd);
short pc_search_inventory(struct map_session_data *sd, unsigned short nameid);
char pc_payzeny(struct map_session_data *sd, int zeny, enum e_log_pick_type type, struct map_session_data *tsd);
char pc_additem(struct map_session_data *sd, struct item *item, int amount, e_log_pick_type log_type);
enum e_additem_result pc_additem(struct map_session_data *sd, struct item *item, int amount, e_log_pick_type log_type);
char pc_getzeny(struct map_session_data *sd, int zeny, enum e_log_pick_type type, struct map_session_data *tsd);
char pc_delitem(struct map_session_data *sd, int n, int amount, int type, short reason, e_log_pick_type log_type);

@@ -1062,7 +1079,7 @@ int pc_bound_chk(TBL_PC *sd,enum bound_type type,int *idxlist);
int pc_paycash( struct map_session_data *sd, int price, int points, e_log_pick_type type );
int pc_getcash( struct map_session_data *sd, int cash, int points, e_log_pick_type type );

unsigned char pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amount,e_log_pick_type log_type);
enum e_additem_result pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amount,e_log_pick_type log_type);
void pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log_pick_type log_type);
void pc_putitemtocart(struct map_session_data *sd,int idx,int amount);
void pc_getitemfromcart(struct map_session_data *sd,int idx,int amount);
@@ -1253,21 +1270,6 @@ void pc_readdb(void);
void do_init_pc(void);
void do_final_pc(void);

enum e_chkitem_result {
CHKADDITEM_EXIST,
CHKADDITEM_NEW,
CHKADDITEM_OVERAMOUNT
};

enum e_additem_result {
ADDITEM_SUCCESS,
ADDITEM_INVALID,
ADDITEM_OVERWEIGHT,
ADDITEM_OVERITEM = 4,
ADDITEM_OVERAMOUNT,
ADDITEM_STACKLIMIT = 7
};

// timer for night.day
extern int day_timer_tid;
extern int night_timer_tid;
@@ -409,6 +409,10 @@ void storage_storageaddfromcart(struct map_session_data *sd, struct s_storage *s
enum e_storage_add result;
nullpo_retv(sd);

if (sd->state.prevend) {
return;
}

result = storage_canAddItem(stor, index, sd->cart.u.items_inventory, amount, MAX_CART);
if (result == STORAGE_ADD_INVALID)
return;
@@ -444,6 +448,10 @@ void storage_storagegettocart(struct map_session_data* sd, struct s_storage *sto

nullpo_retv(sd);

if (sd->state.prevend) {
return;
}

result = storage_canGetItem(stor, index, amount);
if (result != STORAGE_ADD_OK)
return;

1 comment on commit 7ad1b32

@RagVision

This comment has been minimized.

Copy link

commented on 7ad1b32 May 15, 2019

After the correction, items taken from the inventory to the cart, disappears if the cart is at its limit, the items reappear if the character logs in. I made a video to exemplify better.

https://www.youtube.com/watch?v=O4TYTjtZ1_E

Thank you, rathena. I'm a fan of your work.

Please sign in to comment.
You can’t perform that action at this time.