瀏覽代碼

RE cashshop fix, bugreport:4764
-- requires a msgstringtable.txt modification or client will crash (will be in the client svn asap)

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@15137 54d463be-8e91-2dee-dedb-b68131a5f0ec

shennetsind 13 年之前
父節點
當前提交
136a78a9bb
共有 4 個文件被更改,包括 115 次插入15 次删除
  1. 1 0
      db/packet_db.txt
  2. 28 14
      src/map/clif.c
  3. 84 1
      src/map/npc.c
  4. 2 0
      src/map/npc.h

+ 1 - 0
db/packet_db.txt

@@ -1612,6 +1612,7 @@ packet_ver: 25
 
 //2010-11-24aRagexeRE
 packet_ver: 26
+0x0288,-1,cashshopbuy,4:8
 0x0436,19,wanttoconnection,2:6:10:14:18
 0x035f,5,walktoxy,2
 0x0360,6,ticksend,2

+ 28 - 14
src/map/clif.c

@@ -13609,22 +13609,36 @@ void clif_cashshop_ack(struct map_session_data* sd, int error)
 /// 0288 <packet len>.W <kafra points>.L <count>.W { <amount>.W <name id>.W }.4B*count (PACKETVER >= 20100803)
 void clif_parse_cashshop_buy(int fd, struct map_session_data *sd)
 {
-	int fail = 0, amount, points = 0;
-	short nameid;
-	nullpo_retv(sd);
-
-	nameid = RFIFOW(fd,2);
-	amount = RFIFOW(fd,4);
-#if PACKETVER >= 20070711
-	points = RFIFOL(fd,6); // Not Implemented. Should be 0
-#endif
+    int fail = 0;
+    struct npc_data *nd;
+    nullpo_retv(sd);
 
-	if( sd->state.trading || !sd->npc_shopid )
-		fail = 1;
-	else
-		fail = npc_cashshop_buy(sd, nameid, amount, points);
+    if( sd->state.trading || !sd->npc_shopid )
+        fail = 1;
+    else
+    {
+#if PACKETVER < 20101116
+        short nameid = RFIFOW(fd,2);
+        short amount = RFIFOW(fd,4);
+        int points = RFIFOL(fd,6);
 
-	clif_cashshop_ack(sd, fail);
+        fail = npc_cashshop_buy(sd, nameid, amount, points);
+#else
+        int len = RFIFOW(fd,2);
+        int points = RFIFOL(fd,4);
+        int count = RFIFOW(fd,8);
+        unsigned short* item_list = (unsigned short*)RFIFOP(fd,10);
+
+        if( len < 10 || len != 10 + count * 4)
+        {
+            ShowWarning("Player %u sent incorrect cash shop buy packet (len %u:%u)!\n", sd->status.char_id, len, 10 + count * 4);
+            return;
+        }
+        fail = npc_cashshop_buylist(sd,points,count,item_list);
+#endif
+    }
+    
+    clif_cashshop_ack(sd,fail);
 }
 
 /*==========================================

+ 84 - 1
src/map/npc.c

@@ -1190,7 +1190,90 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type)
 	}
 	return 0;
 }
-
+/*==========================================
+* Cash Shop Buy List
+*------------------------------------------*/
+int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, unsigned short* item_list)
+{
+    int i, j, nameid, amount, new_, w, vt;
+    struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid);
+
+    if( !nd || nd->subtype != CASHSHOP )
+        return 1;
+
+    if( sd->state.trading )
+        return 4;
+
+    new_ = 0;
+    w = 0;
+    vt = 0; // Global Value
+
+    // Validating Process ----------------------------------------------------
+    for( i = 0; i < count; i++ )
+    {
+        nameid = item_list[i*2+1];
+        amount = item_list[i*2+0];
+
+        if( !itemdb_exists(nameid) || amount <= 0 )
+            return 5;
+
+        ARR_FIND(0,nd->u.shop.count,j,nd->u.shop.shop_item[j].nameid == nameid);
+        if( j == nd->u.shop.count || nd->u.shop.shop_item[j].value <= 0 )
+            return 5;
+
+        if( !itemdb_isstackable(nameid) && amount > 1 )
+        {
+            ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %d!\n", sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
+            amount = item_list[i*2+0] = 1;
+        }
+
+        switch( pc_checkadditem(sd,nameid,amount) )
+        {
+            case ADDITEM_NEW:
+                new_++;
+                break;
+            case ADDITEM_OVERAMOUNT:
+                return 3;
+        }
+
+        vt += nd->u.shop.shop_item[j].value * amount;
+        w += itemdb_weight(nameid) * amount;
+    }
+
+    if( w + sd->weight > sd->max_weight )
+        return 3;
+    if( pc_inventoryblank(sd) < new_ )
+        return 3;
+    if( points > vt ) points = vt;
+
+    // Payment Process ----------------------------------------------------
+    if( sd->kafraPoints < points || sd->cashPoints < (vt - points) )
+        return 6;
+    pc_paycash(sd,vt,points);
+
+    // Delivery Process ----------------------------------------------------
+    for( i = 0; i < count; i++ )
+    {
+        struct item item_tmp;
+
+        nameid = item_list[i*2+1];
+        amount = item_list[i*2+0];
+
+        memset(&item_tmp,0,sizeof(item_tmp));
+
+        if( !pet_create_egg(sd,nameid) )
+        {
+            item_tmp.nameid = nameid;
+            item_tmp.identify = 1;
+            pc_additem(sd,&item_tmp,amount);
+        }
+
+        if( log_config.enable_logs&0x20 )
+            log_pick_pc(sd, "S", nameid, amount, NULL);
+    }
+
+    return 0;
+}
 //npc_buylist for script-controlled shops.
 static int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd)
 {

+ 2 - 0
src/map/npc.h

@@ -157,6 +157,8 @@ int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int po
 
 extern struct npc_data* fake_nd;
 
+int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, unsigned short* item_list);
+
 /**
  * For the Secure NPC Timeout option (check config/Secure.h) [RR]
  **/