diff options
Diffstat (limited to 'src/map/clif.c')
-rw-r--r-- | src/map/clif.c | 2241 |
1 files changed, 1342 insertions, 899 deletions
diff --git a/src/map/clif.c b/src/map/clif.c index adc7562e1..fd8a3c783 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -56,13 +56,14 @@ #include "map/trade.h" #include "map/unit.h" #include "map/vending.h" +#include "map/achievement.h" #include "common/HPM.h" #include "common/cbasetypes.h" #include "common/conf.h" #include "common/ers.h" #include "common/grfio.h" #include "common/memmgr.h" -#include "common/mmo.h" // NEW_CARTS +#include "common/mmo.h" // NEW_CARTS, char_achievements #include "common/nullpo.h" #include "common/random.h" #include "common/showmsg.h" @@ -434,6 +435,7 @@ static bool clif_send(const void *buf, int len, struct block_list *bl, enum send struct battleground_data *bgd = NULL; int x0 = 0, x1 = 0, y0 = 0, y1 = 0, fd; struct s_mapiterator* iter; + int area_size; if( type != ALL_CLIENT ) nullpo_ret(bl); @@ -472,13 +474,18 @@ static bool clif_send(const void *buf, int len, struct block_list *bl, enum send case AREA: case AREA_WOSC: + case AREA_DEAD: if (sd && bl->prev == NULL) //Otherwise source misses the packet.[Skotlex] clif->send (buf, len, bl, SELF); /* Fall through */ case AREA_WOC: case AREA_WOS: + if (type == AREA_DEAD) + area_size = DEAD_AREA_SIZE; + else + area_size = AREA_SIZE; nullpo_retr(true, bl); - map->foreachinarea(clif->send_sub, bl->m, bl->x-AREA_SIZE, bl->y-AREA_SIZE, bl->x+AREA_SIZE, bl->y+AREA_SIZE, + map->foreachinarea(clif->send_sub, bl->m, bl->x - area_size, bl->y - area_size, bl->x + area_size, bl->y + area_size, BL_PC, buf, len, bl, type); break; case AREA_CHAT_WOC: @@ -909,7 +916,12 @@ static void clif_clearunit_area(struct block_list *bl, clr_type type) WBUFL(buf,2) = bl->id; WBUFB(buf,6) = type; - clif->send(buf, packet_len(0x80), bl, type == CLR_DEAD ? AREA : AREA_WOS); + /** + * When monster dies, there's a delay before the packet is sent, + * so we send it to a bigger area to avoid clients at the edge + * walking out of the area and missing it [KirieZ] + */ + clif->send(buf, packet_len(0x80), bl, type == CLR_DEAD ? AREA_DEAD : AREA_WOS); if (clif->isdisguised(bl)) { WBUFL(buf,2) = -bl->id; @@ -939,7 +951,7 @@ static void clif_clearunit_delayed(struct block_list *bl, clr_type type, int64 t } /// Gets weapon view info from sd's inventory_data and points (*rhand,*lhand) -static void clif_get_weapon_view(struct map_session_data *sd, unsigned short *rhand, unsigned short *lhand) +static void clif_get_weapon_view(struct map_session_data *sd, int *rhand, int *lhand) { nullpo_retv(sd); nullpo_retv(rhand); @@ -1103,7 +1115,7 @@ static void clif_set_unit_idle(struct block_list *bl, struct map_session_data *t p.head = vd->hair_style; p.weapon = vd->weapon; p.accessory = vd->head_bottom; -#if PACKETVER < 7 +#if PACKETVER < 7 || PACKETVER_RE_NUM >= 20180704 p.shield = vd->shield; #endif p.accessory2 = vd->head_top; @@ -1260,7 +1272,7 @@ static void clif_spawn_unit(struct block_list *bl, enum send_target target) p.head = vd->hair_style; p.weapon = vd->weapon; p.accessory = vd->head_bottom; -#if PACKETVER < 7 +#if PACKETVER < 7 || PACKETVER_RE_NUM >= 20180704 p.shield = vd->shield; #endif p.accessory2 = vd->head_top; @@ -1369,7 +1381,7 @@ static void clif_set_unit_walking(struct block_list *bl, struct map_session_data p.weapon = vd->weapon; p.accessory = vd->head_bottom; p.moveStartTime = (unsigned int)timer->gettick(); -#if PACKETVER < 7 +#if PACKETVER < 7 || PACKETVER_RE_NUM >= 20180704 p.shield = vd->shield; #endif p.accessory2 = vd->head_top; @@ -1615,17 +1627,8 @@ static bool clif_spawn(struct block_list *bl) static void clif_hominfo(struct map_session_data *sd, struct homun_data *hd, int flag) { struct status_data *hstatus; - unsigned char buf[128]; enum homun_type htype; - int offset = 0; - -// probably can works also for < 20141223, but in 3CeaM packet size defined only for 20150513 -#if PACKETVER < 20150513 - int cmd = 0x22e; -#else - int cmd = 0x9f7; -#endif - int len = packet_len(cmd); + struct PACKET_ZC_PROPERTY_HOMUN p; nullpo_retv(sd); nullpo_retv(hd); @@ -1633,75 +1636,73 @@ static void clif_hominfo(struct map_session_data *sd, struct homun_data *hd, int hstatus = &hd->battle_status; htype = homun->class2type(hd->homunculus.class_); - memset(buf, 0, len); - WBUFW(buf, 0) = cmd; - memcpy(WBUFP(buf, 2), hd->homunculus.name, NAME_LENGTH); + memset(&p, 0, sizeof(p)); + p.packetType = hominfoType; + memcpy(p.name, hd->homunculus.name, NAME_LENGTH); // Bit field, bit 0 : rename_flag (1 = already renamed), bit 1 : homunc vaporized (1 = true), bit 2 : homunc dead (1 = true) - WBUFB(buf, 26) = (!battle_config.hom_rename && hd->homunculus.rename_flag ? 0x1 : 0x0) | (hd->homunculus.vaporize == HOM_ST_REST ? 0x2 : 0) | (hd->homunculus.hp > 0 ? 0x4 : 0); - WBUFW(buf, 27) = hd->homunculus.level; - WBUFW(buf, 29) = hd->homunculus.hunger; - WBUFW(buf, 31) = (unsigned short) (hd->homunculus.intimacy / 100) ; - WBUFW(buf, 33) = 0; // equip id + p.flags = (!battle_config.hom_rename && hd->homunculus.rename_flag ? 0x1 : 0x0) | (hd->homunculus.vaporize == HOM_ST_REST ? 0x2 : 0) | (hd->homunculus.hp > 0 ? 0x4 : 0); + p.level = hd->homunculus.level; + p.hunger = hd->homunculus.hunger; + p.intimacy = hd->homunculus.intimacy / 100; + p.itemId = 0; // equip id #ifdef RENEWAL - WBUFW(buf, 35) = cap_value(hstatus->rhw.atk2, 0, INT16_MAX); + p.atk2 = cap_value(hstatus->rhw.atk2, 0, INT16_MAX); #else - WBUFW(buf,35) = cap_value(hstatus->rhw.atk2 + hstatus->batk, 0, INT16_MAX); + p.atk2 = cap_value(hstatus->rhw.atk2 + hstatus->batk, 0, INT16_MAX); #endif - WBUFW(buf,37) = cap_value(hstatus->matk_max, 0, INT16_MAX); - WBUFW(buf,39) = hstatus->hit; + p.matk = cap_value(hstatus->matk_max, 0, INT16_MAX); + p.hit = hstatus->hit; if (battle_config.hom_setting&0x10) - WBUFW(buf, 41) = hstatus->luk / 3 + 1; //crit is a +1 decimal value! Just display purpose.[Vicious] + p.crit = hstatus->luk / 3 + 1; //crit is a +1 decimal value! Just display purpose.[Vicious] else - WBUFW(buf, 41) = hstatus->cri / 10; + p.crit = hstatus->cri / 10; #ifdef RENEWAL - WBUFW(buf, 43) = hstatus->def + hstatus->def2; - WBUFW(buf, 45) = hstatus->mdef + hstatus->mdef2; + p.def = hstatus->def + hstatus->def2; + p.mdef = hstatus->mdef + hstatus->mdef2; #else - WBUFW(buf, 43) =hstatus->def + hstatus->vit ; - WBUFW(buf, 45) = hstatus->mdef; + p.def = hstatus->def + hstatus->vit ; + p.mdef = hstatus->mdef; #endif - WBUFW(buf, 47) = hstatus->flee; - WBUFW(buf, 49) = (flag) ? 0 : hstatus->amotion; + p.flee = hstatus->flee; + p.amotion = (flag) ? 0 : hstatus->amotion; // probably can works also for < 20141223, but in 3CeaM packet size defined only for 20150513 #if PACKETVER < 20150513 if (hstatus->max_hp > INT16_MAX) { - WBUFW(buf, 51) = hstatus->hp / (hstatus->max_hp / 100); - WBUFW(buf, 53) = 100; + p.hp = hstatus->hp / (hstatus->max_hp / 100); + p.maxHp = 100; } else { - WBUFW(buf, 51) = hstatus->hp; - WBUFW(buf, 53) = hstatus->max_hp; + p.hp = hstatus->hp; + p.maxHp = hstatus->max_hp; } #else - WBUFL(buf, 51) = hstatus->hp; - WBUFL(buf, 55) = hstatus->max_hp; - offset = 4; + p.hp = hstatus->hp; + p.maxHp = hstatus->max_hp; #endif if (hstatus->max_sp > INT16_MAX) { - WBUFW(buf, 55 + offset) = hstatus->sp / (hstatus->max_sp / 100); - WBUFW(buf, 57 + offset) = 100; + p.sp = hstatus->sp / (hstatus->max_sp / 100); + p.maxSp = 100; } else { - WBUFW(buf, 55 + offset) = hstatus->sp; - WBUFW(buf, 57 + offset) = hstatus->max_sp; + p.sp = hstatus->sp; + p.maxSp = hstatus->max_sp; } - WBUFL(buf, 59 + offset) = hd->homunculus.exp; - WBUFL(buf, 63 + offset) = hd->exp_next; + p.exp = hd->homunculus.exp; + p.expNext = hd->exp_next; switch (htype) { case HT_REG: case HT_EVO: if (hd->homunculus.level >= battle_config.hom_max_level) - WBUFL(buf, 63 + offset) = 0; + p.expNext = 0; break; case HT_S: if (hd->homunculus.level >= battle_config.hom_S_max_level) - WBUFL(buf, 63 + offset) = 0; + p.expNext = 0; break; } - WBUFW(buf, 67 + offset) = hd->homunculus.skillpts; - WBUFW(buf, 69 + offset) = status_get_range(&hd->bl); - - clif->send(buf, len, &sd->bl, SELF); + p.skillPoints = hd->homunculus.skillpts; + p.range = status_get_range(&hd->bl); + clif->send(&p, sizeof(p), &sd->bl, SELF); } /// Notification about a change in homunuculus' state (ZC_CHANGESTATE_MER). @@ -1799,19 +1800,25 @@ static void clif_homskillup(struct map_session_data *sd, uint16 skill_id) WFIFOSET(fd,packet_len(0x239)); } +/// Result of request to feed a homun/merc (ZC_FEED_MER). +/// 022f <result>.B <name id>.W +/// result: +/// 0 = failure +/// 1 = success static void clif_hom_food(struct map_session_data *sd, int foodid, int fail) { int fd; + struct PACKET_ZC_FEED_MER p; + nullpo_retv(sd); fd = sd->fd; - WFIFOHEAD(fd,packet_len(0x22f)); - WFIFOW(fd,0)=0x22f; - WFIFOB(fd,2)=fail; - WFIFOW(fd,3)=foodid; - WFIFOSET(fd,packet_len(0x22f)); - - return; + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x22f; + p.result = fail; + p.itemId = foodid; + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Notifies the client, that it is walking (ZC_NOTIFY_PLAYERMOVE). @@ -2003,8 +2010,8 @@ static void clif_changemap_airship(struct map_session_data *sd, short m, int x, /// Notifies the client of a position change to coordinates on given map, which is on another map-server (ZC_NPCACK_SERVERMOVE). /// 0092 <map name>.16B <x>.W <y>.W <ip>.L <port>.W -/// 0ac7 <map name>.16B <x>.W <y>.W <ip>.L <port>.W <zero>.128B -static void clif_changemapserver(struct map_session_data *sd, unsigned short map_index, int x, int y, uint32 ip, uint16 port) +/// 0ac7 <map name>.16B <x>.W <y>.W <ip>.L <port>.W <dns host>.128B +static void clif_changemapserver(struct map_session_data *sd, unsigned short map_index, int x, int y, uint32 ip, uint16 port, char *dnsHost) { int fd; #if PACKETVER >= 20170315 @@ -2022,6 +2029,15 @@ static void clif_changemapserver(struct map_session_data *sd, unsigned short map WFIFOW(fd, 20) = y; WFIFOL(fd, 22) = htonl(ip); WFIFOW(fd, 26) = sockt->ntows(htons(port)); // [!] LE byte order here [!] + +#if PACKETVER >= 20170315 + if (dnsHost != NULL) { + safestrncpy(WFIFOP(fd, 28), dnsHost, 128); + } else { + memset(WFIFOP(fd, 28), 0, 128); + } +#endif + WFIFOSET(fd, packet_len(cmd)); } @@ -2098,12 +2114,13 @@ static void clif_buylist(struct map_session_data *sd, struct npc_data *nd) { struct npc_item_list *shop = NULL; unsigned short shop_size = 0; - int fd,i,c; + int fd, i, c, len; + struct PACKET_ZC_PC_PURCHASE_ITEMLIST *p; nullpo_retv(sd); nullpo_retv(nd); - if( nd->subtype == SCRIPT ) { + if (nd->subtype == SCRIPT) { shop = nd->u.scr.shop->item; shop_size = nd->u.scr.shop->items; } else { @@ -2113,26 +2130,29 @@ static void clif_buylist(struct map_session_data *sd, struct npc_data *nd) fd = sd->fd; - WFIFOHEAD(fd, 4 + shop_size * 11); - WFIFOW(fd,0) = 0xc6; + len = sizeof(struct PACKET_ZC_PC_PURCHASE_ITEMLIST) + shop_size * sizeof(struct PACKET_ZC_PC_PURCHASE_ITEMLIST_sub); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0xc6; c = 0; - for( i = 0; i < shop_size; i++ ) { - if( shop[i].nameid ) { + for (i = 0; i < shop_size; i++) { + if (shop[i].nameid) { struct item_data* id = itemdb->exists(shop[i].nameid); int val = shop[i].value; - if( id == NULL ) + if (id == NULL) continue; - WFIFOL(fd, 4+c*11) = val; - WFIFOL(fd, 8+c*11) = pc->modifybuyvalue(sd,val); - WFIFOB(fd,12+c*11) = itemtype(id->type); - WFIFOW(fd,13+c*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; + p->items[c].price = val; + p->items[c].discountPrice = pc->modifybuyvalue(sd, val); + p->items[c].itemType = itemtype(id->type); + p->items[c].itemId = (id->view_id > 0) ? id->view_id : id->nameid; c++; } } - WFIFOW(fd,2) = 4 + c*11; - WFIFOSET(fd,WFIFOW(fd,2)); + len = sizeof(struct PACKET_ZC_PC_PURCHASE_ITEMLIST) + c * sizeof(struct PACKET_ZC_PC_PURCHASE_ITEMLIST_sub); + p->packetLength = len; + WFIFOSET(fd, len); } /// Presents list of items, that can be sold to an NPC shop (ZC_PC_SELL_ITEMLIST). @@ -2453,106 +2473,55 @@ static void clif_cutin(struct map_session_data *sd, const char *image, int type) /*========================================== * Fills in card data from the given item and into the buffer. [Skotlex] *------------------------------------------*/ -static void clif_addcards(unsigned char *buf, struct item *item) +static void clif_addcards(struct EQUIPSLOTINFO *buf, struct item *item) { - int i=0,j; + int i = 0, j; nullpo_retv(buf); - if( item == NULL ) { //Blank data - WBUFW(buf,0) = 0; - WBUFW(buf,2) = 0; - WBUFW(buf,4) = 0; - WBUFW(buf,6) = 0; + if (item == NULL) { //Blank data + buf->card[0] = 0; + buf->card[1] = 0; + buf->card[2] = 0; + buf->card[3] = 0; return; } - if( item->card[0] == CARD0_PET ) { //pet eggs - WBUFW(buf,0) = 0; - WBUFW(buf,2) = 0; - WBUFW(buf,4) = 0; - WBUFW(buf,6) = item->card[3]; //Pet renamed flag. + if (item->card[0] == CARD0_PET) { //pet eggs + buf->card[0] = 0; + buf->card[1] = 0; + buf->card[2] = 0; + buf->card[3] = item->card[3]; //Pet renamed flag. return; } - if( item->card[0] == CARD0_FORGE || item->card[0] == CARD0_CREATE ) { //Forged/created items - WBUFW(buf,0) = item->card[0]; - WBUFW(buf,2) = item->card[1]; - WBUFW(buf,4) = item->card[2]; - WBUFW(buf,6) = item->card[3]; + if (item->card[0] == CARD0_FORGE || item->card[0] == CARD0_CREATE) { //Forged/created items + buf->card[0] = item->card[0]; + buf->card[1] = item->card[1]; + buf->card[2] = item->card[2]; + buf->card[3] = item->card[3]; return; } //Client only receives four cards.. so randomly send them a set of cards. [Skotlex] - if( MAX_SLOTS > 4 && (j = itemdb_slot(item->nameid)) > 4 ) - i = rnd()%(j-3); //eg: 6 slots, possible i values: 0->3, 1->4, 2->5 => i = rnd()%3; + if (MAX_SLOTS > 4 && (j = itemdb_slot(item->nameid)) > 4) + i = rnd() % (j - 3); //eg: 6 slots, possible i values: 0->3, 1->4, 2->5 => i = rnd()%3; //Normal items. - if( item->card[i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) - WBUFW(buf,0) = j; + if (item->card[i] > 0 && (j = itemdb_viewid(item->card[i])) > 0) + buf->card[0] = j; else - WBUFW(buf,0) = item->card[i]; + buf->card[0] = item->card[i]; - if( item->card[++i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) - WBUFW(buf,2) = j; + if (item->card[++i] > 0 && (j = itemdb_viewid(item->card[i])) > 0) + buf->card[1] = j; else - WBUFW(buf,2) = item->card[i]; + buf->card[1] = item->card[i]; - if( item->card[++i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) - WBUFW(buf,4) = j; + if (item->card[++i] > 0 && (j = itemdb_viewid(item->card[i])) > 0) + buf->card[2] = j; else - WBUFW(buf,4) = item->card[i]; + buf->card[2] = item->card[i]; - if( item->card[++i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) - WBUFW(buf,6) = j; + if (item->card[++i] > 0 && (j = itemdb_viewid(item->card[i])) > 0) + buf->card[3] = j; else - WBUFW(buf,6) = item->card[i]; -} - -static void clif_addcards2(unsigned short *cards, struct item *item) -{ - int i=0,j; - nullpo_retv(cards); - if( item == NULL ) { //Blank data - cards[0] = 0; - cards[1] = 0; - cards[2] = 0; - cards[3] = 0; - return; - } - if( item->card[0] == CARD0_PET ) { //pet eggs - cards[0] = 0; - cards[1] = 0; - cards[2] = 0; - cards[3] = item->card[3]; //Pet renamed flag. - return; - } - if( item->card[0] == CARD0_FORGE || item->card[0] == CARD0_CREATE ) { //Forged/created items - cards[0] = item->card[0]; - cards[1] = item->card[1]; - cards[2] = item->card[2]; - cards[3] = item->card[3]; - return; - } - //Client only receives four cards.. so randomly send them a set of cards. [Skotlex] - if( MAX_SLOTS > 4 && (j = itemdb_slot(item->nameid)) > 4 ) - i = rnd()%(j-3); //eg: 6 slots, possible i values: 0->3, 1->4, 2->5 => i = rnd()%3; - - //Normal items. - if( item->card[i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) - cards[0] = j; - else - cards[0] = item->card[i]; - - if( item->card[++i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) - cards[1] = j; - else - cards[1] = item->card[i]; - - if( item->card[++i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) - cards[2] = j; - else - cards[2] = item->card[i]; - - if( item->card[++i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) - cards[3] = j; - else - cards[3] = item->card[i]; + buf->card[3] = item->card[i]; } /** @@ -2623,7 +2592,7 @@ static void clif_additem(struct map_session_data *sd, int n, int amount, int fai p.IsIdentified = sd->status.inventory[n].identify ? 1 : 0; p.IsDamaged = (sd->status.inventory[n].attribute & ATTR_BROKEN) != 0 ? 1 : 0; p.refiningLevel =sd->status.inventory[n].refine; - clif->addcards2(&p.slot.card[0], &sd->status.inventory[n]); + clif->addcards(&p.slot, &sd->status.inventory[n]); p.location = pc->equippoint(sd,n); p.type = itemtype(sd->inventory_data[n]->type); #if PACKETVER >= 20061218 @@ -2664,6 +2633,22 @@ static void clif_dropitem(struct map_session_data *sd, int n, int amount) WFIFOSET(fd,packet_len(0xaf)); } +static void clif_item_movefailed(struct map_session_data *sd, int n) +{ +#if PACKETVER_MAIN_NUM >= 20161214 || PACKETVER_RE_NUM >= 20161130 || defined(PACKETVER_ZERO) + int fd = sd->fd; + const int len = sizeof(struct PACKET_ZC_INVENTORY_MOVE_FAILED); + WFIFOHEAD(fd, len); + struct PACKET_ZC_INVENTORY_MOVE_FAILED *p = WFIFOP(fd, 0); + p->packetType = 0xaa7; + p->index = n; + p->unknown = 1; + WFIFOSET(fd, len); +#else + clif->dropitem(sd, n, 0); +#endif +} + /// Notifies the client, that an inventory item was deleted (ZC_DELETE_ITEM_FROM_BODY). /// 07fa <delete type>.W <index>.W <amount>.W /// delete type: @see enum delitem_reason @@ -2739,7 +2724,7 @@ static void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *it #endif p->RefiningLevel = it->refine; - clif->addcards2(&p->slot.card[0], it); + clif->addcards(&p->slot, it); #if PACKETVER >= 20071002 p->HireExpireDate = it->expire_time; @@ -2788,7 +2773,7 @@ static void clif_item_normal(short idx, struct NORMALITEM_INFO *p, struct item * p->WearState = id->equip; #if PACKETVER >= 5 - clif->addcards2(&p->slot.card[0], i); + clif->addcards(&p->slot, i); #endif #if PACKETVER >= 20080102 @@ -3188,12 +3173,13 @@ static void clif_updatestatus(struct map_session_data *sd, int type) WFIFOL(fd,4)=pc_leftside_matk(sd); break; case SP_ZENY: +// [4144] possible send 64 bit value from PACKETVER_MAIN_NUM >= 20170906 || PACKETVER_RE_NUM >= 20170830 || defined(PACKETVER_ZERO) +// but kro sending 0xb1 packet only. WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=sd->status.zeny; len = packet_len(0xb1); break; -// [4144] exact version unknown, between 20170405 to 20170913? -#if PACKETVER >= 20170830 +#if PACKETVER_MAIN_NUM >= 20170906 || PACKETVER_RE_NUM >= 20170830 || defined(PACKETVER_ZERO) case SP_BASEEXP: WFIFOW(fd, 0) = 0xacb; WFIFOQ(fd, 4) = sd->status.base_exp; @@ -3521,21 +3507,15 @@ static void clif_changetraplook(struct block_list *bl, int val) /// 01d7 <id>.L <type>.B <value>.L (ZC_SPRITE_CHANGE2) static void clif_sendlook(struct block_list *bl, int id, int type, int val, int val2, enum send_target target) { - unsigned char buf[32]; -#if PACKETVER < 4 - WBUFW(buf,0)=0xc3; - WBUFL(buf,2)=id; - WBUFB(buf,6)=type; - WBUFB(buf,7)=val; - clif->send(buf,packet_len(0xc3),bl,target); -#else - WBUFW(buf,0)=0x1d7; - WBUFL(buf,2)=id; - WBUFB(buf,6)=type; - WBUFW(buf,7)=val; - WBUFW(buf,9)=val2; - clif->send(buf,packet_len(0x1d7),bl,target); + struct PACKET_ZC_SPRITE_CHANGE p; + p.packetType = sendLookType; + p.AID = id; + p.type = type; + p.val = val; +#if PACKETVER >= 4 + p.val2 = val2; #endif + clif->send(&p, sizeof(p), bl, target); } //For the stupid cloth-dye bug. Resends the given view data to the area specified by bl. @@ -3654,12 +3634,16 @@ static void clif_arrow_create_list(struct map_session_data *sd) { int i, c; int fd; + int len; + struct PACKET_ZC_MAKINGARROW_LIST *p; nullpo_retv(sd); fd = sd->fd; - WFIFOHEAD(fd, MAX_SKILL_ARROW_DB*2+4); - WFIFOW(fd,0) = 0x1ad; + len = MAX_SKILL_ARROW_DB * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x1ad; for (i = 0, c = 0; i < MAX_SKILL_ARROW_DB; i++) { int j; @@ -3668,14 +3652,15 @@ static void clif_arrow_create_list(struct map_session_data *sd) && !sd->status.inventory[j].equip && sd->status.inventory[j].identify ) { if ((j = itemdb_viewid(skill->dbs->arrow_db[i].nameid)) > 0) - WFIFOW(fd,c*2+4) = j; + p->items[c].itemId = j; else - WFIFOW(fd,c*2+4) = skill->dbs->arrow_db[i].nameid; + p->items[c].itemId = skill->dbs->arrow_db[i].nameid; c++; } } - WFIFOW(fd,2) = c*2+4; - WFIFOSET(fd, WFIFOW(fd,2)); + len = c * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST); + p->packetLength = len; + WFIFOSET(fd, len); if (c > 0) { sd->menuskill_id = AC_MAKINGARROW; sd->menuskill_val = c; @@ -3853,40 +3838,33 @@ static void clif_changeoption2(struct block_list *bl) /// 01c8 <index>.W <name id>.W <id>.L <amount>.W <result>.B (ZC_USE_ITEM_ACK2) static void clif_useitemack(struct map_session_data *sd, int index, int amount, bool ok) { + struct PACKET_ZC_USE_ITEM_ACK p; + int fd; + nullpo_retv(sd); - if(!ok) { - int fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xa8)); - WFIFOW(fd,0)=0xa8; - WFIFOW(fd,2)=index+2; - WFIFOW(fd,4)=amount; - WFIFOB(fd,6)=ok; - WFIFOSET(fd,packet_len(0xa8)); - } - else { -#if PACKETVER < 3 - int fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xa8)); - WFIFOW(fd,0)=0xa8; - WFIFOW(fd,2)=index+2; - WFIFOW(fd,4)=amount; - WFIFOB(fd,6)=ok; - WFIFOSET(fd,packet_len(0xa8)); -#else - unsigned char buf[32]; + if (index < 0 || index >= MAX_INVENTORY) + return; - WBUFW(buf,0)=0x1c8; - WBUFW(buf,2)=index+2; - if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0) - WBUFW(buf,4)=sd->inventory_data[index]->view_id; - else - WBUFW(buf,4)=sd->status.inventory[index].nameid; - WBUFL(buf,6)=sd->bl.id; - WBUFW(buf,10)=amount; - WBUFB(buf,12)=ok; - clif->send(buf,packet_len(0x1c8),&sd->bl,AREA); + fd = sd->fd; + p.packetType = useItemAckType; + p.index = index + 2; +#if PACKETVER > 3 + if (sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0) + p.itemId = sd->inventory_data[index]->view_id; + else + p.itemId = sd->status.inventory[index].nameid; + p.AID = sd->bl.id; #endif + p.amount = amount; + p.result = ok; + + if (!ok) { + WFIFOHEAD(fd, sizeof(p)); + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); + } else { + clif->send(&p, sizeof(p), &sd->bl, AREA); } } @@ -4170,13 +4148,13 @@ static void clif_traderequest(struct map_session_data *sd, const char *name) static void clif_tradestart(struct map_session_data *sd, uint8 type) { int fd; -#if PACKETVER >= 6 +#if PACKETVER >= 20090406 struct map_session_data *tsd = NULL; #endif // PACKETVER >= 6 nullpo_retv(sd); fd = sd->fd; -#if PACKETVER >= 6 +#if PACKETVER >= 20090406 tsd = map->id2sd(sd->trade_partner); if (tsd) { WFIFOHEAD(fd,packet_len(0x1f5)); @@ -4187,11 +4165,12 @@ static void clif_tradestart(struct map_session_data *sd, uint8 type) WFIFOSET(fd,packet_len(0x1f5)); return; } -#endif // PACKETVER >= 6 +#else WFIFOHEAD(fd,packet_len(0xe7)); WFIFOW(fd,0) = 0xe7; WFIFOB(fd,2) = type; WFIFOSET(fd,packet_len(0xe7)); +#endif // PACKETVER >= 6 } /// Notifies the client about an item from other player in current trade. @@ -4200,63 +4179,37 @@ static void clif_tradestart(struct map_session_data *sd, uint8 type) static void clif_tradeadditem(struct map_session_data *sd, struct map_session_data *tsd, int index, int amount) { int fd; - unsigned char *buf; + struct PACKET_ZC_ADD_EXCHANGE_ITEM p; + nullpo_retv(sd); nullpo_retv(tsd); fd = tsd->fd; - buf = WFIFOP(fd,0); - WFIFOHEAD(fd,packet_len(tradeaddType)); - WBUFW(buf,0) = tradeaddType; - if( index == 0 ) - { -#if PACKETVER < 20100223 - WBUFL(buf,2) = amount; //amount - WBUFW(buf,6) = 0; // type id -#else - WBUFW(buf,2) = 0; // type id - WBUFB(buf,4) = 0; // item type - WBUFL(buf,5) = amount; // amount - buf = WBUFP(buf,1); //Advance 1B -#endif - WBUFB(buf,8) = 0; //identify flag - WBUFB(buf,9) = 0; // attribute - WBUFB(buf,10)= 0; //refine - WBUFW(buf,11)= 0; //card (4w) - WBUFW(buf,13)= 0; //card (4w) - WBUFW(buf,15)= 0; //card (4w) - WBUFW(buf,17)= 0; //card (4w) -#if PACKETVER >= 20150226 - clif->add_item_options(WBUFP(buf, 19), &sd->status.inventory[index]); -#endif - } - else + WFIFOHEAD(fd, sizeof(p)); + memset(&p, 0, sizeof(p)); + p.packetType = tradeaddType; + p.amount = amount; + if (index != 0) { index -= 2; //index fix -#if PACKETVER < 20100223 - WBUFL(buf,2) = amount; //amount - if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0) - WBUFW(buf,6) = sd->inventory_data[index]->view_id; - else - WBUFW(buf,6) = sd->status.inventory[index].nameid; // type id -#else + Assert_retv(index >= 0 && index < MAX_INVENTORY); if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0) - WBUFW(buf,2) = sd->inventory_data[index]->view_id; + p.itemId = sd->inventory_data[index]->view_id; else - WBUFW(buf,2) = sd->status.inventory[index].nameid; // type id - WBUFB(buf,4) = sd->inventory_data[index]->type; // item type - WBUFL(buf,5) = amount; // amount - buf = WBUFP(buf,1); //Advance 1B -#endif - WBUFB(buf,8) = sd->status.inventory[index].identify; //identify flag - WBUFB(buf,9) = sd->status.inventory[index].attribute; // attribute - WBUFB(buf,10)= sd->status.inventory[index].refine; //refine - clif->addcards(WBUFP(buf, 11), &sd->status.inventory[index]); + p.itemId = sd->status.inventory[index].nameid; +#if PACKETVER >= 20100223 + p.itemType = sd->inventory_data[index]->type; +#endif + p.identified = sd->status.inventory[index].identify; + p.damaged = sd->status.inventory[index].attribute; + p.refine = sd->status.inventory[index].refine; + clif->addcards(&p.slot, &sd->status.inventory[index]); #if PACKETVER >= 20150226 - clif->add_item_options(WBUFP(buf, 19), &sd->status.inventory[index]); + clif->add_item_options(&p.option_data[0], &sd->status.inventory[index]); #endif } - WFIFOSET(fd,packet_len(tradeaddType)); + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Notifies the client about the result of request to add an item to the current trade (ZC_ACK_ADD_EXCHANGE_ITEM). @@ -4265,6 +4218,8 @@ static void clif_tradeadditem(struct map_session_data *sd, struct map_session_da /// 0 = success /// 1 = overweight /// 2 = trade canceled +/// 3 = amount is exceeded. message 0x792 +/// 4 = other amount is exceeded. message 0x793 static void clif_tradeitemok(struct map_session_data *sd, int index, int fail) { int fd; @@ -4362,31 +4317,32 @@ static void clif_updatestorageamount(struct map_session_data *sd, int amount, in /// 01c4 <index>.W <amount>.L <nameid>.W <type>.B <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W (ZC_ADD_ITEM_TO_STORE2) static void clif_storageitemadded(struct map_session_data *sd, struct item *i, int index, int amount) { - int view,fd; - int offset = 0; + int view, fd; + struct PACKET_ZC_ADD_ITEM_TO_STORE p; nullpo_retv(sd); nullpo_retv(i); - fd=sd->fd; + + fd = sd->fd; view = itemdb_viewid(i->nameid); - WFIFOHEAD(fd,packet_len(storageaddType)); - WFIFOW(fd, 0) = storageaddType; // Storage item added - WFIFOW(fd, 2) = index+1; // index - WFIFOL(fd, 4) = amount; // amount - WFIFOW(fd, 8) = ( view > 0 ) ? view : i->nameid; // id + WFIFOHEAD(fd, sizeof(p)); + p.packetType = storageaddType; // Storage item added + p.index = index + 1; // index + p.amount = amount; // amount + p.itemId = (view > 0) ? view : i->nameid; // id #if PACKETVER >= 5 - WFIFOB(fd,10) = itemtype(itemdb_type(i->nameid)); //type - offset += 1; + p.itemType = itemtype(itemdb_type(i->nameid)); //type #endif - WFIFOB(fd,10+offset) = i->identify; //identify flag - WFIFOB(fd,11+offset) = i->attribute; // attribute - WFIFOB(fd,12+offset) = i->refine; //refine - clif->addcards(WFIFOP(fd,13+offset), i); + p.identified = i->identify; //identify flag + p.damaged = i->attribute; // attribute + p.refine = i->refine; //refine + clif->addcards(&p.slot, i); #if PACKETVER >= 20150226 - clif->add_item_options(WFIFOP(fd, 21 + offset), i); + clif->add_item_options(&p.option_data[0], i); #endif - WFIFOSET(fd,packet_len(storageaddType)); + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Notifies the client of an item being deleted from the storage (ZC_DELETE_ITEM_FROM_STORE). @@ -4755,26 +4711,29 @@ static void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum sen /// 009d <id>.L <name id>.W <identified>.B <x>.W <y>.W <amount>.W <subX>.B <subY>.B static void clif_getareachar_item(struct map_session_data *sd, struct flooritem_data *fitem) { - int view,fd; + int view, fd; + struct PACKET_ZC_ITEM_ENTRY p; nullpo_retv(sd); nullpo_retv(fitem); - fd=sd->fd; + fd = sd->fd; - WFIFOHEAD(fd,packet_len(0x9d)); - WFIFOW(fd,0)=0x9d; - WFIFOL(fd,2)=fitem->bl.id; - if((view = itemdb_viewid(fitem->item_data.nameid)) > 0) - WFIFOW(fd,6)=view; + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x9d; + p.AID = fitem->bl.id; + if ((view = itemdb_viewid(fitem->item_data.nameid)) > 0) + p.itemId = view; else - WFIFOW(fd,6)=fitem->item_data.nameid; - WFIFOB(fd,8)=fitem->item_data.identify; - WFIFOW(fd,9)=fitem->bl.x; - WFIFOW(fd,11)=fitem->bl.y; - WFIFOW(fd,13)=fitem->item_data.amount; - WFIFOB(fd,15)=fitem->subx; - WFIFOB(fd,16)=fitem->suby; - WFIFOSET(fd,packet_len(0x9d)); + p.itemId = fitem->item_data.nameid; + p.identify = fitem->item_data.identify; + p.x = fitem->bl.x; + p.y = fitem->bl.y; + p.amount = fitem->item_data.amount; + p.subX = fitem->subx; + p.subY = fitem->suby; + + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } static void clif_graffiti_entry(struct block_list *bl, struct skill_unit *su, enum send_target target) @@ -5274,9 +5233,10 @@ static void clif_skillcastcancel(struct block_list *bl) /// if(result!=0) doesn't display any of the previous messages /// Note: when this packet is received an unknown flag is always set to 0, /// suggesting this is an ACK packet for the UseSkill packets and should be sent on success too [FlavioJS] -static void clif_skill_fail(struct map_session_data *sd, uint16 skill_id, enum useskill_fail_cause cause, int btype) +static void clif_skill_fail(struct map_session_data *sd, uint16 skill_id, enum useskill_fail_cause cause, int btype, int32 item_id) { int fd; + struct PACKET_ZC_ACK_TOUSESKILL p; if (!sd) { //Since this is the most common nullpo.... @@ -5284,28 +5244,31 @@ static void clif_skill_fail(struct map_session_data *sd, uint16 skill_id, enum u return; } - fd=sd->fd; + fd = sd->fd; if (!fd) return; - if(battle_config.display_skill_fail&1) + if (battle_config.display_skill_fail&1) return; //Disable all skill failed messages - if(cause==USESKILL_FAIL_SKILLINTERVAL && !sd->state.showdelay) + if (cause == USESKILL_FAIL_SKILLINTERVAL && !sd->state.showdelay) return; //Disable delay failed messages - if(skill_id == RG_SNATCHER && battle_config.display_skill_fail&4) + if (skill_id == RG_SNATCHER && battle_config.display_skill_fail & 4) return; - if(skill_id == TF_POISON && battle_config.display_skill_fail&8) + if (skill_id == TF_POISON && battle_config.display_skill_fail & 8) return; - WFIFOHEAD(fd,packet_len(0x110)); - WFIFOW(fd,0) = 0x110; - WFIFOW(fd,2) = skill_id; - WFIFOL(fd,4) = btype; - WFIFOB(fd,8) = 0;// success - WFIFOB(fd,9) = cause; - WFIFOSET(fd,packet_len(0x110)); + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x110; + p.skillId = skill_id; + p.btype = btype; + p.itemId = item_id; + p.flag = 0; // 0 - failed + p.cause = cause; + + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Skill cooldown display icon (ZC_SKILL_POSTDELAY). @@ -5560,28 +5523,46 @@ static void clif_skill_poseffect(struct block_list *src, uint16 skill_id, int va static void clif_skill_warppoint(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4) { int fd; + int len; + int mapsCount = 0; + struct PACKET_ZC_WARPLIST *p; nullpo_retv(sd); fd = sd->fd; +#if PACKETVER_MAIN_NUM >= 20170502 || PACKETVER_RE_NUM >= 20170419 || defined(PACKETVER_ZERO) + len = sizeof(struct PACKET_ZC_WARPLIST) + sizeof(struct PACKET_ZC_WARPLIST_sub) * mapsCount; +#else + len = sizeof(struct PACKET_ZC_WARPLIST); +#endif - WFIFOHEAD(fd,packet_len(0x11c)); - WFIFOW(fd,0) = 0x11c; - WFIFOW(fd,2) = skill_id; - memset(WFIFOP(fd,4), 0x00, 4*MAP_NAME_LENGTH_EXT); - if (map1 == (unsigned short)-1) strcpy(WFIFOP(fd,4), "Random"); - else // normal map name - if (map1 > 0) mapindex->getmapname_ext(mapindex_id2name(map1), WFIFOP(fd,4)); - if (map2 > 0) mapindex->getmapname_ext(mapindex_id2name(map2), WFIFOP(fd,20)); - if (map3 > 0) mapindex->getmapname_ext(mapindex_id2name(map3), WFIFOP(fd,36)); - if (map4 > 0) mapindex->getmapname_ext(mapindex_id2name(map4), WFIFOP(fd,52)); - WFIFOSET(fd,packet_len(0x11c)); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + memset(p, 0, len); + p->packetType = skilWarpPointType; + p->skillId = skill_id; + if (map1 == (unsigned short)-1) { + strcpy(p->maps[mapsCount++].map, "Random"); + } else { // normal map name + if (map1 > 0) mapindex->getmapname_ext(mapindex_id2name(map1), p->maps[mapsCount++].map); + } + if (map2 > 0) mapindex->getmapname_ext(mapindex_id2name(map2), p->maps[mapsCount++].map); + if (map3 > 0) mapindex->getmapname_ext(mapindex_id2name(map3), p->maps[mapsCount++].map); + if (map4 > 0) mapindex->getmapname_ext(mapindex_id2name(map4), p->maps[mapsCount++].map); + +#if PACKETVER_MAIN_NUM >= 20170502 || PACKETVER_RE_NUM >= 20170419 || defined(PACKETVER_ZERO) + len = sizeof(struct PACKET_ZC_WARPLIST) + sizeof(struct PACKET_ZC_WARPLIST_sub) * mapsCount; + p->packetLength = len; +#endif + + WFIFOSET(fd, len); sd->menuskill_id = skill_id; - if (skill_id == AL_WARP){ - sd->menuskill_val = (sd->ud.skillx<<16)|sd->ud.skilly; //Store warp position here. + if (skill_id == AL_WARP) { + sd->menuskill_val = (sd->ud.skillx << 16) | sd->ud.skilly; //Store warp position here. sd->state.workinprogress = 3; - }else + } else { sd->menuskill_val = skill_lv; + } } /// Memo message (ZC_ACK_REMEMBER_WARPPOINT). @@ -5673,35 +5654,40 @@ static void clif_skill_estimation(struct map_session_data *sd, struct block_list /// unused by the client static void clif_skill_produce_mix_list(struct map_session_data *sd, int skill_id, int trigger) { - int i,c,view,fd; + int i, c, view, fd; + int len; + struct PACKET_ZC_MAKABLEITEMLIST *p; + nullpo_retv(sd); - if(sd->menuskill_id == skill_id) + if (sd->menuskill_id == skill_id) return; //Avoid resending the menu twice or more times... - if( skill_id == GC_CREATENEWPOISON ) + if (skill_id == GC_CREATENEWPOISON) skill_id = GC_RESEARCHNEWPOISON; - fd=sd->fd; - WFIFOHEAD(fd, MAX_SKILL_PRODUCE_DB * 8 + 8); - WFIFOW(fd, 0)=0x18d; - - for(i=0,c=0;i<MAX_SKILL_PRODUCE_DB;i++){ - if( skill->can_produce_mix(sd,skill->dbs->produce_db[i].nameid, trigger, 1) && - ( ( skill_id > 0 && skill->dbs->produce_db[i].req_skill == skill_id ) || skill_id < 0 ) - ){ - if((view = itemdb_viewid(skill->dbs->produce_db[i].nameid)) > 0) - WFIFOW(fd,c*8+ 4)= view; + fd = sd->fd; + len = MAX_SKILL_PRODUCE_DB * sizeof(struct PACKET_ZC_MAKABLEITEMLIST_sub) + sizeof(struct PACKET_ZC_MAKABLEITEMLIST); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x18d; + + for (i = 0, c = 0; i < MAX_SKILL_PRODUCE_DB; i++) { + if (skill->can_produce_mix(sd, skill->dbs->produce_db[i].nameid, trigger, 1) && + ((skill_id > 0 && skill->dbs->produce_db[i].req_skill == skill_id) || skill_id < 0)) { + if ((view = itemdb_viewid(skill->dbs->produce_db[i].nameid)) > 0) + p->items[c].itemId = view; else - WFIFOW(fd,c*8+ 4)= skill->dbs->produce_db[i].nameid; - WFIFOW(fd,c*8+ 6)= 0; - WFIFOW(fd,c*8+ 8)= 0; - WFIFOW(fd,c*8+10)= 0; + p->items[c].itemId = skill->dbs->produce_db[i].nameid; + p->items[c].material[0] = 0; + p->items[c].material[1] = 0; + p->items[c].material[2] = 0; c++; } } - WFIFOW(fd, 2)=c*8+8; - WFIFOSET(fd,WFIFOW(fd,2)); - if(c > 0) { + len = c * sizeof(struct PACKET_ZC_MAKABLEITEMLIST_sub) + sizeof(struct PACKET_ZC_MAKABLEITEMLIST); + p->packetLength = len; + WFIFOSET(fd, len); + if (c > 0) { sd->menuskill_id = skill_id; sd->menuskill_val = trigger; return; @@ -5722,50 +5708,53 @@ static void clif_cooking_list(struct map_session_data *sd, int trigger, uint16 s int fd; int i, c; int view; + int len; + struct PACKET_ZC_MAKINGITEM_LIST *p; nullpo_retv(sd); fd = sd->fd; - WFIFOHEAD(fd, 6 + 2 * MAX_SKILL_PRODUCE_DB); - WFIFOW(fd,0) = 0x25a; - WFIFOW(fd,4) = list_type; // list type + len = sizeof(struct PACKET_ZC_MAKINGITEM_LIST) + MAX_SKILL_PRODUCE_DB * sizeof(struct PACKET_ZC_MAKINGITEM_LIST_sub); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x25a; + p->makeItem = list_type; // list type c = 0; - for( i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ) { - if( !skill->can_produce_mix(sd,skill->dbs->produce_db[i].nameid,trigger, qty) ) + for (i = 0; i < MAX_SKILL_PRODUCE_DB; i++) { + if (!skill->can_produce_mix(sd,skill->dbs->produce_db[i].nameid,trigger, qty)) continue; - if( (view = itemdb_viewid(skill->dbs->produce_db[i].nameid)) > 0 ) - WFIFOW(fd, 6 + 2 * c) = view; + if ((view = itemdb_viewid(skill->dbs->produce_db[i].nameid)) > 0) + p->items[c].itemId = view; else - WFIFOW(fd, 6 + 2 * c) = skill->dbs->produce_db[i].nameid; + p->items[c].itemId = skill->dbs->produce_db[i].nameid; c++; } - if( skill_id == AM_PHARMACY ) { + len = sizeof(struct PACKET_ZC_MAKINGITEM_LIST) + c * sizeof(struct PACKET_ZC_MAKINGITEM_LIST_sub); + p->packetLength = len; + if (skill_id == AM_PHARMACY) { // Only send it while Cooking else check for c. - WFIFOW(fd,2) = 6 + 2 * c; - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOSET(fd, len); } - if( c > 0 ) { + if (c > 0) { sd->menuskill_id = skill_id; sd->menuskill_val = trigger; - if( skill_id != AM_PHARMACY ) { + if (skill_id != AM_PHARMACY) { sd->menuskill_val2 = qty; // amount. - WFIFOW(fd,2) = 6 + 2 * c; - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOSET(fd, len); } } else { clif_menuskill_clear(sd); - if( skill_id != AM_PHARMACY ) { // AM_PHARMACY is used to Cooking. + if (skill_id != AM_PHARMACY) { // AM_PHARMACY is used to Cooking. // It fails. #if PACKETVER >= 20091013 clif->msgtable_skill(sd, skill_id, MSG_SKILL_MATERIAL_FAIL); #else - WFIFOW(fd,2) = 6 + 2 * c; - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOSET(fd, len); #endif } } @@ -6126,6 +6115,7 @@ static void clif_map_property_mapall(int mapid, enum map_property property) struct block_list bl; unsigned char buf[16]; + memset(&bl, 0, sizeof(bl)); bl.id = 0; bl.type = BL_NUL; bl.m = mapid; @@ -6159,11 +6149,13 @@ static void clif_refine(int fd, int fail, int index, int val) /// 3 = "you lack the item %s to upgrade the weapon" MsgStringTable[914] in rgb(255,200,200) static void clif_upgrademessage(int fd, int result, int item_id) { - WFIFOHEAD(fd,packet_len(0x223)); - WFIFOW(fd,0)=0x223; - WFIFOL(fd,2)=result; - WFIFOW(fd,6)=item_id; - WFIFOSET(fd,packet_len(0x223)); + struct PACKET_ZC_ACK_WEAPONREFINE p; + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x223; + p.result = result; + p.itemId = item_id; + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Whisper is transmitted to the destination player (ZC_WHISPER). @@ -6204,6 +6196,7 @@ static void clif_wis_message(int fd, const char *nick, const char *mes, int mes_ /// 1 = target character is not logged in /// 2 = ignored by target /// 3 = everyone ignored by target +/// other = target character is not logged in static void clif_wis_end(int fd, int flag) { struct map_session_data *sd = sockt->session_is_valid(fd) ? sockt->session[fd]->session_data : NULL; @@ -6215,7 +6208,7 @@ static void clif_wis_end(int fd, int flag) p.PacketType = wisendType; p.result = (char)flag; #if PACKETVER >= 20131223 - p.unknown = 0; + p.AID = sd->bl.id; #endif clif->send(&p, sizeof(p), &sd->bl, SELF); @@ -6249,7 +6242,7 @@ static void clif_solved_charname(int fd, int charid, const char *name) } /// Presents a list of items that can be carded/composed (ZC_ITEMCOMPOSITION_LIST). -/// 017b <packet len>.W { <name id>.W }* +/// 017b <packet len>.W { <index>.W }* static void clif_use_card(struct map_session_data *sd, int idx) { int i, c; @@ -6299,7 +6292,7 @@ static void clif_insert_card(struct map_session_data *sd, int idx_equip, int idx } /// Presents a list of items that can be identified (ZC_ITEMIDENTIFY_LIST). -/// 0177 <packet len>.W { <name id>.W }* +/// 0177 <packet len>.W { <index>.W }* static void clif_item_identify_list(struct map_session_data *sd) { int i,c; @@ -6348,32 +6341,38 @@ static void clif_item_repair_list(struct map_session_data *sd, struct map_sessio { int i,c; int fd; + int len; + struct PACKET_ZC_REPAIRITEMLIST *p; nullpo_retv(sd); nullpo_retv(dstsd); - fd=sd->fd; + fd = sd->fd; - WFIFOHEAD(fd, MAX_INVENTORY * 13 + 4); - WFIFOW(fd,0)=0x1fc; + len = MAX_INVENTORY * sizeof(struct PACKET_ZC_REPAIRITEMLIST_sub) + sizeof(struct PACKET_ZC_REPAIRITEMLIST); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x1fc; for (i = c = 0; i < MAX_INVENTORY; i++) { int nameid = dstsd->status.inventory[i].nameid; if (nameid > 0 && (dstsd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { // && skill_can_repair(sd,nameid)) { - WFIFOW(fd,c*13+4) = i; - WFIFOW(fd,c*13+6) = nameid; - WFIFOB(fd,c*13+8) = dstsd->status.inventory[i].refine; - clif->addcards(WFIFOP(fd,c*13+9), &dstsd->status.inventory[i]); + p->items[c].index = i; + p->items[c].itemId = nameid; + p->items[c].refine = dstsd->status.inventory[i].refine; + clif->addcards(&p->items[c].slot, &dstsd->status.inventory[i]); c++; } } - if(c > 0) { - WFIFOW(fd,2)=c*13+4; - WFIFOSET(fd,WFIFOW(fd,2)); + if (c > 0) { + len = c * sizeof(struct PACKET_ZC_REPAIRITEMLIST_sub) + sizeof(struct PACKET_ZC_REPAIRITEMLIST); + p->packetLength = len; + WFIFOSET(fd, len); sd->menuskill_id = BS_REPAIRWEAPON; sd->menuskill_val = dstsd->bl.id; sd->menuskill_val2 = lv; - }else - clif->skill_fail(sd,sd->ud.skill_id,USESKILL_FAIL_LEVEL,0); + } else { + clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0); + } } /// Notifies the client about the result of a item repair request (ZC_ACK_ITEMREPAIR). @@ -6421,30 +6420,34 @@ static void clif_item_refine_list(struct map_session_data *sd) { int i,c; int fd; + int len; + struct PACKET_ZC_NOTIFY_WEAPONITEMLIST *p; uint16 skill_lv; nullpo_retv(sd); - skill_lv = pc->checkskill(sd,WS_WEAPONREFINE); - - fd=sd->fd; + skill_lv = pc->checkskill(sd, WS_WEAPONREFINE); - WFIFOHEAD(fd, MAX_INVENTORY * 13 + 4); - WFIFOW(fd,0)=0x221; + fd = sd->fd; + len = MAX_INVENTORY * sizeof(struct PACKET_ZC_NOTIFY_WEAPONITEMLIST_sub) + sizeof(struct PACKET_ZC_NOTIFY_WEAPONITEMLIST); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x221; for (i = c = 0; i < MAX_INVENTORY; i++) { - if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify + if (sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify && itemdb_wlv(sd->status.inventory[i].nameid) >= 1 && !sd->inventory_data[i]->flag.no_refine - && !(sd->status.inventory[i].equip&EQP_ARMS)){ - WFIFOW(fd,c*13+ 4)=i+2; - WFIFOW(fd,c*13+ 6)=sd->status.inventory[i].nameid; - WFIFOB(fd,c*13+ 8)=sd->status.inventory[i].refine; - clif->addcards(WFIFOP(fd,c*13+9), &sd->status.inventory[i]); + && !(sd->status.inventory[i].equip & EQP_ARMS)) { + p->items[c].index = i + 2; + p->items[c].itemId = sd->status.inventory[i].nameid; + p->items[c].refine = sd->status.inventory[i].refine; + clif->addcards(&p->items[c].slot, &sd->status.inventory[i]); c++; } } - WFIFOW(fd,2)=c*13+4; - WFIFOSET(fd,WFIFOW(fd,2)); + len = c * sizeof(struct PACKET_ZC_NOTIFY_WEAPONITEMLIST_sub) + sizeof(struct PACKET_ZC_NOTIFY_WEAPONITEMLIST); + p->packetLength = len; + WFIFOSET(fd, len); if (c > 0) { sd->menuskill_id = WS_WEAPONREFINE; sd->menuskill_val = skill_lv; @@ -6477,37 +6480,35 @@ static void clif_item_skill(struct map_session_data *sd, uint16 skill_id, uint16 /// 01c5 <index>.W <amount>.L <name id>.W <type>.B <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W (ZC_ADD_ITEM_TO_CART2) static void clif_cart_additem(struct map_session_data *sd, int n, int amount, int fail) { - int view,fd; - unsigned char *buf; - int offset = 0; + int view, fd; + struct PACKET_ZC_ADD_ITEM_TO_CART p; nullpo_retv(sd); - fd=sd->fd; - if(n<0 || n>=MAX_CART || sd->status.cart[n].nameid<=0) + fd = sd->fd; + if (n < 0 || n >= MAX_CART || sd->status.cart[n].nameid <= 0) return; - WFIFOHEAD(fd,packet_len(cartaddType)); - buf=WFIFOP(fd,0); - WBUFW(buf,0)=cartaddType; - WBUFW(buf,2)=n+2; - WBUFL(buf,4)=amount; - if((view = itemdb_viewid(sd->status.cart[n].nameid)) > 0) - WBUFW(buf,8)=view; + WFIFOHEAD(fd, sizeof(p)); + p.packetType = cartaddType; + p.index = n + 2; + p.amount = amount; + if ((view = itemdb_viewid(sd->status.cart[n].nameid)) > 0) + p.itemId = view; else - WBUFW(buf,8)=sd->status.cart[n].nameid; + p.itemId = sd->status.cart[n].nameid; #if PACKETVER >= 5 - WBUFB(buf,10)=itemdb_type(sd->status.cart[n].nameid); - offset = 1; + p.itemType = itemdb_type(sd->status.cart[n].nameid); #endif - WBUFB(buf,10+offset)=sd->status.cart[n].identify; - WBUFB(buf,11+offset)=sd->status.cart[n].attribute; - WBUFB(buf,12+offset)=sd->status.cart[n].refine; - clif->addcards(WBUFP(buf,13+offset), &sd->status.cart[n]); + p.identified = sd->status.cart[n].identify; + p.damaged = sd->status.cart[n].attribute; + p.refine = sd->status.cart[n].refine; + clif->addcards(&p.slot, &sd->status.cart[n]); #if PACKETVER >= 20150226 - clif->add_item_options(WBUFP(buf, 21 + offset), &sd->status.cart[n]); + clif->add_item_options(&p.option_data[0], &sd->status.cart[n]); #endif - WFIFOSET(fd,packet_len(cartaddType)); + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Deletes an item from character's cart (ZC_DELETE_ITEM_FROM_CART). @@ -6589,25 +6590,11 @@ static void clif_closevendingboard(struct block_list *bl, int fd) /// R 0800 <packet len>.W <owner id>.L <unique id>.L { <price>.L <amount>.W <index>.W <type>.B <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W }* (ZC_PC_PURCHASE_ITEMLIST_FROMMC2) static void clif_vendinglist(struct map_session_data *sd, unsigned int id, struct s_vending *vending_items) { - int i,fd; + int i, fd; int count; struct map_session_data* vsd; -#if PACKETVER < 20100105 - const int cmd = 0x133; - const int offset = 8; -#else - const int cmd = 0x800; - const int offset = 12; -#endif - -#if PACKETVER < 20150226 - const int item_length = 22; -// [4144] date 20160921 not confirmend. Can be bigger or smaller -#elif PACKETVER < 20160921 - const int item_length = 47; -#else - const int item_length = 53; -#endif + int len; + struct PACKET_ZC_PC_PURCHASE_ITEMLIST_FROMMC *p; nullpo_retv(sd); nullpo_retv(vending_items); @@ -6615,37 +6602,39 @@ static void clif_vendinglist(struct map_session_data *sd, unsigned int id, struc fd = sd->fd; count = vsd->vend_num; + len = sizeof(struct PACKET_ZC_PC_PURCHASE_ITEMLIST_FROMMC) + count * sizeof(struct PACKET_ZC_PC_PURCHASE_ITEMLIST_FROMMC_sub); - WFIFOHEAD(fd, offset+count*item_length); - WFIFOW(fd,0) = cmd; - WFIFOW(fd,2) = offset+count*item_length; - WFIFOL(fd,4) = id; + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = vendinglistType; + p->packetLength = len; + p->AID = id; #if PACKETVER >= 20100105 - WFIFOL(fd,8) = vsd->vender_id; + p->venderId = vsd->vender_id; #endif - for( i = 0; i < count; i++ ) { + for (i = 0; i < count; i++) { int index = vending_items[i].index; struct item_data* data = itemdb->search(vsd->status.cart[index].nameid); - WFIFOL(fd,offset+ 0+i*item_length) = vending_items[i].value; - WFIFOW(fd,offset+ 4+i*item_length) = vending_items[i].amount; - WFIFOW(fd,offset+ 6+i*item_length) = vending_items[i].index + 2; - WFIFOB(fd,offset+ 8+i*item_length) = itemtype(data->type); - WFIFOW(fd,offset+ 9+i*item_length) = ( data->view_id > 0 ) ? data->view_id : vsd->status.cart[index].nameid; - WFIFOB(fd,offset+11+i*item_length) = vsd->status.cart[index].identify; - WFIFOB(fd,offset+12+i*item_length) = vsd->status.cart[index].attribute; - WFIFOB(fd,offset+13+i*item_length) = vsd->status.cart[index].refine; - clif->addcards(WFIFOP(fd,offset+14+i*item_length), &vsd->status.cart[index]); + p->items[i].price = vending_items[i].value; + p->items[i].amount = vending_items[i].amount; + p->items[i].index = vending_items[i].index + 2; + p->items[i].itemType = itemtype(data->type); + p->items[i].itemId = (data->view_id > 0) ? data->view_id : vsd->status.cart[index].nameid; + p->items[i].identified = vsd->status.cart[index].identify; + p->items[i].damaged = vsd->status.cart[index].attribute; + p->items[i].refine = vsd->status.cart[index].refine; + clif->addcards(&p->items[i].slot, &vsd->status.cart[index]); #if PACKETVER >= 20150226 - clif->add_item_options(WFIFOP(fd, offset + 22 + i * item_length), &vsd->status.cart[index]); + clif->add_item_options(&p->items[i].option_data[0], &vsd->status.cart[index]); #endif -// [4144] date 20160921 not confirmend. Can be bigger or smaller +// [4144] date 20160921 not confirmed. Can be bigger or smaller #if PACKETVER >= 20160921 - WFIFOL(fd, offset + 47 + i * item_length) = pc->item_equippoint(sd, data); - WFIFOW(fd, offset + 51 + i * item_length) = data->view_sprite; + p->items[i].location = pc->item_equippoint(sd, data); + p->items[i].viewSprite = data->view_sprite; #endif } - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOSET(fd, len); } /// Shop purchase failure (ZC_PC_PURCHASE_RESULT_FROMMC). @@ -6677,48 +6666,54 @@ static void clif_buyvending(struct map_session_data *sd, int index, int amount, /// 0136 <packet len>.W <owner id>.L { <price>.L <index>.W <amount>.W <type>.B <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W }* static void clif_openvending(struct map_session_data *sd, int id, struct s_vending *vending_items) { - int i,fd; + int i, fd; int count; -#if PACKETVER >= 20150226 - const int item_length = 47; -#else - const int item_length = 22; -#endif + struct PACKET_ZC_PC_PURCHASE_MYITEMLIST *p; + int len; nullpo_retv(sd); nullpo_retv(vending_items); fd = sd->fd; count = sd->vend_num; - - WFIFOHEAD(fd, 8+count*item_length); - WFIFOW(fd,0) = 0x136; - WFIFOW(fd,2) = 8+count*item_length; - WFIFOL(fd,4) = id; - for( i = 0; i < count; i++ ) { + len = sizeof(struct PACKET_ZC_PC_PURCHASE_MYITEMLIST) + count * sizeof(struct PACKET_ZC_PC_PURCHASE_MYITEMLIST_sub); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x136; + p->packetLength = len; + p->AID = id; + for (i = 0; i < count; i++) { int index = vending_items[i].index; struct item_data* data = itemdb->search(sd->status.cart[index].nameid); - WFIFOL(fd, 8+i*item_length) = vending_items[i].value; - WFIFOW(fd,12+i*item_length) = vending_items[i].index + 2; - WFIFOW(fd,14+i*item_length) = vending_items[i].amount; - WFIFOB(fd,16+i*item_length) = itemtype(data->type); - WFIFOW(fd,17+i*item_length) = ( data->view_id > 0 ) ? data->view_id : sd->status.cart[index].nameid; - WFIFOB(fd,19+i*item_length) = sd->status.cart[index].identify; - WFIFOB(fd,20+i*item_length) = sd->status.cart[index].attribute; - WFIFOB(fd,21+i*item_length) = sd->status.cart[index].refine; - clif->addcards(WFIFOP(fd,22+i*item_length), &sd->status.cart[index]); + p->items[i].price = vending_items[i].value; + p->items[i].index = vending_items[i].index + 2; + p->items[i].amount = vending_items[i].amount; + p->items[i].itemType = itemtype(data->type); + p->items[i].itemId = (data->view_id > 0) ? data->view_id : sd->status.cart[index].nameid; + p->items[i].identified = sd->status.cart[index].identify; + p->items[i].damaged = sd->status.cart[index].attribute; + p->items[i].refine = sd->status.cart[index].refine; + clif->addcards(&p->items[i].slot, &sd->status.cart[index]); #if PACKETVER >= 20150226 - clif->add_item_options(WFIFOP(fd, 30 + i * item_length), &sd->status.cart[index]); + clif->add_item_options(&p->items[i].option_data[0], &sd->status.cart[index]); #endif } - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOSET(fd, len); + clif->openvendingAck(fd, 0); +} + +// 0 - open vending success +// 1 - message MSG_MERCHANTSHOP_MAKING_FAIL +// 2 - silent ignore +// 3 - message MSG_ID_C9D (You can not open a stall at the current location) +static void clif_openvendingAck(int fd, int result) +{ #if PACKETVER >= 20140625 - /** should go elsewhere perhaps? it has to be bundled with this however. **/ WFIFOHEAD(fd, packet_len(0xa28)); - WFIFOW(fd, 0) = 0xa28; - WFIFOB(fd, 2) = 0;/** 1 is failure. our current responses to failure are working so not yet implemented **/ + WFIFOW(fd, 0) = 0xa28; // ZC_ACK_OPENSTORE2 + WFIFOB(fd, 2) = result; WFIFOSET(fd, packet_len(0xa28)); #endif } @@ -6803,7 +6798,7 @@ static void clif_party_member_info(struct party_data *p, struct map_session_data packet.GID = sd->status.char_id; #endif packet.leader = (p->party.member[i].leader) ? 0 : 1; -#if PACKETVER >= 20170502 +#if PACKETVER_MAIN_NUM >= 20170524 || PACKETVER_RE_NUM >= 20170502 || defined(PACKETVER_ZERO) packet.class = sd->status.class; packet.baseLevel = sd->status.base_level; #endif @@ -6854,7 +6849,7 @@ static void clif_party_info(struct party_data *p, struct map_session_data *sd) mapindex->getmapname_ext(mapindex_id2name(m->map), packet->members[c].mapName); packet->members[c].leader = (m->leader) ? 0 : 1; packet->members[c].offline = (m->online) ? 0 : 1; -#if PACKETVER >= 20170502 +#if PACKETVER_MAIN_NUM >= 20170524 || PACKETVER_RE_NUM >= 20170502 || defined(PACKETVER_ZERO) packet->members[c].class = m->class; packet->members[c].baseLevel = m->lv; #endif @@ -6873,8 +6868,7 @@ static void clif_party_info(struct party_data *p, struct map_session_data *sd) /// 0abd <account id>.L <job>.W <level>.W static void clif_party_job_and_level(struct map_session_data *sd) { -// [4144] packet 0xabd added in client in 2017-02-15 because this probably it can works for clients older than 20170502 -#if PACKETVER >= 20170502 +#if PACKETVER_MAIN_NUM >= 20170502 || PACKETVER_RE_NUM >= 20170419 || defined(PACKETVER_ZERO) unsigned char buf[10]; nullpo_retv(sd); @@ -6936,15 +6930,17 @@ static void clif_party_invite(struct map_session_data *sd, struct map_session_da /// Party invite result. /// 00fd <nick>.24S <result>.B (ZC_ACK_REQ_JOIN_GROUP) /// 02c5 <nick>.24S <result>.L (ZC_PARTY_JOIN_REQ_ACK) -/// result=0 : char is already in a party -> MsgStringTable[80] -/// result=1 : party invite was rejected -> MsgStringTable[81] -/// result=2 : party invite was accepted -> MsgStringTable[82] -/// result=3 : party is full -> MsgStringTable[83] -/// result=4 : char of the same account already joined the party -> MsgStringTable[608] -/// result=5 : char blocked party invite -> MsgStringTable[1324] (since 20070904) -/// result=7 : char is not online or doesn't exist -> MsgStringTable[71] (since 20070904) -/// result=8 : (%s) TODO instance related? -> MsgStringTable[1388] (since 20080527) -/// return=9 : TODO map prohibits party joining? -> MsgStringTable[1871] (since 20110205) +/// result=0 : char is already in a party -> MsgStringTable[80] +/// result=1 : party invite was rejected -> MsgStringTable[81] +/// result=2 : party invite was accepted -> MsgStringTable[82] +/// result=3 : party is full -> MsgStringTable[83] +/// result=4 : char of the same account already joined the party -> MsgStringTable[608] +/// result=5 : char blocked party invite -> MsgStringTable[1324] (since 20070904) +/// result=7 : char is not online or doesn't exist -> MsgStringTable[71] (since 20070904) +/// result=8 : (%s) are currently in restricted map to join a party. -> MsgStringTable[1388] (since 20080527) +/// result=9 : Cannot join a party in this map. -> MsgStringTable[1871] (since 20110215) +/// result=10 : You cannot invite or withdraw while in memorial dungeon -> message: MSG_ID_BD3 (since 20161130) +/// result=11 : The character is a level that can not join the party -> message: MSG_ID_C9A (since 20170412) static void clif_party_inviteack(struct map_session_data *sd, const char *nick, int result) { int fd; @@ -7198,22 +7194,28 @@ static void clif_movetoattack(struct map_session_data *sd, struct block_list *bl /// 1 = failure /// 2 = success (alchemist) /// 3 = failure (alchemist) +/// 4 = success (???) +/// 5 = failure (???) +/// 6 = failure (???) +/// 7 = failure (???) static void clif_produceeffect(struct map_session_data *sd, int flag, int nameid) { - int view,fd; + int view, fd; + struct PACKET_ZC_ACK_REQMAKINGITEM p; nullpo_retv(sd); fd = sd->fd; clif->solved_charname(fd, sd->status.char_id, sd->status.name); - WFIFOHEAD(fd,packet_len(0x18f)); - WFIFOW(fd, 0)=0x18f; - WFIFOW(fd, 2)=flag; - if((view = itemdb_viewid(nameid)) > 0) - WFIFOW(fd, 4)=view; + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x18f; + p.result = flag; + if ((view = itemdb_viewid(nameid)) > 0) + p.itemId = view; else - WFIFOW(fd, 4)=nameid; - WFIFOSET(fd,packet_len(0x18f)); + p.itemId = nameid; + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Initiates the pet taming process (ZC_START_CAPTURE). @@ -7288,6 +7290,7 @@ static void clif_sendegg(struct map_session_data *sd) /// 3 = accessory /// 4 = performance (data = 1~3: normal, 4: special) /// 5 = hairstyle +/// 6 = close egg selection ui and update egg in inventory (PACKETVER >= 20180704) /// /// If sd is null, the update is sent to nearby objects, otherwise it is sent only to that player. static void clif_send_petdata(struct map_session_data *sd, struct pet_data *pd, int type, int param) @@ -7367,15 +7370,17 @@ static void clif_pet_emotion(struct pet_data *pd, int param) static void clif_pet_food(struct map_session_data *sd, int foodid, int fail) { int fd; + struct PACKET_ZC_FEED_PET p; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0x1a3)); - WFIFOW(fd,0)=0x1a3; - WFIFOB(fd,2)=fail; - WFIFOW(fd,3)=foodid; - WFIFOSET(fd,packet_len(0x1a3)); + fd = sd->fd; + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x1a3; + p.result = fail; + p.itemId = foodid; + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Presents a list of skills that can be auto-spelled (ZC_AUTOSPELLLIST). @@ -7543,20 +7548,23 @@ static void clif_mvp_effect(struct map_session_data *sd) /// MVP item reward message (ZC_MVP_GETTING_ITEM). /// 010a <name id>.W +/// 010a <name id>.L static void clif_mvp_item(struct map_session_data *sd, int nameid) { - int view,fd; + int view, fd; + struct PACKET_ZC_MVP_GETTING_ITEM p; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0x10a)); - WFIFOW(fd,0)=0x10a; - if((view = itemdb_viewid(nameid)) > 0) - WFIFOW(fd,2)=view; + fd = sd->fd; + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x10a; + if ((view = itemdb_viewid(nameid)) > 0) + p.itemId = view; else - WFIFOW(fd,2)=nameid; - WFIFOSET(fd,packet_len(0x10a)); + p.itemId = nameid; + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// MVP EXP reward message (ZC_MVP_GETTING_SPECIAL_EXP). @@ -7621,12 +7629,13 @@ static void clif_guild_created(struct map_session_data *sd, int flag) /// mode: @see enum guild_permission static void clif_guild_belonginfo(struct map_session_data *sd, struct guild *g) { - int ps,fd; nullpo_retv(sd); nullpo_retv(g); - fd=sd->fd; - ps=guild->getposition(g,sd); + int fd = sd->fd; + int ps = guild->getposition(g, sd); + Assert_retv(ps != -1); + WFIFOHEAD(fd,packet_len(0x16c)); WFIFOW(fd,0)=0x16c; WFIFOL(fd,2)=g->guild_id; @@ -8103,41 +8112,45 @@ static void clif_guild_inviteack(struct map_session_data *sd, int flag) /// Notifies clients of a guild of a leaving member (ZC_ACK_LEAVE_GUILD). /// 015a <char name>.24B <reason>.40B -static void clif_guild_leave(struct map_session_data *sd, const char *name, const char *mes) +static void clif_guild_leave(struct map_session_data *sd, const char *name, int char_id, const char *mes) { - unsigned char buf[128]; - nullpo_retv(sd); + nullpo_retv(name); + nullpo_retv(mes); - WBUFW(buf, 0)=0x15a; - memcpy(WBUFP(buf, 2),name,NAME_LENGTH); - memcpy(WBUFP(buf,26),mes,40); - clif->send(buf,packet_len(0x15a),&sd->bl,GUILD_NOBG); + struct PACKET_ZC_ACK_LEAVE_GUILD p; + p.packetType = guildLeave; +#if PACKETVER_MAIN_NUM >= 20161019 || PACKETVER_RE_NUM >= 20160921 || defined(PACKETVER_ZERO) + p.GID = char_id; +#else + safestrncpy(&p.name[0], name, NAME_LENGTH); +#endif + safestrncpy(&p.reason[0], mes, 40); + clif->send(&p, sizeof(p), &sd->bl, GUILD_NOBG); } /// Notifies clients of a guild of an expelled member. /// 015c <char name>.24B <reason>.40B <account name>.24B (ZC_ACK_BAN_GUILD) /// 0839 <char name>.24B <reason>.40B (ZC_ACK_BAN_GUILD_SSO) -static void clif_guild_expulsion(struct map_session_data *sd, const char *name, const char *mes, int account_id) +static void clif_guild_expulsion(struct map_session_data *sd, const char *name, int char_id, const char *mes, int account_id) { - unsigned char buf[128]; -#if PACKETVER < 20100803 - const unsigned short cmd = 0x15c; -#else - const unsigned short cmd = 0x839; -#endif - nullpo_retv(sd); nullpo_retv(name); nullpo_retv(mes); - WBUFW(buf,0) = cmd; - safestrncpy(WBUFP(buf,2), name, NAME_LENGTH); - safestrncpy(WBUFP(buf,26), mes, 40); + struct PACKET_ZC_ACK_BAN_GUILD p; + p.packetType = guildExpulsion; +#if PACKETVER_MAIN_NUM >= 20161019 || PACKETVER_RE_NUM >= 20160921 || defined(PACKETVER_ZERO) + p.GID = char_id; +#else + safestrncpy(&p.name[0], name, NAME_LENGTH); +#endif + safestrncpy(&p.reason[0], mes, 40); + #if PACKETVER < 20100803 - memset(WBUFP(buf,66), 0, NAME_LENGTH); // account name (not used for security reasons) + memset(&p.account_name, 0, NAME_LENGTH); // account name (not used for security reasons) #endif - clif->send(buf, packet_len(cmd), &sd->bl, GUILD_NOBG); + clif->send(&p, sizeof(p), &sd->bl, GUILD_NOBG); } /// Guild expulsion list (ZC_BAN_LIST). @@ -8319,6 +8332,49 @@ static void clif_guild_broken(struct map_session_data *sd, int flag) WFIFOSET(fd,packet_len(0x15e)); } +static void clif_guild_position_selected(struct map_session_data *sd) +{ +#if PACKETVER >= 20180801 + clif->guild_set_position(sd); +#else + clif->charnameupdate(sd); +#endif +} + +static void clif_guild_set_position(struct map_session_data *sd) +{ + nullpo_retv(sd); + + int len = sizeof(struct PACKET_ZC_GUILD_POSITION); + const char *name = NULL; + if (sd->status.guild_id > 0) { + struct guild *g = sd->guild; + + nullpo_retv(g); + + int i = 0; + int ps = -1; + ARR_FIND(0, g->max_member, i, g->member[i].account_id == sd->status.account_id && g->member[i].char_id == sd->status.char_id); + if (i < g->max_member) + ps = g->member[i].position; + + if (ps >= 0 && ps < MAX_GUILDPOSITION) { + len += 24; + name = g->position[ps].name; + } + } + + unsigned char buf[sizeof(struct PACKET_ZC_GUILD_POSITION) + NAME_LENGTH]; + struct PACKET_ZC_GUILD_POSITION *p = WBUFP(buf, 0); + p->packetType = 0xafd; + p->packetLength = len; + p->AID = sd->bl.id; + if (name != NULL) + memcpy(&p->position, name, 24); + + clif->send(buf, len, &sd->bl, AREA); +} + /// Displays emotion on an object (ZC_EMOTION). /// 00c0 <id>.L <type>.B /// type: @@ -8854,17 +8910,18 @@ static void clif_refresh(struct map_session_data *sd) /// Updates the object's (bl) name on client. /// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME) /// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL) +/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2) static void clif_charnameack(int fd, struct block_list *bl) { - unsigned char buf[103]; - int cmd = 0x95; + struct packet_reqnameall_ack packet = { 0 }; + int len = sizeof(struct packet_reqnameall_ack); nullpo_retv(bl); - WBUFW(buf,0) = cmd; - WBUFL(buf,2) = bl->id; + packet.packet_id = reqName; + packet.gid = bl->id; - switch( bl->type ) { + switch(bl->type) { case BL_PC: { const struct map_session_data *ssd = BL_UCCAST(BL_PC, bl); @@ -8872,17 +8929,28 @@ static void clif_charnameack(int fd, struct block_list *bl) const struct guild *g = NULL; int ps = -1; + if (ssd->fakename[0] != '\0' || ssd->status.guild_id > 0 || ssd->status.party_id > 0 || ssd->status.title_id > 0) { + packet.packet_id = reqNameAllType; + } + //Requesting your own "shadow" name. [Skotlex] - if (ssd->fd == fd && ssd->disguise != -1) - WBUFL(buf,2) = -bl->id; + if (ssd->fd == fd && ssd->disguise != -1) { + packet.gid = -bl->id; + } if (ssd->fakename[0] != '\0') { - WBUFW(buf, 0) = cmd = 0x195; - memcpy(WBUFP(buf,6), ssd->fakename, NAME_LENGTH); - WBUFB(buf,30) = WBUFB(buf,54) = WBUFB(buf,78) = 0; + memcpy(packet.name, ssd->fakename, NAME_LENGTH); break; } - memcpy(WBUFP(buf,6), ssd->status.name, NAME_LENGTH); + +#if PACKETVER >= 20150503 + // Title System [Dastgir/Hercules] + if (ssd->status.title_id > 0) { + packet.title_id = ssd->status.title_id; + } +#endif + + memcpy(packet.name, ssd->status.name, NAME_LENGTH); if (ssd->status.party_id != 0) { p = party->search(ssd->status.party_id); @@ -8904,47 +8972,41 @@ static void clif_charnameack(int fd, struct block_list *bl) if (p == NULL && g == NULL) break; - WBUFW(buf, 0) = cmd = 0x195; - if (p != NULL) - memcpy(WBUFP(buf,30), p->party.name, NAME_LENGTH); - else - WBUFB(buf,30) = 0; + if (p != NULL) { + memcpy(packet.party_name, p->party.name, NAME_LENGTH); + } if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) { - memcpy(WBUFP(buf,54), g->name,NAME_LENGTH); - memcpy(WBUFP(buf,78), g->position[ps].name, NAME_LENGTH); - } else { //Assume no guild. - WBUFB(buf,54) = 0; - WBUFB(buf,78) = 0; + memcpy(packet.guild_name, g->name,NAME_LENGTH); + memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH); } } break; //[blackhole89] case BL_HOM: - memcpy(WBUFP(buf,6), BL_UCCAST(BL_HOM, bl)->homunculus.name, NAME_LENGTH); + memcpy(packet.name, BL_UCCAST(BL_HOM, bl)->homunculus.name, NAME_LENGTH); break; case BL_MER: - memcpy(WBUFP(buf,6), BL_UCCAST(BL_MER, bl)->db->name, NAME_LENGTH); + memcpy(packet.name, BL_UCCAST(BL_MER, bl)->db->name, NAME_LENGTH); break; case BL_PET: - memcpy(WBUFP(buf,6), BL_UCCAST(BL_PET, bl)->pet.name, NAME_LENGTH); + memcpy(packet.name, BL_UCCAST(BL_PET, bl)->pet.name, NAME_LENGTH); break; case BL_NPC: - memcpy(WBUFP(buf,6), BL_UCCAST(BL_NPC, bl)->name, NAME_LENGTH); + memcpy(packet.name, BL_UCCAST(BL_NPC, bl)->name, NAME_LENGTH); break; case BL_MOB: { const struct mob_data *md = BL_UCCAST(BL_MOB, bl); - memcpy(WBUFP(buf,6), md->name, NAME_LENGTH); + memcpy(packet.name, md->name, NAME_LENGTH); if (md->guardian_data && md->guardian_data->g) { - WBUFW(buf, 0) = cmd = 0x195; - WBUFB(buf,30) = 0; - memcpy(WBUFP(buf,54), md->guardian_data->g->name, NAME_LENGTH); - memcpy(WBUFP(buf,78), md->guardian_data->castle->castle_name, NAME_LENGTH); + packet.packet_id = reqNameAllType; + memcpy(packet.guild_name, md->guardian_data->g->name, NAME_LENGTH); + memcpy(packet.position_name, md->guardian_data->castle->castle_name, NAME_LENGTH); } else if (battle_config.show_mob_info) { char mobhp[50], *str_p = mobhp; - WBUFW(buf, 0) = cmd = 0x195; + packet.packet_id = reqNameAllType; if (battle_config.show_mob_info&4) str_p += sprintf(str_p, "Lv. %d | ", md->level); if (battle_config.show_mob_info&1) @@ -8955,34 +9017,39 @@ static void clif_charnameack(int fd, struct block_list *bl) //can parse it. [Skotlex] if (str_p != mobhp) { *(str_p-3) = '\0'; //Remove trailing space + pipe. - memcpy(WBUFP(buf,30), mobhp, NAME_LENGTH); - WBUFB(buf,54) = 0; - WBUFB(buf,78) = 0; + memcpy(packet.party_name, mobhp, NAME_LENGTH); } } } break; case BL_CHAT: #if 0 //FIXME: Clients DO request this... what should be done about it? The chat's title may not fit... [Skotlex] - memcpy(WBUFP(buf,6), BL_UCCAST(BL_CHAT, bl)->title, NAME_LENGTH); + memcpy(packet.name, BL_UCCAST(BL_CHAT, bl)->title, NAME_LENGTH); break; #endif return; case BL_ELEM: - memcpy(WBUFP(buf,6), BL_UCCAST(BL_ELEM, bl)->db->name, NAME_LENGTH); + memcpy(packet.name, BL_UCCAST(BL_ELEM, bl)->db->name, NAME_LENGTH); break; default: ShowError("clif_charnameack: bad type %u(%d)\n", bl->type, bl->id); return; } + if (packet.packet_id == reqName) { + len = sizeof(struct packet_reqname_ack); + } + // if no recipient specified just update nearby clients // if no recipient specified just update nearby clients if (fd == 0) { - clif->send(buf, packet_len(cmd), bl, AREA); + clif->send(&packet, len, bl, AREA); } else { - WFIFOHEAD(fd, packet_len(cmd)); - memcpy(WFIFOP(fd, 0), buf, packet_len(cmd)); - WFIFOSET(fd, packet_len(cmd)); + struct map_session_data *sd = sockt->session_is_valid(fd) ? sockt->session[fd]->session_data : NULL; + if (sd != NULL) { + clif->send(&packet, len, &sd->bl, SELF); + } else { + clif->send(&packet, len, bl, SELF); + } } } @@ -8990,54 +9057,52 @@ static void clif_charnameack(int fd, struct block_list *bl) //Needed because when you send a 0x95 packet, the client will not remove the cached party/guild info that is not sent. static void clif_charnameupdate(struct map_session_data *ssd) { - unsigned char buf[103]; - int cmd = 0x195, ps = -1; + int ps = -1; struct party_data *p = NULL; struct guild *g = NULL; + struct packet_reqnameall_ack packet = { 0 }; nullpo_retv(ssd); - if( ssd->fakename[0] ) + if (ssd->fakename[0]) return; //No need to update as the party/guild was not displayed anyway. - WBUFW(buf,0) = cmd; - WBUFL(buf,2) = ssd->bl.id; + packet.packet_id = reqNameAllType; + packet.gid = ssd->bl.id; - memcpy(WBUFP(buf,6), ssd->status.name, NAME_LENGTH); + memcpy(packet.name, ssd->status.name, NAME_LENGTH); if (!battle_config.display_party_name) { if (ssd->status.party_id > 0 && ssd->status.guild_id > 0 && (g = ssd->guild) != NULL) p = party->search(ssd->status.party_id); - }else{ + } else { if (ssd->status.party_id > 0) p = party->search(ssd->status.party_id); } - if( ssd->status.guild_id > 0 && (g = ssd->guild) != NULL ) - { + if (ssd->status.guild_id > 0 && (g = ssd->guild) != NULL) { int i; ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id); if( i < g->max_member ) ps = g->member[i].position; } - if( p ) - memcpy(WBUFP(buf,30), p->party.name, NAME_LENGTH); - else - WBUFB(buf,30) = 0; + if (p != NULL) + memcpy(packet.party_name, p->party.name, NAME_LENGTH); - if( g && ps >= 0 && ps < MAX_GUILDPOSITION ) - { - memcpy(WBUFP(buf,54), g->name,NAME_LENGTH); - memcpy(WBUFP(buf,78), g->position[ps].name, NAME_LENGTH); + if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) { + memcpy(packet.guild_name, g->name,NAME_LENGTH); + memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH); } - else - { - WBUFB(buf,54) = 0; - WBUFB(buf,78) = 0; + +#if PACKETVER >= 20150503 + // Achievement System [Dastgir/Hercules] + if (ssd->status.title_id > 0) { + packet.title_id = ssd->status.title_id; } +#endif // Update nearby clients - clif->send(buf, packet_len(cmd), &ssd->bl, AREA); + clif->send(&packet, sizeof(packet), &ssd->bl, AREA); } /// Taekwon Jump (TK_HIGHJUMP) effect (ZC_HIGHJUMP). @@ -9327,6 +9392,9 @@ static void clif_viewequip_ack(struct map_session_data *sd, struct map_session_d #endif viewequip_list.headpalette = tsd->vd.hair_color; viewequip_list.bodypalette = tsd->vd.cloth_color; +#if PACKETVER_MAIN_NUM >= 20180801 || PACKETVER_RE_NUM >= 20180801 || PACKETVER_ZERO_NUM >= 20180808 + viewequip_list.body2 = tsd->vd.body_style; +#endif viewequip_list.sex = tsd->vd.sex; clif->send(&viewequip_list, viewequip_list.PacketLength, &sd->bl, SELF); @@ -9433,6 +9501,36 @@ static void clif_msgtable_str(struct map_session_data *sd, enum clif_messages ms } /** + * Displays a format string from msgstringtable.txt with a %s value and color (ZC_FORMATSTRING_MSG). + * + * @param sd The target character. + * @param msg_id msgstringtable message index, 0-based (@see enum clif_messages) + * @param value The value to fill %s. + * @param color The color to use + */ +static void clif_msgtable_str_color(struct map_session_data *sd, enum clif_messages msg_id, const char *value, uint32 color) +{ +#if PACKETVER >= 20160330 + nullpo_retv(sd); + nullpo_retv(value); + + int message_len = (int)strlen(value) + 1; + const int len = sizeof(struct PACKET_ZC_FORMATSTRING_MSG_COLOR) + message_len + 1; + struct PACKET_ZC_FORMATSTRING_MSG_COLOR *p = (struct PACKET_ZC_FORMATSTRING_MSG_COLOR *)aMalloc(len); + + p->PacketType = 0xa6f; + p->PacketLength = len; + p->messageId = msg_id; + p->color = color; + safestrncpy(p->messageString, value, message_len); + p->messageString[message_len] = 0; + + clif->send(p, p->PacketLength, &sd->bl, SELF); + aFree(p); +#endif +} + +/** * Displays a format string from msgstringtable.txt with a color (ZC_MSG_COLOR). * * @param sd The target character. @@ -10105,16 +10203,11 @@ static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd) #if PACKETVER >= 20090218 { int i; - for(i = 0; i < map->list[sd->bl.m].qi_count; i++) { - struct questinfo *qi = &map->list[sd->bl.m].qi_data[i]; - if( quest->check(sd, qi->quest_id, HAVEQUEST) == -1 ) {// Check if quest is not started - if( qi->hasJob ) { // Check if quest is job-specific, check is user is said job class. - if (sd->status.class == qi->job) - clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); - } else { - clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); - } - } + for (i = 0; i < VECTOR_LENGTH(map->list[sd->bl.m].qi_data); i++) { + struct questinfo *qi = &VECTOR_INDEX(map->list[sd->bl.m].qi_data, i); + + if (quest->questinfo_validate(sd, qi)) + clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); } } #endif @@ -10564,13 +10657,13 @@ static void clif_parse_Emotion(int fd, struct map_session_data *sd) if (battle_config.basic_skill_check == 0 || pc->check_basicskill(sd, 2)) { if (emoticon == E_MUTE) {// prevent use of the mute emote [Valaris] - clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1); + clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1, 0); return; } // fix flood of emotion icon (ro-proxy): flood only the hacker player if (sd->emotionlasttime + 1 >= time(NULL)) { // not more than 1 per second sd->emotionlasttime = time(NULL); - clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1); + clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1, 0); return; } sd->emotionlasttime = time(NULL); @@ -10583,7 +10676,7 @@ static void clif_parse_Emotion(int fd, struct map_session_data *sd) clif->emotion(&sd->bl, emoticon); } else - clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1); + clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1, 0); } /// Amount of currently online players, reply to /w /who (ZC_USER_COUNT). @@ -10654,7 +10747,7 @@ static void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action if (!battle_config.sdelay_attack_enable && pc->checkskill(sd, SA_FREECAST) <= 0 && (skill->get_inf2(sd->ud.skill_id) & (INF2_FREE_CAST_REDUCED | INF2_FREE_CAST_NORMAL)) == 0) { if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) { - clif->skill_fail(sd, 1, USESKILL_FAIL_SKILLINTERVAL, 0); + clif->skill_fail(sd, 1, USESKILL_FAIL_SKILLINTERVAL, 0, 0); return; } } @@ -10666,7 +10759,7 @@ static void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action break; case 0x02: // sitdown if (battle_config.basic_skill_check && !pc->check_basicskill(sd, 3)) { - clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 2); + clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 2, 0); break; } @@ -10995,7 +11088,7 @@ static void clif_parse_DropItem(int fd, struct map_session_data *sd) } //Because the client does not like being ignored. - clif->dropitem(sd, item_index, 0); + clif->item_movefailed(sd, item_index); } static void clif_parse_UseItem(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); @@ -11181,12 +11274,13 @@ static void clif_parse_NpcBuyListSend(int fd, struct map_session_data *sd) __att /// 00c8 <packet len>.W { <amount>.W <name id>.W }* static void clif_parse_NpcBuyListSend(int fd, struct map_session_data *sd) { - int n = ((int)RFIFOW(fd,2)-4) / 4; + int n = ((int)RFIFOW(fd, 2) - sizeof(struct PACKET_CZ_PC_PURCHASE_ITEMLIST)) / sizeof(struct PACKET_CZ_PC_PURCHASE_ITEMLIST_sub); int result; + const struct PACKET_CZ_PC_PURCHASE_ITEMLIST *p = RFIFOP(fd, 0); Assert_retv(n >= 0); - if( sd->state.trading || !sd->npc_shopid || pc_has_permission(sd,PC_PERM_DISABLE_STORE) ) { + if (sd->state.trading || !sd->npc_shopid || pc_has_permission(sd, PC_PERM_DISABLE_STORE)) { result = 1; } else { struct itemlist item_list = { 0 }; @@ -11197,8 +11291,8 @@ static void clif_parse_NpcBuyListSend(int fd, struct map_session_data *sd) for (i = 0; i < n; i++) { struct itemlist_entry entry = { 0 }; - entry.amount = RFIFOW(fd, 4 + 4 * i); - entry.id = RFIFOW(fd, 4 + 4 * i + 2); + entry.amount = p->items[i].amount; + entry.id = p->items[i].itemId; VECTOR_PUSH(item_list, entry); } @@ -11293,7 +11387,7 @@ static void clif_parse_CreateChatRoom(int fd, struct map_session_data *sd) if (pc_ismuted(&sd->sc, MANNER_NOROOM)) return; if(battle_config.basic_skill_check && !pc->check_basicskill(sd, 4)) { - clif->skill_fail(sd,1,USESKILL_FAIL_LEVEL,3); + clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 3, 0); return; } if( npc->isnear(&sd->bl) ) { @@ -11301,7 +11395,7 @@ static void clif_parse_CreateChatRoom(int fd, struct map_session_data *sd) //char output[150]; //sprintf(output, msg_txt(862), battle_config.min_npc_vendchat_distance); // "You're too close to a NPC, you must be at least %d cells away from any NPC." //clif_displaymessage(sd->fd, output); - clif->skill_fail(sd,1,USESKILL_FAIL_THERE_ARE_NPC_AROUND,0); + clif->skill_fail(sd, 1, USESKILL_FAIL_THERE_ARE_NPC_AROUND, 0, 0); return; } @@ -11414,7 +11508,7 @@ static void clif_parse_TradeRequest(int fd, struct map_session_data *sd) } if( battle_config.basic_skill_check && !pc->check_basicskill(sd, 1)) { - clif->skill_fail(sd,1,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 0, 0); return; } @@ -11489,7 +11583,7 @@ static void clif_parse_PutItemToCart(int fd, struct map_session_data *sd) if (!pc_iscarton(sd)) return; if ( (flag = pc->putitemtocart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4))) ) { - clif->dropitem(sd, RFIFOW(fd,2)-2,0); + clif->item_movefailed(sd, RFIFOW(fd,2)-2); clif->cart_additem_ack(sd,flag == 1?0x0:0x1); } } @@ -11626,7 +11720,7 @@ static void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_sess else if (DIFF_TICK(tick, hd->ud.canact_tick) < 0){ clif->emotion(&hd->bl, E_DOTS); if (hd->master) - clif->skill_fail(hd->master, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0); + clif->skill_fail(hd->master, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0); return; } @@ -11654,7 +11748,7 @@ static void clif_parse_UseSkillToPos_homun(struct homun_data *hd, struct map_ses } else if ( DIFF_TICK(tick, hd->ud.canact_tick) < 0 ) { clif->emotion(&hd->bl, E_DOTS); if ( hd->master ) - clif->skill_fail(hd->master, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0); + clif->skill_fail(hd->master, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0); return; } @@ -11701,7 +11795,7 @@ static void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct if( md->ud.skilltimer != INVALID_TIMER ) return; if( DIFF_TICK(tick, md->ud.canact_tick) < 0 ) { - clif->skill_fail(md->master, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0); + clif->skill_fail(md->master, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0); return; } @@ -11781,7 +11875,7 @@ static void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) return; } else if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) { if( sd->skillitem != skill_id ) { - clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0); + clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0); return; } } @@ -11863,7 +11957,7 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin return; if( skillmoreinfo != -1 ) { if( pc_issit(sd) ) { - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0, 0); return; } //You can't use Graffiti/TalkieBox AND have a vending open, so this is safe. @@ -11875,7 +11969,7 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) { if( sd->skillitem != skill_id ) { - clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0); + clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0); return; } } @@ -11990,7 +12084,9 @@ static void clif_parse_ProduceMix(int fd, struct map_session_data *sd) __attribu /// 018e <name id>.W { <material id>.W }*3 static void clif_parse_ProduceMix(int fd, struct map_session_data *sd) { - switch( sd->menuskill_id ) { + const struct PACKET_CZ_REQMAKINGITEM *p = RFIFOP(fd, 0); + + switch (sd->menuskill_id) { case -1: case AM_PHARMACY: case RK_RUNEMASTERY: @@ -12001,12 +12097,13 @@ static void clif_parse_ProduceMix(int fd, struct map_session_data *sd) } if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. - clif->skill_fail(sd,sd->ud.skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0); clif_menuskill_clear(sd); return; } - if( skill->can_produce_mix(sd,RFIFOW(fd,2),sd->menuskill_val, 1) ) - skill->produce_mix(sd,0,RFIFOW(fd,2),RFIFOW(fd,4),RFIFOW(fd,6),RFIFOW(fd,8), 1); + + if (skill->can_produce_mix(sd, p->itemId, sd->menuskill_val, 1)) + skill->produce_mix(sd, 0, p->itemId, p->material[0], p->material[1], p->material[2], 1); clif_menuskill_clear(sd); } @@ -12022,20 +12119,21 @@ static void clif_parse_Cooking(int fd, struct map_session_data *sd) __attribute_ /// 6 = GN_S_PHARMACY static void clif_parse_Cooking(int fd, struct map_session_data *sd) { - int type = RFIFOW(fd,2); - int nameid = RFIFOW(fd,4); - int amount = sd->menuskill_val2?sd->menuskill_val2:1; - if( type == 6 && sd->menuskill_id != GN_MIX_COOKING && sd->menuskill_id != GN_S_PHARMACY ) + const struct PACKET_CZ_REQ_MAKINGITEM *p = RFIFOP(fd, 0); + int type = p->type; + int nameid = p->itemId; + int amount = sd->menuskill_val2 ? sd->menuskill_val2 : 1; + if (type == 6 && sd->menuskill_id != GN_MIX_COOKING && sd->menuskill_id != GN_S_PHARMACY) return; if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. - clif->skill_fail(sd,sd->ud.skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0); clif_menuskill_clear(sd); return; } - if( skill->can_produce_mix(sd,nameid,sd->menuskill_val, amount) ) - skill->produce_mix(sd,(type>1?sd->menuskill_id:0),nameid,0,0,0,amount); + if (skill->can_produce_mix(sd, nameid, sd->menuskill_val, amount)) + skill->produce_mix(sd, (type > 1 ? sd->menuskill_id : 0), nameid, 0, 0, 0, amount); clif_menuskill_clear(sd); } @@ -12044,15 +12142,17 @@ static void clif_parse_RepairItem(int fd, struct map_session_data *sd) __attribu /// 01fd <index>.W <name id>.W <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W static void clif_parse_RepairItem(int fd, struct map_session_data *sd) { + const struct PACKET_CZ_REQ_ITEMREPAIR *p = RFIFOP(fd, 0); + if (sd->menuskill_id != BS_REPAIRWEAPON) return; if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. - clif->skill_fail(sd,sd->ud.skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0); clif_menuskill_clear(sd); return; } - skill->repairweapon(sd,RFIFOW(fd,2)); + skill->repairweapon(sd, p->index); clif_menuskill_clear(sd); } @@ -12069,7 +12169,7 @@ static void clif_parse_WeaponRefine(int fd, struct map_session_data *sd) return; if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. - clif->skill_fail(sd,sd->ud.skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0); clif_menuskill_clear(sd); return; } @@ -12209,27 +12309,33 @@ static void clif_parse_SelectArrow(int fd, struct map_session_data *sd) __attrib /// 01ae <name id>.W static void clif_parse_SelectArrow(int fd, struct map_session_data *sd) { + int itemId; if (pc_istrading(sd)) { - //Make it fail to avoid shop exploits where you sell something different than you see. - clif->skill_fail(sd,sd->ud.skill_id,USESKILL_FAIL_LEVEL,0); + //Make it fail to avoid shop exploits where you sell something different than you see. + clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0); clif_menuskill_clear(sd); return; } - switch( sd->menuskill_id ) { +#if PACKETVER_RE_NUM >= 20180704 + itemId = RFIFOL(fd, 2); +#else + itemId = RFIFOW(fd, 2); +#endif + switch (sd->menuskill_id) { case AC_MAKINGARROW: - skill->arrow_create(sd,RFIFOW(fd,2)); + skill->arrow_create(sd, itemId); break; case SA_CREATECON: - skill->produce_mix(sd,SA_CREATECON,RFIFOW(fd,2),0,0,0, 1); + skill->produce_mix(sd, SA_CREATECON, itemId, 0, 0, 0, 1); break; case WL_READING_SB: - skill->spellbook(sd,RFIFOW(fd,2)); + skill->spellbook(sd, itemId); break; case GC_POISONINGWEAPON: - skill->poisoningweapon(sd,RFIFOW(fd,2)); + skill->poisoningweapon(sd, itemId); break; case NC_MAGICDECOY: - skill->magicdecoy(sd,RFIFOW(fd,2)); + skill->magicdecoy(sd, itemId); break; } @@ -12485,7 +12591,7 @@ static void clif_parse_CreateParty(int fd, struct map_session_data *sd) return; } if (battle_config.basic_skill_check && !pc->check_basicskill(sd, 7)) { - clif->skill_fail(sd,1,USESKILL_FAIL_LEVEL,4); + clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 4, 0); return; } @@ -12507,7 +12613,7 @@ static void clif_parse_CreateParty2(int fd, struct map_session_data *sd) return; } if (battle_config.basic_skill_check && !pc->check_basicskill(sd, 7)) { - clif->skill_fail(sd,1,USESKILL_FAIL_LEVEL,4); + clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 4, 0); return; } @@ -14059,7 +14165,7 @@ static void clif_parse_pet_evolution(int fd, struct map_session_data *sd) intif->create_pet( sd->status.account_id, sd->status.char_id, (short)pet->db[pet_id].class_, (short)mob->db(pet->db[pet_id].class_)->lv, - (short)pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate, + pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate, 100, 0, 1, pet->db[pet_id].jname); clif->petEvolutionResult(fd, PET_EVOL_SUCCESS); } else { @@ -14817,6 +14923,7 @@ static void clif_parse_FriendsListReply(int fd, struct map_session_data *sd) f_sd->status.friends[i].char_id = sd->status.char_id; memcpy(f_sd->status.friends[i].name, sd->status.name, NAME_LENGTH); clif->friendslist_reqack(f_sd, sd, 0); + achievement->validate_friend_add(f_sd); // Achievements [Smokexyz/Hercules] if (battle_config.friend_auto_add) { // Also add f_sd to sd's friendlist. @@ -14835,6 +14942,7 @@ static void clif_parse_FriendsListReply(int fd, struct map_session_data *sd) sd->status.friends[i].char_id = f_sd->status.char_id; memcpy(sd->status.friends[i].name, f_sd->status.name, NAME_LENGTH); clif->friendslist_reqack(sd, f_sd, 0); + achievement->validate_friend_add(sd); // Achievements [Smokexyz/Hercules] } } } @@ -16234,13 +16342,10 @@ static void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) { struct npc_item_list *shop = NULL; unsigned short shop_size = 0; - int fd,i, c = 0; + int fd, i, c = 0; int currency[2] = { 0,0 }; -#if PACKETVER < 20070711 - const int offset = 8; -#else - const int offset = 12; -#endif + int len; + struct PACKET_ZC_PC_CASH_POINT_ITEMLIST *p; nullpo_retv(sd); nullpo_retv(nd); @@ -16263,26 +16368,28 @@ static void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) fd = sd->fd; sd->npc_shopid = nd->bl.id; - WFIFOHEAD(fd,offset+shop_size*11); - WFIFOW(fd,0) = 0x287; - /* 0x2 = length, set after parsing */ - WFIFOL(fd,4) = currency[0]; // Cash Points + len = sizeof(struct PACKET_ZC_PC_CASH_POINT_ITEMLIST) + shop_size * sizeof(struct PACKET_ZC_PC_CASH_POINT_ITEMLIST_sub); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x287; + p->cashPoints = currency[0]; #if PACKETVER >= 20070711 - WFIFOL(fd,8) = currency[1]; // Kafra Points + p->kafraPoints = currency[1]; #endif - for( i = 0; i < shop_size; i++ ) { - if( shop[i].nameid ) { + for (i = 0; i < shop_size; i++) { + if (shop[i].nameid) { struct item_data* id = itemdb->search(shop[i].nameid); - WFIFOL(fd,offset+0+i*11) = shop[i].value; - WFIFOL(fd,offset+4+i*11) = shop[i].value; // Discount Price - WFIFOB(fd,offset+8+i*11) = itemtype(id->type); - WFIFOW(fd,offset+9+i*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; + p->items[c].price = shop[i].value; + p->items[c].discountPrice = shop[i].value; + p->items[c].itemType = itemtype(id->type); + p->items[c].itemId = (id->view_id > 0) ? id->view_id : id->nameid; c++; } } - WFIFOW(fd,2) = offset+c*11; - WFIFOSET(fd,WFIFOW(fd,2)); + len = sizeof(struct PACKET_ZC_PC_CASH_POINT_ITEMLIST) + c * sizeof(struct PACKET_ZC_PC_CASH_POINT_ITEMLIST_sub); + p->packetLength = len; + WFIFOSET(fd, len); } /// Cashshop Buy Ack (ZC_PC_CASH_POINT_UPDATE). @@ -16326,33 +16433,33 @@ static void clif_parse_cashshop_buy(int fd, struct map_session_data *sd) __attri static void clif_parse_cashshop_buy(int fd, struct map_session_data *sd) { int fail = 0; + const struct PACKET_CZ_PC_BUY_CASH_POINT_ITEM *p = RFIFOP(fd, 0); - if( sd->state.trading || !sd->npc_shopid || pc_has_permission(sd,PC_PERM_DISABLE_STORE) ) + if (sd->state.trading || !sd->npc_shopid || pc_has_permission(sd,PC_PERM_DISABLE_STORE)) { fail = 1; - else { -#if PACKETVER < 20101116 - short nameid = RFIFOW(fd,2); - short amount = RFIFOW(fd,4); - int points = RFIFOL(fd,6); - - fail = npc->cashshop_buy(sd, nameid, amount, points); + } else { +#if PACKETVER < 20070711 + fail = npc->cashshop_buy(sd, p->itemId, p->amount, 0); +#elif PACKETVER < 20101116 + fail = npc->cashshop_buy(sd, p->itemId, p->amount, p->kafraPoints); #else - int len = RFIFOW(fd,2); + int len = p->packetLength; + int needLen; int points; int count; struct itemlist item_list = { 0 }; int i; - if (len < 10) { + if (len < sizeof(struct PACKET_CZ_PC_BUY_CASH_POINT_ITEM)) { ShowWarning("Player %d sent incorrect cash shop buy packet (len %d)!\n", sd->status.char_id, len); return; } - points = RFIFOL(fd, 4); - count = RFIFOW(fd, 8); - - if (len != 10 + count * 4) { - ShowWarning("Player %d sent incorrect cash shop buy packet (len %d:%d)!\n", sd->status.char_id, len, 10 + count * 4); + points = p->kafraPoints; + count = p->count; + needLen = sizeof(struct PACKET_CZ_PC_BUY_CASH_POINT_ITEM) + count * sizeof(struct PACKET_CZ_PC_BUY_CASH_POINT_ITEM_sub); + if (len != needLen) { + ShowWarning("Player %d sent incorrect cash shop buy packet (len %d:%d)!\n", sd->status.char_id, len, needLen); return; } @@ -16361,8 +16468,8 @@ static void clif_parse_cashshop_buy(int fd, struct map_session_data *sd) for (i = 0; i < count; i++) { struct itemlist_entry entry = { 0 }; - entry.amount = RFIFOW(fd, 10 + 4 * i); - entry.id = RFIFOW(fd, 10 + 4 * i + 2); // Nameid + entry.amount = p->items[i].amount; + entry.id = p->items[i].itemId; VECTOR_PUSH(item_list, entry); } @@ -17065,22 +17172,26 @@ static void clif_mercenary_message(struct map_session_data *sd, int message) /// 0298 <name id>.W <seconds>.L static void clif_rental_time(int fd, int nameid, int seconds) { // '<ItemName>' item will disappear in <seconds/60> minutes. - WFIFOHEAD(fd,packet_len(0x298)); - WFIFOW(fd,0) = 0x298; - WFIFOW(fd,2) = nameid; - WFIFOL(fd,4) = seconds; - WFIFOSET(fd,packet_len(0x298)); + struct PACKET_ZC_CASH_TIME_COUNTER p; + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x298; + p.itemId = nameid; + p.seconds = seconds; + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Deletes a rental item from client's inventory (ZC_CASH_ITEM_DELETE). /// 0299 <index>.W <name id>.W static void clif_rental_expired(int fd, int index, int nameid) { // '<ItemName>' item has been deleted from the Inventory - WFIFOHEAD(fd,packet_len(0x299)); - WFIFOW(fd,0) = 0x299; - WFIFOW(fd,2) = index+2; - WFIFOW(fd,4) = nameid; - WFIFOSET(fd,packet_len(0x299)); + struct PACKET_ZC_CASH_ITEM_DELETE p; + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x299; + p.index = index + 2; + p.itemId = nameid; + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Book Reading (ZC_READ_BOOK). @@ -17231,7 +17342,7 @@ static void clif_bg_updatescore(int16 m) struct block_list bl; unsigned char buf[6]; - bl.id = 0; + memset(&bl, 0, sizeof(bl)); bl.type = BL_NUL; bl.m = m; @@ -17407,22 +17518,22 @@ static void clif_instance_leave(int fd) static void clif_party_show_picker(struct map_session_data *sd, struct item *item_data) { #if PACKETVER >= 20071002 - unsigned char buf[22]; struct item_data* id; + struct PACKET_ZC_ITEM_PICKUP_PARTY p; nullpo_retv(sd); nullpo_retv(item_data); id = itemdb->search(item_data->nameid); - WBUFW(buf,0) = 0x2b8; - WBUFL(buf,2) = sd->status.account_id; - WBUFW(buf,6) = item_data->nameid; - WBUFB(buf,8) = item_data->identify; - WBUFB(buf,9) = item_data->attribute; - WBUFB(buf,10) = item_data->refine; - clif->addcards(WBUFP(buf,11), item_data); - WBUFW(buf,19) = id->equip; // equip location - WBUFB(buf,21) = itemtype(id->type); // item type - clif->send(buf, packet_len(0x2b8), &sd->bl, PARTY_SAMEMAP_WOS); + p.packetType = 0x2b8; + p.AID = sd->status.account_id; + p.itemId = item_data->nameid; + p.identified = item_data->identify; + p.damaged = item_data->attribute; + p.refine = item_data->refine; + clif->addcards(&p.slot, item_data); + p.location = id->equip; // equip location + p.itemType = itemtype(id->type); // item type + clif->send(&p, sizeof(p), &sd->bl, PARTY_SAMEMAP_WOS); #endif } @@ -17437,8 +17548,7 @@ static void clif_displayexp(struct map_session_data *sd, uint64 exp, char type, { int fd; -// [4144] unconfirment exact version can be from 20170405 to 20170913 -#if PACKETVER >= 20170830 +#if PACKETVER_MAIN_NUM >= 20170906 || PACKETVER_RE_NUM >= 20170830 || defined(PACKETVER_ZERO) const int cmd = 0xacc; #else const int cmd = 0x7f6; @@ -17450,8 +17560,7 @@ static void clif_displayexp(struct map_session_data *sd, uint64 exp, char type, WFIFOHEAD(fd, packet_len(cmd)); WFIFOW(fd, 0) = cmd; WFIFOL(fd, 2) = sd->bl.id; -// [4144] unconfirment exact version can be from 20170405 to 20170913 -#if PACKETVER >= 20170830 +#if PACKETVER_MAIN_NUM >= 20170906 || PACKETVER_RE_NUM >= 20170830 || defined(PACKETVER_ZERO) WFIFOQ(fd, 6) = exp; WFIFOW(fd, 14) = type; WFIFOW(fd, 16) = is_quest ? 1 : 0; // Normal exp is shown in yellow, quest exp is shown in purple. @@ -17634,40 +17743,40 @@ static void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data *sd) _ /// 1 = open static void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data *sd) { - const unsigned int blocksize = 8; - const uint8 *itemlist; + const unsigned int blocksize = sizeof(struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub); + const struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub *itemlist; char storename[MESSAGE_SIZE]; unsigned char result; int zenylimit; int count, packet_len; - struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; + const struct PACKET_CZ_REQ_OPEN_BUYING_STORE *p = RFIFOP(fd, 0); - packet_len = RFIFOW(fd,info->pos[0]); + packet_len = p->packetLength; // TODO: Make this check global for all variable length packets. - if( packet_len < 89 ) + if (packet_len < sizeof(struct PACKET_CZ_REQ_OPEN_BUYING_STORE)) {// minimum packet length - ShowError("clif_parse_ReqOpenBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 89U, packet_len, sd->bl.id); + ShowError("clif_parse_ReqOpenBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", (uint32)sizeof(struct PACKET_CZ_REQ_OPEN_BUYING_STORE), packet_len, sd->bl.id); return; } - zenylimit = RFIFOL(fd,info->pos[1]); - result = RFIFOL(fd,info->pos[2]); - safestrncpy(storename, RFIFOP(fd,info->pos[3]), sizeof(storename)); - itemlist = RFIFOP(fd,info->pos[4]); + zenylimit = p->zenyLimit; + result = p->result; + safestrncpy(storename, p->storeName, sizeof(storename)); + itemlist = &p->items[0]; // so that buyingstore_create knows, how many elements it has access to - packet_len-= info->pos[4]; + packet_len -= sizeof(struct PACKET_CZ_REQ_OPEN_BUYING_STORE); if (packet_len < 0) return; - if( packet_len%blocksize ) + if (packet_len % blocksize) { ShowError("clif_parse_ReqOpenBuyingStore: Unexpected item list size %d (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); return; } - count = packet_len/blocksize; + count = packet_len / blocksize; buyingstore->create(sd, zenylimit, result, storename, itemlist, count); } @@ -17677,7 +17786,8 @@ static void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data *sd) /// result: /// 1 = "Failed to open buying store." (0x6cd, MSI_BUYINGSTORE_OPEN_FAILED) /// 2 = "Total amount of then possessed items exceeds the weight limit by <weight/10-maxweight*90%>. Please re-enter." (0x6ce, MSI_BUYINGSTORE_OVERWEIGHT) -/// 8 = "No sale (purchase) information available." (0x705) +/// 9 = "No sale (purchase) information available." (0x705) +/// 10 = "Cant open store at this location." (0xC9D) /// ? = nothing static void clif_buyingstore_open_failed(struct map_session_data *sd, unsigned short result, unsigned int weight) { @@ -17700,24 +17810,28 @@ static void clif_buyingstore_myitemlist(struct map_session_data *sd) { int fd; unsigned int i; + struct PACKET_ZC_MYITEMLIST_BUYING_STORE *p; + int len; nullpo_retv(sd); fd = sd->fd; - WFIFOHEAD(fd,12+sd->buyingstore.slots*9); - WFIFOW(fd,0) = 0x813; - WFIFOW(fd,2) = 12+sd->buyingstore.slots*9; - WFIFOL(fd,4) = sd->bl.id; - WFIFOL(fd,8) = sd->buyingstore.zenylimit; + len = sizeof(struct PACKET_ZC_MYITEMLIST_BUYING_STORE) + sd->buyingstore.slots * sizeof(struct PACKET_ZC_MYITEMLIST_BUYING_STORE_sub); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x813; + p->packetLength = len; + p->AID = sd->bl.id; + p->zenyLimit = sd->buyingstore.zenylimit; - for( i = 0; i < sd->buyingstore.slots; i++ ) + for (i = 0; i < sd->buyingstore.slots; i++) { - WFIFOL(fd,12+i*9) = sd->buyingstore.items[i].price; - WFIFOW(fd,16+i*9) = sd->buyingstore.items[i].amount; - WFIFOB(fd,18+i*9) = itemtype(itemdb_type(sd->buyingstore.items[i].nameid)); - WFIFOW(fd,19+i*9) = sd->buyingstore.items[i].nameid; + p->items[i].price = sd->buyingstore.items[i].price; + p->items[i].amount = sd->buyingstore.items[i].amount; + p->items[i].itemType = itemtype(itemdb_type(sd->buyingstore.items[i].nameid)); + p->items[i].itemId = sd->buyingstore.items[i].nameid; } - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOSET(fd, len); } /// Notifies clients in area of a buying store (ZC_BUYING_STORE_ENTRY). @@ -17805,26 +17919,30 @@ static void clif_buyingstore_itemlist(struct map_session_data *sd, struct map_se { int fd; unsigned int i; + struct PACKET_ZC_ACK_ITEMLIST_BUYING_STORE *p; + int len; nullpo_retv(sd); nullpo_retv(pl_sd); fd = sd->fd; - WFIFOHEAD(fd,16+pl_sd->buyingstore.slots*9); - WFIFOW(fd,0) = 0x818; - WFIFOW(fd,2) = 16+pl_sd->buyingstore.slots*9; - WFIFOL(fd,4) = pl_sd->bl.id; - WFIFOL(fd,8) = pl_sd->buyer_id; - WFIFOL(fd,12) = pl_sd->buyingstore.zenylimit; - - for( i = 0; i < pl_sd->buyingstore.slots; i++ ) + len = sizeof(struct PACKET_ZC_ACK_ITEMLIST_BUYING_STORE) + pl_sd->buyingstore.slots * sizeof(struct PACKET_ZC_ACK_ITEMLIST_BUYING_STORE_sub); + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x818; + p->packetLength = len; + p->AID = pl_sd->bl.id; + p->storeId = pl_sd->buyer_id; + p->zenyLimit = pl_sd->buyingstore.zenylimit; + + for (i = 0; i < pl_sd->buyingstore.slots; i++) { - WFIFOL(fd,16+i*9) = pl_sd->buyingstore.items[i].price; - WFIFOW(fd,20+i*9) = pl_sd->buyingstore.items[i].amount; // TODO: Figure out, if no longer needed items (amount == 0) are listed on official. - WFIFOB(fd,22+i*9) = itemtype(itemdb_type(pl_sd->buyingstore.items[i].nameid)); - WFIFOW(fd,23+i*9) = pl_sd->buyingstore.items[i].nameid; + p->items[i].price = pl_sd->buyingstore.items[i].price; + p->items[i].amount = pl_sd->buyingstore.items[i].amount; // TODO: Figure out, if no longer needed items (amount == 0) are listed on official. + p->items[i].itemType = itemtype(itemdb_type(pl_sd->buyingstore.items[i].nameid)); + p->items[i].itemId = pl_sd->buyingstore.items[i].nameid; } - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOSET(fd, len); } static void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); @@ -17832,36 +17950,35 @@ static void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data *sd) /// 0819 <packet len>.W <account id>.L <store id>.L { <index>.W <name id>.W <amount>.W }* static void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data *sd) { - const unsigned int blocksize = 6; - const uint8 *itemlist; + const unsigned int blocksize = sizeof(struct PACKET_CZ_REQ_TRADE_BUYING_STORE_sub); + const struct PACKET_CZ_REQ_TRADE_BUYING_STORE_sub *itemlist; int account_id; unsigned int buyer_id; int count, packet_len; - struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; + const struct PACKET_CZ_REQ_TRADE_BUYING_STORE *p = RFIFOP(fd, 0); + packet_len = p->packetLength; - packet_len = RFIFOW(fd,info->pos[0]); - - if( packet_len < 12 ) + if (packet_len < sizeof(struct PACKET_CZ_REQ_TRADE_BUYING_STORE)) {// minimum packet length - ShowError("clif_parse_ReqTradeBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 12U, packet_len, sd->bl.id); + ShowError("clif_parse_ReqTradeBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", (uint32)sizeof(struct PACKET_CZ_REQ_TRADE_BUYING_STORE), packet_len, sd->bl.id); return; } - account_id = RFIFOL(fd,info->pos[1]); - buyer_id = RFIFOL(fd,info->pos[2]); - itemlist = RFIFOP(fd,info->pos[3]); + account_id = p->AID; + buyer_id = p->storeId; + itemlist = &p->items[0]; // so that buyingstore_trade knows, how many elements it has access to - packet_len-= info->pos[3]; + packet_len -= sizeof(struct PACKET_CZ_REQ_TRADE_BUYING_STORE); if (packet_len < 0) return; - if( packet_len%blocksize ) + if (packet_len % blocksize) { ShowError("clif_parse_ReqTradeBuyingStore: Unexpected item list size %d (account_id=%d, buyer_id=%d, block size=%u)\n", packet_len, sd->bl.id, account_id, blocksize); return; } - count = packet_len/blocksize; + count = packet_len / blocksize; buyingstore->trade(sd, account_id, buyer_id, itemlist, count); } @@ -17888,31 +18005,26 @@ static void clif_buyingstore_trade_failed_buyer(struct map_session_data *sd, sho /// Updates the zeny limit and an item in the buying store item list (ZC_UPDATE_ITEM_FROM_BUYING_STORE). /// 081b <name id>.W <amount>.W <limit zeny>.L -static void clif_buyingstore_update_item(struct map_session_data *sd, unsigned short nameid, unsigned short amount, uint32 char_id, int zeny) +static void clif_buyingstore_update_item(struct map_session_data *sd, int nameid, unsigned short amount, uint32 char_id, int zeny) { int fd; -#if PACKETVER < 20141016 // TODO : not sure for client date [Napster] - const int cmd = 0x81b; -#else - const int cmd = 0x9e6; -#endif - const int len = packet_len(cmd); + struct PACKET_ZC_UPDATE_ITEM_FROM_BUYING_STORE p; nullpo_retv(sd); + fd = sd->fd; - WFIFOHEAD(fd, len); - WFIFOW(fd, 0) = cmd; - WFIFOW(fd, 2) = nameid; - WFIFOW(fd, 4) = amount; // amount of nameid received -#if PACKETVER < 20141016 - WFIFOL(fd, 6) = sd->buyingstore.zenylimit; -#else - WFIFOL(fd, 6) = zeny; // zeny - WFIFOL(fd, 10) = sd->buyingstore.zenylimit; - WFIFOL(fd, 14) = char_id; // GID - WFIFOL(fd, 18) = (int)time(NULL); // date + WFIFOHEAD(fd, sizeof(p)); + p.packetType = buyingStoreUpdateItemType; + p.itemId = nameid; + p.amount = amount; + p.zenyLimit = sd->buyingstore.zenylimit; +#if PACKETVER >= 20141016 + p.zeny = zeny; + p.charId = char_id; // GID + p.updateTime = (int)time(NULL); #endif - WFIFOSET(fd, len); + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); } /// Deletes item from inventory, that was sold to a buying store (ZC_ITEM_DELETE_BUYING_STORE). @@ -17944,18 +18056,20 @@ static void clif_buyingstore_delete_item(struct map_session_data *sd, short inde /// 6 = "The trade failed, because the entered amount of item %s is higher, than the buyer is willing to buy." (0x6d3, MSI_BUYINGSTORE_TRADE_OVERCOUNT) /// 7 = "The trade failed, because the buyer is lacking required balance." (0x6d1, MSI_BUYINGSTORE_TRADE_LACKBUYERZENY) /// ? = nothing -static void clif_buyingstore_trade_failed_seller(struct map_session_data *sd, short result, unsigned short nameid) +static void clif_buyingstore_trade_failed_seller(struct map_session_data *sd, short result, int nameid) { #if PACKETVER >= 20100420 int fd; + struct PACKET_ZC_FAILED_TRADE_BUYING_STORE_TO_SELLER p; nullpo_retv(sd); fd = sd->fd; - WFIFOHEAD(fd,packet_len(0x824)); - WFIFOW(fd,0) = 0x824; - WFIFOW(fd,2) = result; - WFIFOW(fd,4) = nameid; - WFIFOSET(fd,packet_len(0x824)); + WFIFOHEAD(fd, sizeof(p)); + p.packetType = 0x824; + p.result = result; + p.itemId = nameid; + memcpy(WFIFOP(fd, 0), &p, sizeof(p)); + WFIFOSET(fd, sizeof(p)); #endif } @@ -17974,51 +18088,65 @@ static void clif_parse_SearchStoreInfo(int fd, struct map_session_data *sd) __at /// cannot be searched. static void clif_parse_SearchStoreInfo(int fd, struct map_session_data *sd) { - const unsigned int blocksize = 2; - const uint8* itemlist; - const uint8* cardlist; + const unsigned int blocksize = sizeof(struct PACKET_CZ_SEARCH_STORE_INFO_item); + const struct PACKET_CZ_SEARCH_STORE_INFO_item* itemlist; + const struct PACKET_CZ_SEARCH_STORE_INFO_item* cardlist; unsigned char type; unsigned int min_price, max_price; int packet_len, count, item_count, card_count; - struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; + int i; + const struct PACKET_CZ_SEARCH_STORE_INFO *p = RFIFOP(fd, 0); + uint32 *items_list; + uint32 *cards_list; - packet_len = RFIFOW(fd,info->pos[0]); + packet_len = p->packetLength; - if( packet_len < 15 ) + if (packet_len < sizeof(struct PACKET_CZ_SEARCH_STORE_INFO)) {// minimum packet length - ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 15U, packet_len, sd->bl.id); + ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", (uint32)sizeof(struct PACKET_CZ_SEARCH_STORE_INFO), packet_len, sd->bl.id); return; } - type = RFIFOB(fd,info->pos[1]); - max_price = RFIFOL(fd,info->pos[2]); - min_price = RFIFOL(fd,info->pos[3]); - item_count = RFIFOB(fd,info->pos[4]); - card_count = RFIFOB(fd,info->pos[5]); - itemlist = RFIFOP(fd,info->pos[6]); + type = p->searchType; + max_price = p->maxPrice; + min_price = p->minPrice; + item_count = p->itemsCount; + card_count = p->cardsCount; + itemlist = &p->items[0]; // check, if there is enough data for the claimed count of items - packet_len-= info->pos[6]; + packet_len -= sizeof(struct PACKET_CZ_SEARCH_STORE_INFO); if (packet_len < 0) return; - if( packet_len%blocksize ) + if (packet_len % blocksize) { ShowError("clif_parse_SearchStoreInfo: Unexpected item list size %d (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); return; } - count = packet_len/blocksize; + count = packet_len / blocksize; - if( count < item_count+card_count ) + if (count < item_count + card_count) { - ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected count=%d, count=%d, account_id=%d).\n", item_count+card_count, count, sd->bl.id); + ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected count=%d, count=%d, account_id=%d).\n", item_count + card_count, count, sd->bl.id); return; } - cardlist = RFIFOP(fd, info->pos[6] + blocksize * item_count); + cardlist = RFIFOP(fd, sizeof(struct PACKET_CZ_SEARCH_STORE_INFO) + blocksize * item_count); - searchstore->query(sd, type, min_price, max_price, (const unsigned short*)itemlist, item_count, (const unsigned short*)cardlist, card_count); + items_list = aMalloc(sizeof(uint32) * item_count); + cards_list = aMalloc(sizeof(uint32) * card_count); + for (i = 0; i < item_count; i ++) { + items_list[i] = itemlist[i].itemId; + } + for (i = 0; i < card_count; i ++) { + cards_list[i] = cardlist[i].itemId; + } + // TODO: add search by item options. + searchstore->query(sd, type, min_price, max_price, items_list, item_count, cards_list, card_count); + aFree(items_list); + aFree(cards_list); } /// Results for a store search request (ZC_SEARCH_STORE_INFO_ACK). @@ -18031,38 +18159,38 @@ static void clif_parse_SearchStoreInfo(int fd, struct map_session_data *sd) /// 1 = "next" label to retrieve more results static void clif_search_store_info_ack(struct map_session_data *sd) { -#if PACKETVER >= 20150226 - const unsigned int blocksize = MESSAGE_SIZE + 26 + 5 * MAX_ITEM_OPTIONS; -#else - const unsigned int blocksize = MESSAGE_SIZE + 26; -#endif + const unsigned int blocksize = sizeof(struct PACKET_ZC_SEARCH_STORE_INFO_ACK_sub); int fd; unsigned int i, start, end; + struct PACKET_ZC_SEARCH_STORE_INFO_ACK *p; + int len; nullpo_retv(sd); fd = sd->fd; - start = sd->searchstore.pages*SEARCHSTORE_RESULTS_PER_PAGE; - end = min(sd->searchstore.count, start+SEARCHSTORE_RESULTS_PER_PAGE); - - WFIFOHEAD(fd,7+(end-start)*blocksize); - WFIFOW(fd,0) = 0x836; - WFIFOW(fd,2) = 7+(end-start)*blocksize; - WFIFOB(fd,4) = !sd->searchstore.pages; - WFIFOB(fd,5) = searchstore->querynext(sd); - WFIFOB(fd,6) = (unsigned char)min(sd->searchstore.uses, UINT8_MAX); + start = sd->searchstore.pages * SEARCHSTORE_RESULTS_PER_PAGE; + end = min(sd->searchstore.count, start + SEARCHSTORE_RESULTS_PER_PAGE); - for( i = start; i < end; i++ ) { + len = sizeof(struct PACKET_ZC_SEARCH_STORE_INFO_ACK) + (end - start) * blocksize; + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x836; + p->packetLength = len; + p->firstPage = !sd->searchstore.pages; + p->nextPage = searchstore->querynext(sd); + p->usesCount = (unsigned char)min(sd->searchstore.uses, UINT8_MAX); + + for (i = start; i < end; i++) { struct s_search_store_info_item* ssitem = &sd->searchstore.items[i]; struct item it; - WFIFOL(fd,i*blocksize+ 7) = ssitem->store_id; - WFIFOL(fd,i*blocksize+11) = ssitem->account_id; - memcpy(WFIFOP(fd,i*blocksize+15), ssitem->store_name, MESSAGE_SIZE); - WFIFOW(fd,i*blocksize+15+MESSAGE_SIZE) = ssitem->nameid; - WFIFOB(fd,i*blocksize+17+MESSAGE_SIZE) = itemtype(itemdb_type(ssitem->nameid)); - WFIFOL(fd,i*blocksize+18+MESSAGE_SIZE) = ssitem->price; - WFIFOW(fd,i*blocksize+22+MESSAGE_SIZE) = ssitem->amount; - WFIFOB(fd,i*blocksize+24+MESSAGE_SIZE) = ssitem->refine; + p->items[i].storeId = ssitem->store_id; + p->items[i].AID = ssitem->account_id; + memcpy(&p->items[i].shopName, ssitem->store_name, MESSAGE_SIZE); + p->items[i].itemId = ssitem->nameid; + p->items[i].itemType = itemtype(itemdb_type(ssitem->nameid)); + p->items[i].price = ssitem->price; + p->items[i].amount = ssitem->amount; + p->items[i].refine = ssitem->refine; // make-up an item for clif_addcards memset(&it, 0, sizeof(it)); @@ -18070,14 +18198,14 @@ static void clif_search_store_info_ack(struct map_session_data *sd) it.nameid = ssitem->nameid; it.amount = ssitem->amount; - clif->addcards(WFIFOP(fd, i * blocksize + 25 + MESSAGE_SIZE), &it); + clif->addcards(&p->items[i].slot, &it); #if PACKETVER >= 20150226 memcpy(&it.option, &ssitem->option, sizeof(it.option)); - clif->add_item_options(WFIFOP(fd, i * blocksize + 33 + MESSAGE_SIZE), &it); + clif->add_item_options(&p->items[i].option_data[0], &it); #endif } - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOSET(fd, len); } /// Notification of failure when searching for stores (ZC_SEARCH_STORE_INFO_FAILED). @@ -18145,15 +18273,8 @@ static void clif_parse_SearchStoreInfoListItemClick(int fd, struct map_session_d /// 083c <account id>.L <store id>.L <nameid>.W static void clif_parse_SearchStoreInfoListItemClick(int fd, struct map_session_data *sd) { - unsigned short nameid; - int account_id, store_id; - struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; - - account_id = RFIFOL(fd,info->pos[0]); - store_id = RFIFOL(fd,info->pos[1]); - nameid = RFIFOW(fd,info->pos[2]); - - searchstore->click(sd, account_id, store_id, nameid); + const struct PACKET_CZ_SSILIST_ITEM_CLICK *p = RFIFOP(fd, 0); + searchstore->click(sd, p->AID, p->storeId, p->itemId); } /// Notification of the store position on current map (ZC_SSILIST_ITEM_CLICK_ACK). @@ -18279,7 +18400,7 @@ static int clif_spellbook_list(struct map_session_data *sd) } else{ status_change_end(&sd->bl,SC_STOP,INVALID_TIMER); - clif->skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK, 0); + clif->skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK, 0, 0); } return 1; @@ -18315,7 +18436,7 @@ static int clif_magicdecoy_list(struct map_session_data *sd, uint16 skill_lv, sh WFIFOW(fd,2) = c * 2 + 4; WFIFOSET(fd, WFIFOW(fd, 2)); } else { - clif->skill_fail(sd,NC_MAGICDECOY,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd, NC_MAGICDECOY, USESKILL_FAIL_LEVEL, 0, 0); return 0; } @@ -18350,7 +18471,7 @@ static int clif_poison_list(struct map_session_data *sd, uint16 skill_lv) WFIFOW(fd,2) = c * 2 + 4; WFIFOSET(fd, WFIFOW(fd, 2)); } else { - clif->skill_fail(sd,GC_POISONINGWEAPON,USESKILL_FAIL_GUILLONTINE_POISON,0); + clif->skill_fail(sd, GC_POISONINGWEAPON, USESKILL_FAIL_GUILLONTINE_POISON, 0, 0); return 0; } @@ -18384,7 +18505,7 @@ static int clif_autoshadowspell_list(struct map_session_data *sd) sd->menuskill_val = c; } else { status_change_end(&sd->bl,SC_STOP,INVALID_TIMER); - clif->skill_fail(sd,SC_AUTOSHADOWSPELL,USESKILL_FAIL_IMITATION_SKILL_NONE,0); + clif->skill_fail(sd, SC_AUTOSHADOWSPELL, USESKILL_FAIL_IMITATION_SKILL_NONE, 0, 0); } return 1; @@ -18431,7 +18552,7 @@ static void clif_parse_SkillSelectMenu(int fd, struct map_session_data *sd) return; if( pc_istrading(sd) ) { - clif->skill_fail(sd,sd->ud.skill_id,0,0); + clif->skill_fail(sd, sd->ud.skill_id, 0, 0, 0); clif_menuskill_clear(sd); return; } @@ -18531,7 +18652,7 @@ static void clif_cashshop_db(void) continue; } - if( name[0] == 'I' && name[1] == 'D' && strlen(name) <= 7 ) { + if (name[0] == 'I' && name[1] == 'D' && strlen(name) <= 12) { if( !( data = itemdb->exists(atoi(name+2))) ) { ShowWarning("cashshop_db: unknown item id '%s' in category '%s'\n", name+2, entry_name); continue; @@ -18636,25 +18757,35 @@ static void clif_parse_CashShopClose(int fd, struct map_session_data *sd) static void clif_parse_CashShopSchedule(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); static void clif_parse_CashShopSchedule(int fd, struct map_session_data *sd) { + clif->cashShopSchedule(fd, sd); +} + +void clif_cashShopSchedule(int fd, struct map_session_data *sd) +{ #if PACKETVER >= 20110614 - int i, j = 0; + int i = 0; - for( i = 0; i < CASHSHOP_TAB_MAX; i++ ) { - if( clif->cs.item_count[i] == 0 ) + nullpo_retv(sd); + for (i = 0; i < CASHSHOP_TAB_MAX; i++) { + const int len = sizeof(struct PACKET_ZC_ACK_SCHEDULER_CASHITEM) + (clif->cs.item_count[i] * sizeof(struct PACKET_ZC_ACK_SCHEDULER_CASHITEM_sub)); + int j = 0; + struct PACKET_ZC_ACK_SCHEDULER_CASHITEM *p; + if (clif->cs.item_count[i] == 0) continue; // Skip empty tabs, the client only expects filled ones - WFIFOHEAD(fd, 8 + ( clif->cs.item_count[i] * 6 ) ); - WFIFOW(fd, 0) = 0x8ca; - WFIFOW(fd, 2) = 8 + ( clif->cs.item_count[i] * 6 ); - WFIFOW(fd, 4) = clif->cs.item_count[i]; - WFIFOW(fd, 6) = i; + WFIFOHEAD(fd, len); + p = WFIFOP(fd, 0); + p->packetType = 0x8ca; + p->packetLength = len; + p->count = clif->cs.item_count[i]; + p->tabNum = i; - for( j = 0; j < clif->cs.item_count[i]; j++ ) { - WFIFOW(fd, 8 + ( 6 * j ) ) = clif->cs.data[i][j]->id; - WFIFOL(fd, 10 + ( 6 * j ) ) = clif->cs.data[i][j]->price; + for (j = 0; j < clif->cs.item_count[i]; j++) { + p->items[j].itemId = clif->cs.data[i][j]->id; + p->items[j].price = clif->cs.data[i][j]->price; } - WFIFOSET(fd, 8 + ( clif->cs.item_count[i] * 6 )); + WFIFOSET(fd, len); } #endif } @@ -18773,7 +18904,8 @@ static void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd) __att /* [Ind/Hercules] */ static void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd) { -#if PACKETVER >= 20110222 +// [4144] packet exists only in 2011 and was dropped after +#if PACKETVER >= 20110222 && PACKETVER < 20120000 short tab = RFIFOW(fd, 2); int j; @@ -19049,13 +19181,13 @@ static void clif_scriptclear(struct map_session_data *sd, int npcid) } /* Made Possible Thanks to Yommy! */ -static void clif_package_item_announce(struct map_session_data *sd, unsigned short nameid, unsigned short containerid) +static void clif_package_item_announce(struct map_session_data *sd, int nameid, int containerid) { struct packet_package_item_announce p; nullpo_retv(sd); p.PacketType = package_item_announceType; - p.PacketLength = 11+NAME_LENGTH; + p.PacketLength = 11 + NAME_LENGTH; p.type = 0x0; p.ItemID = nameid; p.len = NAME_LENGTH; @@ -19067,21 +19199,26 @@ static void clif_package_item_announce(struct map_session_data *sd, unsigned sho } /* Made Possible Thanks to Yommy! */ -static void clif_item_drop_announce(struct map_session_data *sd, unsigned short nameid, char *monsterName) +static void clif_item_drop_announce(struct map_session_data *sd, int nameid, char *monsterName) { struct packet_item_drop_announce p; nullpo_retv(sd); p.PacketType = item_drop_announceType; p.PacketLength = sizeof(p); - p.type = 0x1; p.ItemID = nameid; + p.monsterNameLen = NAME_LENGTH; p.len = NAME_LENGTH; safestrncpy(p.Name, sd->status.name, sizeof(p.Name)); - p.monsterNameLen = NAME_LENGTH; - safestrncpy(p.monsterName, monsterName, sizeof(p.monsterName)); - - clif->send(&p,sizeof(p), &sd->bl, ALL_CLIENT); + if (monsterName == NULL) { + // message: MSG_BROADCASTING_SPECIAL_ITEM_OBTAIN2 + p.type = 0x2; + } else { + // message: MSG_BROADCASTING_SPECIAL_ITEM_OBTAIN + p.type = 0x1; + safestrncpy(p.monsterName, monsterName, sizeof(p.monsterName)); + } + clif->send(&p, sizeof(p), &sd->bl, ALL_CLIENT); } /* [Ind/Hercules] special thanks to Yommy~! */ @@ -19539,7 +19676,7 @@ static void clif_parse_RouletteInfo(int fd, struct map_session_data *sd) p.ItemInfo[count].Position = j; p.ItemInfo[count].ItemId = clif->rd.nameid[i][j]; p.ItemInfo[count].Count = clif->rd.qty[i][j]; -#if PACKETVER >= 20180523 // unknown real version +#if PACKETVER >= 20180511 p.ItemInfo[count].unused = 0; #endif count++; @@ -19706,7 +19843,7 @@ static bool clif_parse_roulette_db(void) continue; } - if( name[0] == 'I' && name[1] == 'D' && strlen(name) <= 7 ) { + if (name[0] == 'I' && name[1] == 'D' && strlen(name) <= 12) { if( !( data = itemdb->exists(atoi(name+2))) ) { ShowWarning("roulette_db: unknown item id '%s' in category '%s'\n", name+2, entry_name); continue; @@ -19763,7 +19900,7 @@ static bool clif_parse_roulette_db(void) /** * **/ -static void clif_roulette_generate_ack(struct map_session_data *sd, unsigned char result, short stage, short prizeIdx, short bonusItemID) +static void clif_roulette_generate_ack(struct map_session_data *sd, unsigned char result, short stage, short prizeIdx, int bonusItemID) { #if PACKETVER >= 20140612 struct packet_roulette_generate_ack p; @@ -19849,7 +19986,8 @@ static void clif_ackmergeitems(int fd, struct map_session_data *sd) { #if PACKETVER > 20120228 int i = 0, n = 0, length = 0, count = 0; - int16 nameid = 0, indexes[MAX_INVENTORY] = {0}, amounts[MAX_INVENTORY] = {0}; + int nameid = 0; + int16 indexes[MAX_INVENTORY] = {0}, amounts[MAX_INVENTORY] = {0}; struct item item_data; nullpo_retv(sd); @@ -20222,6 +20360,214 @@ static unsigned short clif_parse_cmd_optional(int fd, struct map_session_data *s return cmd; } +/** + * Send all of a session's achievement information to client. + * Called only once on login/char-loading. (PACKET_ZC_ALL_ACH_LIST) + * @packet [out] 0x0A23 <ID>.W <Length>.W <ach_count>.L <total_points>.L <rank>.W <current_rank_points>.L <next_rank_points>.L <struct ach_list_info *[]>.P + * @param fd socket descriptor + * @param sd pointer to map_session_data + */ +static void clif_achievement_send_list(int fd, struct map_session_data *sd) +{ +#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO) + int i = 0, count = 0, curr_exp_tmp = 0; + struct packet_achievement_list p = { 0 }; + + nullpo_retv(sd); + + /* Browse through the session's achievement list and gather their values. */ + for (i = 0; i < VECTOR_LENGTH(sd->achievement); i++) { + int j = 0; + struct achievement *a = &VECTOR_INDEX(sd->achievement, i); + const struct achievement_data *ad = NULL; + + /* Sanity check for nonull pointers. */ + if (a == NULL || (ad = achievement->get(a->id)) == NULL) + continue; + + p.ach[count].ach_id = a->id; + + for (j = 0; j < VECTOR_LENGTH(ad->objective); j++) + p.ach[count].objective[j] = a->objective[j]; + + if (a->completed_at) { + p.ach[count].completed = 1; + p.ach[count].completed_at = (uint32) a->completed_at; + p.ach[count].reward = a->rewarded_at ? 1 : 0; + p.total_points += ad->points; + } + + count++; + } + + p.packet_id = achievementListType; + p.packet_len = sizeof(struct ach_list_info) * count + 22; + p.total_achievements = count; + /* Determine Achievement Rank and current exp */ + curr_exp_tmp = p.total_points; + for (i = 0; curr_exp_tmp && i < MAX_ACHIEVEMENT_RANKS && i < VECTOR_LENGTH(achievement->rank_exp); i++) { + if (curr_exp_tmp >= VECTOR_INDEX(achievement->rank_exp, i)) { + curr_exp_tmp -= VECTOR_INDEX(achievement->rank_exp, i); + p.rank++; + + // Validate achievement rank type achievements. + achievement->validate_achievement_rank(sd, p.rank); + } + } + /* Determine Achievement Rank Exp */ + p.current_rank_points = curr_exp_tmp; + p.next_rank_points = VECTOR_INDEX(achievement->rank_exp, p.rank); + /* Send payload */ + clif->send(&p, p.packet_len, &sd->bl, SELF); +#endif // PACKETVER >= 20141016 +} + +/** + * Sends achievement information for a single achievement. + * Called on objective progress updates/completion. (PACKET_ZC_ACH_UPDATE) + * @packet [out] 0x0A24 <ID>.W <total_points>.L <rank>.W <current_rank_points>.L <next_rank_points>.L <struct ach_list_info *>.P + * @param fd socket descriptor + * @param sd pointer to struct map_session_data + * @param ad const pointer to struct achievement_data from the achievement db. + */ +static void clif_achievement_send_update(int fd, struct map_session_data *sd, const struct achievement_data *ad) +{ +#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO) + struct packet_achievement_update p = { 0 }; + struct achievement *a = NULL; + int i = 0, points = 0, rank = 0, curr_rank_points = 0; + + nullpo_retv(sd); + nullpo_retv(ad); + + /* Get Session Achievement Data */ + if ((a = achievement->ensure(sd, ad)) == NULL) + return; + + /* Get total points, current rank and current rank points from the session. */ + achievement->calculate_totals(sd, &points, NULL, &rank, &curr_rank_points); + + p.packet_id = achievementUpdateType; + + /* Determine Total Achievement Points */ + p.total_points = points; + + /* Determine Achievement Rank */ + p.rank = rank; + + /* Determine Achievement Rank Exp */ + p.current_rank_points = curr_rank_points; + p.next_rank_points = VECTOR_INDEX(achievement->rank_exp, p.rank); + + p.ach.ach_id = ad->id; + p.ach.completed = (uint8) achievement->check_complete(sd, ad); + + for (i = 0; i < VECTOR_LENGTH(ad->objective); i++) + p.ach.objective[i] = a->objective[i]; + + p.ach.completed_at = (uint32) a->completed_at; + + p.ach.reward = a->rewarded_at ? 1 : 0; + + clif->send(&p, packet_len(achievementUpdateType), &sd->bl, SELF); + + /* Validate rank-related achievements */ + achievement->validate_achievement_rank(sd, rank); + +#endif // PACKETVER >= 20141016 +} + +/** + * Parses achievement reward packet from session. + * @packet [in] 0x0A25 <ach_id>.L + * @param fd socket descriptor. + * @param sd ptr to session data. + */ +static void clif_parse_achievement_get_reward(int fd, struct map_session_data *sd) __attribute__((nonnull(2))); +static void clif_parse_achievement_get_reward(int fd, struct map_session_data *sd) +{ + int ach_id = RFIFOL(fd, 2); + const struct achievement_data *ad = NULL; + struct achievement *ach = NULL; + + if (ach_id <= 0 || (ad = achievement->get(ach_id)) == NULL) + return; + + if ((ach = achievement->ensure(sd, ad)) == NULL) + return; + + if (achievement->check_complete(sd, ad) && ach->completed_at && ach->rewarded_at == 0) { + achievement->get_rewards(sd, ad); + } +} + +/** + * Sends achievement reward collection acknowledgement to the client. + * @packet [out] 0x0A26 <packet_id>.W <received + */ +static void clif_achievement_reward_ack(int fd, struct map_session_data *sd, const struct achievement_data *ad) +{ +#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO) + struct packet_achievement_reward_ack p = { 0 }; + + nullpo_retv(sd); + nullpo_retv(ad); + + p.packet_id = achievementRewardAckType; + p.received = 1; + p.ach_id = ad->id; + + clif->send(&p, packet_len(achievementRewardAckType), &sd->bl, SELF); +#endif // PACKETVER >= 20141016 +} + +/** + * Sends achievement reward collection acknowledgement to the client. + * @packet[in] 0x0A2E <packet_id>.W <title_id>.L + */ +static void clif_parse_change_title(int fd, struct map_session_data *sd) __attribute__((nonnull(2))); +static void clif_parse_change_title(int fd, struct map_session_data *sd) +{ + int title_id = RFIFOL(fd, 2); + + if (title_id == sd->status.title_id) { // Same Title + return; + } else if (title_id < 0) { + title_id = 0; + } + + clif->change_title_ack(fd, sd, title_id); +} + +/** + * [clif_change_title_ack description] + * @packet [out] 0x0A2F <packet_id>.W <Result>.B <title_id>.L + */ +static void clif_change_title_ack(int fd, struct map_session_data *sd, int title_id) +{ +#if PACKETVER >= 20141016 + unsigned char failed = 0; + + if (!achievement->check_title(sd, title_id)) { + clif->message(fd, "Title is not yet earned."); + failed = 1; + } + + sd->status.title_id = title_id; + + WFIFOHEAD(fd, packet_len(0xa2f)); + WFIFOW(fd, 0) = 0xa2f; + WFIFOB(fd, 2) = failed; + WFIFOL(fd, 3) = sd->status.title_id; + WFIFOSET(fd, packet_len(0xa2f)); + + // Update names + clif->charnameack(fd, &sd->bl); + clif->charnameack(0, &sd->bl); +#endif +} +// End of Achievement System + /*========================================== * RoDEX *------------------------------------------*/ @@ -20260,7 +20606,7 @@ static void clif_parse_rodex_add_item(int fd, struct map_session_data *sd) rodex->add_item(sd, idx, (int16)rPacket->count); } -static void clif_rodex_add_item_result(struct map_session_data *sd, int16 idx, int16 amount, int8 result) +static void clif_rodex_add_item_result(struct map_session_data *sd, int16 idx, int16 amount, enum rodex_add_item result) { #if PACKETVER >= 20141119 struct PACKET_ZC_ADD_ITEM_TO_MAIL *packet; @@ -20268,7 +20614,7 @@ static void clif_rodex_add_item_result(struct map_session_data *sd, int16 idx, i nullpo_retv(sd); if (idx < 0 || idx >= MAX_INVENTORY) - result = RODEX_ADD_ITEM_FATAL_ERROR; + return; fd = sd->fd; @@ -20285,7 +20631,7 @@ static void clif_rodex_add_item_result(struct map_session_data *sd, int16 idx, i packet->index = idx + 2; packet->count = amount; - packet->ITID = sd->status.inventory[idx].nameid; + packet->itemId = sd->status.inventory[idx].nameid; packet->type = itemtype(sd->inventory_data[idx]->type); packet->IsIdentified = sd->status.inventory[idx].identify ? 1 : 0; packet->IsDamaged = (sd->status.inventory[idx].attribute & ATTR_BROKEN) != 0 ? 1 : 0; @@ -20298,6 +20644,8 @@ static void clif_rodex_add_item_result(struct map_session_data *sd, int16 idx, i packet->optionData[j].value = sd->status.inventory[idx].option[j].value; } packet->weight = sd->rodex.tmp.weight / 10; + packet->favorite = sd->status.inventory[idx].favorite; + packet->location = pc->equippoint(sd, idx); WFIFOSET(fd, sizeof(*packet)); #endif } @@ -20646,11 +20994,14 @@ static void clif_rodex_read_mail(struct map_session_data *sd, int8 opentype, str size += body_len; for (i = 0; i < RODEX_MAX_ITEM; ++i) { struct item *it = &msg->items[i].item; + struct item_data *data; int j, k; - if (it->nameid == 0) { + if (it->nameid == 0) + continue; + data = itemdb->search(it->nameid); + if (data == NULL) continue; - } item = WFIFOP(fd, size); memset(item, 0x0, sizeof(*item)); @@ -20660,6 +21011,9 @@ static void clif_rodex_read_mail(struct map_session_data *sd, int8 opentype, str item->IsIdentified = it->identify ? 1 : 0; item->IsDamaged = (it->attribute & ATTR_BROKEN) != 0 ? 1 : 0; item->refiningLevel = it->refine; + item->location = pc->item_equippoint(sd, data); + item->viewSprite = data->view_sprite; + item->bindOnEquip = it->bound ? 2 : data->flag.bindonequip ? 1 : 0; for (k = 0; k < MAX_SLOTS; ++k) { item->slot.card[k] = it->card[k]; } @@ -20710,7 +21064,7 @@ static void clif_parse_rodex_request_zeny(int fd, struct map_session_data *sd) rodex->get_zeny(sd, rPacket->opentype, rPacket->MailID); } -static void clif_rodex_request_zeny(struct map_session_data *sd, int8 opentype, int64 mail_id, int8 result) +static void clif_rodex_request_zeny(struct map_session_data *sd, int8 opentype, int64 mail_id, enum rodex_get_zeny result) { #if PACKETVER >= 20140409 struct PACKET_ZC_ACK_ZENY_FROM_MAIL *sPacket; @@ -20738,7 +21092,7 @@ static void clif_parse_rodex_request_items(int fd, struct map_session_data *sd) rodex->get_items(sd, rPacket->opentype, rPacket->MailID); } -static void clif_rodex_request_items(struct map_session_data *sd, int8 opentype, int64 mail_id, int8 result) +static void clif_rodex_request_items(struct map_session_data *sd, int8 opentype, int64 mail_id, enum rodex_get_items result) { #if PACKETVER >= 20140409 struct PACKET_ZC_ACK_ITEM_FROM_MAIL *sPacket; @@ -20785,7 +21139,7 @@ static void clif_parse_rodex_open_mailbox(int fd, struct map_session_data *sd) { const struct PACKET_CZ_REQ_OPEN_MAIL *packet = RFIFOP(fd, 0); #if PACKETVER >= 20170419 - rodex->open(sd, RODEX_OPENTYPE_UNSET, packet->Upper_MailID); + rodex->open(sd, RODEX_OPENTYPE_UNSET, packet->char_Upper_MailID); #else rodex->open(sd, packet->opentype, packet->Upper_MailID); #endif @@ -20966,18 +21320,8 @@ static time_t clif_attendance_getendtime(void) static void clif_parse_open_ui_request(int fd, struct map_session_data *sd) __attribute__((nonnull(2))); static void clif_parse_open_ui_request(int fd, struct map_session_data *sd) { - const struct PACKET_CZ_OPEN_UI *p = RP2PTR(fd); - if (clif->attendance_getendtime() < time(NULL)) { -#if PACKETVER >= 20180207 - clif->msgtable_color(sd, MSG_ATTENDANCE_UNAVAILABLE, COLOR_RED); -#endif - return; - } - - if (battle_config.feature_enable_attendance_system != 1) - return; clif->open_ui(sd, p->UIType); } @@ -20986,6 +21330,9 @@ static void clif_open_ui(struct map_session_data *sd, enum cz_ui_types uiType) { #if PACKETVER >= 20150128 struct PACKET_ZC_OPEN_UI p; +#if PACKETVER_RE_NUM >= 20180307 || PACKETVER_MAIN_NUM >= 20180404 || PACKETVER_ZERO_NUM >= 20180411 + int claimed = 0; +#endif nullpo_retv(sd); @@ -20999,8 +21346,15 @@ static void clif_open_ui(struct map_session_data *sd, enum cz_ui_types uiType) break; case CZ_ATTENDANCE_UI: { + if (clif->attendance_getendtime() < time(NULL)) { +#if PACKETVER >= 20180207 + clif->msgtable_color(sd, MSG_ATTENDANCE_UNAVAILABLE, COLOR_RED); +#endif + return; + } + if (battle_config.feature_enable_attendance_system != 1) + return; #if PACKETVER_RE_NUM >= 20180307 || PACKETVER_MAIN_NUM >= 20180404 || PACKETVER_ZERO_NUM >= 20180411 - int claimed = 0; if (clif->attendance_timediff(sd) != true) ++claimed; else if (sd->status.attendance_count >= VECTOR_LENGTH(clif->attendance_data)) @@ -21189,7 +21543,7 @@ static bool clif_stylist_read_db_libconfig_sub(struct config_setting_t *it, int ShowWarning("clif_stylist_read_db_libconfig_sub: Invalid or missing Type (%d) in \"%s\", entry #%d, skipping.\n", type, source, idx); return false; } - if (!itemdb->lookup_const(it, "Id", &i32) || i32 <= 0) { + if (!itemdb->lookup_const(it, "Id", &i32) || i32 < 0) { ShowWarning("clif_stylist_read_db_libconfig_sub: Invalid or missing Id (%d) in \"%s\", entry #%d, skipping.\n", i32, source, idx); return false; } @@ -21210,6 +21564,9 @@ static bool clif_stylist_read_db_libconfig_sub(struct config_setting_t *it, int if (itemdb->lookup_const(it, "BoxItemID", &i32)) entry.boxid = i32; + if (libconfig->setting_lookup_bool(it, "AllowDoram", &i32)) + entry.allow_doram = (i32 == 0) ? false : true; + VECTOR_ENSURE(stylist_data[type], 1, 1); VECTOR_PUSH(stylist_data[type], entry); return true; @@ -21226,7 +21583,10 @@ static bool clif_style_change_validate_requirements(struct map_session_data *sd, entry = &VECTOR_INDEX(stylist_data[type], idx); - if (entry->id != 0) { + if (sd->status.class == JOB_SUMMONER && (entry->allow_doram == false)) + return false; + + if (entry->id >= 0) { if (entry->zeny != 0) { if (sd->status.zeny < entry->zeny) return false; @@ -21246,7 +21606,7 @@ static bool clif_style_change_validate_requirements(struct map_session_data *sd, } return false; } -static void clif_stylist_send_rodexitem(struct map_session_data *sd, int16 itemid) +static void clif_stylist_send_rodexitem(struct map_session_data *sd, int itemid) { struct rodex_message msg = { 0 }; @@ -21284,7 +21644,32 @@ static void clif_parse_cz_req_style_change(int fd, struct map_session_data *sd) clif->cz_req_style_change_sub(sd, LOOK_HEAD_MID, p->MidAccessory, true); if (p->BottomAccessory > 0) clif->cz_req_style_change_sub(sd, LOOK_HEAD_BOTTOM, p->BottomAccessory, true); + clif->style_change_response(sd, STYLIST_SHOP_SUCCESS); + return; +} + +static void clif_parse_cz_req_style_change2(int fd, struct map_session_data *sd) __attribute__((nonnull(2))); +static void clif_parse_cz_req_style_change2(int fd, struct map_session_data *sd) +{ + const struct PACKET_CZ_REQ_STYLE_CHANGE2 *p = RP2PTR(fd); + if (p->HeadStyle > 0) + clif->cz_req_style_change_sub(sd, LOOK_HAIR, p->HeadStyle, false); + if (p->HeadPalette > 0) + clif->cz_req_style_change_sub(sd, LOOK_HAIR_COLOR, p->HeadPalette, false); + if (p->BodyPalette > 0) + clif->cz_req_style_change_sub(sd, LOOK_CLOTHES_COLOR, p->BodyPalette, false); + if (p->TopAccessory > 0) + clif->cz_req_style_change_sub(sd, LOOK_HEAD_TOP, p->TopAccessory, true); + if (p->MidAccessory > 0) + clif->cz_req_style_change_sub(sd, LOOK_HEAD_MID, p->MidAccessory, true); + if (p->BottomAccessory > 0) + clif->cz_req_style_change_sub(sd, LOOK_HEAD_BOTTOM, p->BottomAccessory, true); + if (p->BodyStyle > 0) { + if (pc->has_second_costume(sd)) { + clif->cz_req_style_change_sub(sd, LOOK_BODY2, p->BodyStyle, false); + } + } clif->style_change_response(sd, STYLIST_SHOP_SUCCESS); return; } @@ -21324,6 +21709,44 @@ static void clif_style_change_response(struct map_session_data *sd, enum stylist #endif } +static void clif_overweight_percent(struct map_session_data *sd) +{ +#if PACKETVER_MAIN_NUM >= 20171108 || PACKETVER_RE_NUM >= 20171025 || PACKETVER_ZERO_NUM >= 20171019 + struct PACKET_ZC_OVERWEIGHT_PERCENT p; + + nullpo_retv(sd); + + p.packetType = 0xade; + p.percent = battle_config.natural_heal_weight_rate; + clif->send(&p, sizeof(p), &sd->bl, SELF); +#endif +} + +static void clif_parse_changeDress(int fd, struct map_session_data *sd) __attribute__((nonnull(2))); +/// 0ae8 <packet len>.W +static void clif_parse_changeDress(int fd, struct map_session_data *sd) +{ + const char commandname[] = "changedress"; + char command[sizeof commandname + 3] = ""; // '@' command + ' ' + NUL + + sprintf(command, "%c%s ", atcommand->at_symbol, commandname); + atcommand->exec(fd, sd, command, true); +} + +static void clif_party_dead_notification(struct map_session_data *sd) +{ +#if PACKETVER_MAIN_NUM >= 20170524 || PACKETVER_RE_NUM >= 20170502 || defined(PACKETVER_ZERO) + struct PACKET_ZC_GROUP_ISALIVE p; + + nullpo_retv(sd); + + p.packetType = 0xab2; + p.AID = sd->bl.id; + p.isDead = pc_isdead(sd); + clif->send(&p, sizeof(p), &sd->bl, PARTY_WOS); +#endif +} + /*========================================== * Main client packet processing function *------------------------------------------*/ @@ -21542,6 +21965,8 @@ static void packetdb_loaddb(void) #include "packets.h" /* load structure data */ #ifdef PACKETVER_ZERO #include "packets_shuffle_zero.h" +#elif defined(PACKETVER_RE) +#include "packets_shuffle_re.h" #else // PACKETVER_ZERO #include "packets_shuffle_main.h" #endif // PACKETVER_ZERO @@ -21663,6 +22088,7 @@ void clif_defaults(void) clif->dropitem = clif_dropitem; clif->delitem = clif_delitem; clif->takeitem = clif_takeitem; + clif->item_movefailed = clif_item_movefailed; clif->item_equip = clif_item_equip; clif->item_normal = clif_item_normal; clif->arrowequip = clif_arrowequip; @@ -21674,11 +22100,11 @@ void clif_defaults(void) clif->unequipitemack = clif_unequipitemack; clif->useitemack = clif_useitemack; clif->addcards = clif_addcards; - clif->addcards2 = clif_addcards2; clif->item_sub = clif_item_sub; // look like unused clif->getareachar_item = clif_getareachar_item; clif->cart_additem_ack = clif_cart_additem_ack; clif->cashshop_load = clif_cashshop_db; + clif->cashShopSchedule = clif_cashShopSchedule; clif->package_announce = clif_package_item_announce; clif->item_drop_announce = clif_item_drop_announce; /* unit-related */ @@ -21899,6 +22325,7 @@ void clif_defaults(void) clif->msgtable = clif_msgtable; clif->msgtable_num = clif_msgtable_num; clif->msgtable_str = clif_msgtable_str; + clif->msgtable_str_color = clif_msgtable_str_color; clif->msgtable_color = clif_msgtable_color; clif->message = clif_displaymessage; clif->messageln = clif_displaymessage2; @@ -21925,6 +22352,7 @@ void clif_defaults(void) clif->vendinglist = clif_vendinglist; clif->buyvending = clif_buyvending; clif->openvending = clif_openvending; + clif->openvendingAck = clif_openvendingAck; clif->vendingreport = clif_vendingreport; /* storage handling */ clif->storagelist = clif_storagelist; @@ -21986,6 +22414,8 @@ void clif_defaults(void) clif->guild_positionnamelist = clif_guild_positionnamelist; clif->guild_positioninfolist = clif_guild_positioninfolist; clif->guild_expulsionlist = clif_guild_expulsionlist; + clif->guild_set_position = clif_guild_set_position; + clif->guild_position_selected = clif_guild_position_selected; clif->validate_emblem = clif_validate_emblem; /* battleground-specific */ clif->bg_hp = clif_bg_hp; @@ -22147,6 +22577,14 @@ void clif_defaults(void) clif->isdisguised = clif_isdisguised; clif->navigate_to = clif_navigate_to; clif->bl_type = clif_bl_type; + /* Achievement System */ + clif->achievement_send_list = clif_achievement_send_list; + clif->achievement_send_update = clif_achievement_send_update; + clif->pAchievementGetReward = clif_parse_achievement_get_reward; + clif->achievement_reward_ack = clif_achievement_reward_ack; + /* Title */ + clif->change_title_ack = clif_change_title_ack; + clif->pChangeTitle = clif_parse_change_title; /*------------------------ *- Parse Incoming Packet @@ -22350,6 +22788,8 @@ void clif_defaults(void) clif->pSkillSelectMenu = clif_parse_SkillSelectMenu; clif->pMoveItem = clif_parse_MoveItem; clif->p_cz_blocking_play_cancel = clif_parse_cz_blocking_play_cancel; + clif->overweight_percent = clif_overweight_percent; + clif->pChangeDress = clif_parse_changeDress; /* dull */ clif->pDull = clif_parse_dull; /* BGQueue */ @@ -22394,6 +22834,7 @@ void clif_defaults(void) clif->pHotkeyRowShift = clif_parse_HotkeyRowShift; clif->dressroom_open = clif_dressroom_open; clif->pOneClick_ItemIdentify = clif_parse_OneClick_ItemIdentify; + /* Achievements [Smokexyz/Hercules] */ clif->get_bl_name = clif_get_bl_name; /* RODEX */ clif->pRodexOpenWriteMail = clif_parse_rodex_open_write_mail; @@ -22433,6 +22874,7 @@ void clif_defaults(void) // -- Hat Effect clif->hat_effect = clif_hat_effect; clif->hat_effect_single = clif_hat_effect_single; + clif->party_dead_notification = clif_party_dead_notification; clif->pAttendanceDB = clif_parse_attendance_db; clif->attendancedb_libconfig_sub = clif_attendancedb_libconfig_sub; @@ -22452,6 +22894,7 @@ void clif_defaults(void) clif->style_change_validate_requirements = clif_style_change_validate_requirements; clif->stylist_send_rodexitem = clif_stylist_send_rodexitem; clif->pReqStyleChange = clif_parse_cz_req_style_change; + clif->pReqStyleChange2 = clif_parse_cz_req_style_change2; clif->cz_req_style_change_sub = clif_cz_req_style_change_sub; clif->style_change_response = clif_style_change_response; |