diff options
Diffstat (limited to 'src/map/clif.c')
-rw-r--r-- | src/map/clif.c | 3032 |
1 files changed, 1758 insertions, 1274 deletions
diff --git a/src/map/clif.c b/src/map/clif.c index 9b2f76c0e..a3541cab9 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -45,7 +45,6 @@ #include "clif.h" #include "mail.h" #include "quest.h" -#include "packets_struct.h" #include "irc-bot.h" #include <stdio.h> @@ -56,15 +55,24 @@ struct clif_interface clif_s; +/* re-usable */ +static struct packet_itemlist_normal itemlist_normal; +static struct packet_itemlist_equip itemlist_equip; +static struct packet_storelist_normal storelist_normal; +static struct packet_storelist_equip storelist_equip; +static struct packet_viewequip_ack viewequip_list; +static struct packet_npc_market_result_ack npcmarket_result; +static struct packet_npc_market_open npcmarket_open; //#define DUMP_UNKNOWN_PACKET //#define DUMP_INVALID_PACKET //Converts item type in case of pet eggs. static inline int itemtype(int type) { - switch( type ){ + switch( type ) { #if PACKETVER >= 20080827 case IT_WEAPON: return IT_ARMOR; case IT_ARMOR: + case IT_PETARMOR: #endif case IT_PETEGG: return IT_WEAPON; default: return type; @@ -177,27 +185,28 @@ static inline unsigned int mes_len_check(char* mes, unsigned int len, unsigned i /*========================================== * Ip setting of map-server *------------------------------------------*/ -int clif_setip(const char* ip) { +bool clif_setip(const char* ip) { char ip_str[16]; clif->map_ip = host2ip(ip); - if (!clif->map_ip) { + if ( !clif->map_ip ) { ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip); - return 0; + return false; } safestrncpy(clif->map_ip_str, ip, sizeof(clif->map_ip_str)); ShowInfo("Map Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(clif->map_ip, ip_str)); - return 1; + return true; } -void clif_setbindip(const char* ip) { +bool clif_setbindip(const char* ip) { clif->bind_ip = host2ip(ip); - if (clif->bind_ip) { + if ( clif->bind_ip ) { char ip_str[16]; ShowInfo("Map Server Bind IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(clif->bind_ip, ip_str)); - } else { - ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip); + return true; } + ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip); + return false; } /*========================================== @@ -224,18 +233,21 @@ uint16 clif_getport(void) { return clif->map_port; } - +/*========================================== + * Updates server ip resolution and returns it + *------------------------------------------*/ uint32 clif_refresh_ip(void) { uint32 new_ip; - + new_ip = host2ip(clif->map_ip_str); - if (new_ip && new_ip != clif->map_ip) { + if ( new_ip && new_ip != clif->map_ip ) { clif->map_ip = new_ip; ShowInfo("Updating IP resolution of [%s].\n", clif->map_ip_str); return clif->map_ip; } return 0; } + #if PACKETVER >= 20071106 static inline unsigned char clif_bl_type(struct block_list *bl) { switch (bl->type) { @@ -313,6 +325,10 @@ int clif_send_sub(struct block_list *bl, va_list ap) { #endif } + /* unless visible, hold it here */ + if( clif->ally_only && !sd->sc.data[SC_CLAIRVOYANCE] && !sd->special_state.intravision && battle->check_target( src_bl, &sd->bl, BCT_ENEMY ) > 0 ) + return 0; + WFIFOHEAD(fd, len); if (WFIFOP(fd,0) == buf) { ShowError("WARNING: Invalid use of clif->send function\n"); @@ -334,7 +350,7 @@ int clif_send_sub(struct block_list *bl, va_list ap) { * Packet Delegation (called on all packets that require data to be sent to more than one client) * functions that are sent solely to one use whose ID it posses use WFIFOSET *------------------------------------------*/ -int clif_send(const void* buf, int len, struct block_list* bl, enum send_target type) { +bool clif_send(const void* buf, int len, struct block_list* bl, enum send_target type) { int i; struct map_session_data *sd, *tsd; struct party_data *p = NULL; @@ -565,25 +581,25 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target case BG_QUEUE: if( sd && sd->bg_queue.arena ) { struct hQueue *queue = &script->hq[sd->bg_queue.arena->queue_id]; - + for( i = 0; i < queue->size; i++ ) { - struct map_session_data * sd = NULL; - - if( queue->item[i] > 0 && ( sd = map->id2sd(queue->item[i]) ) ) { - WFIFOHEAD(sd->fd,len); - memcpy(WFIFOP(sd->fd,0), buf, len); - WFIFOSET(sd->fd,len); + struct map_session_data *qsd = NULL; + + if( queue->item[i] > 0 && ( qsd = map->id2sd(queue->item[i]) ) ) { + WFIFOHEAD(qsd->fd,len); + memcpy(WFIFOP(qsd->fd,0), buf, len); + WFIFOSET(qsd->fd,len); } } } break; - + default: ShowError("clif_send: Unrecognized type %d\n",type); - return -1; + return false; } - return 0; + return true; } /// Notifies the client, that it's connection attempt was accepted. @@ -592,16 +608,16 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target void clif_authok(struct map_session_data *sd) { struct packet_authok p; - + p.PacketType = authokType; - p.startTime = timer->gettick(); + p.startTime = (unsigned int)timer->gettick(); WBUFPOS(&p.PosDir[0],0,sd->bl.x,sd->bl.y,sd->ud.dir); /* do the stupid client math */ p.xSize = p.ySize = 5; /* not-used */ #if PACKETVER >= 20080102 - p.font = sd->user_font; // FIXME: Font is currently not saved. + p.font = sd->status.font; #endif - + clif->send(&p,sizeof(p),&sd->bl,SELF); } @@ -626,7 +642,7 @@ void clif_authrefuse(int fd, uint8 error_code) /// Notifies the client of a ban or forced disconnect (SC_NOTIFY_BAN). /// 0081 <error code>.B /// error code: -/// 0 = BAN_UNFAIR +/// 0 = BAN_UNFAIR -> "disconnected from server" -> MsgStringTable[3] /// 1 = server closed -> MsgStringTable[4] /// 2 = ID already logged in -> MsgStringTable[5] /// 3 = timeout/too much lag -> MsgStringTable[241] @@ -699,20 +715,20 @@ void clif_dropflooritem(struct flooritem_data* fitem) { if (fitem->item_data.nameid <= 0) return; - + p.PacketType = dropflooritemType; p.ITAID = fitem->bl.id; p.ITID = ((view = itemdb_viewid(fitem->item_data.nameid)) > 0) ? view : fitem->item_data.nameid; #if PACKETVER >= 20130000 /* not sure date */ p.type = itemtype(itemdb_type(fitem->item_data.nameid)); #endif - p.IsIdentified = fitem->item_data.identify; + p.IsIdentified = fitem->item_data.identify ? 1 : 0; p.xPos = fitem->bl.x; p.yPos = fitem->bl.y; p.subX = fitem->subx; p.subY = fitem->suby; p.count = fitem->item_data.amount; - + clif->send(&p, sizeof(p), &fitem->bl, AREA); } @@ -786,22 +802,23 @@ void clif_clearunit_area(struct block_list* bl, clr_type type) /// Used to make monsters with player-sprites disappear after dying /// like normal monsters, because the client does not remove those /// automatically. -int clif_clearunit_delayed_sub(int tid, unsigned int tick, int id, intptr_t data) { +int clif_clearunit_delayed_sub(int tid, int64 tick, int id, intptr_t data) { struct block_list *bl = (struct block_list *)data; clif->clearunit_area(bl, (clr_type) id); ers_free(clif->delay_clearunit_ers,bl); return 0; } -void clif_clearunit_delayed(struct block_list* bl, clr_type type, unsigned int tick) -{ + +void clif_clearunit_delayed(struct block_list* bl, clr_type type, int64 tick) { struct block_list *tbl = ers_alloc(clif->delay_clearunit_ers, struct block_list); memcpy (tbl, bl, sizeof (struct block_list)); timer->add(tick, clif->clearunit_delayed_sub, (int)type, (intptr_t)tbl); } +/// Gets weapon view info from sd's inventory_data and points (*rhand,*lhand) void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, unsigned short *lhand) { - if(sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK)) { + if(sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST)) { *rhand = *lhand = 0; return; } @@ -868,9 +885,9 @@ void clif_set_unit_idle2(struct block_list* bl, struct map_session_data *tsd, en struct view_data* vd = status->get_viewdata(bl); struct packet_idle_unit2 p; int g_id = status->get_guild_id(bl); - + sd = BL_CAST(BL_PC, bl); - + p.PacketType = idle_unit2Type; #if PACKETVER >= 20071106 p.objecttype = clif_bl_type(bl); @@ -899,13 +916,13 @@ void clif_set_unit_idle2(struct block_list* bl, struct map_session_data *tsd, en p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; p.state = vd->dead_sit; p.clevel = clif_setlevel(bl); - + clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); #else return; @@ -920,6 +937,8 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu struct view_data* vd = status->get_viewdata(bl); struct packet_idle_unit p; int g_id = status->get_guild_id(bl); + + nullpo_retv(bl); #if PACKETVER < 20091103 if( !pcdb_checkid(vd->class_) ) { @@ -927,9 +946,9 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu return; } #endif - + sd = BL_CAST(BL_PC, bl); - + p.PacketType = idle_unitType; #if PACKETVER >= 20091103 p.PacketLength = sizeof(p); @@ -964,16 +983,16 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; p.state = vd->dead_sit; p.clevel = clif_setlevel(bl); #if PACKETVER >= 20080102 - p.font = (sd) ? sd->user_font : 0; + p.font = (sd) ? sd->status.font : 0; #endif -#if PACKETVER >= 20140000 //actual 20120221 +#if PACKETVER >= 20150000 //actual 20120221 if( bl->type == BL_MOB ) { p.maxHP = status_get_max_hp(bl); p.HP = status_get_hp(bl); @@ -984,7 +1003,7 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu p.isBoss = 0; } #endif - + clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); if( disguised(bl) ) { @@ -996,7 +1015,7 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu #endif clif->send(&p,sizeof(p),bl,SELF); } - + } /* for 'packetver < 20091103' 0x7c non-pc-looking unit handling */ void clif_spawn_unit2(struct block_list* bl, enum send_target target) { @@ -1006,9 +1025,9 @@ void clif_spawn_unit2(struct block_list* bl, enum send_target target) { struct view_data* vd = status->get_viewdata(bl); struct packet_spawn_unit2 p; int g_id = status->get_guild_id(bl); - + sd = BL_CAST(BL_PC, bl); - + p.PacketType = spawn_unit2Type; #if PACKETVER >= 20071106 p.objecttype = clif_bl_type(bl); @@ -1033,7 +1052,7 @@ void clif_spawn_unit2(struct block_list* bl, enum send_target target) { p.headpalette = vd->hair_color; p.bodypalette = vd->cloth_color; p.headDir = (sd)? sd->head_dir : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; @@ -1050,15 +1069,17 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { struct packet_spawn_unit p; int g_id = status->get_guild_id(bl); + nullpo_retv(bl); + #if PACKETVER < 20091103 if( !pcdb_checkid(vd->class_) ) { clif->spawn_unit2(bl,target); return; } #endif - + sd = BL_CAST(BL_PC, bl); - + p.PacketType = spawn_unitType; #if PACKETVER >= 20091103 p.PacketLength = sizeof(p); @@ -1093,15 +1114,15 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; p.clevel = clif_setlevel(bl); #if PACKETVER >= 20080102 - p.font = (sd) ? sd->user_font : 0; + p.font = (sd) ? sd->status.font : 0; #endif -#if PACKETVER >= 20140000 //actual 20120221 +#if PACKETVER >= 20150000 //actual 20120221 if( bl->type == BL_MOB ) { p.maxHP = status_get_max_hp(bl); p.HP = status_get_hp(bl); @@ -1113,6 +1134,7 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { } #endif if( disguised(bl) ) { + nullpo_retv(sd); if( sd->status.class_ != sd->disguise ) clif->send(&p,sizeof(p),bl,target); #if PACKETVER >= 20091103 @@ -1136,9 +1158,11 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, struct view_data* vd = status->get_viewdata(bl); struct packet_unit_walking p; int g_id = status->get_guild_id(bl); - + + nullpo_retv(bl); + sd = BL_CAST(BL_PC, bl); - + p.PacketType = unit_walkingType; #if PACKETVER >= 20091103 p.PacketLength = sizeof(p); @@ -1155,7 +1179,7 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, p.head = vd->hair_style; p.weapon = vd->weapon; p.accessory = vd->head_bottom; - p.moveStartTime = timer->gettick(); + p.moveStartTime = (unsigned int)timer->gettick(); #if PACKETVER < 7 p.shield = vd->shield; #endif @@ -1171,15 +1195,15 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS2(&p.MoveData[0],0,bl->x,bl->y,ud->to_x,ud->to_y,8,8); p.xSize = p.ySize = (sd) ? 5 : 0; p.clevel = clif_setlevel(bl); #if PACKETVER >= 20080102 - p.font = (sd) ? sd->user_font : 0; + p.font = (sd) ? sd->status.font : 0; #endif -#if PACKETVER >= 20140000 //actual 20120221 +#if PACKETVER >= 20150000 //actual 20120221 if( bl->type == BL_MOB ) { p.maxHP = status_get_max_hp(bl); p.HP = status_get_hp(bl); @@ -1190,7 +1214,7 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, p.isBoss = 0; } #endif - + clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); if( disguised(bl) ) { @@ -1292,19 +1316,20 @@ void clif_weather(int16 m) /** * Main function to spawn a unit on the client (player/mob/pet/etc) **/ -int clif_spawn(struct block_list *bl) +bool clif_spawn(struct block_list *bl) { struct view_data *vd; vd = status->get_viewdata(bl); - if( !vd || vd->class_ == INVISIBLE_CLASS ) - return 0; + if( !vd ) + return false; - /** - * Hide NPC from maya purple card. - **/ - if(bl->type == BL_NPC && !((TBL_NPC*)bl)->chat_id && (((TBL_NPC*)bl)->option&OPTION_INVISIBLE)) - return 0; + if( ( bl->type == BL_NPC + && !((TBL_NPC*)bl)->chat_id + && (((TBL_NPC*)bl)->option&OPTION_INVISIBLE) ) // Hide NPC from maya purple card. + || ( vd->class_ == INVISIBLE_CLASS ) + ) + return true; // Doesn't need to be spawned, so everything is alright clif->spawn_unit(bl,AREA_WOS); @@ -1321,7 +1346,7 @@ int clif_spawn(struct block_list *bl) clif->spiritball(&sd->bl); if(sd->state.size==SZ_BIG) // tiny/big players [Valaris] clif->specialeffect(bl,423,AREA); - else if(sd->state.size==SZ_MEDIUM) + else if(sd->state.size==SZ_SMALL) clif->specialeffect(bl,421,AREA); if( sd->bg_id && map->list[sd->bl.m].flag.battleground ) clif->sendbgemblem_area(sd); @@ -1341,7 +1366,7 @@ int clif_spawn(struct block_list *bl) TBL_MOB *md = ((TBL_MOB*)bl); if(md->special_state.size==SZ_BIG) // tiny/big mobs [Valaris] clif->specialeffect(&md->bl,423,AREA); - else if(md->special_state.size==SZ_MEDIUM) + else if(md->special_state.size==SZ_SMALL) clif->specialeffect(&md->bl,421,AREA); } break; @@ -1350,7 +1375,7 @@ int clif_spawn(struct block_list *bl) TBL_NPC *nd = ((TBL_NPC*)bl); if( nd->size == SZ_BIG ) clif->specialeffect(&nd->bl,423,AREA); - else if( nd->size == SZ_MEDIUM ) + else if( nd->size == SZ_SMALL ) clif->specialeffect(&nd->bl,421,AREA); } break; @@ -1359,7 +1384,7 @@ int clif_spawn(struct block_list *bl) clif->send_petdata(NULL, (TBL_PET*)bl, 3, vd->head_bottom); // needed to display pet equip properly break; } - return 0; + return true; } /// Sends information about owned homunculus to the client (ZC_PROPERTY_HOMUN). [orn] @@ -1378,7 +1403,7 @@ void clif_hominfo(struct map_session_data *sd, struct homun_data *hd, int flag) WBUFW(buf,0)=0x22e; memcpy(WBUFP(buf,2),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?0:hd->homunculus.rename_flag) | (hd->homunculus.vaporize << 1) | (hd->homunculus.hp?0:4); + 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) ; @@ -1453,18 +1478,23 @@ void clif_send_homdata(struct map_session_data *sd, int state, int param) WFIFOSET(fd,packet_len(0x230)); } - -int clif_homskillinfoblock(struct map_session_data *sd) { //[orn] +/// Prepares and sends homun related information [orn] +void clif_homskillinfoblock(struct map_session_data *sd) { struct homun_data *hd; - int fd = sd->fd; - int i,j,len=4,id; - WFIFOHEAD(fd, 4+37*MAX_HOMUNSKILL); + int fd; + int i,j; + int len=4,id; + nullpo_retv(sd); + fd = sd->fd; hd = sd->hd; + if ( !hd ) - return 0 ; + return; + WFIFOHEAD(fd, 4+37*MAX_HOMUNSKILL); WFIFOW(fd,0)=0x235; + for ( i = 0; i < MAX_HOMUNSKILL; i++){ if( (id = hd->homunculus.hskill[i].id) != 0 ){ j = id - HM_SKILLBASE; @@ -1482,7 +1512,7 @@ int clif_homskillinfoblock(struct map_session_data *sd) { //[orn] WFIFOW(fd,2)=len; WFIFOSET(fd,len); - return 0; + return; } void clif_homskillup(struct map_session_data *sd, uint16 skill_id) { //[orn] @@ -1504,16 +1534,19 @@ void clif_homskillup(struct map_session_data *sd, uint16 skill_id) { //[orn] WFIFOSET(fd,packet_len(0x239)); } -int clif_hom_food(struct map_session_data *sd,int foodid,int fail) //[orn] +void clif_hom_food(struct map_session_data *sd,int foodid,int fail) //[orn] { - int fd=sd->fd; + int fd; + 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 0; + return; } @@ -1525,14 +1558,19 @@ void clif_walkok(struct map_session_data *sd) WFIFOHEAD(fd, packet_len(0x87)); WFIFOW(fd,0)=0x87; - WFIFOL(fd,2)=timer->gettick(); + WFIFOL(fd,2)=(unsigned int)timer->gettick(); WFIFOPOS2(fd,6,sd->bl.x,sd->bl.y,sd->ud.to_x,sd->ud.to_y,8,8); WFIFOSET(fd,packet_len(0x87)); } void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *ud) { +#ifdef ANTI_MAYAP_CHEAT + struct status_change *sc = NULL; + if( (sc = status->get_sc(bl)) && sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE|OPTION_CHASEWALK) ) + clif->ally_only = true; +#endif clif->set_unit_walking(bl,NULL,ud,AREA_WOS); if(vd->cloth_color) @@ -1545,7 +1583,7 @@ void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *u // clif_movepc(sd); if(sd->state.size==SZ_BIG) // tiny/big players [Valaris] clif->specialeffect(&sd->bl,423,AREA); - else if(sd->state.size==SZ_MEDIUM) + else if(sd->state.size==SZ_SMALL) clif->specialeffect(&sd->bl,421,AREA); } break; @@ -1554,7 +1592,7 @@ void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *u TBL_MOB *md = ((TBL_MOB*)bl); if(md->special_state.size==SZ_BIG) // tiny/big mobs [Valaris] clif->specialeffect(&md->bl,423,AREA); - else if(md->special_state.size==SZ_MEDIUM) + else if(md->special_state.size==SZ_SMALL) clif->specialeffect(&md->bl,421,AREA); } break; @@ -1563,6 +1601,9 @@ void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *u clif->send_petdata(NULL, (TBL_PET*)bl, 3, vd->head_bottom); break; } +#ifdef ANTI_MAYAP_CHEAT + clif->ally_only = false; +#endif } @@ -1572,9 +1613,11 @@ void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *u void clif_move(struct unit_data *ud) { unsigned char buf[16]; - struct view_data* vd; - struct block_list* bl = ud->bl; - + struct view_data *vd; + struct block_list *bl = ud->bl; +#ifdef ANTI_MAYAP_CHEAT + struct status_change *sc = NULL; +#endif vd = status->get_viewdata(bl); if (!vd || vd->class_ == INVISIBLE_CLASS) return; //This performance check is needed to keep GM-hidden objects from being notified to bots. @@ -1592,23 +1635,32 @@ void clif_move(struct unit_data *ud) clif->move2(bl, vd, ud); return; } +#ifdef ANTI_MAYAP_CHEAT + if( (sc = status->get_sc(bl)) && sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE) ) + clif->ally_only = true; +#endif WBUFW(buf,0)=0x86; WBUFL(buf,2)=bl->id; WBUFPOS2(buf,6,bl->x,bl->y,ud->to_x,ud->to_y,8,8); - WBUFL(buf,12)=timer->gettick(); + WBUFL(buf,12)=(unsigned int)timer->gettick(); + clif->send(buf, packet_len(0x86), bl, AREA_WOS); + if (disguised(bl)) { WBUFL(buf,2)=-bl->id; clif->send(buf, packet_len(0x86), bl, SELF); } +#ifdef ANTI_MAYAP_CHEAT + clif->ally_only = false; +#endif } /*========================================== * Delays the map->quit of a player after they are disconnected. [Skotlex] *------------------------------------------*/ -int clif_delayquit(int tid, unsigned int tick, int id, intptr_t data) { +int clif_delayquit(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd = NULL; //Remove player from map server @@ -1642,7 +1694,7 @@ void clif_changemap(struct map_session_data *sd, short m, int x, int y) { WFIFOHEAD(fd,packet_len(0x91)); WFIFOW(fd,0) = 0x91; - mapindex_getmapname_ext(map->list[m].custom_name ? map->list[map->list[m].instance_src_map].name : map->list[m].name, (char*)WFIFOP(fd,2)); + mapindex->getmapname_ext(map->list[m].custom_name ? map->list[map->list[m].instance_src_map].name : map->list[m].name, (char*)WFIFOP(fd,2)); WFIFOW(fd,18) = x; WFIFOW(fd,20) = y; WFIFOSET(fd,packet_len(0x91)); @@ -1658,7 +1710,7 @@ void clif_changemapserver(struct map_session_data* sd, unsigned short map_index, WFIFOHEAD(fd,packet_len(0x92)); WFIFOW(fd,0) = 0x92; - mapindex_getmapname_ext(mapindex_id2name(map_index), (char*)WFIFOP(fd,2)); + mapindex->getmapname_ext(mapindex_id2name(map_index), (char*)WFIFOP(fd,2)); WFIFOW(fd,18) = x; WFIFOW(fd,20) = y; WFIFOL(fd,22) = htonl(ip); @@ -1679,9 +1731,9 @@ void clif_blown(struct block_list *bl) /// isn't walkable, the char doesn't move at all. If the char is /// sitting it will stand up (ZC_STOPMOVE). /// 0088 <id>.L <x>.W <y>.W -void clif_fixpos(struct block_list *bl) -{ +void clif_fixpos(struct block_list *bl) { unsigned char buf[10]; + nullpo_retv(bl); WBUFW(buf,0) = 0x88; @@ -1715,29 +1767,40 @@ void clif_npcbuysell(struct map_session_data* sd, int id) /// Presents list of items, that can be bought in an NPC shop (ZC_PC_PURCHASE_ITEMLIST). /// 00c6 <packet len>.W { <price>.L <discount price>.L <item type>.B <name id>.W }* -void clif_buylist(struct map_session_data *sd, struct npc_data *nd) -{ +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; nullpo_retv(sd); nullpo_retv(nd); + if( nd->subtype == SCRIPT ) { + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + } else { + shop = nd->u.shop.shop_item; + shop_size = nd->u.shop.count; + } + fd = sd->fd; - WFIFOHEAD(fd, 4 + nd->u.shop.count * 11); + + WFIFOHEAD(fd, 4 + shop_size * 11); WFIFOW(fd,0) = 0xc6; c = 0; - for( i = 0; i < nd->u.shop.count; i++ ) - { - struct item_data* id = itemdb->exists(nd->u.shop.shop_item[i].nameid); - int val = nd->u.shop.shop_item[i].value; - 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; - c++; + 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 ) + 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; + c++; + } } WFIFOW(fd,2) = 4 + c*11; @@ -1752,12 +1815,12 @@ void clif_hercules_chsys_create(struct hChSysCh *channel, char *name, char *pass channel->pass[0] = '\0'; else safestrncpy(channel->pass, pass, HCHSYS_NAME_LENGTH); - + channel->opt = hChSys_OPT_BASE; channel->banned = NULL; - + channel->msg_delay = 0; - + if( channel->type != hChSys_MAP && channel->type != hChSys_ALLY ) strdb_put(clif->channel_db, channel->name, channel); } @@ -1777,11 +1840,14 @@ void clif_selllist(struct map_session_data *sd) { if( sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] ) { - if( !itemdb_cansell(&sd->status.inventory[i], pc->get_group_level(sd)) ) + if( !itemdb_cansell(&sd->status.inventory[i], pc_get_group_level(sd)) ) continue; if( sd->status.inventory[i].expire_time ) continue; // Cannot Sell Rental Items + + if( sd->status.inventory[i].bound && !pc_can_give_bound_items(sd)) + continue; // Don't allow sale of bound items val=sd->inventory_data[i]->value_sell; if( val < 0 ) @@ -1807,10 +1873,10 @@ void clif_selllist(struct map_session_data *sd) /// - append this text void clif_scriptmes(struct map_session_data *sd, int npcid, const char *mes) { int fd = sd->fd; - int slen = strlen(mes) + 9; + size_t slen = strlen(mes) + 9; sd->state.dialog = 1; - + WFIFOHEAD(fd, slen); WFIFOW(fd,0)=0xb4; WFIFOW(fd,2)=slen; @@ -1919,7 +1985,7 @@ void clif_sendfakenpc(struct map_session_data *sd, int npcid) { /// TODO investigate behavior of other windows [FlavioJS] void clif_scriptmenu(struct map_session_data* sd, int npcid, const char* mes) { int fd = sd->fd; - int slen = strlen(mes) + 9; + size_t slen = strlen(mes) + 9; struct block_list *bl = NULL; if (!sd->state.using_fake_npc && (npcid == npc->fake_nd->bl.id || ((bl = map->id2bl(npcid)) && (bl->m!=sd->bl.m || @@ -2026,10 +2092,10 @@ void clif_viewpoint(struct map_session_data *sd, int npc_id, int type, int x, in void clif_hercules_chsys_join(struct hChSysCh *channel, struct map_session_data *sd) { if( idb_put(channel->users, sd->status.char_id, sd) ) return; - + RECREATE(sd->channels, struct hChSysCh *, ++sd->channel_count); sd->channels[ sd->channel_count - 1 ] = channel; - + if( sd->stealth ) { sd->stealth = false; } else if( channel->opt & hChSys_OPT_ANNOUNCE_JOIN ) { @@ -2037,12 +2103,12 @@ void clif_hercules_chsys_join(struct hChSysCh *channel, struct map_session_data sprintf(message, "#%s '%s' joined",channel->name,sd->status.name); clif->chsys_msg(channel,sd,message); } - + /* someone is cheating, we kindly disconnect the bastard */ if( sd->channel_count > 200 ) { set_eof(sd->fd); } - + } /// Displays an illustration image. /// 0145 <image name>.16B <type>.B (ZC_SHOW_IMAGE) @@ -2146,23 +2212,23 @@ void clif_addcards2(unsigned short *cards, struct item* item) { //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 @@ -2187,18 +2253,18 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { p.PacketType = additemType; p.Index = n+2; p.count = amount; - + if( !fail ) { if( n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <=0 || sd->inventory_data[n] == NULL ) return; - + if (sd->inventory_data[n]->view_id > 0) p.nameid = sd->inventory_data[n]->view_id; else p.nameid = sd->status.inventory[n].nameid; - - p.IsIdentified = sd->status.inventory[n].identify; - p.IsDamaged = sd->status.inventory[n].attribute; + + p.IsIdentified = sd->status.inventory[n].identify ? 1 : 0; + p.IsDamaged = sd->status.inventory[n].attribute ? 1 : 0; p.refiningLevel =sd->status.inventory[n].refine; clif->addcards2(&p.slot.card[0], &sd->status.inventory[n]); p.location = pc->equippoint(sd,n); @@ -2207,7 +2273,10 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { p.HireExpireDate = sd->status.inventory[n].expire_time; #endif #if PACKETVER >= 20071002 - p.bindOnEquipType = 0; // unused + /* why restrict the flag to non-stackable? because this is the only packet allows stackable to, + * show the color, and therefore it'd be inconsistent with the rest (aka it'd show yellow, you relog/refresh and boom its gone) + */ + p.bindOnEquipType = sd->status.inventory[n].bound && !itemdb->isstackable2(sd->inventory_data[n]) ? 2 : sd->inventory_data[n]->flag.bindonequip ? 1 : 0; #endif } p.result = (unsigned char)fail; @@ -2289,91 +2358,112 @@ void clif_item_sub(unsigned char *buf, int n, struct item *i, struct item_data * } } -//Unified inventory function which sends all of the inventory (requires two packets, one for equipable items and one for stackable ones. [Skotlex] -void clif_inventorylist(struct map_session_data *sd) { - int i,n,ne,arrow=-1; - unsigned char *buf; - unsigned char *bufe; +void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct item_data *id, int eqp_pos) { -#if PACKETVER < 5 - const int s = 10; //Entry size. -#elif PACKETVER < 20080102 - const int s = 18; -#else - const int s = 22; -#endif -#if PACKETVER < 20071002 - const int se = 20; -#elif PACKETVER < 20100629 - const int se = 26; -#else - const int se = 28; + p->index = idx; + + if (id->view_id > 0) + p->ITID = id->view_id; + else + p->ITID = i->nameid; + + p->type = itemtype(id->type); + +#if PACKETVER < 20120925 + p->IsIdentified = i->identify ? 1 : 0; #endif - buf = (unsigned char*)aMalloc(MAX_INVENTORY * s + 4); - bufe = (unsigned char*)aMalloc(MAX_INVENTORY * se + 4); + p->location = eqp_pos; + p->WearState = i->equip; + +#if PACKETVER < 20120925 + p->IsDamaged = i->attribute ? 1 : 0; +#endif + p->RefiningLevel = i->refine; - for( i = 0, n = 0, ne = 0; i < MAX_INVENTORY; i++ ) - { - if( sd->status.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL ) - continue; + clif->addcards2(&p->slot.card[0], i); - if( !itemdb->isstackable2(sd->inventory_data[i]) ) - { //Non-stackable (Equippable) - WBUFW(bufe,ne*se+4)=i+2; - clif->item_sub(bufe, ne*se+6, &sd->status.inventory[i], sd->inventory_data[i], pc->equippoint(sd,i)); - clif->addcards(WBUFP(bufe, ne*se+16), &sd->status.inventory[i]); #if PACKETVER >= 20071002 - WBUFL(bufe,ne*se+24)=sd->status.inventory[i].expire_time; - WBUFW(bufe,ne*se+28)=0; //Unknown + p->HireExpireDate = i->expire_time; +#endif + +#if PACKETVER >= 20080102 + p->bindOnEquipType = i->bound ? 2 : id->flag.bindonequip ? 1 : 0; #endif + #if PACKETVER >= 20100629 - if (sd->inventory_data[i]->equip&EQP_VISIBLE) - WBUFW(bufe,ne*se+30)= sd->inventory_data[i]->look; - else - WBUFW(bufe,ne*se+30)=0; + p->wItemSpriteNumber = id->equip&EQP_VISIBLE ? id->look : 0; #endif - ne++; - } - else - { //Stackable. - WBUFW(buf,n*s+4)=i+2; - clif->item_sub(buf, n*s+6, &sd->status.inventory[i], sd->inventory_data[i], -2); - if( sd->inventory_data[i]->equip == EQP_AMMO && sd->status.inventory[i].equip ) - arrow=i; + +#if PACKETVER >= 20120925 + p->Flag.IsIdentified = i->identify ? 1 : 0; + p->Flag.IsDamaged = i->attribute ? 1 : 0; + p->Flag.PlaceETCTab = i->favorite ? 1 : 0; + p->Flag.SpareBits = 0; +#endif +} +void clif_item_normal(short idx, struct NORMALITEM_INFO *p, struct item *i, struct item_data *id) { + p->index = idx; + + if (id->view_id > 0) + p->ITID = id->view_id; + else + p->ITID = i->nameid; + + p->type = itemtype(id->type); + +#if PACKETVER < 20120925 + p->IsIdentified = i->identify ? 1 : 0; +#endif + + p->count = i->amount; + p->WearState = id->equip; + #if PACKETVER >= 5 - clif->addcards(WBUFP(buf, n*s+14), &sd->status.inventory[i]); + clif->addcards2(&p->slot.card[0], i); #endif + #if PACKETVER >= 20080102 - WBUFL(buf,n*s+22)=sd->status.inventory[i].expire_time; + p->HireExpireDate = i->expire_time; #endif - n++; - } - } - if( n ) { -#if PACKETVER < 5 - WBUFW(buf,0)=0xa3; -#elif PACKETVER < 20080102 - WBUFW(buf,0)=0x1ee; -#else - WBUFW(buf,0)=0x2e8; + +#if PACKETVER >= 20120925 + p->Flag.IsIdentified = i->identify ? 1 : 0; + p->Flag.PlaceETCTab = i->favorite ? 1 : 0; + p->Flag.SpareBits = 0; #endif - WBUFW(buf,2)=4+n*s; - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); +} +void clif_inventorylist(struct map_session_data *sd) { + int i, normal = 0, equip = 0; + + for( i = 0; i < MAX_INVENTORY; i++ ) { + + if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) + continue; + if( !itemdb->isstackable2(sd->inventory_data[i]) ) //Non-stackable (Equippable) + clif_item_equip(i+2,&itemlist_equip.list[equip++],&sd->status.inventory[i],sd->inventory_data[i],pc->equippoint(sd,i)); + else //Stackable (Normal) + clif_item_normal(i+2,&itemlist_normal.list[normal++],&sd->status.inventory[i],sd->inventory_data[i]); } - if( arrow >= 0 ) - clif->arrowequip(sd,arrow); - if( ne ) { -#if PACKETVER < 20071002 - WBUFW(bufe,0)=0xa4; -#else - WBUFW(bufe,0)=0x2d0; -#endif - WBUFW(bufe,2)=4+ne*se; - clif->send(bufe, WBUFW(bufe,2), &sd->bl, SELF); + if( normal ) { + itemlist_normal.PacketType = inventorylistnormalType; + itemlist_normal.PacketLength = 4 + (sizeof(struct NORMALITEM_INFO) * normal); + + clif->send(&itemlist_normal, itemlist_normal.PacketLength, &sd->bl, SELF); } -#if PACKETVER >= 20111122 + + if( sd->equip_index[EQI_AMMO] >= 0 ) + clif->arrowequip(sd,sd->equip_index[EQI_AMMO]); + + if( equip ) { + itemlist_equip.PacketType = inventorylistequipType; + itemlist_equip.PacketLength = 4 + (sizeof(struct EQUIPITEM_INFO) * equip); + + clif->send(&itemlist_equip, itemlist_equip.PacketLength, &sd->bl, SELF); + } +/* on 20120925 onwards this is a field on clif_item_equip/normal */ +#if PACKETVER >= 20111122 && PACKETVER < 20120925 for( i = 0; i < MAX_INVENTORY; i++ ) { if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) continue; @@ -2382,218 +2472,115 @@ void clif_inventorylist(struct map_session_data *sd) { clif->favorite_item(sd, i); } #endif - - if( buf ) aFree(buf); - if( bufe ) aFree(bufe); } //Required when items break/get-repaired. Only sends equippable item list. -void clif_equiplist(struct map_session_data *sd) -{ - int i,n,fd = sd->fd; - unsigned char *buf; -#if PACKETVER < 20071002 - const int cmd = 20; -#elif PACKETVER < 20100629 - const int cmd = 26; -#else - const int cmd = 28; -#endif +void clif_equiplist(struct map_session_data *sd) { + int i, equip = 0; - WFIFOHEAD(fd, MAX_INVENTORY * cmd + 4); - buf = WFIFOP(fd,0); + for( i = 0; i < MAX_INVENTORY; i++ ) { - for(i=0,n=0;i<MAX_INVENTORY;i++){ - if (sd->status.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL) + if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) continue; + if( !itemdb->isstackable2(sd->inventory_data[i]) ) //Non-stackable (Equippable) + clif_item_equip(i+2,&itemlist_equip.list[equip++],&sd->status.inventory[i],sd->inventory_data[i],pc->equippoint(sd,i)); + } + + if( equip ) { + itemlist_equip.PacketType = inventorylistequipType; + itemlist_equip.PacketLength = 4 + (sizeof(struct EQUIPITEM_INFO) * equip); - if(itemdb->isstackable2(sd->inventory_data[i])) + clif->send(&itemlist_equip, itemlist_equip.PacketLength, &sd->bl, SELF); + } + + /* on 20120925 onwards this is a field on clif_item_equip */ +#if PACKETVER >= 20111122 && PACKETVER < 20120925 + for( i = 0; i < MAX_INVENTORY; i++ ) { + if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) continue; - //Equippable - WBUFW(buf,n*cmd+4)=i+2; - clif->item_sub(buf, n*cmd+6, &sd->status.inventory[i], sd->inventory_data[i], pc->equippoint(sd,i)); - clif->addcards(WBUFP(buf, n*cmd+16), &sd->status.inventory[i]); -#if PACKETVER >= 20071002 - WBUFL(buf,n*cmd+24)=sd->status.inventory[i].expire_time; - WBUFW(buf,n*cmd+28)=0; //Unknown -#endif -#if PACKETVER >= 20100629 - if (sd->inventory_data[i]->equip&EQP_VISIBLE) - WBUFW(buf,n*cmd+30)= sd->inventory_data[i]->look; - else - WBUFW(buf,n*cmd+30)=0; -#endif - n++; + + if ( sd->status.inventory[i].favorite ) + clif->favorite_item(sd, i); } - if (n) { -#if PACKETVER < 20071002 - WBUFW(buf,0)=0xa4; -#else - WBUFW(buf,0)=0x2d0; #endif - WBUFW(buf,2)=4+n*cmd; - WFIFOSET(fd,WFIFOW(fd,2)); - } } -void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length) -{ +void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length) { + int i = 0; struct item_data *id; - int i,n,ne; - unsigned char *buf; - unsigned char *bufe; -#if PACKETVER < 5 - const int s = 10; //Entry size. -#elif PACKETVER < 20080102 - const int s = 18; -#else - const int s = 22; -#endif -#if PACKETVER < 20071002 - const int cmd = 20; -#elif PACKETVER < 20100629 - const int cmd = 26; -#else - const int cmd = 28; -#endif - buf = (unsigned char*)aMalloc(items_length * s + 4); - bufe = (unsigned char*)aMalloc(items_length * cmd + 4); + do { + int normal = 0, equip = 0, k = 0; - for( i = 0, n = 0, ne = 0; i < items_length; i++ ) - { - if( items[i].nameid <= 0 ) - continue; - id = itemdb->search(items[i].nameid); - if( !itemdb->isstackable2(id) ) - { //Equippable - WBUFW(bufe,ne*cmd+4)=i+1; - clif->item_sub(bufe, ne*cmd+6, &items[i], id, id->equip); - clif->addcards(WBUFP(bufe, ne*cmd+16), &items[i]); -#if PACKETVER >= 20071002 - WBUFL(bufe,ne*cmd+24)=items[i].expire_time; - WBUFW(bufe,ne*cmd+28)=0; //Unknown -#endif - ne++; + for( ; i < items_length && k < 500; i++, k++ ) { + + if( items[i].nameid <= 0 ) + continue; + + id = itemdb->search(items[i].nameid); + + if( !itemdb->isstackable2(id) ) //Non-stackable (Equippable) + clif_item_equip(i+1,&storelist_equip.list[equip++],&items[i],id,id->equip); + else //Stackable (Normal) + clif_item_normal(i+1,&storelist_normal.list[normal++],&items[i],id); } - else - { //Stackable - WBUFW(buf,n*s+4)=i+1; - clif->item_sub(buf, n*s+6, &items[i], id,-1); -#if PACKETVER >= 5 - clif->addcards(WBUFP(buf,n*s+14), &items[i]); -#endif -#if PACKETVER >= 20080102 - WBUFL(buf,n*s+22)=items[i].expire_time; + + if( normal ) { + storelist_normal.PacketType = storagelistnormalType; + storelist_normal.PacketLength = ( sizeof( storelist_normal ) - sizeof( storelist_normal.list ) ) + (sizeof(struct NORMALITEM_INFO) * normal); + +#if PACKETVER >= 20120925 + safestrncpy(storelist_normal.name, "Storage", NAME_LENGTH); #endif - n++; + + clif->send(&storelist_normal, storelist_normal.PacketLength, &sd->bl, SELF); } - } - if( n ) - { -#if PACKETVER < 5 - WBUFW(buf,0)=0xa5; -#elif PACKETVER < 20080102 - WBUFW(buf,0)=0x1f0; -#else - WBUFW(buf,0)=0x2ea; -#endif - WBUFW(buf,2)=4+n*s; - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); - } - if( ne ) - { -#if PACKETVER < 20071002 - WBUFW(bufe,0)=0xa6; -#else - WBUFW(bufe,0)=0x2d1; + + if( equip ) { + storelist_equip.PacketType = storagelistequipType; + storelist_equip.PacketLength = ( sizeof( storelist_equip ) - sizeof( storelist_equip.list ) ) + (sizeof(struct EQUIPITEM_INFO) * equip); + +#if PACKETVER >= 20120925 + safestrncpy(storelist_equip.name, "Storage", NAME_LENGTH); #endif - WBUFW(bufe,2)=4+ne*cmd; - clif->send(bufe, WBUFW(bufe,2), &sd->bl, SELF); - } - if( buf ) aFree(buf); - if( bufe ) aFree(bufe); + clif->send(&storelist_equip, storelist_equip.PacketLength, &sd->bl, SELF); + } + + } while ( i < items_length ); + } -void clif_cartlist(struct map_session_data *sd) -{ +void clif_cartlist(struct map_session_data *sd) { + int i, normal = 0, equip = 0; struct item_data *id; - int i,n,ne; - unsigned char *buf; - unsigned char *bufe; -#if PACKETVER < 5 - const int s = 10; //Entry size. -#elif PACKETVER < 20080102 - const int s = 18; -#else - const int s = 22; -#endif -#if PACKETVER < 20071002 - const int cmd = 20; -#elif PACKETVER < 20100629 - const int cmd = 26; -#else - const int cmd = 28; -#endif - buf = (unsigned char*)aMalloc(MAX_CART * s + 4); - bufe = (unsigned char*)aMalloc(MAX_CART * cmd + 4); + for( i = 0; i < MAX_CART; i++ ) { - for( i = 0, n = 0, ne = 0; i < MAX_CART; i++ ) - { if( sd->status.cart[i].nameid <= 0 ) continue; + id = itemdb->search(sd->status.cart[i].nameid); - if( !itemdb->isstackable2(id) ) - { //Equippable - WBUFW(bufe,ne*cmd+4)=i+2; - clif->item_sub(bufe, ne*cmd+6, &sd->status.cart[i], id, id->equip); - clif->addcards(WBUFP(bufe, ne*cmd+16), &sd->status.cart[i]); -#if PACKETVER >= 20071002 - WBUFL(bufe,ne*cmd+24)=sd->status.cart[i].expire_time; - WBUFW(bufe,ne*cmd+28)=0; //Unknown -#endif - ne++; - } - else - { //Stackable - WBUFW(buf,n*s+4)=i+2; - clif->item_sub(buf, n*s+6, &sd->status.cart[i], id,-1); -#if PACKETVER >= 5 - clif->addcards(WBUFP(buf,n*s+14), &sd->status.cart[i]); -#endif -#if PACKETVER >= 20080102 - WBUFL(buf,n*s+22)=sd->status.cart[i].expire_time; -#endif - n++; - } - } - if( n ) - { -#if PACKETVER < 5 - WBUFW(buf,0)=0x123; -#elif PACKETVER < 20080102 - WBUFW(buf,0)=0x1ef; -#else - WBUFW(buf,0)=0x2e9; -#endif - WBUFW(buf,2)=4+n*s; - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); + + if( !itemdb->isstackable2(id) ) //Non-stackable (Equippable) + clif_item_equip(i+2,&itemlist_equip.list[equip++],&sd->status.cart[i],id,id->equip); + else //Stackable (Normal) + clif_item_normal(i+2,&itemlist_normal.list[normal++],&sd->status.cart[i],id); } - if( ne ) - { -#if PACKETVER < 20071002 - WBUFW(bufe,0)=0x122; -#else - WBUFW(bufe,0)=0x2d2; -#endif - WBUFW(bufe,2)=4+ne*cmd; - clif->send(bufe, WBUFW(bufe,2), &sd->bl, SELF); + + if( normal ) { + itemlist_normal.PacketType = cartlistnormalType; + itemlist_normal.PacketLength = 4 + (sizeof(struct NORMALITEM_INFO) * normal); + + clif->send(&itemlist_normal, itemlist_normal.PacketLength, &sd->bl, SELF); } - if( buf ) aFree(buf); - if( bufe ) aFree(bufe); + if( equip ) { + itemlist_equip.PacketType = cartlistequipType; + itemlist_equip.PacketLength = 4 + (sizeof(struct EQUIPITEM_INFO) * equip); + + clif->send(&itemlist_equip, itemlist_equip.PacketLength, &sd->bl, SELF); + } } @@ -2659,14 +2646,14 @@ void read_channels_config(void) { config_t channels_conf; config_setting_t *chsys = NULL; const char *config_filename = "conf/channels.conf"; // FIXME hardcoded name - - if (conf_read_file(&channels_conf, config_filename)) + + if (libconfig->read_file(&channels_conf, config_filename)) return; - - chsys = config_lookup(&channels_conf, "chsys"); - + + chsys = libconfig->lookup(&channels_conf, "chsys"); + if (chsys != NULL) { - config_setting_t *settings = config_setting_get_elem(chsys, 0); + config_setting_t *settings = libconfig->setting_get_elem(chsys, 0); config_setting_t *channels; config_setting_t *colors; int i,k; @@ -2677,46 +2664,46 @@ void read_channels_config(void) { local_autojoin = 0, ally_autojoin = 0, allow_user_channel_creation = 0, irc_enabled = 0; - - if( !config_setting_lookup_string(settings, "map_local_channel_name", &local_name) ) + + if( !libconfig->setting_lookup_string(settings, "map_local_channel_name", &local_name) ) local_name = "map"; safestrncpy(hChSys.local_name, local_name, HCHSYS_NAME_LENGTH); - - if( !config_setting_lookup_string(settings, "ally_channel_name", &ally_name) ) + + if( !libconfig->setting_lookup_string(settings, "ally_channel_name", &ally_name) ) ally_name = "ally"; safestrncpy(hChSys.ally_name, ally_name, HCHSYS_NAME_LENGTH); - - if( !config_setting_lookup_string(settings, "irc_channel_name", &irc_name) ) + + if( !libconfig->setting_lookup_string(settings, "irc_channel_name", &irc_name) ) irc_name = "irc"; safestrncpy(hChSys.irc_name, irc_name, HCHSYS_NAME_LENGTH); - - config_setting_lookup_bool(settings, "map_local_channel", &local_enabled); - config_setting_lookup_bool(settings, "ally_channel_enabled", &ally_enabled); - config_setting_lookup_bool(settings, "irc_channel_enabled", &irc_enabled); - + + libconfig->setting_lookup_bool(settings, "map_local_channel", &local_enabled); + libconfig->setting_lookup_bool(settings, "ally_channel_enabled", &ally_enabled); + libconfig->setting_lookup_bool(settings, "irc_channel_enabled", &irc_enabled); + if( local_enabled ) hChSys.local = true; if( ally_enabled ) hChSys.ally = true; if( irc_enabled ) hChSys.irc = true; - + hChSys.irc_server[0] = hChSys.irc_channel[0] = hChSys.irc_nick[0] = hChSys.irc_nick_pw[0] = '\0'; - + if( hChSys.irc ) { const char *irc_server, *irc_channel, *irc_nick, *irc_nick_pw; int irc_use_ghost = 0; - if( config_setting_lookup_string(settings, "irc_channel_network", &irc_server) ) { + if( libconfig->setting_lookup_string(settings, "irc_channel_network", &irc_server) ) { if( !strstr(irc_server,":") ) { hChSys.irc = false; ShowWarning("channels.conf : network port wasn't found in 'irc_channel_network', disabling irc channel...\n"); } else { unsigned char d = 0, dlen = strlen(irc_server); char server[40]; - + memset(server, '\0', sizeof(server)); - + for(d = 0; d < dlen; d++) { if(irc_server[d] == ':') { memcpy(server, irc_server, d); @@ -2731,13 +2718,13 @@ void read_channels_config(void) { hChSys.irc = false; ShowWarning("channels.conf : irc channel enabled but irc_channel_network wasn't found, disabling irc channel...\n"); } - if( config_setting_lookup_string(settings, "irc_channel_channel", &irc_channel) ) + if( libconfig->setting_lookup_string(settings, "irc_channel_channel", &irc_channel) ) safestrncpy(hChSys.irc_channel, irc_channel, 50); else { hChSys.irc = false; ShowWarning("channels.conf : irc channel enabled but irc_channel_channel wasn't found, disabling irc channel...\n"); } - if( config_setting_lookup_string(settings, "irc_channel_nick", &irc_nick) ) { + if( libconfig->setting_lookup_string(settings, "irc_channel_nick", &irc_nick) ) { if( strcmpi(irc_nick,"Hercules_chSysBot") == 0 ) { sprintf(hChSys.irc_nick, "Hercules_chSysBot%d",rand()%777); } else @@ -2746,106 +2733,106 @@ void read_channels_config(void) { hChSys.irc = false; ShowWarning("channels.conf : irc channel enabled but irc_channel_nick wasn't found, disabling irc channel...\n"); } - if( config_setting_lookup_string(settings, "irc_channel_nick_pw", &irc_nick_pw) ) { + if( libconfig->setting_lookup_string(settings, "irc_channel_nick_pw", &irc_nick_pw) ) { safestrncpy(hChSys.irc_nick_pw, irc_nick_pw, 30); config_setting_lookup_bool(settings, "irc_channel_use_ghost", &irc_use_ghost); hChSys.irc_use_ghost = irc_use_ghost; } } - - config_setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin); - config_setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin); + + libconfig->setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin); + libconfig->setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin); if( local_autojoin ) hChSys.local_autojoin = true; if( ally_autojoin ) hChSys.ally_autojoin = true; - - config_setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation); + + libconfig->setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation); if( allow_user_channel_creation ) hChSys.allow_user_channel_creation = true; - if( (colors = config_setting_get_member(settings, "colors")) != NULL ) { - int color_count = config_setting_length(colors); - CREATE( hChSys.colors, unsigned long, color_count ); + if( (colors = libconfig->setting_get_member(settings, "colors")) != NULL ) { + int color_count = libconfig->setting_length(colors); + CREATE( hChSys.colors, unsigned int, color_count ); CREATE( hChSys.colors_name, char *, color_count ); for(i = 0; i < color_count; i++) { - config_setting_t *color = config_setting_get_elem(colors, i); + config_setting_t *color = libconfig->setting_get_elem(colors, i); CREATE( hChSys.colors_name[i], char, HCHSYS_NAME_LENGTH ); - + safestrncpy(hChSys.colors_name[i], config_setting_name(color), HCHSYS_NAME_LENGTH); - hChSys.colors[i] = strtoul(config_setting_get_string_elem(colors,i),NULL,0); + hChSys.colors[i] = (unsigned int)strtoul(libconfig->setting_get_string_elem(colors,i),NULL,0); hChSys.colors[i] = (hChSys.colors[i] & 0x0000FF) << 16 | (hChSys.colors[i] & 0x00FF00) | (hChSys.colors[i] & 0xFF0000) >> 16;//RGB to BGR } hChSys.colors_count = color_count; } - - config_setting_lookup_string(settings, "map_local_channel_color", &local_color); - + + libconfig->setting_lookup_string(settings, "map_local_channel_color", &local_color); + for (k = 0; k < hChSys.colors_count; k++) { if( strcmpi(hChSys.colors_name[k],local_color) == 0 ) break; } - + if( k < hChSys.colors_count ) { hChSys.local_color = k; } else { ShowError("channels.conf: unknown color '%s' for 'map_local_channel_color', disabling '#%s'...\n",local_color,local_name); hChSys.local = false; } - - config_setting_lookup_string(settings, "ally_channel_color", &ally_color); - + + libconfig->setting_lookup_string(settings, "ally_channel_color", &ally_color); + for (k = 0; k < hChSys.colors_count; k++) { if( strcmpi(hChSys.colors_name[k],ally_color) == 0 ) break; } - + if( k < hChSys.colors_count ) { hChSys.ally_color = k; } else { ShowError("channels.conf: unknown color '%s' for 'ally_channel_color', disabling '#%s'...\n",ally_color,ally_name); hChSys.ally = false; } - - config_setting_lookup_string(settings, "irc_channel_color", &irc_color); - + + libconfig->setting_lookup_string(settings, "irc_channel_color", &irc_color); + for (k = 0; k < hChSys.colors_count; k++) { if( strcmpi(hChSys.colors_name[k],irc_color) == 0 ) break; } - + if( k < hChSys.colors_count ) { hChSys.irc_color = k; } else { ShowError("channels.conf: unknown color '%s' for 'irc_channel_color', disabling '#%s'...\n",irc_color,irc_name); hChSys.irc = false; } - + if( hChSys.irc ) { struct hChSysCh *chd; CREATE( chd, struct hChSysCh, 1 ); - + safestrncpy(chd->name, hChSys.irc_name, HCHSYS_NAME_LENGTH); chd->type = hChSys_IRC; - + clif->chsys_create(chd,NULL,NULL,hChSys.irc_color); ircbot->channel = chd; } - - if( (channels = config_setting_get_member(settings, "default_channels")) != NULL ) { - int channel_count = config_setting_length(channels); - + + if( (channels = libconfig->setting_get_member(settings, "default_channels")) != NULL ) { + int channel_count = libconfig->setting_length(channels); + for(i = 0; i < channel_count; i++) { - config_setting_t *channel = config_setting_get_elem(channels, i); + config_setting_t *channel = libconfig->setting_get_elem(channels, i); const char *name = config_setting_name(channel); - const char *color = config_setting_get_string_elem(channels,i); + const char *color = libconfig->setting_get_string_elem(channels,i); struct hChSysCh *chd; - + for (k = 0; k < hChSys.colors_count; k++) { if( strcmpi(hChSys.colors_name[k],color) == 0 ) break; @@ -2860,16 +2847,16 @@ void read_channels_config(void) { } CREATE( chd, struct hChSysCh, 1 ); - + safestrncpy(chd->name, name, HCHSYS_NAME_LENGTH); chd->type = hChSys_PUBLIC; - + clif->chsys_create(chd,NULL,NULL,k); } } - + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' channels in '"CL_WHITE"%s"CL_RESET"'.\n", db_size(clif->channel_db), config_filename); - config_destroy(&channels_conf); + libconfig->destroy(&channels_conf); } } @@ -2894,7 +2881,7 @@ int clif_hpmeter_sub(struct block_list *bl, va_list ap) { if( !tsd->fd || tsd == sd ) return 0; - if( !pc->has_permission(tsd, PC_PERM_VIEW_HPMETER) ) + if( !pc_has_permission(tsd, PC_PERM_VIEW_HPMETER) ) return 0; WFIFOHEAD(tsd->fd,packet_len(cmd)); WFIFOW(tsd->fd,0) = cmd; @@ -2934,10 +2921,9 @@ int clif_hpmeter(struct map_session_data *sd) { /// 013a <atk range>.W (ZC_ATTACK_RANGE) /// 0141 <status id>.L <base status>.L <plus status>.L (ZC_COUPLESTATUS) /// TODO: Extract individual packets. -/// FIXME: Packet lengths from packet_len(cmd) void clif_updatestatus(struct map_session_data *sd,int type) { - int fd,len=8; + int fd,len; nullpo_retv(sd); @@ -2949,6 +2935,7 @@ void clif_updatestatus(struct map_session_data *sd,int type) WFIFOHEAD(fd, 14); WFIFOW(fd,0)=0xb0; WFIFOW(fd,2)=type; + len = packet_len(0xb0); switch(type){ // 00b0 case SP_WEIGHT: @@ -3000,7 +2987,8 @@ void clif_updatestatus(struct map_session_data *sd,int type) case SP_HP: WFIFOL(fd,4)=sd->battle_status.hp; // TODO: Won't these overwrite the current packet? - clif->hpmeter(sd); + if( map->list[sd->bl.m].hpmeter_visible ) + clif->hpmeter(sd); if( !battle_config.party_hp_mode && sd->status.party_id ) clif->party_hp(sd); if( sd->bg_id ) @@ -3053,22 +3041,27 @@ void clif_updatestatus(struct map_session_data *sd,int type) case SP_ZENY: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=sd->status.zeny; + len = packet_len(0xb1); break; case SP_BASEEXP: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=sd->status.base_exp; + len = packet_len(0xb1); break; case SP_JOBEXP: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=sd->status.job_exp; + len = packet_len(0xb1); break; case SP_NEXTBASEEXP: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=pc->nextbaseexp(sd); + len = packet_len(0xb1); break; case SP_NEXTJOBEXP: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=pc->nextjobexp(sd); + len = packet_len(0xb1); break; /** @@ -3082,7 +3075,7 @@ void clif_updatestatus(struct map_session_data *sd,int type) case SP_ULUK: WFIFOW(fd,0)=0xbe; WFIFOB(fd,4)=pc->need_status_point(sd,type-SP_USTR+SP_STR,1); - len=5; + len = packet_len(0xbe); break; /** @@ -3091,7 +3084,7 @@ void clif_updatestatus(struct map_session_data *sd,int type) case SP_ATTACKRANGE: WFIFOW(fd,0)=0x13a; WFIFOW(fd,2)=sd->battle_status.rhw.range; - len=4; + len = packet_len(0x13a); break; case SP_STR: @@ -3099,42 +3092,42 @@ void clif_updatestatus(struct map_session_data *sd,int type) WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.str; WFIFOL(fd,10)=sd->battle_status.str - sd->status.str; - len=14; + len = packet_len(0x141); break; case SP_AGI: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.agi; WFIFOL(fd,10)=sd->battle_status.agi - sd->status.agi; - len=14; + len = packet_len(0x141); break; case SP_VIT: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.vit; WFIFOL(fd,10)=sd->battle_status.vit - sd->status.vit; - len=14; + len = packet_len(0x141); break; case SP_INT: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.int_; WFIFOL(fd,10)=sd->battle_status.int_ - sd->status.int_; - len=14; + len = packet_len(0x141); break; case SP_DEX: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.dex; WFIFOL(fd,10)=sd->battle_status.dex - sd->status.dex; - len=14; + len = packet_len(0x141); break; case SP_LUK: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.luk; WFIFOL(fd,10)=sd->battle_status.luk - sd->status.luk; - len=14; + len = packet_len(0x141); break; case SP_CARTINFO: @@ -3143,7 +3136,7 @@ void clif_updatestatus(struct map_session_data *sd,int type) WFIFOW(fd,4)=MAX_CART; WFIFOL(fd,6)=sd->cart_weight; WFIFOL(fd,10)=sd->cart_weight_max; - len=14; + len = packet_len(0x121); break; default: @@ -3153,7 +3146,6 @@ void clif_updatestatus(struct map_session_data *sd,int type) WFIFOSET(fd,len); } - /// Notifies client of a parameter change of an another player (ZC_PAR_CHANGE_USER). /// 01ab <account id>.L <var id>.W <value>.L void clif_changestatus(struct map_session_data* sd,int type,int val) @@ -3195,7 +3187,7 @@ void clif_changelook(struct block_list *bl,int type,int val) sd = BL_CAST(BL_PC, bl); sc = status->get_sc(bl); vd = status->get_viewdata(bl); - //nullpo_ret(vd); + if( vd ) //temp hack to let Warp Portal change appearance switch(type) { case LOOK_WEAPON: @@ -3216,13 +3208,13 @@ void clif_changelook(struct block_list *bl,int type,int val) break; case LOOK_BASE: if( !sd ) break; - - if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK) ) + + if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST) ) vd->weapon = vd->shield = 0; - + if( !vd->cloth_color ) break; - + if( sd ) { if( sd->sc.option&OPTION_WEDDING && battle_config.wedding_ignorepalette ) vd->cloth_color = 0; @@ -3232,6 +3224,8 @@ void clif_changelook(struct block_list *bl,int type,int val) vd->cloth_color = 0; if( sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette ) vd->cloth_color = 0; + if( sd->sc.option&OPTION_OKTOBERFEST /* TODO: config? */ ) + vd->cloth_color = 0; } break; case LOOK_HAIR: @@ -3259,6 +3253,8 @@ void clif_changelook(struct block_list *bl,int type,int val) val = 0; if( sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette ) val = 0; + if( sd->sc.option&OPTION_OKTOBERFEST /* TODO: config? */ ) + val = 0; } vd->cloth_color = val; break; @@ -3304,6 +3300,7 @@ void clif_changelook(struct block_list *bl,int type,int val) WBUFW(buf,0)=0x1d7; WBUFL(buf,2)=bl->id; if(type == LOOK_WEAPON || type == LOOK_SHIELD) { + nullpo_retv(vd); WBUFB(buf,6)=LOOK_WEAPON; WBUFW(buf,7)=vd->weapon; WBUFW(buf,9)=vd->shield; @@ -3312,7 +3309,7 @@ void clif_changelook(struct block_list *bl,int type,int val) WBUFL(buf,7)=val; } clif->send(buf,packet_len(0x1d7),bl,target); - if( disguised(bl) && ((TBL_PC*)sd)->fontcolor ) { + if( disguised(bl) && sd && sd->fontcolor ) { WBUFL(buf,2)=-bl->id; clif->send(buf,packet_len(0x1d7),bl,SELF); } @@ -3527,52 +3524,39 @@ void clif_statusupack(struct map_session_data *sd,int type,int ok,int val) /// Notifies the client about the result of a request to equip an item (ZC_REQ_WEAR_EQUIP_ACK). /// 00aa <index>.W <equip location>.W <result>.B /// 00aa <index>.W <equip location>.W <view id>.W <result>.B (PACKETVER >= 20100629) -/// result: -/// 0 = failure -/// 1 = success -/// 2 = failure due to low level -void clif_equipitemack(struct map_session_data *sd,int n,int pos,int ok) -{ - int fd; +void clif_equipitemack(struct map_session_data *sd,int n,int pos,enum e_EQUIP_ITEM_ACK result) { + struct packet_equipitem_ack p; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xaa)); - WFIFOW(fd,0)=0xaa; - WFIFOW(fd,2)=n+2; - WFIFOW(fd,4)=pos; -#if PACKETVER < 20100629 - WFIFOB(fd,6)=ok; -#else - if (ok && sd->inventory_data[n]->equip&EQP_VISIBLE) - WFIFOW(fd,6)=sd->inventory_data[n]->look; + p.PacketType = equipitemackType; + p.index = n+2; + p.wearLocation = pos; +#if PACKETVER >= 20100629 + if (result == EIA_SUCCESS && sd->inventory_data[n]->equip&EQP_VISIBLE) + p.wItemSpriteNumber = sd->inventory_data[n]->look; else - WFIFOW(fd,6)=0; - WFIFOB(fd,8)=ok; + p.wItemSpriteNumber = 0; #endif - WFIFOSET(fd,packet_len(0xaa)); + p.result = (unsigned char)result; + + clif->send(&p, sizeof(p), &sd->bl, SELF); } /// Notifies the client about the result of a request to take off an item (ZC_REQ_TAKEOFF_EQUIP_ACK). /// 00ac <index>.W <equip location>.W <result>.B -/// result: -/// 0 = failure -/// 1 = success -void clif_unequipitemack(struct map_session_data *sd,int n,int pos,int ok) -{ - int fd; +void clif_unequipitemack(struct map_session_data *sd,int n,int pos,enum e_UNEQUIP_ITEM_ACK result) { + struct packet_unequipitem_ack p; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xac)); - WFIFOW(fd,0)=0xac; - WFIFOW(fd,2)=n+2; - WFIFOW(fd,4)=pos; - WFIFOB(fd,6)=ok; - WFIFOSET(fd,packet_len(0xac)); + p.PacketType = unequipitemackType; + p.index = n+2; + p.wearLocation = pos; + p.result = (unsigned char)result; + + clif->send(&p, sizeof(p), &sd->bl, SELF); } @@ -3613,9 +3597,9 @@ void clif_changeoption(struct block_list* bl) struct map_session_data* sd; nullpo_retv(bl); - + if ( !(sc = status->get_sc(bl)) && bl->type != BL_NPC ) return; //How can an option change if there's no sc? - + sd = BL_CAST(BL_PC, bl); #if PACKETVER >= 7 @@ -3722,7 +3706,7 @@ void clif_useitemack(struct map_session_data *sd,int index,int amount,bool ok) } void clif_hercules_chsys_send(struct hChSysCh *channel, struct map_session_data *sd, const char *msg) { - if( channel->msg_delay != 0 && DIFF_TICK(sd->hchsysch_tick + ( channel->msg_delay * 1000 ), timer->gettick()) > 0 && !pc->has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if( channel->msg_delay != 0 && DIFF_TICK(sd->hchsysch_tick + ( channel->msg_delay * 1000 ), timer->gettick()) > 0 && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { clif->colormes(sd->fd,COLOR_RED,msg_txt(1455)); return; } else { @@ -4291,7 +4275,7 @@ void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* ds } if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting. (sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround - pc->has_permission(sd, PC_PERM_VIEW_HPMETER) + pc_has_permission(sd, PC_PERM_VIEW_HPMETER) ) clif->hpmeter_single(sd->fd, dstsd->bl.id, dstsd->battle_status.hp, dstsd->battle_status.max_hp); @@ -4334,7 +4318,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { clif->getareachar_pc(sd, tsd); if(tsd->state.size==SZ_BIG) // tiny/big players [Valaris] clif->specialeffect_single(bl,423,sd->fd); - else if(tsd->state.size==SZ_MEDIUM) + else if(tsd->state.size==SZ_SMALL) clif->specialeffect_single(bl,421,sd->fd); if( tsd->bg_id && map->list[tsd->bl.m].flag.battleground ) clif->sendbgemblem_single(sd->fd,tsd); @@ -4353,7 +4337,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { clif->dispchat((struct chat_data*)map->id2bl(nd->chat_id),sd->fd); if( nd->size == SZ_BIG ) clif->specialeffect_single(bl,423,sd->fd); - else if( nd->size == SZ_MEDIUM ) + else if( nd->size == SZ_SMALL ) clif->specialeffect_single(bl,421,sd->fd); } break; @@ -4362,7 +4346,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { TBL_MOB* md = (TBL_MOB*)bl; if(md->special_state.size==SZ_BIG) // tiny/big mobs [Valaris] clif->specialeffect_single(bl,423,sd->fd); - else if(md->special_state.size==SZ_MEDIUM) + else if(md->special_state.size==SZ_SMALL) clif->specialeffect_single(bl,421,sd->fd); #if PACKETVER >= 20120404 if( !(md->status.mode&MD_BOSS) ){ @@ -4429,83 +4413,74 @@ int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int damage, i /// 10 = critical hit /// 11 = lucky dodge /// 12 = (touch skill?) -int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tick, int sdelay, int ddelay, int64 in_damage, int div, int type, int64 in_damage2) -{ - unsigned char buf[33]; +int clif_damage(struct block_list* src, struct block_list* dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type, int64 in_damage2) { + struct packet_damage p; struct status_change *sc; - int damage,damage2; #if PACKETVER < 20071113 - const int cmd = 0x8a; + short damage,damage2; #else - const int cmd = 0x2e1; + int damage,damage2; #endif nullpo_ret(src); nullpo_ret(dst); - - damage = (int)cap_value(in_damage,INT_MIN,INT_MAX); - damage2 = (int)cap_value(in_damage2,INT_MIN,INT_MAX); - - type = clif_calc_delay(type,div,damage+damage2,ddelay); + sc = status->get_sc(dst); - if(sc && sc->count) { - if(sc->data[SC_ILLUSION]) { - if(damage) damage = damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; - if(damage2) damage2 = damage2*(sc->data[SC_ILLUSION]->val2) + rnd()%100; - } - } - WBUFW(buf,0)=cmd; - WBUFL(buf,2)=src->id; - WBUFL(buf,6)=dst->id; - WBUFL(buf,10)=tick; - WBUFL(buf,14)=sdelay; - WBUFL(buf,18)=ddelay; -#if PACKETVER < 20071113 - if (battle_config.hide_woe_damage && map_flag_gvg2(src->m)) { - WBUFW(buf,22)=damage?div:0; - WBUFW(buf,27)=damage2?div:0; - } else { - WBUFW(buf,22)=min(damage, INT16_MAX); - WBUFW(buf,27)=damage2; + if(sc && sc->count && sc->data[SC_ILLUSION]) { + if(in_damage) in_damage = in_damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; + if(in_damage2) in_damage2 = in_damage2*(sc->data[SC_ILLUSION]->val2) + rnd()%100; } - WBUFW(buf,24)=div; - WBUFB(buf,26)=type; + +#if PACKETVER < 20071113 + damage = (short)min(in_damage,INT16_MAX); + damage2 = (short)min(in_damage2,INT16_MAX); #else - if (battle_config.hide_woe_damage && map_flag_gvg2(src->m)) { - WBUFL(buf,22)=damage?div:0; - WBUFL(buf,29)=damage2?div:0; + damage = (int)min(in_damage,INT_MAX); + damage2 = (int)min(in_damage2,INT_MAX); +#endif + + type = clif_calc_delay(type,div,damage+damage2,ddelay); + + p.PacketType = damageType; + p.GID = src->id; + p.targetGID = dst->id; + p.startTime = (uint32)timer->gettick(); + p.attackMT = sdelay; + p.attackedMT = ddelay; + p.count = div; + p.action = type; + + if( battle_config.hide_woe_damage && map_flag_gvg2(src->m) ) { + p.damage = damage?div:0; + p.leftDamage = damage2?div:0; } else { - WBUFL(buf,22)=damage; - WBUFL(buf,29)=damage2; + p.damage = damage; + p.leftDamage = damage2; } - WBUFW(buf,26)=div; - WBUFB(buf,28)=type; -#endif + if(disguised(dst)) { - clif->send(buf,packet_len(cmd),dst,AREA_WOS); - WBUFL(buf,6) = -dst->id; - clif->send(buf,packet_len(cmd),dst,SELF); + clif->send(&p,sizeof(p),dst,AREA_WOS); + p.targetGID = -dst->id; + clif->send(&p,sizeof(p),dst,SELF); } else - clif->send(buf,packet_len(cmd),dst,AREA); + clif->send(&p,sizeof(p),dst,AREA); if(disguised(src)) { - WBUFL(buf,2) = -src->id; + p.GID = -src->id; if (disguised(dst)) - WBUFL(buf,6) = dst->id; -#if PACKETVER < 20071113 - if(damage > 0) WBUFW(buf,22) = -1; - if(damage2 > 0) WBUFW(buf,27) = -1; -#else - if(damage > 0) WBUFL(buf,22) = -1; - if(damage2 > 0) WBUFL(buf,29) = -1; -#endif - clif->send(buf,packet_len(cmd),src,SELF); + p.targetGID = dst->id; + + if(damage > 0) p.damage = -1; + if(damage2 > 0) p.leftDamage = -1; + + clif->send(&p,sizeof(p),src,SELF); } if(src == dst) { unit->setdir(src,unit->getdir(src)); } + //Return adjusted can't walk delay for further processing. return clif->calc_walkdelay(dst,ddelay,type,damage+damage2,div); } @@ -4515,7 +4490,7 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic *------------------------------------------*/ void clif_takeitem(struct block_list* src, struct block_list* dst) { - //clif_damage(src,dst,0,0,0,0,0,1,0); + //clif->damage(src,dst,0,0,0,0,1,0); unsigned char buf[32]; nullpo_retv(src); @@ -4570,15 +4545,14 @@ void clif_standing(struct block_list* bl) /// Inform client(s) about a map-cell change (ZC_UPDATE_MAPINFO). /// 0192 <x>.W <y>.W <type>.W <map name>.16B -void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_target target) -{ +void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_target target) { unsigned char buf[32]; WBUFW(buf,0) = 0x192; WBUFW(buf,2) = x; WBUFW(buf,4) = y; WBUFW(buf,6) = type; - mapindex_getmapname_ext(map->list[m].custom_name ? map->list[map->list[m].instance_src_map].name : map->list[m].name,(char*)WBUFP(buf,8)); + mapindex->getmapname_ext(map->list[m].custom_name ? map->list[map->list[m].instance_src_map].name : map->list[m].name,(char*)WBUFP(buf,8)); if( fd ) { WFIFOHEAD(fd,packet_len(0x192)); @@ -4617,65 +4591,72 @@ void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fi WFIFOSET(fd,packet_len(0x9d)); } +void clif_graffiti_entry(struct block_list *bl, struct skill_unit *su, enum send_target target) { + struct packet_graffiti_entry p; + + p.PacketType = graffiti_entryType; + p.AID = su->bl.id; + p.creatorAID = su->group->src_id; + p.xPos = su->bl.x; + p.yPos = su->bl.y; + p.job = su->group->unit_id; + p.isContens = 1; + p.isVisible = 1; + safestrncpy(p.msg, su->group->valstr, 80); + + clif->send(&p,sizeof(p),bl,target); +} /// Notifies the client of a skill unit. /// 011f <id>.L <creator id>.L <x>.W <y>.W <unit id>.B <visible>.B (ZC_SKILL_ENTRY) /// 01c9 <id>.L <creator id>.L <x>.W <y>.W <unit id>.B <visible>.B <has msg>.B <msg>.80B (ZC_SKILL_ENTRY2) /// 08c7 <lenght>.W <id> L <creator id>.L <x>.W <y>.W <unit id>.B <range>.W <visible>.B (ZC_SKILL_ENTRY3) /// 099f <lenght>.W <id> L <creator id>.L <x>.W <y>.W <unit id>.L <range>.W <visible>.B (ZC_SKILL_ENTRY4) -void clif_getareachar_skillunit(struct map_session_data *sd, struct skill_unit *su) { - int fd = sd->fd, header = 0x11f, pos=0; +void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *su, enum send_target target) { + struct packet_skill_entry p; if( su->group->state.guildaura ) return; -#if PACKETVER >= 20130320 - if(su->group->unit_id > UCHAR_MAX) { - header = 0x99f; - pos = 2; - } -#endif - #if PACKETVER >= 3 - if(su->group->unit_id==UNT_GRAFFITI) { - // Graffiti [Valaris] - WFIFOHEAD(fd,packet_len(0x1c9)); - WFIFOW(fd, 0)=0x1c9; - WFIFOL(fd, 2)=su->bl.id; - WFIFOL(fd, 6)=su->group->src_id; - WFIFOW(fd,10)=su->bl.x; - WFIFOW(fd,12)=su->bl.y; - WFIFOB(fd,14)=su->group->unit_id; - WFIFOB(fd,15)=1; - WFIFOB(fd,16)=1; - safestrncpy((char*)WFIFOP(fd,17),su->group->valstr,MESSAGE_SIZE); - WFIFOSET(fd,packet_len(0x1c9)); + if(su->group->unit_id == UNT_GRAFFITI) { + clif->graffiti_entry(bl,su,target); return; } #endif - WFIFOHEAD(fd,packet_len(header)); - WFIFOW(fd, 0)=header; - if(pos > 0) - WFIFOL(fd, pos)=packet_len(header); - WFIFOL(fd, 2 + pos)=su->bl.id; - WFIFOL(fd, 6 + pos)=su->group->src_id; - WFIFOW(fd,10 + pos)=su->bl.x; - WFIFOW(fd,12 + pos)=su->bl.y; - if (battle_config.traps_setting&1 && skill->get_inf2(su->group->skill_id)&INF2_TRAP) - WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. - else if (skill->get_unit_flag(su->group->skill_id) & UF_RANGEDSINGLEUNIT && !(su->val2 & UF_RANGEDSINGLEUNIT)) - WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. - else if(pos > 0){ - WFIFOL(fd,16)=su->group->unit_id; - WFIFOW(fd,20)=su->range; - pos += 5; - }else - WFIFOB(fd,14)=su->group->unit_id; - WFIFOB(fd,15 + pos)=1; // ignored by client (always gets set to 1) - WFIFOSET(fd,packet_len(header)); + + p.PacketType = skill_entryType; + +#if PACKETVER >= 20110718 + p.PacketLength = sizeof(p); +#endif + + p.AID = su->bl.id; + p.creatorAID = su->group->src_id; + p.xPos = su->bl.x; + p.yPos = su->bl.y; + + //Use invisible unit id for traps. + if ((battle_config.traps_setting&1 && skill->get_inf2(su->group->skill_id)&INF2_TRAP) || + (skill->get_unit_flag(su->group->skill_id) & UF_RANGEDSINGLEUNIT && !(su->val2 & UF_RANGEDSINGLEUNIT))) + p.job = UNT_DUMMYSKILL; + else + p.job = su->group->unit_id; + +#if PACKETVER >= 20110718 + p.RadiusRange = (unsigned char)su->range; +#endif + + p.isVisible = 1; + +#if PACKETVER >= 20130731 + p.level = (unsigned char)su->group->skill_lv; +#endif + + clif->send(&p,sizeof(p),bl,target); if(su->group->skill_id == WZ_ICEWALL) - clif->changemapcell(fd,su->bl.m,su->bl.x,su->bl.y,5,SELF); + clif->changemapcell(bl->type == BL_PC ? ((TBL_PC*)bl)->fd : 0,su->bl.m,su->bl.x,su->bl.y,5,SELF); } @@ -4741,7 +4722,7 @@ int clif_getareachar(struct block_list* bl,va_list ap) { clif->getareachar_item(sd,(struct flooritem_data*) bl); break; case BL_SKILL: - clif->getareachar_skillunit(sd,(TBL_SKILL*)bl); + clif->getareachar_skillunit(&sd->bl,(TBL_SKILL*)bl,SELF); break; default: if(&sd->bl == bl) @@ -4766,6 +4747,7 @@ int clif_outsight(struct block_list *bl,va_list ap) tsd = BL_CAST(BL_PC, tbl); if (tsd && tsd->fd) { //tsd has lost sight of the bl object. + nullpo_ret(bl); switch(bl->type){ case BL_PC: if (sd->vd.class_ != INVISIBLE_CLASS) @@ -4798,6 +4780,7 @@ int clif_outsight(struct block_list *bl,va_list ap) } } if (sd && sd->fd) { //sd is watching tbl go out of view. + nullpo_ret(tbl); if (((vd=status->get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS) && !(tbl->type == BL_NPC && (((TBL_NPC*)tbl)->option&OPTION_INVISIBLE))) clif->clearunit_single(tbl->id,CLR_OUTSIGHT,sd->fd); @@ -4820,12 +4803,13 @@ int clif_insight(struct block_list *bl,va_list ap) tsd = BL_CAST(BL_PC, tbl); if (tsd && tsd->fd) { //Tell tsd that bl entered into his view - switch(bl->type){ + nullpo_ret(bl); + switch(bl->type) { case BL_ITEM: clif->getareachar_item(tsd,(struct flooritem_data*)bl); break; case BL_SKILL: - clif->getareachar_skillunit(tsd,(TBL_SKILL*)bl); + clif->getareachar_skillunit(&tsd->bl,(TBL_SKILL*)bl,SELF); break; default: clif->getareachar_unit(tsd,bl); @@ -4936,23 +4920,31 @@ void clif_deleteskill(struct map_session_data *sd, int id) clif->skillinfoblock(sd); } - /// Updates a skill in the skill tree (ZC_SKILLINFO_UPDATE). /// 010e <skill id>.W <level>.W <sp cost>.W <attack range>.W <upgradable>.B -void clif_skillup(struct map_session_data *sd,uint16 skill_id) { - int fd, idx = skill->get_index(skill_id); - +/// Merged clif_skillup and clif_guild_skillup, same packet was used [panikon] +/// flag: +/// 0: guild call +/// 1: player call +void clif_skillup(struct map_session_data *sd, uint16 skill_id, int skill_lv, int flag) +{ + int fd; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0x10e)); - WFIFOW(fd,0) = 0x10e; - WFIFOW(fd,2) = skill_id; - WFIFOW(fd,4) = sd->status.skill[idx].lv; - WFIFOW(fd,6) = skill->get_sp(skill_id,sd->status.skill[idx].lv); - WFIFOW(fd,8) = skill->get_range2(&sd->bl,skill_id,sd->status.skill[idx].lv); - WFIFOB(fd,10) = (sd->status.skill[idx].lv < skill->tree_get_max(sd->status.skill[idx].id, sd->status.class_)) ? 1 : 0; - WFIFOSET(fd,packet_len(0x10e)); + fd = sd->fd; + + WFIFOHEAD(fd, packet_len(0x10e)); + WFIFOW(fd, 0) = 0x10e; + WFIFOW(fd, 2) = skill_id; + WFIFOW(fd, 4) = skill_lv; + WFIFOW(fd, 6) = skill->get_sp(skill_id, skill_lv); + WFIFOW(fd, 8) = (flag)?skill->get_range2(&sd->bl, skill_id, skill_lv) : skill->get_range(skill_id, skill_lv); + if( flag ) + WFIFOB(fd,10) = (skill_lv < skill->tree_get_max(skill_id, sd->status.class_)) ? 1 : 0; + else + WFIFOB(fd,10) = 1; + + WFIFOSET(fd, packet_len(0x10e)); } @@ -5096,7 +5088,7 @@ void clif_skill_fail(struct map_session_data *sd,uint16 skill_id,enum useskill_f /// Skill cooldown display icon (ZC_SKILL_POSTDELAY). /// 043d <skill ID>.W <tick>.L -void clif_skill_cooldown(struct map_session_data *sd, uint16 skill_id, unsigned int tick) +void clif_skill_cooldown(struct map_session_data *sd, uint16 skill_id, unsigned int duration) { #if PACKETVER>=20081112 int fd; @@ -5107,7 +5099,7 @@ void clif_skill_cooldown(struct map_session_data *sd, uint16 skill_id, unsigned WFIFOHEAD(fd,packet_len(0x43d)); WFIFOW(fd,0) = 0x43d; WFIFOW(fd,2) = skill_id; - WFIFOL(fd,4) = tick; + WFIFOL(fd,4) = duration; WFIFOSET(fd,packet_len(0x43d)); #endif } @@ -5116,7 +5108,7 @@ void clif_skill_cooldown(struct map_session_data *sd, uint16 skill_id, unsigned /// Skill attack effect and damage. /// 0114 <skill id>.W <src id>.L <dst id>.L <tick>.L <src delay>.L <dst delay>.L <damage>.W <level>.W <div>.W <type>.B (ZC_NOTIFY_SKILL) /// 01de <skill id>.W <src id>.L <dst id>.L <tick>.L <src delay>.L <dst delay>.L <damage>.L <level>.W <div>.W <type>.B (ZC_NOTIFY_SKILL2) -int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int tick,int sdelay,int ddelay,int64 in_damage,int div,uint16 skill_id,uint16 skill_lv,int type) { +int clif_skill_damage(struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int64 in_damage, int div, uint16 skill_id, uint16 skill_lv, int type) { unsigned char buf[64]; struct status_change *sc; int damage; @@ -5137,7 +5129,7 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int WBUFW(buf,2)=skill_id; WBUFL(buf,4)=src->id; WBUFL(buf,8)=dst->id; - WBUFL(buf,12)=tick; + WBUFL(buf,12)=(uint32)tick; WBUFL(buf,16)=sdelay; WBUFL(buf,20)=ddelay; if (battle_config.hide_woe_damage && map_flag_gvg2(src->m)) { @@ -5168,7 +5160,7 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int WBUFW(buf,2)=skill_id; WBUFL(buf,4)=src->id; WBUFL(buf,8)=dst->id; - WBUFL(buf,12)=tick; + WBUFL(buf,12)=(uint32)tick; WBUFL(buf,16)=sdelay; WBUFL(buf,20)=ddelay; if (battle_config.hide_woe_damage && map_flag_gvg2(src->m)) { @@ -5204,7 +5196,7 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int /// Ground skill attack effect and damage (ZC_NOTIFY_SKILL_POSITION). /// 0115 <skill id>.W <src id>.L <dst id>.L <tick>.L <src delay>.L <dst delay>.L <x>.W <y>.W <damage>.W <level>.W <div>.W <type>.B #if 0 -int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned int tick,int sdelay,int ddelay,int damage,int div,uint16 skill_id,uint16 skill_lv,int type) { +int clif_skill_damage2(struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int damage, int div, uint16 skill_id, uint16 skill_lv, int type) { unsigned char buf[64]; struct status_change *sc; @@ -5224,7 +5216,7 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned in WBUFW(buf,2)=skill_id; WBUFL(buf,4)=src->id; WBUFL(buf,8)=dst->id; - WBUFL(buf,12)=tick; + WBUFL(buf,12)=(uint32)tick; WBUFL(buf,16)=sdelay; WBUFL(buf,20)=ddelay; WBUFW(buf,24)=dst->x; @@ -5294,8 +5286,7 @@ int clif_skill_nodamage(struct block_list *src,struct block_list *dst,uint16 ski /// Non-damaging ground skill effect (ZC_NOTIFY_GROUNDSKILL). /// 0117 <skill id>.W <src id>.L <level>.W <x>.W <y>.W <tick>.L -void clif_skill_poseffect(struct block_list *src,uint16 skill_id,int val,int x,int y,int tick) -{ +void clif_skill_poseffect(struct block_list *src, uint16 skill_id, int val, int x, int y, int64 tick) { unsigned char buf[32]; nullpo_retv(src); @@ -5306,7 +5297,7 @@ void clif_skill_poseffect(struct block_list *src,uint16 skill_id,int val,int x,i WBUFW(buf,8)=val; WBUFW(buf,10)=x; WBUFW(buf,12)=y; - WBUFL(buf,14)=tick; + WBUFL(buf,14)=(uint32)tick; if(disguised(src)) { clif->send(buf,packet_len(0x117),src,AREA_WOS); WBUFL(buf,4)=-src->id; @@ -5315,65 +5306,6 @@ void clif_skill_poseffect(struct block_list *src,uint16 skill_id,int val,int x,i clif->send(buf,packet_len(0x117),src,AREA); } - -/*========================================== - * Tells all client's nearby 'unit' sight range that it spawned - *------------------------------------------*/ -//FIXME: this is just an AREA version of clif_getareachar_skillunit() -void clif_skill_setunit(struct skill_unit *su) { - unsigned char buf[128]; - int header = 0x11f, pos = 0; - - nullpo_retv(su); - - if( su->group->state.guildaura ) - return; - -#if PACKETVER >= 20130320 - if(su->group->unit_id > UCHAR_MAX) { - header = 0x99f; - pos = 2; - } -#endif - -#if PACKETVER >= 3 - if(su->group->unit_id==UNT_GRAFFITI) { - // Graffiti [Valaris] - WBUFW(buf, 0)=0x1c9; - WBUFL(buf, 2)=su->bl.id; - WBUFL(buf, 6)=su->group->src_id; - WBUFW(buf,10)=su->bl.x; - WBUFW(buf,12)=su->bl.y; - WBUFB(buf,14)=su->group->unit_id; - WBUFB(buf,15)=1; - WBUFB(buf,16)=1; - safestrncpy((char*)WBUFP(buf,17),su->group->valstr,MESSAGE_SIZE); - clif->send(buf,packet_len(0x1c9),&su->bl,AREA); - return; - } -#endif - WBUFW(buf, 0)=header; - if(pos > 0) - WBUFW(buf, pos)=packet_len(header); - WBUFL(buf, 2 + pos)=su->bl.id; - WBUFL(buf, 6 + pos)=su->group->src_id; - WBUFW(buf,10 + pos)=su->bl.x; - WBUFW(buf,12 + pos)=su->bl.y; - if (su->group->state.song_dance&0x1 && su->val2&UF_ENSEMBLE) - WBUFB(buf,14)=su->val2&UF_SONG?UNT_DISSONANCE:UNT_UGLYDANCE; - else if (skill->get_unit_flag(su->group->skill_id) & UF_RANGEDSINGLEUNIT && !(su->val2 & UF_RANGEDSINGLEUNIT)) - WBUFB(buf, 14) = UNT_DUMMYSKILL; // Only display the unit at center. - else if(pos > 0) { - WBUFL(buf,16)=su->group->unit_id; - WBUFW(buf,20)=su->range; - pos += 5; - }else - WBUFB(buf,14)=su->group->unit_id; - WBUFB(buf,15 + pos)=1; // ignored by client (always gets set to 1) - clif->send(buf,packet_len(header),&su->bl,AREA); -} - - /// Presents a list of available warp destinations (ZC_WARPLIST). /// 011c <skill id>.W { <map name>.16B }*4 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) @@ -5388,10 +5320,10 @@ void clif_skill_warppoint(struct map_session_data* sd, uint16 skill_id, uint16 s memset(WFIFOP(fd,4), 0x00, 4*MAP_NAME_LENGTH_EXT); if (map1 == (unsigned short)-1) strcpy((char*)WFIFOP(fd,4), "Random"); else // normal map name - if (map1 > 0) mapindex_getmapname_ext(mapindex_id2name(map1), (char*)WFIFOP(fd,4)); - if (map2 > 0) mapindex_getmapname_ext(mapindex_id2name(map2), (char*)WFIFOP(fd,20)); - if (map3 > 0) mapindex_getmapname_ext(mapindex_id2name(map3), (char*)WFIFOP(fd,36)); - if (map4 > 0) mapindex_getmapname_ext(mapindex_id2name(map4), (char*)WFIFOP(fd,52)); + if (map1 > 0) mapindex->getmapname_ext(mapindex_id2name(map1), (char*)WFIFOP(fd,4)); + if (map2 > 0) mapindex->getmapname_ext(mapindex_id2name(map2), (char*)WFIFOP(fd,20)); + if (map3 > 0) mapindex->getmapname_ext(mapindex_id2name(map3), (char*)WFIFOP(fd,36)); + if (map4 > 0) mapindex->getmapname_ext(mapindex_id2name(map4), (char*)WFIFOP(fd,52)); WFIFOSET(fd,packet_len(0x11c)); sd->menuskill_id = skill_id; @@ -5592,22 +5524,22 @@ void clif_cooking_list(struct map_session_data *sd, int trigger, uint16 skill_id void clif_status_change_notick(struct block_list *bl,int type,int flag,int tick,int val1, int val2, int val3) { struct packet_sc_notick p; struct map_session_data *sd; - + nullpo_retv(bl); - - if (!(status->type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client - return; - + if (type == SI_BLANK) //It shows nothing on the client... return; - + + if (!(status->type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client + return; + sd = BL_CAST(BL_PC, bl); - + p.PacketType = sc_notickType; p.index = type; p.AID = bl->id; p.state = (unsigned char)flag; - + clif->send(&p,packet_len(p.PacketType), bl, (sd && sd->status.option&OPTION_INVISIBLE) ? SELF : AREA); } @@ -5655,11 +5587,11 @@ void clif_status_change(struct block_list *bl,int type,int flag,int tick,int val void clif_displaymessage(const int fd, const char* mes) { nullpo_retv(mes); - if( fd == -2 ) { + if( map->cpsd_active && fd == 0 ) { ShowInfo("HCP: %s\n",mes); } else if ( fd > 0 ) { - int len; - + size_t len; + if ( ( len = strnlen(mes, 255) ) > 0 ) { // don't send a void message (it's not displaying on the client chat). @help can send void line. WFIFOHEAD(fd, 5 + len); WFIFOW(fd,0) = 0x8e; @@ -5672,22 +5604,22 @@ void clif_displaymessage(const int fd, const char* mes) { void clif_displaymessage2(const int fd, const char* mes) { // invalid pointer? nullpo_retv(mes); - + //Scrapped, as these are shared by disconnected players =X [Skotlex] if (fd == 0) ; else { // Limit message to 255+1 characters (otherwise it causes a buffer overflow in the client) char *message, *line; - + message = aStrdup(mes); line = strtok(message, "\n"); while(line != NULL) { // Limit message to 255+1 characters (otherwise it causes a buffer overflow in the client) - int len = strnlen(line, 255); - + size_t len = strnlen(line, 255); + if (len > 0) { // don't send a void message (it's not displaying on the client chat). @help can send void line. - if( fd == -2 ) { + if( map->cpsd_active && fd == 0 ) { ShowInfo("HCP: %s\n",line); } else { WFIFOHEAD(fd, 5 + len); @@ -5702,10 +5634,41 @@ void clif_displaymessage2(const int fd, const char* mes) { aFree(message); } } +/* oh noo! another version of 0x8e! */ +void clif_displaymessage_sprintf(const int fd, const char* mes, ...) { + va_list ap; + + if( map->cpsd_active && fd == 0 ) { + ShowInfo("HCP: "); + va_start(ap,mes); + _vShowMessage(MSG_NONE,mes,ap); + va_end(ap); + ShowMessage("\n"); + } else if ( fd > 0 ) { + int len = 1; + char *ptr; + WFIFOHEAD(fd, 5 + 255);/* ensure the maximum */ + + /* process */ + va_start(ap,mes); + len += vsnprintf((char *)WFIFOP(fd,4), 255, mes, ap); + va_end(ap); + + /* adjusting */ + ptr = (char *)WFIFOP(fd,4); + ptr[len - 1] = '\0'; + + /* */ + WFIFOW(fd,0) = 0x8e; + WFIFOW(fd,2) = 5 + len; // 4 + len + NULL teminate + + WFIFOSET(fd, 5 + len); + } +} /// Send broadcast message in yellow or blue without font formatting (ZC_BROADCAST). /// 009a <packet len>.W <message>.?B -void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target) +void clif_broadcast(struct block_list* bl, const char* mes, size_t len, int type, enum send_target target) { int lp = (type&BC_COLOR_MASK) ? 4 : 0; unsigned char *buf = (unsigned char*)aMalloc((4 + lp + len)*sizeof(unsigned char)); @@ -5729,7 +5692,7 @@ void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, e *------------------------------------------*/ void clif_GlobalMessage(struct block_list* bl, const char* message) { char buf[256]; - int len; + size_t len; nullpo_retv(bl); if(!message) @@ -5752,7 +5715,7 @@ void clif_GlobalMessage(struct block_list* bl, const char* message) { /// Send broadcast message with font formatting (ZC_BROADCAST2). /// 01c3 <packet len>.W <fontColor>.L <fontType>.W <fontSize>.W <fontAlign>.W <fontY>.W <message>.?B -void clif_broadcast2(struct block_list* bl, const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target) +void clif_broadcast2(struct block_list* bl, const char* mes, size_t len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target) { unsigned char *buf = (unsigned char*)aMalloc((16 + len)*sizeof(unsigned char)); @@ -5796,7 +5759,7 @@ void clif_resurrection(struct block_list *bl,int type) unsigned char buf[16]; nullpo_retv(bl); - + WBUFW(buf,0)=0x148; WBUFL(buf,2)=bl->id; WBUFW(buf,6)=0; @@ -5819,7 +5782,7 @@ void clif_map_property(struct map_session_data* sd, enum map_property property) int fd; nullpo_retv(sd); - + fd=sd->fd; WFIFOHEAD(fd,packet_len(0x199)); WFIFOW(fd,0)=0x199; @@ -5881,7 +5844,7 @@ void clif_map_property_mapall(int mapid, enum map_property property) { struct block_list bl; unsigned char buf[16]; - + bl.id = 0; bl.type = BL_NUL; bl.m = mapid; @@ -5928,7 +5891,7 @@ void clif_upgrademessage(int fd, int result, int item_id) /// Whisper is transmitted to the destination player (ZC_WHISPER). /// 0097 <packet len>.W <nick>.24B <message>.?B /// 0097 <packet len>.W <nick>.24B <isAdmin>.L <message>.?B (PACKETVER >= 20091104) -void clif_wis_message(int fd, const char* nick, const char* mes, int mes_len) { +void clif_wis_message(int fd, const char* nick, const char* mes, size_t mes_len) { #if PACKETVER < 20091104 WFIFOHEAD(fd, mes_len + NAME_LENGTH + 4); WFIFOW(fd,0) = 0x97; @@ -5943,7 +5906,7 @@ void clif_wis_message(int fd, const char* nick, const char* mes, int mes_len) { WFIFOW(fd,0) = 0x97; WFIFOW(fd,2) = mes_len + NAME_LENGTH + 8; safestrncpy((char*)WFIFOP(fd,4), nick, NAME_LENGTH); - WFIFOL(fd,28) = (ssd && pc->get_group_level(ssd) == 99) ? 1 : 0; // isAdmin; if nonzero, also displays text above char + WFIFOL(fd,28) = (ssd && pc_get_group_level(ssd) == 99) ? 1 : 0; // isAdmin; if nonzero, also displays text above char safestrncpy((char*)WFIFOP(fd,32), mes, mes_len); WFIFOSET(fd,WFIFOW(fd,2)); #endif @@ -5959,10 +5922,15 @@ void clif_wis_message(int fd, const char* nick, const char* mes, int mes_len) { /// 3 = everyone ignored by target void clif_wis_end(int fd, int flag) { - WFIFOHEAD(fd,packet_len(0x98)); - WFIFOW(fd,0) = 0x98; +#if PACKETVER >= 20131223 + const int cmd = 0x9df; +#else + const int cmd = 0x98; +#endif + WFIFOHEAD(fd,packet_len(cmd)); + WFIFOW(fd,0) = cmd; WFIFOW(fd,2) = flag; - WFIFOSET(fd,packet_len(0x98)); + WFIFOSET(fd,packet_len(cmd)); } @@ -6019,9 +5987,15 @@ void clif_use_card(struct map_session_data *sd,int idx) if( j == sd->inventory_data[i]->slot ) // No room continue; + if( sd->status.inventory[i].equip > 0 ) // Do not check items that are already equipped + continue; + WFIFOW(fd,4+c*2)=i+2; c++; } + + if( !c ) return; // no item is available for card insertion + WFIFOW(fd,2)=4+c*2; WFIFOSET(fd,WFIFOW(fd,2)); } @@ -6181,7 +6155,7 @@ void clif_item_refine_list(struct map_session_data *sd) skill_lv = pc->checkskill(sd,WS_WEAPONREFINE); fd=sd->fd; - + WFIFOHEAD(fd, MAX_INVENTORY * 13 + 4); WFIFOW(fd,0)=0x221; for(i=c=0;i<MAX_INVENTORY;i++){ @@ -6529,7 +6503,7 @@ void clif_party_member_info(struct party_data *p, struct map_session_data *sd) WBUFB(buf,14) = (p->party.member[i].online)?0:1; memcpy(WBUFP(buf,15), p->party.name, NAME_LENGTH); memcpy(WBUFP(buf,39), sd->status.name, NAME_LENGTH); - mapindex_getmapname_ext(map->list[sd->bl.m].custom_name ? map->list[map->list[sd->bl.m].instance_src_map].name : map->list[sd->bl.m].name, (char*)WBUFP(buf,63)); + mapindex->getmapname_ext(map->list[sd->bl.m].custom_name ? map->list[map->list[sd->bl.m].instance_src_map].name : map->list[sd->bl.m].name, (char*)WBUFP(buf,63)); WBUFB(buf,79) = (p->party.item&1)?1:0; WBUFB(buf,80) = (p->party.item&2)?1:0; clif->send(buf,packet_len(0x1e9),&sd->bl,PARTY); @@ -6563,7 +6537,7 @@ void clif_party_info(struct party_data* p, struct map_session_data *sd) WBUFL(buf,28+c*46) = m->account_id; memcpy(WBUFP(buf,28+c*46+4), m->name, NAME_LENGTH); - mapindex_getmapname_ext(mapindex_id2name(m->map), (char*)WBUFP(buf,28+c*46+28)); + mapindex->getmapname_ext(mapindex_id2name(m->map), (char*)WBUFP(buf,28+c*46+28)); WBUFB(buf,28+c*46+44) = (m->leader) ? 0 : 1; WBUFB(buf,28+c*46+45) = (m->online) ? 0 : 1; c++; @@ -7889,29 +7863,6 @@ void clif_guild_message(struct guild *g,int account_id,const char *mes,int len) clif->send(buf, WBUFW(buf,2), &sd->bl, GUILD_NOBG); } - -/*========================================== - * Server tells client 'sd' that his guild skill 'skill_id' gone to level 'lv' - *------------------------------------------*/ -int clif_guild_skillup(struct map_session_data *sd,uint16 skill_id,int lv) -{// TODO: Merge with clif_skillup (same packet). - int fd; - - nullpo_ret(sd); - - fd=sd->fd; - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x10e; - WFIFOW(fd,2) = skill_id; - WFIFOW(fd,4) = lv; - WFIFOW(fd,6) = skill->get_sp(skill_id,lv); - WFIFOW(fd,8) = skill->get_range(skill_id,lv); - WFIFOB(fd,10) = 1; - WFIFOSET(fd,11); - return 0; -} - - /// Request for guild alliance (ZC_REQ_ALLY_GUILD). /// 0171 <inviter account id>.L <guild name>.24B void clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name) @@ -8148,18 +8099,10 @@ void clif_marriage_proposal(int fd, struct map_session_data *sd, struct map_sess } */ - -/*========================================== - * - *------------------------------------------*/ -void clif_disp_onlyself(struct map_session_data *sd, const char *mes, int len) { - clif->disp_message(&sd->bl, mes, len, SELF); -} - /*========================================== * Displays a message using the guild-chat colors to the specified targets. [Skotlex] *------------------------------------------*/ -void clif_disp_message(struct block_list* src, const char* mes, int len, enum send_target target) +void clif_disp_message(struct block_list* src, const char* mes, size_t len, enum send_target target) { unsigned char buf[256]; @@ -8416,7 +8359,7 @@ void clif_specialeffect_value(struct block_list* bl, int effect_id, int num, sen // Modification of clif_messagecolor to send colored messages to players to chat log only (doesn't display overhead) /// 02c1 <packet len>.W <id>.L <color>.L <message>.?B int clif_colormes(int fd, enum clif_colors color, const char* msg) { - unsigned short msg_len = strlen(msg) + 1; + size_t msg_len = strlen(msg) + 1; WFIFOHEAD(fd,msg_len + 12); WFIFOW(fd,0) = 0x2C1; @@ -8431,8 +8374,8 @@ int clif_colormes(int fd, enum clif_colors color, const char* msg) { /// Monster/NPC color chat [SnakeDrak] (ZC_NPC_CHAT). /// 02c1 <packet len>.W <id>.L <color>.L <message>.?B -void clif_messagecolor(struct block_list* bl, unsigned long color, const char* msg) { - unsigned short msg_len = strlen(msg) + 1; +void clif_messagecolor(struct block_list* bl, unsigned int color, const char* msg) { + size_t msg_len = strlen(msg) + 1; uint8 buf[256]; color = (color & 0x0000FF) << 16 | (color & 0x00FF00) | (color & 0xFF0000) >> 16; // RGB to BGR @@ -8525,13 +8468,13 @@ void clif_refresh(struct map_session_data *sd) buyingstore->close(sd); mail->clear(sd); - + if( disguised(&sd->bl) ) {/* refresh-da */ short disguise = sd->disguise; pc->disguise(sd, -1); pc->disguise(sd, disguise); } - + } @@ -8756,7 +8699,7 @@ void clif_slide(struct block_list *bl, int x, int y) void clif_disp_overhead(struct block_list *bl, const char* mes) { unsigned char buf[256]; //This should be more than sufficient, the theorical max is CHAT_SIZE + 8 (pads and extra inserted crap) - int len_mes = strlen(mes)+1; //Account for \0 + size_t len_mes = strlen(mes)+1; //Account for \0 if (len_mes > sizeof(buf)-8) { ShowError("clif_disp_overhead: Message too long (length %d)\n", len_mes); @@ -8776,7 +8719,7 @@ void clif_disp_overhead(struct block_list *bl, const char* mes) safestrncpy((char*)WBUFP(buf,4), mes, len_mes); clif->send(buf, WBUFW(buf,2), bl, SELF); } - + } /*========================== @@ -8870,7 +8813,7 @@ void clif_feel_info(struct map_session_data* sd, unsigned char feel_level, unsig { char mapname[MAP_NAME_LENGTH_EXT]; - mapindex_getmapname_ext(mapindex_id2name(sd->feel_map[feel_level].index), mapname); + mapindex->getmapname_ext(mapindex_id2name(sd->feel_map[feel_level].index), mapname); clif->starskill(sd, mapname, 0, feel_level, type ? 1 : 0); } @@ -8950,69 +8893,41 @@ void clif_equpcheckbox(struct map_session_data* sd) /// 02d7 <packet len>.W <name>.24B <class>.W <hairstyle>.W <bottom-viewid>.W <mid-viewid>.W <up-viewid>.W <haircolor>.W <cloth-dye>.W <gender>.B {equip item}.28B* (ZC_EQUIPWIN_MICROSCOPE, PACKETVER >= 20100629) /// 0859 <packet len>.W <name>.24B <class>.W <hairstyle>.W <bottom-viewid>.W <mid-viewid>.W <up-viewid>.W <haircolor>.W <cloth-dye>.W <gender>.B {equip item}.28B* (ZC_EQUIPWIN_MICROSCOPE2, PACKETVER >= 20101124) /// 0859 <packet len>.W <name>.24B <class>.W <hairstyle>.W <bottom-viewid>.W <mid-viewid>.W <up-viewid>.W <robe>.W <haircolor>.W <cloth-dye>.W <gender>.B {equip item}.28B* (ZC_EQUIPWIN_MICROSCOPE2, PACKETVER >= 20110111) -void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* tsd) -{ - uint8* buf; - int i, n, fd, offset = 0; -#if PACKETVER < 20100629 - const int s = 26; -#else - const int s = 28; -#endif +void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* tsd) { + int i, k, equip = 0; + nullpo_retv(sd); nullpo_retv(tsd); - fd = sd->fd; - WFIFOHEAD(fd, MAX_INVENTORY * s + 43); - buf = WFIFOP(fd,0); + for( i = 0; i < EQI_MAX; i++ ) { + if( (k = tsd->equip_index[i]) >= 0 ) { -#if PACKETVER < 20101124 - WBUFW(buf, 0) = 0x2d7; -#else - WBUFW(buf, 0) = 0x859; -#endif - safestrncpy((char*)WBUFP(buf, 4), tsd->status.name, NAME_LENGTH); - WBUFW(buf,28) = tsd->status.class_; - WBUFW(buf,30) = tsd->vd.hair_style; - WBUFW(buf,32) = tsd->vd.head_bottom; - WBUFW(buf,34) = tsd->vd.head_mid; - WBUFW(buf,36) = tsd->vd.head_top; -#if PACKETVER >= 20110111 - WBUFW(buf,38) = tsd->vd.robe; - offset+= 2; - buf = WBUFP(buf,2); -#endif - WBUFW(buf,38) = tsd->vd.hair_color; - WBUFW(buf,40) = tsd->vd.cloth_color; - WBUFB(buf,42) = tsd->vd.sex; + if (tsd->status.inventory[k].nameid <= 0 || tsd->inventory_data[k] == NULL) // Item doesn't exist + continue; - for(i=0,n=0; i < MAX_INVENTORY; i++) - { - if (tsd->status.inventory[i].nameid <= 0 || tsd->inventory_data[i] == NULL) // Item doesn't exist - continue; - if (!itemdb->isequip2(tsd->inventory_data[i])) // Is not equippable - continue; + clif_item_equip(k+2,&viewequip_list.list[equip++],&tsd->status.inventory[k],tsd->inventory_data[k],pc->equippoint(tsd,k)); - // Inventory position - WBUFW(buf, n*s+43) = i + 2; - // Add refine, identify flag, element, etc. - clif->item_sub(WBUFP(buf,0), n*s+45, &tsd->status.inventory[i], tsd->inventory_data[i], pc->equippoint(tsd, i)); - // Add cards - clif->addcards(WBUFP(buf, n*s+55), &tsd->status.inventory[i]); - // Expiration date stuff, if all of those are set to 0 then the client doesn't show anything related (6 bytes) - WBUFL(buf, n*s+63) = tsd->status.inventory[i].expire_time; - WBUFW(buf, n*s+67) = 0; -#if PACKETVER >= 20100629 - if (tsd->inventory_data[i]->equip&EQP_VISIBLE) - WBUFW(buf, n*s+69) = tsd->inventory_data[i]->look; - else - WBUFW(buf, n*s+69) = 0; -#endif - n++; + } } - WFIFOW(fd, 2) = 43+offset+n*s; // Set length - WFIFOSET(fd, WFIFOW(fd, 2)); + viewequip_list.PacketType = viewequipackType; + viewequip_list.PacketLength = ( sizeof( viewequip_list ) - sizeof( viewequip_list.list ) ) + ( sizeof(struct EQUIPITEM_INFO) * equip ); + + safestrncpy(viewequip_list.characterName, tsd->status.name, NAME_LENGTH); + + viewequip_list.job = tsd->status.class_; + viewequip_list.head = tsd->vd.hair_style; + viewequip_list.accessory = tsd->vd.head_bottom; + viewequip_list.accessory2 = tsd->vd.head_mid; + viewequip_list.accessory3 = tsd->vd.head_top; +#if PACKETVER >= 20110111 + viewequip_list.robe = tsd->vd.robe; +#endif + viewequip_list.headpalette = tsd->vd.hair_color; + viewequip_list.bodypalette = tsd->vd.cloth_color; + viewequip_list.sex = tsd->vd.sex; + + clif->send(&viewequip_list, viewequip_list.PacketLength, &sd->bl, SELF); } @@ -9061,21 +8976,14 @@ void clif_msg_skill(struct map_session_data* sd, uint16 skill_id, int msg_id) WFIFOSET(fd, packet_len(0x7e6)); } - -/// View player equip request denied -void clif_viewequip_fail(struct map_session_data* sd) -{ - clif_msg(sd, 0x54d); -} - - /// Validates one global/guild/party/whisper message packet and tries to recognize its components. /// Returns true if the packet was parsed successfully. /// Formats: 0 - <packet id>.w <packet len>.w (<name> : <message>).?B 00 /// 1 - <packet id>.w <packet len>.w <name>.24B <message>.?B 00 -bool clif_process_message(struct map_session_data* sd, int format, char** name_, int* namelen_, char** message_, int* messagelen_) { +bool clif_process_message(struct map_session_data *sd, int format, char **name_, size_t *namelen_, char **message_, size_t *messagelen_) { char *text, *name, *message; - unsigned int packetlen, textlen, namelen, messagelen; + unsigned int packetlen, textlen; + size_t namelen, messagelen; int fd = sd->fd; *name_ = NULL; @@ -9167,14 +9075,14 @@ void clif_hercules_chsys_msg(struct hChSysCh *channel, struct map_session_data * DBIterator *iter = db_iterator(channel->users); struct map_session_data *user; unsigned short msg_len = strlen(msg) + 1; - + WFIFOHEAD(sd->fd,msg_len + 12); WFIFOW(sd->fd,0) = 0x2C1; WFIFOW(sd->fd,2) = msg_len + 12; WFIFOL(sd->fd,4) = 0; WFIFOL(sd->fd,8) = hChSys.colors[channel->color]; safestrncpy((char*)WFIFOP(sd->fd,12), msg, msg_len); - + for( user = dbi_first(iter); dbi_exists(iter); user = dbi_next(iter) ) { if( user->fd == sd->fd ) continue; @@ -9182,9 +9090,9 @@ void clif_hercules_chsys_msg(struct hChSysCh *channel, struct map_session_data * memcpy(WFIFOP(user->fd,0), WFIFOP(sd->fd,0), msg_len + 12); WFIFOSET(user->fd, msg_len + 12); } - + WFIFOSET(sd->fd, msg_len + 12); - + dbi_destroy(iter); } @@ -9193,19 +9101,19 @@ void clif_hercules_chsys_msg2(struct hChSysCh *channel, char *msg) { struct map_session_data *user; unsigned char buf[210]; unsigned short msg_len = strlen(msg) + 1; - + WBUFW(buf,0) = 0x2C1; WBUFW(buf,2) = msg_len + 12; WBUFL(buf,4) = 0; WBUFL(buf,8) = hChSys.colors[channel->color]; safestrncpy((char*)WBUFP(buf,12), msg, msg_len); - + for( user = dbi_first(iter); dbi_exists(iter); user = dbi_next(iter) ) { WFIFOHEAD(user->fd,msg_len + 12); memcpy(WFIFOP(user->fd,0), WBUFP(buf,0), msg_len + 12); WFIFOSET(user->fd, msg_len + 12); } - + dbi_destroy(iter); } @@ -9287,24 +9195,30 @@ void clif_parse_WantToConnection(int fd, struct map_session_data* sd) { WFIFOSET(fd,packet_len(0x283)); #endif - chrif->authreq(sd); + chrif->authreq(sd,false); } void clif_hercules_chsys_mjoin(struct map_session_data *sd) { + if( sd->state.autotrade || sd->state.standalone ) + return; if( !map->list[sd->bl.m].channel ) { + + if (map->list[sd->bl.m].flag.chsysnolocalaj || (map->list[sd->bl.m].instance_id >= 0 && instance->list[map->list[sd->bl.m].instance_id].owner_type != IOT_NONE) ) + return; + CREATE(map->list[sd->bl.m].channel, struct hChSysCh , 1); safestrncpy(map->list[sd->bl.m].channel->name, hChSys.local_name, HCHSYS_NAME_LENGTH); map->list[sd->bl.m].channel->type = hChSys_MAP; map->list[sd->bl.m].channel->m = sd->bl.m; - + clif->chsys_create(map->list[sd->bl.m].channel,NULL,NULL,hChSys.local_color); } - + if( map->list[sd->bl.m].channel->banned && idb_exists(map->list[sd->bl.m].channel->banned, sd->status.account_id) ) { return; } - + clif->chsys_join(map->list[sd->bl.m].channel,sd); - + if( !( map->list[sd->bl.m].channel->opt & hChSys_OPT_ANNOUNCE_JOIN ) ) { char mout[60]; sprintf(mout, msg_txt(1435),hChSys.local_name,map->list[sd->bl.m].name); // You're now in the '#%s' channel for '%s' @@ -9315,6 +9229,10 @@ void clif_hercules_chsys_mjoin(struct map_session_data *sd) { /// Notification from the client, that it has finished map loading and is about to display player's character (CZ_NOTIFY_ACTORINIT). /// 007d void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { +#if PACKETVER >= 20090218 + int i; +#endif + if(sd->bl.prev != NULL) return; @@ -9368,13 +9286,21 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { if( map->list[sd->bl.m].users++ == 0 && battle_config.dynamic_mobs ) map->spawnmobs(sd->bl.m); - if( !(sd->sc.option&OPTION_INVISIBLE) ) { // increment the number of pvp players on the map - map->list[sd->bl.m].users_pvp++; - } + if( map->list[sd->bl.m].instance_id >= 0 ) { instance->list[map->list[sd->bl.m].instance_id].users++; instance->check_idle(map->list[sd->bl.m].instance_id); } + + if( pc_has_permission(sd,PC_PERM_VIEW_HPMETER) ) { + map->list[sd->bl.m].hpmeter_visible++; + sd->state.hpmeter_visible = 1; + } + + if( !(sd->sc.option&OPTION_INVISIBLE) ) { // increment the number of pvp players on the map + map->list[sd->bl.m].users_pvp++; + } + sd->state.debug_remove_map = 0; // temporary state to track double remove_map's [FlavioJS] // reset the callshop flag if the player changes map @@ -9391,7 +9317,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { } if( sd->bg_id ) clif->bg_hp(sd); // BattleGround System - + if(map->list[sd->bl.m].flag.pvp && !(sd->sc.option&OPTION_INVISIBLE)) { if(!battle_config.pk_mode) { // remove pvp stuff for pk_mode [Valaris] if (!map->list[sd->bl.m].flag.pvp_nocalcrank) @@ -9428,7 +9354,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { clif->spawn(&sd->pd->bl); clif->send_petdata(sd,sd->pd,0,0); clif->send_petstatus(sd); -// skill->unit_move(&sd->pd->bl,gettick(),1); +// skill->unit_move(&sd->pd->bl,timer->gettick(),1); } } @@ -9484,14 +9410,14 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { clif->status_change(&sd->bl, SI_WUGRIDER, 1, 0, 0, 0, 0); if(sd->status.manner < 0) - sc_start(&sd->bl,SC_NOCHAT,100,0,0); + sc_start(NULL,&sd->bl,SC_NOCHAT,100,0,0); //Auron reported that This skill only triggers when you logon on the map o.O [Skotlex] if ((lv = pc->checkskill(sd,SG_KNOWLEDGE)) > 0) { if(sd->bl.m == sd->feel_map[0].m || sd->bl.m == sd->feel_map[1].m || sd->bl.m == sd->feel_map[2].m) - sc_start(&sd->bl, SC_KNOWLEDGE, 100, lv, skill->get_time(SG_KNOWLEDGE, lv)); + sc_start(NULL,&sd->bl, SC_KNOWLEDGE, 100, lv, skill->get_time(SG_KNOWLEDGE, lv)); } if(sd->pd && sd->pd->pet.intimate > 900) @@ -9526,7 +9452,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { if(sd->npc_id) npc->event_dequeue(sd); - + if( sd->guild && ( battle_config.guild_notice_changemap == 2 || ( battle_config.guild_notice_changemap == 1 && sd->state.changemap ) ) ) clif->guild_notice(sd,sd->guild); } @@ -9565,10 +9491,10 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { } map->iwall_get(sd); // Updates Walls Info on this Map to Client - status_calc_pc(sd, false);/* some conditions are map-dependent so we must recalculate */ + status_calc_pc(sd, SCO_NONE);/* some conditions are map-dependent so we must recalculate */ sd->state.changemap = false; - - if( hChSys.local && hChSys.local_autojoin && !map->list[sd->bl.m].flag.chsysnolocalaj ) { + + if( hChSys.local && hChSys.local_autojoin ) { clif->chsys_mjoin(sd); } } @@ -9576,7 +9502,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { mail->clear(sd); clif->maptypeproperty2(&sd->bl,SELF); - + /* Guild Aura Init */ if( sd->state.gmaster_flag ) { guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->guild,GD_LEADERSHIP)); @@ -9599,6 +9525,11 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { if (sd->sc.opt2) //Client loses these on warp. clif->changeoption(&sd->bl); + if( sd->sc.data[SC_MONSTER_TRANSFORM] && battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m) ){ + status_change_end(&sd->bl, SC_MONSTER_TRANSFORM, INVALID_TIMER); + clif->message(sd->fd, msg_txt(1488)); // Transforming into monster is not allowed in Guild Wars. + } + clif->weather_check(sd); // For automatic triggering of NPCs after map loading (so you don't need to walk 1 step first) @@ -9616,24 +9547,38 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { clif->clearunit_area(&sd->bl, CLR_DEAD); else { skill->usave_trigger(sd); - clif->changed_dir(&sd->bl, SELF); + sd->ud.dir = 0;/* enforce north-facing (not visually, virtually) */ } -// Trigger skill effects if you appear standing on them + // Trigger skill effects if you appear standing on them if(!battle_config.pc_invincible_time) skill->unit_move(&sd->bl,timer->gettick(),1); - + + // NPC Quest / Event Icon Check [Kisuka] +#if PACKETVER >= 20090218 + 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->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); + } + } + } +#endif } /// Server's tick (ZC_NOTIFY_TIME). /// 007f <time>.L -void clif_notify_time(struct map_session_data* sd, unsigned long time) { +void clif_notify_time(struct map_session_data* sd, int64 time) { int fd = sd->fd; WFIFOHEAD(fd,packet_len(0x7f)); WFIFOW(fd,0) = 0x7f; - WFIFOL(fd,2) = time; + WFIFOL(fd,2) = (uint32)time; WFIFOSET(fd,packet_len(0x7f)); } @@ -9696,7 +9641,8 @@ void clif_parse_Hotkey(int fd, struct map_session_data *sd) { /// Displays cast-like progress bar (ZC_PROGRESS). /// 02f0 <color>.L <time>.L -void clif_progressbar(struct map_session_data * sd, unsigned long color, unsigned int second) +/* TODO ZC_PROGRESS_ACTOR <account_id>.L */ +void clif_progressbar(struct map_session_data * sd, unsigned int color, unsigned int second) { int fd = sd->fd; @@ -9729,7 +9675,7 @@ void clif_parse_progressbar(int fd, struct map_session_data * sd) if( timer->gettick() < sd->progressbar.timeout && sd->st ) sd->st->state = END; - sd->state.workinprogress = sd->progressbar.npc_id = sd->progressbar.timeout = 0; + sd->progressbar.timeout = sd->state.workinprogress = sd->progressbar.npc_id = 0; npc->scriptcont(sd, npc_id, false); } @@ -9762,7 +9708,8 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) RFIFOPOS(fd, packet_db[RFIFOW(fd,0)].pos[0], &x, &y, NULL); //Set last idle time... [Skotlex] - sd->idletime = last_tick; + if( battle_config.idletime_criteria & BCIDLE_WALK ) + sd->idletime = sockt->last_tick; unit->walktoxy(&sd->bl, x, y, 4); } @@ -9792,7 +9739,7 @@ void clif_disconnect_ack(struct map_session_data* sd, short result) void clif_parse_QuitGame(int fd, struct map_session_data *sd) { /* Rovert's prevent logout option fixed [Valaris] */ - if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && + if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] && (!battle_config.prevent_logout || DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) { set_eof(fd); @@ -9828,7 +9775,7 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) { sc = status->get_sc(bl); if (sc && sc->option&OPTION_INVISIBLE && !disguised(bl) && bl->type != BL_NPC && //Skip hidden NPCs which can be seen using Maya Purple - pc->get_group_level(sd) < battle_config.hack_info_GM_level + pc_get_group_level(sd) < battle_config.hack_info_GM_level ) { char gm_msg[256]; sprintf(gm_msg, "Hack on NameRequest: character '%s' (account: %d) requested the name of an invisible target (id: %d).\n", sd->status.name, sd->status.account_id, id); @@ -9841,7 +9788,7 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) { clif->charnameack(fd, bl); } -int clif_undisguise_timer(int tid, unsigned int tick, int id, intptr_t data) { +int clif_undisguise_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data * sd; if( (sd = map->id2sd(id)) ) { sd->fontcolor_tid = INVALID_TIMER; @@ -9857,10 +9804,10 @@ int clif_undisguise_timer(int tid, unsigned int tick, int id, intptr_t data) { void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) { const char* text = (char*)RFIFOP(fd,4); - int textlen = RFIFOW(fd,2) - 4; + size_t textlen = RFIFOW(fd,2) - 4; char *name, *message, *fakename = NULL; - int namelen, messagelen; + size_t namelen, messagelen; bool is_fake; @@ -9868,10 +9815,10 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if( atcommand->parse(fd, sd, message, 1) ) + if( atcommand->exec(fd, sd, message, true) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) { //[Skotlex] @@ -9903,7 +9850,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) sd->state.snovice_call_flag = 3; break; case 3: - sc_start(&sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex] + sc_start(NULL,&sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex] clif->skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1); // prayer always shows successful Lv5 cast and disregards noskill restrictions sd->state.snovice_call_flag = 0; break; @@ -9911,7 +9858,10 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) } } } - + + if( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + if( sd->gcbind ) { clif->chsys_send(sd->gcbind,sd,message); return; @@ -9932,9 +9882,9 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) timer->settick(sd->fontcolor_tid, td->tick+5000); } } - + mylen += snprintf(mout, 200, "%s : %s",sd->fakename[0]?sd->fakename:sd->status.name,message); - + WFIFOHEAD(fd,mylen + 12); WFIFOW(fd,0) = 0x2C1; WFIFOW(fd,2) = mylen + 12; @@ -9946,7 +9896,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) WFIFOSET(fd, mylen + 12); return; } - + /** * Fake Name Design by FatalEror (bug report #9) **/ @@ -9977,6 +9927,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) WFIFOW(fd,0) = 0x8e; } WFIFOSET(fd, WFIFOW(fd,2)); + #ifdef PCRE_SUPPORT // trigger listening npcs map->foreachinrange(npc_chat->sub, &sd->bl, AREA_SIZE, BL_NPC, text, textlen, &sd->bl); @@ -9998,7 +9949,7 @@ void clif_parse_MapMove(int fd, struct map_session_data *sd) map_name = (char*)RFIFOP(fd,2); map_name[MAP_NAME_LENGTH_EXT-1]='\0'; sprintf(command, "%cmapmove %s %d %d", atcommand->at_symbol, map_name, RFIFOW(fd,18), RFIFOW(fd,20)); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -10073,6 +10024,9 @@ void clif_parse_Emotion(int fd, struct map_session_data *sd) } sd->emotionlasttime = time(NULL); + if( battle_config.idletime_criteria & BCIDLE_EMOTION ) + sd->idletime = sockt->last_tick; + if(battle_config.client_reshuffle_dice && emoticon>=E_DICE1 && emoticon<=E_DICE6) {// re-roll dice emoticon = rnd()%6+E_DICE1; } @@ -10103,8 +10057,7 @@ void clif_parse_HowManyConnections(int fd, struct map_session_data *sd) { } -void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, unsigned int tick) -{ +void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, int64 tick) { if (pc_isdead(sd)) { clif->clearunit_area(&sd->bl, CLR_DEAD); return; @@ -10114,6 +10067,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, (sd->sc.data[SC_TRICKDEAD] || sd->sc.data[SC_AUTOCOUNTER] || sd->sc.data[SC_BLADESTOP] || + sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC__MANHOLE] || sd->sc.data[SC_CURSEDCIRCLE_ATKER] || sd->sc.data[SC_CURSEDCIRCLE_TARGET] )) @@ -10132,10 +10086,11 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, if( pc_cant_act(sd) || sd->sc.option&OPTION_HIDE ) return; - if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK) ) + if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST) ) return; - if( sd->sc.data[SC_BASILICA] || sd->sc.data[SC__SHADOWFORM] ) + if( sd->sc.data[SC_BASILICA] || sd->sc.data[SC__SHADOWFORM] || + (sd->sc.data[SC_SIREN] && sd->sc.data[SC_SIREN]->val2 == target_id) ) return; if (!battle_config.sdelay_attack_enable && pc->checkskill(sd, SA_FREECAST) <= 0) { @@ -10146,7 +10101,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, } pc->delinvincibletimer(sd); - sd->idletime = last_tick; + if( battle_config.idletime_criteria & BCIDLE_ATTACK ) + sd->idletime = sockt->last_tick; unit->attack(&sd->bl, target_id, action_type != 0); break; case 0x02: // sitdown @@ -10170,6 +10126,9 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, )) //No sitting during these states either. break; + if( battle_config.idletime_criteria & BCIDLE_SIT ) + sd->idletime = sockt->last_tick; + pc_setsit(sd); skill->sit(sd,1); clif->sitting(&sd->bl); @@ -10180,6 +10139,10 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, clif->standing(&sd->bl); return; } + + if( battle_config.idletime_criteria & BCIDLE_SIT ) + sd->idletime = sockt->last_tick; + pc->setstand(sd); skill->sit(sd,0); clif->standing(&sd->bl); @@ -10189,13 +10152,13 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, void clif_hercules_chsys_left(struct hChSysCh *channel, struct map_session_data *sd) { unsigned char i; - + if ( !idb_remove(channel->users,sd->status.char_id) ) return; - + if( channel == sd->gcbind ) sd->gcbind = NULL; - + if( !db_size(channel->users) && channel->type == hChSys_PRIVATE ) { clif->chsys_delete(channel); } else if( !hChSys.closing && (channel->opt & hChSys_OPT_ANNOUNCE_JOIN) ) { @@ -10203,14 +10166,14 @@ void clif_hercules_chsys_left(struct hChSysCh *channel, struct map_session_data sprintf(message, "#%s '%s' left",channel->name,sd->status.name); clif->chsys_msg(channel,sd,message); } - + for( i = 0; i < sd->channel_count; i++ ) { if( sd->channels[i] == channel ) { sd->channels[i] = NULL; break; } } - + if( i < sd->channel_count ) { unsigned char cursor = 0; for( i = 0; i < sd->channel_count; i++ ) { @@ -10232,16 +10195,16 @@ void clif_hercules_chsys_left(struct hChSysCh *channel, struct map_session_data void clif_hercules_chsys_quitg(struct map_session_data *sd) { unsigned char i; struct hChSysCh *channel = NULL; - + for( i = 0; i < sd->channel_count; i++ ) { if( (channel = sd->channels[i] ) != NULL && channel->type == hChSys_ALLY ) { - + if ( !idb_remove(channel->users,sd->status.char_id) ) continue; - + if( channel == sd->gcbind ) sd->gcbind = NULL; - + if( !db_size(channel->users) && channel->type == hChSys_PRIVATE ) { clif->chsys_delete(channel); } else if( !hChSys.closing && (channel->opt & hChSys_OPT_ANNOUNCE_JOIN) ) { @@ -10252,7 +10215,7 @@ void clif_hercules_chsys_quitg(struct map_session_data *sd) { sd->channels[i] = NULL; } } - + if( i < sd->channel_count ) { unsigned char cursor = 0; for( i = 0; i < sd->channel_count; i++ ) { @@ -10268,21 +10231,21 @@ void clif_hercules_chsys_quitg(struct map_session_data *sd) { sd->channels = NULL; } } - + } void clif_hercules_chsys_quit(struct map_session_data *sd) { unsigned char i; struct hChSysCh *channel = NULL; - + for( i = 0; i < sd->channel_count; i++ ) { if( (channel = sd->channels[i] ) != NULL ) { idb_remove(channel->users,sd->status.char_id); - + if( channel == sd->gcbind ) sd->gcbind = NULL; - + if( !db_size(channel->users) && channel->type == hChSys_PRIVATE ) { clif->chsys_delete(channel); } else if( !hChSys.closing && (channel->opt & hChSys_OPT_ANNOUNCE_JOIN) ) { @@ -10290,7 +10253,7 @@ void clif_hercules_chsys_quit(struct map_session_data *sd) { sprintf(message, "#%s '%s' left",channel->name,sd->status.name); clif->chsys_msg(channel,sd,message); } - + } } @@ -10332,7 +10295,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd) { break; case 0x01: /* Rovert's Prevent logout option - Fixed [Valaris] */ - if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && + if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] && (!battle_config.prevent_logout || DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) { //Send to char-server for character selection. chrif->charselectreq(sd, session[fd]->client_addr); @@ -10352,16 +10315,16 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) int i; char *target, *message; - int namelen, messagelen; + size_t namelen, messagelen; // validate packet and retrieve name and message if( !clif->process_message(sd, 1, &target, &namelen, &message, &messagelen) ) return; - if ( atcommand->parse(fd, sd, message, 1) ) + if ( atcommand->exec(fd, sd, message, true) ) return; - if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT)) + if (sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT)) return; if (battle_config.min_chat_delay) { //[Skotlex] @@ -10371,6 +10334,9 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } + if( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + // Chat logging type 'W' / Whisper logs->chat(LOG_CHAT_WHISPER, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, target, message); @@ -10417,7 +10383,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) char* chname = target; chname++; - + if( hChSys.local && strcmpi(chname, hChSys.local_name) == 0 ) { if( !map->list[sd->bl.m].channel ) { clif->chsys_mjoin(sd); @@ -10426,10 +10392,10 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) } else if( hChSys.ally && sd->status.guild_id && strcmpi(chname, hChSys.ally_name) == 0 ) { struct guild *g = sd->guild; if( !g ) return; - channel = (struct hChSysCh *)g->channel; + channel = g->channel; } if( channel || (channel = strdb_get(clif->channel_db,chname)) ) { - unsigned char k; + int k; for( k = 0; k < sd->channel_count; k++ ) { if( sd->channels[k] == channel ) break; @@ -10439,11 +10405,10 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) } else if( channel->pass[0] == '\0' && !(channel->banned && idb_exists(channel->banned, sd->status.account_id)) ) { if( channel->type == hChSys_ALLY ) { struct guild *g = sd->guild, *sg = NULL; - int k; for (k = 0; k < MAX_GUILDALLIANCE; k++) { if( g->alliance[k].opposition == 0 && g->alliance[k].guild_id && (sg = guild->search(g->alliance[k].guild_id) ) ) { - if( !(((struct hChSysCh*)sg->channel)->banned && idb_exists(((struct hChSysCh*)sg->channel)->banned, sd->status.account_id))) - clif->chsys_join((struct hChSysCh *)sg->channel,sd); + if( !(sg->channel->banned && idb_exists(sg->channel->banned, sd->status.account_id))) + clif->chsys_join(sg->channel,sd); } } } @@ -10470,8 +10435,8 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) } // if player ignores everyone - if (dstsd->state.ignoreAll && pc->get_group_level(sd) <= pc->get_group_level(dstsd)) { - if (dstsd->sc.option & OPTION_INVISIBLE && pc->get_group_level(sd) < pc->get_group_level(dstsd)) + if (dstsd->state.ignoreAll && pc_get_group_level(sd) <= pc_get_group_level(dstsd)) { + if (dstsd->sc.option & OPTION_INVISIBLE && pc_get_group_level(sd) < pc_get_group_level(dstsd)) clif->wis_end(fd, 1); // 1: target character is not logged in else clif->wis_end(fd, 3); // 3: everyone ignored by target @@ -10486,7 +10451,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) return; } - if( pc->get_group_level(sd) <= pc->get_group_level(dstsd) ) { + if( pc_get_group_level(sd) <= pc_get_group_level(dstsd) ) { // if player ignores the source character ARR_FIND(0, MAX_IGNORE_LIST, i, dstsd->ignore[i].name[0] == '\0' || strcmp(dstsd->ignore[i].name, sd->status.name) == 0); if(i < MAX_IGNORE_LIST && dstsd->ignore[i].name[0] != '\0') { // source char present in ignore list @@ -10515,7 +10480,7 @@ void clif_parse_Broadcast(int fd, struct map_session_data* sd) { mes_len_check(msg, len, CHAT_SIZE_MAX); sprintf(command, "%ckami %s", atcommand->at_symbol, msg); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -10589,6 +10554,9 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd) if (!pc->dropitem(sd, item_index, item_amount)) break; + if( battle_config.idletime_criteria & BCIDLE_DROPITEM ) + sd->idletime = sockt->last_tick; + return; } @@ -10614,7 +10582,8 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) return; //Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if( battle_config.idletime_criteria & BCIDLE_USEITEM ) + sd->idletime = sockt->last_tick; n = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[0])-2; if(n <0 || n >= MAX_INVENTORY) @@ -10626,16 +10595,17 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) /// Request to equip an item (CZ_REQ_WEAR_EQUIP). /// 00a9 <index>.W <position>.W -void clif_parse_EquipItem(int fd,struct map_session_data *sd) -{ - int index; +/// 0998 <index>.W <position>.L +void clif_parse_EquipItem(int fd,struct map_session_data *sd) { + struct packet_equip_item *p = P2PTR(fd); if(pc_isdead(sd)) { clif->clearunit_area(&sd->bl,CLR_DEAD); return; } - index = RFIFOW(fd,2)-2; - if (index < 0 || index >= MAX_INVENTORY) + + p->index = p->index - 2; + if (p->index >= MAX_INVENTORY) return; //Out of bounds check. if( sd->npc_id ) { @@ -10646,24 +10616,27 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd) else if ( pc_cant_act2(sd) || sd->state.prerefining ) return; - if(!sd->status.inventory[index].identify) { - clif->equipitemack(sd,index,0,0); // fail + if(!sd->status.inventory[p->index].identify) { + clif->equipitemack(sd,p->index,0,EIA_FAIL);// fail return; } - if(!sd->inventory_data[index]) + if(!sd->inventory_data[p->index]) return; - if(sd->inventory_data[index]->type == IT_PETARMOR){ - pet->equipitem(sd,index); + if(sd->inventory_data[p->index]->type == IT_PETARMOR){ + pet->equipitem(sd,p->index); return; } + if( battle_config.idletime_criteria & BCIDLE_USEITEM ) + sd->idletime = sockt->last_tick; + //Client doesn't send the position for ammo. - if(sd->inventory_data[index]->type == IT_AMMO) - pc->equipitem(sd,index,EQP_AMMO); + if(sd->inventory_data[p->index]->type == IT_AMMO) + pc->equipitem(sd,p->index,EQP_AMMO); else - pc->equipitem(sd,index,RFIFOW(fd,4)); + pc->equipitem(sd,p->index,p->wearLocation); } void clif_hercules_chsys_delete(struct hChSysCh *channel) { @@ -10714,20 +10687,20 @@ void clif_hercules_chsys_gjoin(struct guild *g1,struct guild *g2) { struct map_session_data *sd; struct hChSysCh *channel; int j; - - if( (channel = (struct hChSysCh*)g1->channel) ) { + + if( (channel = g1->channel) ) { for(j = 0; j < g2->max_member; j++) { if( (sd = g2->member[j].sd) != NULL ) { - if( !(((struct hChSysCh*)g1->channel)->banned && idb_exists(((struct hChSysCh*)g1->channel)->banned, sd->status.account_id))) + if( !(g1->channel->banned && idb_exists(g1->channel->banned, sd->status.account_id))) clif->chsys_join(channel,sd); } } } - - if( (channel = (struct hChSysCh*)g2->channel) ) { + + if( (channel = g2->channel) ) { for(j = 0; j < g1->max_member; j++) { if( (sd = g1->member[j].sd) != NULL ) { - if( !(((struct hChSysCh*)g2->channel)->banned && idb_exists(((struct hChSysCh*)g2->channel)->banned, sd->status.account_id))) + if( !(g2->channel->banned && idb_exists(g2->channel->banned, sd->status.account_id))) clif->chsys_join(channel,sd); } } @@ -10737,16 +10710,16 @@ void clif_hercules_chsys_gleave(struct guild *g1,struct guild *g2) { struct map_session_data *sd; struct hChSysCh *channel; int j; - - if( (channel = (struct hChSysCh*)g1->channel) ) { + + if( (channel = g1->channel) ) { for(j = 0; j < g2->max_member; j++) { if( (sd = g2->member[j].sd) != NULL ) { clif->chsys_left(channel,sd); } } } - - if( (channel = (struct hChSysCh*)g2->channel) ) { + + if( (channel = g2->channel) ) { for(j = 0; j < g1->max_member; j++) { if( (sd = g1->member[j].sd) != NULL ) { clif->chsys_left(channel,sd); @@ -10776,6 +10749,9 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd) index = RFIFOW(fd,2)-2; + if( battle_config.idletime_criteria & BCIDLE_USEITEM ) + sd->idletime = sockt->last_tick; + pc->unequipitem(sd,index,1); } @@ -10800,7 +10776,7 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd) } if ( pc_cant_act2(sd) || !(bl = map->id2bl(RFIFOL(fd,2))) || sd->state.vending ) return; - + switch (bl->type) { case BL_MOB: case BL_PC: @@ -11016,10 +10992,10 @@ void clif_noask_sub(struct map_session_data *src, struct map_session_data *targe char output[256]; // Your request has been rejected by autoreject option. msg = msg_txt(392); - clif->disp_onlyself(src, msg, strlen(msg)); + clif_disp_onlyself(src, msg, strlen(msg)); //Notice that a request was rejected. snprintf(output, 256, msg_txt(393+type), src->status.name, 256); - clif->disp_onlyself(target, output, strlen(output)); + clif_disp_onlyself(target, output, strlen(output)); } @@ -11153,7 +11129,9 @@ void clif_parse_ChangeCart(int fd,struct map_session_data *sd) {// TODO: State tracking? int type; - if( sd && pc->checkskill(sd, MC_CHANGECART) < 1 ) + nullpo_retv(sd); + + if( pc->checkskill(sd, MC_CHANGECART) < 1 ) return; #ifdef RENEWAL @@ -11190,11 +11168,10 @@ void clif_parse_ChangeCart(int fd,struct map_session_data *sd) /// status id: /// SP_STR ~ SP_LUK /// amount: -/// client sends always 1 for this, even when using /str+ and -/// the like -void clif_parse_StatusUp(int fd,struct map_session_data *sd) -{ - pc->statusup(sd,RFIFOW(fd,2)); +/// Old clients send always 1 for this, even when using /str+ and the like. +/// Newer clients (2013-12-23 and newer) send the correct amount. +void clif_parse_StatusUp(int fd,struct map_session_data *sd) { + pc->statusup(sd,RFIFOW(fd,2), RFIFOB(fd, 4)); } @@ -11205,8 +11182,7 @@ void clif_parse_SkillUp(int fd,struct map_session_data *sd) pc->skillup(sd,RFIFOW(fd,2)); } -void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, int target_id) -{ +void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, int target_id) { int lv; if( !hd ) @@ -11227,8 +11203,7 @@ void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_session_dat unit->skilluse_id(&hd->bl, target_id, skill_id, skill_lv); } -void clif_parse_UseSkillToPos_homun(struct homun_data *hd, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo) -{ +void clif_parse_UseSkillToPos_homun(struct homun_data *hd, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo) { int lv; if( !hd ) return; @@ -11248,8 +11223,7 @@ void clif_parse_UseSkillToPos_homun(struct homun_data *hd, struct map_session_da unit->skilluse_pos(&hd->bl, x, y, skill_id, skill_lv); } -void clif_parse_UseSkillToId_mercenary(struct mercenary_data *md, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, int target_id) -{ +void clif_parse_UseSkillToId_mercenary(struct mercenary_data *md, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, int target_id) { int lv; if( !md ) @@ -11270,8 +11244,7 @@ void clif_parse_UseSkillToId_mercenary(struct mercenary_data *md, struct map_ses unit->skilluse_id(&md->bl, target_id, skill_id, skill_lv); } -void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo) -{ +void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo) { int lv; if( !md ) return; @@ -11302,7 +11275,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) { uint16 skill_id, skill_lv; int tmp, target_id; - unsigned int tick = timer->gettick(); + int64 tick = timer->gettick(); skill_lv = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[0]); skill_id = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[1]); @@ -11325,7 +11298,8 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) } // Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if( battle_config.idletime_criteria & BCIDLE_USESKILLTOID ) + sd->idletime = sockt->last_tick; if( sd->npc_id || sd->state.workinprogress&1 ){ #ifdef RENEWAL @@ -11357,7 +11331,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) } } - if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK) ) + if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST) ) return; if( sd->sc.data[SC_BASILICA] && (skill_id != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) @@ -11402,7 +11376,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uint16 skill_lv, uint16 skill_id, short x, short y, int skillmoreinfo) { - unsigned int tick = timer->gettick(); + int64 tick = timer->gettick(); if( !(skill->get_inf(skill_id)&INF_GROUND_SKILL) ) return; //Using a target skill on the ground? WRONG. @@ -11425,7 +11399,8 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uint16 ski #endif //Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if( battle_config.idletime_criteria & BCIDLE_USESKILLTOPOS ) + sd->idletime = sockt->last_tick; if( skill->not_ok(skill_id, sd) ) return; @@ -11448,7 +11423,7 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uint16 ski } } - if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK) ) + if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST) ) return; if( sd->sc.data[SC_BASILICA] && (skill_id != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) @@ -11528,7 +11503,7 @@ void clif_parse_UseSkillMap(int fd, struct map_session_data* sd) uint16 skill_id = RFIFOW(fd,2); char map_name[MAP_NAME_LENGTH]; - mapindex_getmapname((char*)RFIFOP(fd,4), map_name); + mapindex->getmapname((char*)RFIFOP(fd,4), map_name); sd->state.workinprogress = 0; if(skill_id != sd->menuskill_id) @@ -11839,7 +11814,7 @@ void clif_parse_ResetChar(int fd, struct map_session_data *sd) { else sprintf(cmd,"%cstreset",atcommand->at_symbol); - atcommand->parse(fd, sd, cmd, 1); + atcommand->exec(fd, sd, cmd, true); } @@ -11856,7 +11831,7 @@ void clif_parse_LocalBroadcast(int fd, struct map_session_data* sd) mes_len_check(msg, len, CHAT_SIZE_MAX); sprintf(command, "%clkami %s", atcommand->at_symbol, msg); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -12161,16 +12136,16 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd) int textlen = RFIFOW(fd,2) - 4; char *name, *message; - int namelen, messagelen; + size_t namelen, messagelen; // validate packet and retrieve name and message if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if( atcommand->parse(fd, sd, message, 1) ) + if( atcommand->exec(fd, sd, message, true) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) @@ -12180,6 +12155,9 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd) sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } + if( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + party->send_message(sd, text, textlen); } @@ -12528,7 +12506,7 @@ void clif_parse_PartyRecruitUpdateReq(int fd, struct map_session_data *sd) const char *notice; notice = (const char*)RFIFOP(fd, 2); - + party->recruit_update(sd, notice); #else return; @@ -12563,7 +12541,7 @@ void clif_PartyRecruitUpdateNotify(struct map_session_data *sd, struct party_boo { #ifdef PARTY_RECRUIT unsigned char buf[2+6+37+1]; - + WBUFW(buf, 0) = 0x8ed; WBUFL(buf, 2) = pb_ad->index; memcpy(WBUFP(buf, 6), pb_ad->p_detail.notice, PB_NOTICE_LENGTH); @@ -12635,13 +12613,13 @@ void clif_PartyBookingVolunteerInfo(int index, struct map_session_data *sd) { #ifdef PARTY_RECRUIT unsigned char buf[2+4+4+2+24+1]; - + WBUFW(buf, 0) = 0x8f2; WBUFL(buf, 2) = sd->status.account_id; WBUFL(buf, 6) = sd->status.class_; WBUFW(buf, 10) = sd->status.base_level; memcpy(WBUFP(buf, 12), sd->status.name, NAME_LENGTH); - + clif->send(buf, packet_len(0x8f2), &sd->bl, ALL_CLIENT); #else return; @@ -12690,7 +12668,7 @@ void clif_PartyBookingFailedRecall(int fd, struct map_session_data *sd) void clif_parse_PartyBookingRefuseVolunteer(int fd, struct map_session_data *sd) { #ifdef PARTY_RECRUIT - unsigned long aid = RFIFOL(fd, 2); + unsigned int aid = RFIFOL(fd, 2); clif->PartyBookingRefuseVolunteer(aid, sd); #else @@ -12699,14 +12677,14 @@ void clif_parse_PartyBookingRefuseVolunteer(int fd, struct map_session_data *sd) } /// 08fa <index>.L -void clif_PartyBookingRefuseVolunteer(unsigned long aid, struct map_session_data *sd) +void clif_PartyBookingRefuseVolunteer(unsigned int aid, struct map_session_data *sd) { #ifdef PARTY_RECRUIT unsigned char buf[2+6]; - + WBUFW(buf, 0) = 0x8fa; WBUFL(buf, 2) = aid; - + clif->send(buf, packet_len(0x8fa), &sd->bl, ALL_CLIENT); #else return; @@ -12730,10 +12708,10 @@ void clif_PartyBookingCancelVolunteer(int index, struct map_session_data *sd) { #ifdef PARTY_RECRUIT unsigned char buf[2+6+1]; - + WBUFW(buf, 0) = 0x909; WBUFL(buf, 2) = index; - + clif->send(buf, packet_len(0x909), &sd->bl, ALL_CLIENT); #else return; @@ -12749,7 +12727,7 @@ void clif_PartyBookingAddFilteringList(int index, struct map_session_data *sd) WBUFW(buf, 0) = 0x90b; WBUFL(buf, 2) = sd->bl.id; memcpy(WBUFP(buf, 6), sd->status.name, NAME_LENGTH); - + clif->send(buf, packet_len(0x90b), &sd->bl, ALL_CLIENT); #else return; @@ -12765,7 +12743,7 @@ void clif_PartyBookingSubFilteringList(int gid, struct map_session_data *sd) WBUFW(buf, 0) = 0x90c; WBUFL(buf, 2) = gid; memcpy(WBUFP(buf, 6), sd->status.name, NAME_LENGTH); - + clif->send(buf, packet_len(0x90c), &sd->bl, ALL_CLIENT); #else return; @@ -12845,7 +12823,7 @@ void clif_parse_OpenVending(int fd, struct map_session_data* sd) { const char* message = (char*)RFIFOP(fd,4); bool flag = (bool)RFIFOB(fd,84); const uint8* data = (uint8*)RFIFOP(fd,85); - + if( !flag ) sd->state.prevend = sd->state.workinprogress = 0; @@ -12973,20 +12951,126 @@ void clif_parse_GuildRequestEmblem(int fd,struct map_session_data *sd) clif->guild_emblem(sd,g); } - /// Validates data of a guild emblem (compressed bitmap) -bool clif_validate_emblem(const uint8* emblem, unsigned long emblem_len) { - bool success; - uint8 buf[1800]; // no well-formed emblem bitmap is larger than 1782 (24 bit) / 1654 (8 bit) bytes +bool clif_validate_emblem(const uint8 *emblem, unsigned long emblem_len) { + enum e_bitmapconst { + RGBTRIPLE_SIZE = 3, // sizeof(RGBTRIPLE) + RGBQUAD_SIZE = 4, // sizeof(RGBQUAD) + BITMAPFILEHEADER_SIZE = 14, // sizeof(BITMAPFILEHEADER) + BITMAPINFOHEADER_SIZE = 40, // sizeof(BITMAPINFOHEADER) + BITMAP_WIDTH = 24, + BITMAP_HEIGHT = 24, + }; +#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute +#pragma pack(push, 1) +#endif // not NetBSD < 6 / Solaris + struct s_bitmaptripple { + //uint8 b; + //uint8 g; + //uint8 r; + unsigned int rgb:24; + } __attribute__((packed)); +#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute +#pragma pack(pop) +#endif // not NetBSD < 6 / Solaris + uint8 buf[1800]; // no well-formed emblem bitmap is larger than 1782 (24 bit) / 1654 (8 bit) bytes unsigned long buf_len = sizeof(buf); + int header = 0, bitmap = 0, offbits = 0, palettesize = 0, i = 0; + + if( decode_zip(buf, &buf_len, emblem, emblem_len) != 0 || buf_len < BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + || RBUFW(buf,0) != 0x4d42 // BITMAPFILEHEADER.bfType (signature) + || RBUFL(buf,2) != buf_len // BITMAPFILEHEADER.bfSize (file size) + || RBUFL(buf,14) != BITMAPINFOHEADER_SIZE // BITMAPINFOHEADER.biSize (other headers are not supported) + || RBUFL(buf,18) != BITMAP_WIDTH // BITMAPINFOHEADER.biWidth + || RBUFL(buf,22) != BITMAP_HEIGHT // BITMAPINFOHEADER.biHeight (top-down bitmaps (-24) are not supported) + || RBUFL(buf,30) != 0 // BITMAPINFOHEADER.biCompression == BI_RGB (compression not supported) + ) { + // Invalid data + return false; + } - success = ( decode_zip(buf, &buf_len, emblem, emblem_len) == 0 && buf_len >= 18 ) // sizeof(BITMAPFILEHEADER) + sizeof(biSize) of the following info header struct - && RBUFW(buf,0) == 0x4d42 // BITMAPFILEHEADER.bfType (signature) - && RBUFL(buf,2) == buf_len // BITMAPFILEHEADER.bfSize (file size) - && RBUFL(buf,10) < buf_len // BITMAPFILEHEADER.bfOffBits (offset to bitmap bits) - ; + offbits = RBUFL(buf,10); // BITMAPFILEHEADER.bfOffBits (offset to bitmap bits) + + switch( RBUFW(buf,28) ) { // BITMAPINFOHEADER.biBitCount + case 8: + palettesize = RBUFL(buf,46); // BITMAPINFOHEADER.biClrUsed (number of colors in the palette) + if( palettesize == 0 ) + palettesize = 256; // Defaults to 2^n if set to zero + else if( palettesize > 256 ) + return false; + header = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + RGBQUAD_SIZE * palettesize; // headers + palette + bitmap = BITMAP_WIDTH * BITMAP_HEIGHT; + break; + case 24: + header = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; + bitmap = BITMAP_WIDTH * BITMAP_HEIGHT * RGBTRIPLE_SIZE; + break; + default: + return false; + } - return success; + // NOTE: This check gives a little freedom for bitmap-producing implementations, + // that align the start of bitmap data, which is harmless but unnecessary. + // If you want it paranoidly strict, change the first condition from < to !=. + // This also allows files with trailing garbage at the end of the file. + // If you want to avoid that, change the last condition to !=. + if( offbits < header || buf_len <= bitmap || offbits > buf_len - bitmap ) { + return false; + } + + if( battle_config.client_emblem_max_blank_percent < 100 ) { + int required_pixels = BITMAP_WIDTH * BITMAP_HEIGHT * (100 - battle_config.client_emblem_max_blank_percent) / 100; + int found_pixels = 0; + /// Checks what percentage of a guild emblem is blank. A blank emblem + /// consists solely of magenta pixels. Since the client uses 16-bit + /// colors, any magenta shade that reduces to #ff00ff passes off as + /// transparent color as well (down to #f807f8). + /// + /// Unlike real magenta, reduced magenta causes the guild window to + /// become see-through in the transparent parts of the emblem + /// background (glitch). + switch( RBUFW(buf,28) ) { + case 8: // palette indexes + { + const uint8 *indexes = (const uint8 *)RBUFP(buf,offbits); + const uint32 *palette = (const uint32 *)RBUFP(buf,BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE); + + for( i = 0; i < BITMAP_WIDTH * BITMAP_HEIGHT; i++ ) { + if( indexes[i] >= palettesize ) // Invalid color + return false; + + // if( color->r < 0xF8 || color->g > 0x07 || color->b < 0xF8 ) + if( ( palette[indexes[i]]&0x00F8F8F8 ) != 0x00F800F8 ) { + if( ++found_pixels >= required_pixels ) { + // Enough valid pixels were found + return true; + } + } + } + break; + } + case 24: // full colors + { + const struct s_bitmaptripple *pixels = (const struct s_bitmaptripple*)RBUFP(buf,offbits); + + for( i = 0; i < BITMAP_WIDTH * BITMAP_HEIGHT; i++ ) { + // if( pixels[i].r < 0xF8 || pixels[i].g > 0x07 || pixels[i].b < 0xF8 ) + if( ( pixels[i].rgb&0xF8F8F8 ) != 0xF800F8 ) { + if( ++found_pixels >= required_pixels ) { + // Enough valid pixels were found + return true; + } + } + } + break; + } + } + + // Not enough non-blank pixels found + return false; + } + + return true; } @@ -12994,7 +13078,7 @@ bool clif_validate_emblem(const uint8* emblem, unsigned long emblem_len) { /// 0153 <packet len>.W <emblem data>.?B void clif_parse_GuildChangeEmblem(int fd,struct map_session_data *sd) { - unsigned long emblem_len = RFIFOW(fd,2)-4; + unsigned int emblem_len = RFIFOW(fd,2)-4; const uint8* emblem = RFIFOP(fd,4); if( !emblem_len || !sd->state.gmaster_flag ) @@ -13029,25 +13113,23 @@ void clif_parse_GuildChangeNotice(int fd, struct map_session_data* sd) } // Helper function for guild invite functions -int -clif_sub_guild_invite(int fd, struct map_session_data *sd, struct map_session_data *t_sd) { - if (t_sd == NULL) {// not online or does not exist - return 1; - } - - if (map->list[sd->bl.m].flag.guildlock) { +bool clif_sub_guild_invite(int fd, struct map_session_data *sd, struct map_session_data *t_sd) { + if ( t_sd == NULL )// not online or does not exist + return false; + + if ( map->list[sd->bl.m].flag.guildlock ) { //Guild locked. clif->message(fd, msg_txt(228)); - return 1; + return false; } - - if (t_sd && t_sd->state.noask) {// @noask [LuzZza] + + if ( t_sd && t_sd->state.noask ) {// @noask [LuzZza] clif->noask_sub(sd, t_sd, 2); - return 1; + return false; } guild->invite(sd,t_sd); - return 0; + return true; } /// Guild invite request (CZ_REQ_JOIN_GUILD). @@ -13055,7 +13137,7 @@ clif_sub_guild_invite(int fd, struct map_session_data *sd, struct map_session_da void clif_parse_GuildInvite(int fd,struct map_session_data *sd) { struct map_session_data *t_sd = map->id2sd(RFIFOL(fd,2)); - if (clif_sub_guild_invite(fd, sd, t_sd)) + if (!clif_sub_guild_invite(fd, sd, t_sd)) return; } @@ -13063,8 +13145,8 @@ void clif_parse_GuildInvite(int fd,struct map_session_data *sd) { /// 0916 <char name>.24B void clif_parse_GuildInvite2(int fd, struct map_session_data *sd) { struct map_session_data *t_sd = map->nick2sd((char *)RFIFOP(fd, 2)); - - if (clif_sub_guild_invite(fd, sd, t_sd)) + + if (!clif_sub_guild_invite(fd, sd, t_sd)) return; } @@ -13116,16 +13198,16 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) int textlen = RFIFOW(fd,2) - 4; char *name, *message; - int namelen, messagelen; + size_t namelen, messagelen; // validate packet and retrieve name and message if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if( atcommand->parse(fd, sd, message, 1) ) + if( atcommand->exec(fd, sd, message, true) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) @@ -13135,6 +13217,9 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } + if( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + if( sd->bg_id ) bg->send_message(sd, text, textlen); else @@ -13268,8 +13353,6 @@ void clif_parse_CatchPet(int fd, struct map_session_data *sd) void clif_parse_SelectEgg(int fd, struct map_session_data *sd) { if (sd->menuskill_id != SA_TAMINGMONSTER || sd->menuskill_val != -1) { - //Forged packet, disconnect them [Kevin] - clif->authfail_fd(fd, 0); return; } pet->select_egg(sd,RFIFOW(fd,2)-2); @@ -13336,7 +13419,7 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd) { { char command[NAME_LENGTH+6]; sprintf(command, "%ckick %s", atcommand->at_symbol, status->get_name(target)); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } break; @@ -13381,7 +13464,7 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd) { void clif_parse_GMKickAll(int fd, struct map_session_data* sd) { char cmd[15]; sprintf(cmd,"%ckickall",atcommand->at_symbol); - atcommand->parse(fd, sd, cmd, 1); + atcommand->exec(fd, sd, cmd, true); } @@ -13401,7 +13484,7 @@ void clif_parse_GMShift(int fd, struct map_session_data *sd) player_name[NAME_LENGTH-1] = '\0'; sprintf(command, "%cjumpto %s", atcommand->at_symbol, player_name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -13416,7 +13499,7 @@ void clif_parse_GMRemove2(int fd, struct map_session_data* sd) { if( (pl_sd = map->id2sd(account_id)) != NULL ) { char command[NAME_LENGTH+8]; sprintf(command, "%cjumpto %s", atcommand->at_symbol, pl_sd->status.name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } } @@ -13437,7 +13520,7 @@ void clif_parse_GMRecall(int fd, struct map_session_data *sd) player_name[NAME_LENGTH-1] = '\0'; sprintf(command, "%crecall %s", atcommand->at_symbol, player_name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -13452,7 +13535,7 @@ void clif_parse_GMRecall2(int fd, struct map_session_data* sd) { if( (pl_sd = map->id2sd(account_id)) != NULL ) { char command[NAME_LENGTH+8]; sprintf(command, "%crecall %s", atcommand->at_symbol, pl_sd->status.name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } } @@ -13469,48 +13552,59 @@ void clif_parse_GMRecall2(int fd, struct map_session_data* sd) { /// /item cap_n - capture n monster as pet.(not yet implemented) /// /item agitinvest - reset current global agit investments.(not yet implemented) /// 013f <item/mob name>.24B -void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd) -{ +/// 09ce <item/mob name>.100B [Ind/Yommy<3] +void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd) { + struct packet_gm_monster_item *p = P2PTR(fd); int i, count; char *item_monster_name; struct item_data *item_array[10]; struct mob_db *mob_array[10]; - char command[NAME_LENGTH+10]; + char command[256]; - item_monster_name = (char*)RFIFOP(fd,2); - item_monster_name[NAME_LENGTH-1] = '\0'; + item_monster_name = p->str; + item_monster_name[(sizeof(struct packet_gm_monster_item)-2)-1] = '\0'; - if ( (count=itemdb->search_name_array(item_array, 10, item_monster_name, 1)) > 0 ){ - for(i = 0; i < count; i++){ - if( item_array[i] && strcmp(item_array[i]->name, item_monster_name) == 0 )// It only accepts aegis name + if ( (count=itemdb->search_name_array(item_array, 10, item_monster_name, 1)) > 0 ) { + for(i = 0; i < count; i++) { + if( !item_array[i] ) + continue; + // It only accepts aegis name + if( battle_config.case_sensitive_aegisnames && strcmp(item_array[i]->name, item_monster_name) == 0 ) + break; + if( !battle_config.case_sensitive_aegisnames && strcasecmp(item_array[i]->name, item_monster_name) == 0 ) break; } - if( i < count ){ + if( i < count ) { if( item_array[i]->type == IT_WEAPON || item_array[i]->type == IT_ARMOR ) // nonstackable snprintf(command, sizeof(command)-1, "%citem2 %d 1 0 0 0 0 0 0 0", atcommand->at_symbol, item_array[i]->nameid); else snprintf(command, sizeof(command)-1, "%citem %d 20", atcommand->at_symbol, item_array[i]->nameid); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); return; } } if( strcmp("money", item_monster_name) == 0 ){ snprintf(command, sizeof(command)-1, "%czeny %d", atcommand->at_symbol, INT_MAX); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); return; } - if( (count=mob->db_searchname_array(mob_array, 10, item_monster_name, 1)) > 0){ - for(i = 0; i < count; i++){ - if( mob_array[i] && strcmp(mob_array[i]->sprite, item_monster_name) == 0 ) // It only accepts sprite name + if( (count=mob->db_searchname_array(mob_array, 10, item_monster_name, 1)) > 0) { + for(i = 0; i < count; i++) { + if( !mob_array[i] ) + continue; + // It only accepts sprite name + if( battle_config.case_sensitive_aegisnames && strcmp(mob_array[i]->sprite, item_monster_name) == 0 ) + break; + if( !battle_config.case_sensitive_aegisnames && strcasecmp(mob_array[i]->sprite, item_monster_name) == 0 ) break; } if( i < count ){ snprintf(command, sizeof(command)-1, "%cmonster %s", atcommand->at_symbol, mob_array[i]->sprite); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } } } @@ -13525,7 +13619,7 @@ void clif_parse_GMHide(int fd, struct map_session_data *sd) { sprintf(cmd,"%chide",atcommand->at_symbol); - atcommand->parse(fd, sd, cmd, 1); + atcommand->exec(fd, sd, cmd, true); } @@ -13550,7 +13644,7 @@ void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd) { if (type == 2) { if (!battle_config.client_accept_chatdori) return; - if (pc->get_group_level(sd) > 0 || sd->bl.id != id) + if (pc_get_group_level(sd) > 0 || sd->bl.id != id) return; value = battle_config.client_accept_chatdori; @@ -13560,26 +13654,26 @@ void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd) { if( dstsd == NULL ) return; } - - if (type == 2 || ( (pc->get_group_level(sd)) > pc->get_group_level(dstsd) && !pc->can_use_command(sd, "@mute"))) { + + if (type == 2 || ( (pc_get_group_level(sd)) > pc_get_group_level(dstsd) && !pc->can_use_command(sd, "@mute"))) { clif->manner_message(sd, 0); clif->manner_message(dstsd, 5); if (dstsd->status.manner < value) { dstsd->status.manner -= value; - sc_start(&dstsd->bl,SC_NOCHAT,100,0,0); - + sc_start(NULL,&dstsd->bl,SC_NOCHAT,100,0,0); + } else { dstsd->status.manner = 0; status_change_end(&dstsd->bl, SC_NOCHAT, INVALID_TIMER); } - + if( type != 2 ) clif->GM_silence(sd, dstsd, type); } sprintf(command, "%cmute %d %s", atcommand->at_symbol, value, dstsd->status.name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -13593,7 +13687,7 @@ void clif_parse_GMRc(int fd, struct map_session_data* sd) name[NAME_LENGTH-1] = '\0'; sprintf(command, "%cmute %d %s", atcommand->at_symbol, 60, name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -13630,7 +13724,7 @@ void clif_parse_GMReqAccountName(int fd, struct map_session_data *sd) void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd) { int x,y,type; - if (!pc->has_permission(sd, PC_PERM_USE_CHANGEMAPTYPE)) + if (!pc_has_permission(sd, PC_PERM_USE_CHANGEMAPTYPE)) return; x = RFIFOW(fd,2); @@ -13796,7 +13890,7 @@ void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *sd) int percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. ); if( percent && ( percent%100 ) == 0 ) {// 10.0%, 20.0%, ..., 90.0% - sc_start(&sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex] + sc_start(NULL,&sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex] clif->skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1); // prayer always shows successful Lv5 cast and disregards noskill restrictions } } @@ -14064,7 +14158,7 @@ void clif_parse_FriendsListRemove(int fd, struct map_session_data *sd) } } else { //friend not online -- ask char server to delete from his friendlist - if(chrif->removefriend(char_id,sd->status.char_id)) { // char-server offline, abort + if(!chrif->removefriend(char_id,sd->status.char_id)) { // char-server offline, abort clif->message(fd, msg_txt(673)); //"This action can't be performed at the moment. Please try again later." return; } @@ -14329,7 +14423,7 @@ void clif_parse_FeelSaveOk(int fd,struct map_session_data *sd) sd->feel_map[i].index = map_id2index(sd->bl.m); sd->feel_map[i].m = sd->bl.m; - pc_setglobalreg(sd,pc->sg_info[i].feel_var,sd->feel_map[i].index); + pc_setglobalreg(sd,script->add_str(pc->sg_info[i].feel_var),sd->feel_map[i].index); //Are these really needed? Shouldn't they show up automatically from the feel save packet? // clif_misceffect2(&sd->bl, 0x1b0); @@ -14514,12 +14608,12 @@ void clif_parse_Check(int fd, struct map_session_data *sd) char charname[NAME_LENGTH]; struct map_session_data* pl_sd; - if(!pc->has_permission(sd, PC_PERM_USE_CHECK)) + if(!pc_has_permission(sd, PC_PERM_USE_CHECK)) return; safestrncpy(charname, (const char*)RFIFOP(fd,packet_db[RFIFOW(fd,0)].pos[0]), sizeof(charname)); - if( ( pl_sd = map->nick2sd(charname) ) == NULL || pc->get_group_level(sd) < pc->get_group_level(pl_sd) ) { + if( ( pl_sd = map->nick2sd(charname) ) == NULL || pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) { return; } @@ -14669,7 +14763,7 @@ void clif_Mail_refreshinbox(struct map_session_data *sd) if( md->full ) {// TODO: is this official? char output[100]; sprintf(output, "Inbox is full (Max %d). Delete some mails.", MAIL_MAX_INBOX); - clif->disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output, strlen(output)); } } @@ -14707,7 +14801,7 @@ void clif_Mail_read(struct map_session_data *sd, int mail_id) struct mail_message *msg = &sd->mail.inbox.msg[i]; struct item *item = &msg->item; struct item_data *data; - int msg_len = strlen(msg->body), len; + size_t msg_len = strlen(msg->body), len; if( msg_len == 0 ) { strcpy(msg->body, "(no message)"); @@ -14801,6 +14895,11 @@ void clif_parse_Mail_getattach(int fd, struct map_session_data *sd) if ((data = itemdb->exists(sd->mail.inbox.msg[i].item.nameid)) == NULL) return; + if( pc_is90overweight(sd) ) { + clif->mail_getattachment(fd, 2); + return; + } + switch( pc->checkadditem(sd, data->nameid, sd->mail.inbox.msg[i].item.amount) ) { case ADDITEM_NEW: fail = ( pc->inventoryblank(sd) == 0 ); @@ -14987,6 +15086,9 @@ void clif_Auction_openwindow(struct map_session_data *sd) if( sd->state.storage_flag || sd->state.vending || sd->state.buyingstore || sd->state.trading ) return; + if( !battle_config.feature_auction ) + return; + WFIFOHEAD(fd,packet_len(0x25f)); WFIFOW(fd,0) = 0x25f; WFIFOL(fd,2) = 0; @@ -15076,6 +15178,9 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd) int amount = RFIFOL(fd,4); // Always 1 struct item_data *item; + if( !battle_config.feature_auction ) + return; + if( sd->auction.amount > 0 ) sd->auction.amount = 0; @@ -15095,10 +15200,11 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd) return; } - if( !pc->can_give_items(sd) || sd->status.inventory[idx].expire_time || + if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time || !sd->status.inventory[idx].identify || - !itemdb_canauction(&sd->status.inventory[idx],pc->get_group_level(sd)) ) { // Quest Item or something else - clif->auction_setitem(sd->fd, idx, true); + !itemdb_canauction(&sd->status.inventory[idx],pc_get_group_level(sd)) || // Quest Item or something else + (sd->status.inventory[idx].bound && !pc_can_give_bound_items(sd)) ) { + clif->auction_setitem(sd->fd, idx, true); return; } @@ -15151,6 +15257,9 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd) struct auction_data auction; struct item_data *item; + if( !battle_config.feature_auction ) + return; + auction.price = RFIFOL(fd,2); auction.buynow = RFIFOL(fd,6); auction.hours = RFIFOW(fd,10); @@ -15171,9 +15280,8 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd) return; } - // Auction checks... if( sd->status.zeny < (auction.hours * battle_config.auction_feeperhour) ) { - clif->auction_message(fd, 5); // You do not have enough zeny to pay the Auction Fee. + clif_Auction_message(fd, 5); // You do not have enough zeny to pay the Auction Fee. return; } @@ -15202,6 +15310,13 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd) return; } + // Auction checks... + if( sd->status.inventory[sd->auction.index].bound && !pc_can_give_bound_items(sd) ) { + clif->message(sd->fd, msg_txt(293)); + clif->auction_message(fd, 2); // The auction has been canceled + return; + } + safestrncpy(auction.item_name, item->jname, sizeof(auction.item_name)); auction.type = item->type; memcpy(&auction.item, &sd->status.inventory[sd->auction.index], sizeof(struct item)); @@ -15249,7 +15364,7 @@ void clif_parse_Auction_bid(int fd, struct map_session_data *sd) unsigned int auction_id = RFIFOL(fd,2); int bid = RFIFOL(fd,6); - if( !pc->can_give_items(sd) ) { //They aren't supposed to give zeny [Inkfish] + if( !pc_can_give_items(sd) ) { //They aren't supposed to give zeny [Inkfish] clif->message(sd->fd, msg_txt(246)); return; } @@ -15282,6 +15397,9 @@ void clif_parse_Auction_search(int fd, struct map_session_data* sd) short type = RFIFOW(fd,2), page = RFIFOW(fd,32); int price = RFIFOL(fd,4); // FIXME: bug #5071 + if( !battle_config.feature_auction ) + return; + clif->pAuction_cancelreg(fd, sd); safestrncpy(search_text, (char*)RFIFOP(fd,8), sizeof(search_text)); @@ -15297,6 +15415,10 @@ void clif_parse_Auction_search(int fd, struct map_session_data* sd) void clif_parse_Auction_buysell(int fd, struct map_session_data* sd) { short type = RFIFOW(fd,2) + 6; + + if( !battle_config.feature_auction ) + return; + clif->pAuction_cancelreg(fd, sd); intif->Auction_requestlist(sd->status.char_id, type, 0, "", 1); @@ -15309,9 +15431,11 @@ void clif_parse_Auction_buysell(int fd, struct map_session_data* sd) /// List of items offered in a cash shop (ZC_PC_CASH_POINT_ITEMLIST). /// 0287 <packet len>.W <cash point>.L { <sell price>.L <discount price>.L <item type>.B <name id>.W }* /// 0287 <packet len>.W <cash point>.L <kafra point>.L { <sell price>.L <discount price>.L <item type>.B <name id>.W }* (PACKETVER >= 20070711) -void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) -{ - int fd,i; +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 currency[2] = { 0,0 }; #if PACKETVER < 20070711 const int offset = 8; #else @@ -15321,23 +15445,43 @@ void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) nullpo_retv(sd); nullpo_retv(nd); + if( nd->subtype == SCRIPT ) { + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + + npc->trader_count_funds(nd, sd); + + currency[0] = npc->trader_funds[0]; + currency[1] = npc->trader_funds[1]; + } else { + shop = nd->u.shop.shop_item; + shop_size = nd->u.shop.count; + + currency[0] = sd->cashPoints; + currency[1] = sd->kafraPoints; + } + fd = sd->fd; sd->npc_shopid = nd->bl.id; - WFIFOHEAD(fd,offset+nd->u.shop.count*11); + WFIFOHEAD(fd,offset+shop_size*11); WFIFOW(fd,0) = 0x287; - WFIFOW(fd,2) = offset+nd->u.shop.count*11; - WFIFOL(fd,4) = sd->cashPoints; // Cash Points + /* 0x2 = length, set after parsing */ + WFIFOL(fd,4) = currency[0]; // Cash Points #if PACKETVER >= 20070711 - WFIFOL(fd,8) = sd->kafraPoints; // Kafra Points + WFIFOL(fd,8) = currency[1]; // Kafra Points #endif - for( i = 0; i < nd->u.shop.count; i++ ) { - struct item_data* id = itemdb->search(nd->u.shop.shop_item[i].nameid); - WFIFOL(fd,offset+0+i*11) = nd->u.shop.shop_item[i].value; - WFIFOL(fd,offset+4+i*11) = nd->u.shop.shop_item[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; + 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; + c++; + } } + WFIFOW(fd,2) = offset+c*11; WFIFOSET(fd,WFIFOW(fd,2)); } @@ -15356,15 +15500,26 @@ void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) /// 7 = You can purchase up to 10 items. /// 8 = Some items could not be purchased. void clif_cashshop_ack(struct map_session_data* sd, int error) { - int fd = sd->fd; + struct npc_data *nd; + int fd = sd->fd; + int currency[2] = { 0,0 }; + + if( (nd = map->id2nd(sd->npc_shopid)) && nd->subtype == SCRIPT ) { + npc->trader_count_funds(nd,sd); + currency[0] = npc->trader_funds[0]; + currency[1] = npc->trader_funds[1]; + } else { + currency[0] = sd->cashPoints; + currency[1] = sd->kafraPoints; + } WFIFOHEAD(fd, packet_len(0x289)); WFIFOW(fd,0) = 0x289; - WFIFOL(fd,2) = sd->cashPoints; + WFIFOL(fd,2) = currency[0]; #if PACKETVER < 20070711 WFIFOW(fd,6) = TOW(error); #else - WFIFOL(fd,6) = sd->kafraPoints; + WFIFOL(fd,6) = currency[1]; WFIFOW(fd,10) = TOW(error); #endif WFIFOSET(fd, packet_len(0x289)); @@ -15508,7 +15663,7 @@ void clif_bossmapinfo(int fd, struct mob_data *md, short flag) unsigned int seconds; int hours, minutes; - seconds = DIFF_TICK(timer_data->tick, timer->gettick()) / 1000 + 60; + seconds = (unsigned int)(DIFF_TICK(timer_data->tick, timer->gettick()) / 1000 + 60); hours = seconds / (60 * 60); seconds = seconds - (60 * 60 * hours); minutes = seconds / 60; @@ -15533,10 +15688,10 @@ void clif_parse_ViewPlayerEquip(int fd, struct map_session_data* sd) { if (!tsd) return; - if( tsd->status.show_equip || pc->has_permission(sd, PC_PERM_VIEW_EQUIPMENT) ) + if( tsd->status.show_equip || pc_has_permission(sd, PC_PERM_VIEW_EQUIPMENT) ) clif->viewequip_ack(sd, tsd); else - clif->viewequip_fail(sd); + clif_viewequip_fail(sd); } @@ -15570,8 +15725,7 @@ void clif_parse_PartyTick(int fd, struct map_session_data* sd) /// Sends list of all quest states (ZC_ALL_QUEST_LIST). /// 02b1 <packet len>.W <num>.L { <quest id>.L <active>.B }*num -void clif_quest_send_list(struct map_session_data * sd) -{ +void clif_quest_send_list(struct map_session_data *sd) { int fd = sd->fd; int i; int len = sd->avail_quests*5+8; @@ -15592,8 +15746,7 @@ void clif_quest_send_list(struct map_session_data * sd) /// Sends list of all quest missions (ZC_ALL_QUEST_MISSION). /// 02b2 <packet len>.W <num>.L { <quest id>.L <start time>.L <expire time>.L <mobs>.W { <mob id>.L <mob count>.W <mob name>.24B }*3 }*num -void clif_quest_send_mission(struct map_session_data * sd) -{ +void clif_quest_send_mission(struct map_session_data *sd) { int fd = sd->fd; int i, j; int len = sd->avail_quests*104+8; @@ -15605,17 +15758,17 @@ void clif_quest_send_mission(struct map_session_data * sd) WFIFOL(fd, 4) = sd->avail_quests; for( i = 0; i < sd->avail_quests; i++ ) { + struct quest_db *qi = quest->db(sd->quest_log[i].quest_id); WFIFOL(fd, i*104+8) = sd->quest_log[i].quest_id; - WFIFOL(fd, i*104+12) = sd->quest_log[i].time - quest->db[sd->quest_index[i]].time; + WFIFOL(fd, i*104+12) = sd->quest_log[i].time - qi->time; WFIFOL(fd, i*104+16) = sd->quest_log[i].time; - WFIFOW(fd, i*104+20) = quest->db[sd->quest_index[i]].num_objectives; + WFIFOW(fd, i*104+20) = qi->num_objectives; - for( j = 0 ; j < quest->db[sd->quest_index[i]].num_objectives; j++ ) - { - WFIFOL(fd, i*104+22+j*30) = quest->db[sd->quest_index[i]].mob[j]; + for( j = 0 ; j < qi->num_objectives; j++ ) { + WFIFOL(fd, i*104+22+j*30) = qi->mob[j]; WFIFOW(fd, i*104+26+j*30) = sd->quest_log[i].count[j]; - monster = mob->db(quest->db[sd->quest_index[i]].mob[j]); - memcpy(WFIFOP(fd, i*104+28+j*30), monster?monster->jname:"NULL", NAME_LENGTH); + monster = mob->db(qi->mob[j]); + memcpy(WFIFOP(fd, i*104+28+j*30), monster->jname, NAME_LENGTH); } } @@ -15625,25 +15778,25 @@ void clif_quest_send_mission(struct map_session_data * sd) /// Notification about a new quest (ZC_ADD_QUEST). /// 02b3 <quest id>.L <active>.B <start time>.L <expire time>.L <mobs>.W { <mob id>.L <mob count>.W <mob name>.24B }*3 -void clif_quest_add(struct map_session_data * sd, struct quest * qd, int index) -{ +void clif_quest_add(struct map_session_data *sd, struct quest *qd) { int fd = sd->fd; int i; struct mob_db *monster; + struct quest_db *qi = quest->db(qd->quest_id); WFIFOHEAD(fd, packet_len(0x2b3)); WFIFOW(fd, 0) = 0x2b3; WFIFOL(fd, 2) = qd->quest_id; WFIFOB(fd, 6) = qd->state; - WFIFOB(fd, 7) = qd->time - quest->db[index].time; + WFIFOB(fd, 7) = qd->time - qi->time; WFIFOL(fd, 11) = qd->time; - WFIFOW(fd, 15) = quest->db[index].num_objectives; + WFIFOW(fd, 15) = qi->num_objectives; - for( i = 0; i < quest->db[index].num_objectives; i++ ) { - WFIFOL(fd, i*30+17) = quest->db[index].mob[i]; + for( i = 0; i < qi->num_objectives; i++ ) { + WFIFOL(fd, i*30+17) = qi->mob[i]; WFIFOW(fd, i*30+21) = qd->count[i]; - monster = mob->db(quest->db[index].mob[i]); - memcpy(WFIFOP(fd, i*30+23), monster?monster->jname:"NULL", NAME_LENGTH); + monster = mob->db(qi->mob[i]); + memcpy(WFIFOP(fd, i*30+23), monster->jname, NAME_LENGTH); } WFIFOSET(fd, packet_len(0x2b3)); @@ -15652,8 +15805,7 @@ void clif_quest_add(struct map_session_data * sd, struct quest * qd, int index) /// Notification about a quest being removed (ZC_DEL_QUEST). /// 02b4 <quest id>.L -void clif_quest_delete(struct map_session_data * sd, int quest_id) -{ +void clif_quest_delete(struct map_session_data *sd, int quest_id) { int fd = sd->fd; WFIFOHEAD(fd, packet_len(0x2b4)); @@ -15665,21 +15817,21 @@ void clif_quest_delete(struct map_session_data * sd, int quest_id) /// Notification of an update to the hunting mission counter (ZC_UPDATE_MISSION_HUNT). /// 02b5 <packet len>.W <mobs>.W { <quest id>.L <mob id>.L <total count>.W <current count>.W }*3 -void clif_quest_update_objective(struct map_session_data * sd, struct quest * qd, int index) -{ +void clif_quest_update_objective(struct map_session_data *sd, struct quest *qd) { int fd = sd->fd; int i; - int len = quest->db[index].num_objectives*12+6; + struct quest_db *qi = quest->db(qd->quest_id); + int len = qi->num_objectives*12+6; WFIFOHEAD(fd, len); WFIFOW(fd, 0) = 0x2b5; WFIFOW(fd, 2) = len; - WFIFOW(fd, 4) = quest->db[index].num_objectives; + WFIFOW(fd, 4) = qi->num_objectives; - for( i = 0; i < quest->db[index].num_objectives; i++ ) { + for( i = 0; i < qi->num_objectives; i++ ) { WFIFOL(fd, i*12+6) = qd->quest_id; - WFIFOL(fd, i*12+10) = quest->db[index].mob[i]; - WFIFOW(fd, i*12+14) = quest->db[index].count[i]; + WFIFOL(fd, i*12+10) = qi->mob[i]; + WFIFOW(fd, i*12+14) = qi->count[i]; WFIFOW(fd, i*12+16) = qd->count[i]; } @@ -15689,16 +15841,14 @@ void clif_quest_update_objective(struct map_session_data * sd, struct quest * qd /// Request to change the state of a quest (CZ_ACTIVE_QUEST). /// 02b6 <quest id>.L <active>.B -void clif_parse_questStateAck(int fd, struct map_session_data * sd) -{ +void clif_parse_questStateAck(int fd, struct map_session_data *sd) { quest->update_status(sd, RFIFOL(fd,2), RFIFOB(fd,6)?Q_ACTIVE:Q_INACTIVE); } /// Notification about the change of a quest state (ZC_ACTIVE_QUEST). /// 02b7 <quest id>.L <active>.B -void clif_quest_update_status(struct map_session_data * sd, int quest_id, bool active) -{ +void clif_quest_update_status(struct map_session_data *sd, int quest_id, bool active) { int fd = sd->fd; WFIFOHEAD(fd, packet_len(0x2b7)); @@ -16010,7 +16160,7 @@ void clif_bg_xy_remove(struct map_session_data *sd) /// Notifies clients of a battleground message (ZC_BATTLEFIELD_CHAT). /// 02dc <packet len>.W <account id>.L <name>.24B <message>.?B -void clif_bg_message(struct battleground_data *bgd, int src_id, const char *name, const char *mes, int len) +void clif_bg_message(struct battleground_data *bgd, int src_id, const char *name, const char *mes, size_t len) { struct map_session_data *sd; unsigned char *buf; @@ -16039,15 +16189,15 @@ void clif_parse_BattleChat(int fd, struct map_session_data* sd) int textlen = RFIFOW(fd,2) - 4; char *name, *message; - int namelen, messagelen; + size_t namelen, messagelen; if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if( atcommand->parse(fd, sd, message, 1) ) + if( atcommand->exec(fd, sd, message, true) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) { @@ -16056,6 +16206,9 @@ void clif_parse_BattleChat(int fd, struct map_session_data* sd) sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } + if( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + bg->send_message(sd, text, textlen); } @@ -16124,7 +16277,7 @@ void clif_font(struct map_session_data *sd) nullpo_retv(sd); WBUFW(buf,0) = 0x2ef; WBUFL(buf,2) = sd->bl.id; - WBUFW(buf,6) = sd->user_font; + WBUFW(buf,6) = sd->status.font; clif->send(buf, packet_len(0x2ef), &sd->bl, AREA); #endif } @@ -16137,7 +16290,7 @@ int clif_instance(int instance_id, int type, int flag) { struct map_session_data *sd = NULL; unsigned char buf[255]; enum send_target target = PARTY; - + switch( instance->list[instance_id].owner_type ) { case IOT_NONE: return 0; @@ -16157,7 +16310,7 @@ int clif_instance(int instance_id, int type, int flag) { if( !sd ) return 0; - + switch( type ) { case 1: // S 0x2cb <Instance name>.61B <Standby Position>.W @@ -16914,7 +17067,7 @@ void clif_parse_debug(int fd,struct map_session_data *sd) { } ShowDebug("Packet debug of 0x%04X (length %d), %s session #%d, %d/%d (AID/CID)\n", cmd, packet_len, sd->state.active ? "authed" : "unauthed", fd, sd->status.account_id, sd->status.char_id); } else { - packet_len = RFIFOREST(fd); + packet_len = (int)RFIFOREST(fd); ShowDebug("Packet debug of 0x%04X (length %d), session #%d\n", cmd, packet_len, fd); } @@ -16956,15 +17109,15 @@ int clif_elementalconverter_list(struct map_session_data *sd) { /** * Rune Knight **/ -void clif_millenniumshield(struct map_session_data *sd, short shields ) { +void clif_millenniumshield(struct block_list *bl, short shields ) { #if PACKETVER >= 20081217 unsigned char buf[10]; WBUFW(buf,0) = 0x440; - WBUFL(buf,2) = sd->bl.id; + WBUFL(buf,2) = bl->id; WBUFW(buf,6) = shields; WBUFW(buf,8) = 0; - clif->send(buf,packet_len(0x440),&sd->bl,AREA); + clif->send(buf,packet_len(0x440),bl,AREA); #endif } /** @@ -17226,82 +17379,68 @@ void clif_parse_MoveItem(int fd, struct map_session_data *sd) { /* [Ind/Hercules] */ void clif_cashshop_db(void) { config_t cashshop_conf; - config_setting_t *cashshop = NULL; + config_setting_t *cashshop = NULL, *cats = NULL; const char *config_filename = "db/cashshop_db.conf"; // FIXME hardcoded name - int i; + int i, item_count_t = 0; for( i = 0; i < CASHSHOP_TAB_MAX; i++ ) { CREATE(clif->cs.data[i], struct hCSData *, 1); clif->cs.item_count[i] = 0; } - - if (conf_read_file(&cashshop_conf, config_filename)) { + + if (libconfig->read_file(&cashshop_conf, config_filename)) { ShowError("can't read %s\n", config_filename); return; } - - cashshop = config_lookup(&cashshop_conf, "cash_shop"); - - if (cashshop != NULL) { - config_setting_t *cats = config_setting_get_elem(cashshop, 0); - config_setting_t *cat; - int k, item_count_t = 0; - + + cashshop = libconfig->lookup(&cashshop_conf, "cash_shop"); + + if( cashshop != NULL && (cats = libconfig->setting_get_elem(cashshop, 0)) != NULL ) { for(i = 0; i < CASHSHOP_TAB_MAX; i++) { + config_setting_t *cat; char entry_name[10]; - + sprintf(entry_name,"cat_%d",i); - - if( (cat = config_setting_get_member(cats, entry_name)) != NULL ) { - int item_count = config_setting_length(cat); - - if( item_count == 0 ) { - ShowWarning("cashshop_db: category '%s' is empty! adding dull apple!\n", entry_name); - RECREATE(clif->cs.data[i], struct hCSData *, ++clif->cs.item_count[i]); - CREATE(clif->cs.data[i][ clif->cs.item_count[i] - 1 ], struct hCSData , 1); - - clif->cs.data[i][ clif->cs.item_count[i] - 1 ]->id = UNKNOWN_ITEM_ID; - clif->cs.data[i][ clif->cs.item_count[i] - 1 ]->price = 999; - } else { - for(k = 0; k < item_count; k++) { - config_setting_t *entry = config_setting_get_elem(cat,k); - const char *name = config_setting_name(entry); - int price = config_setting_get_int(entry); - struct item_data * data = NULL; - - if( price < 1 ) { - ShowWarning("cashshop_db: unsupported price '%d' for entry named '%s' in category '%s'\n", price, name, entry_name); + + if( (cat = libconfig->setting_get_member(cats, entry_name)) != NULL ) { + int k, item_count = libconfig->setting_length(cat); + + for(k = 0; k < item_count; k++) { + config_setting_t *entry = libconfig->setting_get_elem(cat,k); + const char *name = config_setting_name(entry); + int price = libconfig->setting_get_int(entry); + struct item_data * data = NULL; + + if( price < 1 ) { + ShowWarning("cashshop_db: unsupported price '%d' for entry named '%s' in category '%s'\n", price, name, entry_name); + continue; + } + + if( name[0] == 'I' && name[1] == 'D' && strlen(name) <= 7 ) { + if( !( data = itemdb->exists(atoi(name+2))) ) { + ShowWarning("cashshop_db: unknown item id '%s' in category '%s'\n", name+2, entry_name); continue; } - - if( name[0] == 'I' && name[1] == 'D' && strlen(name) <= 7 ) { - if( !( data = itemdb->exists(atoi(name+2))) ) { - ShowWarning("cashshop_db: unknown item id '%s' in category '%s'\n", name+2, entry_name); - continue; - } - } else { - if( !( data = itemdb->search_name(name) ) ) { - ShowWarning("cashshop_db: unknown item name '%s' in category '%s'\n", name, entry_name); - continue; - } + } else { + if( !( data = itemdb->search_name(name) ) ) { + ShowWarning("cashshop_db: unknown item name '%s' in category '%s'\n", name, entry_name); + continue; } - - - RECREATE(clif->cs.data[i], struct hCSData *, ++clif->cs.item_count[i]); - CREATE(clif->cs.data[i][ clif->cs.item_count[i] - 1 ], struct hCSData , 1); - - clif->cs.data[i][ clif->cs.item_count[i] - 1 ]->id = data->nameid; - clif->cs.data[i][ clif->cs.item_count[i] - 1 ]->price = price; - item_count_t++; } + + + RECREATE(clif->cs.data[i], struct hCSData *, ++clif->cs.item_count[i]); + CREATE(clif->cs.data[i][ clif->cs.item_count[i] - 1 ], struct hCSData , 1); + + clif->cs.data[i][ clif->cs.item_count[i] - 1 ]->id = data->nameid; + clif->cs.data[i][ clif->cs.item_count[i] - 1 ]->price = price; + item_count_t++; } - } else { - ShowError("cashshop_db: category '%s' (%d) not found!!\n",entry_name,i); } } - - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", item_count_t, config_filename); - config_destroy(&cashshop_conf); + + libconfig->destroy(&cashshop_conf); } + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", item_count_t, config_filename); } /// Items that are in favorite tab of inventory (ZC_ITEM_FAVORITE). /// 0900 <index>.W <favorite>.B @@ -17328,12 +17467,12 @@ void clif_snap( struct block_list *bl, short x, short y ) { void clif_monster_hp_bar( struct mob_data* md, struct map_session_data *sd ) { struct packet_monster_hp p; - + p.PacketType = monsterhpType; p.GID = md->bl.id; p.HP = md->status.hp; p.MaxHP = md->status.max_hp; - + clif->send(&p,sizeof(p),&sd->bl,SELF); } /* [Ind/Hercules] placeholder for unsupported incoming packets (avoids server disconnecting client) */ @@ -17341,6 +17480,12 @@ void __attribute__ ((unused)) clif_parse_dull(int fd,struct map_session_data *sd return; } void clif_parse_CashShopOpen(int fd, struct map_session_data *sd) { + + if( map->list[sd->bl.m].flag.nocashshop ) { + clif->colormes(fd,COLOR_RED,msg_txt(1489)); //Cash Shop is disabled in this map + return; + } + WFIFOHEAD(fd, 10); WFIFOW(fd, 0) = 0x845; WFIFOL(fd, 2) = sd->cashPoints; //[Ryuuzaki] - switched positions to reflect proper values @@ -17354,19 +17499,22 @@ void clif_parse_CashShopClose(int fd, struct map_session_data *sd) { void clif_parse_CashShopSchedule(int fd, struct map_session_data *sd) { int i, j = 0; - + for( i = 0; i < CASHSHOP_TAB_MAX; i++ ) { + 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; - + 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; } - + WFIFOSET(fd, 8 + ( clif->cs.item_count[i] * 6 )); } } @@ -17374,15 +17522,20 @@ void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) { unsigned short limit = RFIFOW(fd, 4), i, j; unsigned int kafra_pay = RFIFOL(fd, 6);// [Ryuuzaki] - These are free cash points (strangely #CASH = main cash curreny for us, confusing) + if( map->list[sd->bl.m].flag.nocashshop ) { + clif->colormes(fd,COLOR_RED,msg_txt(1489)); //Cash Shop is disabled in this map + return; + } + for(i = 0; i < limit; i++) { int qty = RFIFOL(fd, 14 + ( i * 10 )); int id = RFIFOL(fd, 10 + ( i * 10 )); short tab = RFIFOW(fd, 18 + ( i * 10 )); enum CASH_SHOP_BUY_RESULT result = CSBR_UNKNOWN; - + if( tab < 0 || tab > CASHSHOP_TAB_MAX ) continue; - + for( j = 0; j < clif->cs.item_count[tab]; j++ ) { if( clif->cs.data[tab][j]->id == id ) break; @@ -17398,19 +17551,19 @@ void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) { } else { struct item item_tmp; int k, get_count; - + get_count = qty; - + if (!itemdb->isstackable2(data)) get_count = 1; - + pc->paycash(sd, clif->cs.data[tab][j]->price * qty, kafra_pay);// [Ryuuzaki] for (k = 0; k < qty; k += get_count) { if (!pet->create_egg(sd, data->nameid)) { memset(&item_tmp, 0, sizeof(item_tmp)); item_tmp.nameid = data->nameid; item_tmp.identify = 1; - + switch (pc->additem(sd, &item_tmp, get_count, LOG_TYPE_NPC)) { case 0: result = CSBR_SUCCESS; @@ -17431,16 +17584,17 @@ void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) { result = CSBR_RUNE_OVERCOUNT; break; } - + if( result != CSBR_SUCCESS ) pc->getcash(sd, clif->cs.data[tab][j]->price * get_count,0); - } + } else /* create_egg succeeded so mark as success */ + result = CSBR_SUCCESS; } } } else { result = CSBR_UNKONWN_ITEM; } - + WFIFOHEAD(fd, 16); WFIFOW(fd, 0) = 0x849; WFIFOL(fd, 2) = id; @@ -17456,7 +17610,7 @@ void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd) { short tab = RFIFOW(fd, 2); int j; - if( tab < 0 || tab > CASHSHOP_TAB_MAX ) + if( tab < 0 || tab > CASHSHOP_TAB_MAX || clif->cs.item_count[tab] == 0 ) return; WFIFOHEAD(fd, 10 + ( clif->cs.item_count[tab] * 6 ) ); @@ -17464,19 +17618,19 @@ void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd) { WFIFOW(fd, 2) = 10 + ( clif->cs.item_count[tab] * 6 ); WFIFOL(fd, 4) = tab; WFIFOW(fd, 8) = clif->cs.item_count[tab]; - + for( j = 0; j < clif->cs.item_count[tab]; j++ ) { WFIFOW(fd, 10 + ( 6 * j ) ) = clif->cs.data[tab][j]->id; WFIFOL(fd, 12 + ( 6 * j ) ) = clif->cs.data[tab][j]->price; } - + WFIFOSET(fd, 10 + ( clif->cs.item_count[tab] * 6 )); } /* [Ind/Hercules] */ void clif_maptypeproperty2(struct block_list *bl,enum send_target t) { #if PACKETVER >= 20121010 struct packet_maptypeproperty2 p; - + p.PacketType = maptypeproperty2Type; p.type = 0x28; p.flag.party = map->list[bl->m].flag.pvp ? 1 : 0; @@ -17491,14 +17645,14 @@ void clif_maptypeproperty2(struct block_list *bl,enum send_target t) { p.flag.summonstarmiracle = 0; // TODO p.flag.usecart = 1; // TODO p.flag.SpareBits = 0; - + clif->send(&p,sizeof(p),bl,t); #endif } void clif_status_change2(struct block_list *bl, int tid, enum send_target target, int type, int val1, int val2, int val3) { struct packet_status_change2 p; - + p.PacketType = status_change2Type; p.index = type; p.AID = tid; @@ -17507,29 +17661,51 @@ void clif_status_change2(struct block_list *bl, int tid, enum send_target target p.val1 = val1; p.val2 = val2; p.val3 = val3; - + clif->send(&p,sizeof(p), bl, target); } void clif_partytickack(struct map_session_data* sd, bool flag) { - + WFIFOHEAD(sd->fd, packet_len(0x2c9)); WFIFOW(sd->fd, 0) = 0x2c9; WFIFOB(sd->fd, 2) = flag; WFIFOSET(sd->fd, packet_len(0x2c9)); } +void clif_ShowScript(struct block_list* bl, const char* message) { + char buf[256]; + size_t len; + nullpo_retv(bl); + + if(!message) + return; + + len = strlen(message)+1; + + if( len > sizeof(buf)-8 ) { + ShowWarning("clif_ShowScript: Truncating too long message '%s' (len=%d).\n", message, len); + len = sizeof(buf)-8; + } + + WBUFW(buf,0)=0x8b3; + WBUFW(buf,2)=len+8; + WBUFL(buf,4)=bl->id; + safestrncpy((char *) WBUFP(buf,8),message,len); + clif->send((unsigned char *) buf,WBUFW(buf,2),bl,ALL_CLIENT); +} + void clif_status_change_end(struct block_list *bl, int tid, enum send_target target, int type) { struct packet_status_change_end p; - + if( bl->type == BL_PC && !((TBL_PC*)bl)->state.active ) return; - + p.PacketType = status_change_endType; p.index = type; p.AID = tid; p.state = 0; - + clif->send(&p,sizeof(p), bl, target); } @@ -17541,11 +17717,11 @@ void clif_bgqueue_ack(struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_ACK break; default: { struct packet_bgqueue_ack p; - + p.PacketType = bgqueue_ackType; p.type = response; safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name)); - + clif->send(&p,sizeof(p), &sd->bl, SELF); } break; @@ -17555,11 +17731,11 @@ void clif_bgqueue_ack(struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_ACK void clif_bgqueue_notice_delete(struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED response, char *name) { struct packet_bgqueue_notice_delete p; - + p.PacketType = bgqueue_notice_deleteType; p.type = response; safestrncpy(p.bg_name, name, sizeof(p.bg_name)); - + clif->send(&p,sizeof(p), &sd->bl, SELF); } @@ -17567,14 +17743,12 @@ void clif_parse_bgqueue_register(int fd, struct map_session_data *sd) { struct packet_bgqueue_register *p = P2PTR(fd); struct bg_arena *arena = NULL; if( !bg->queue_on ) return; /* temp, until feature is complete */ - + if( !(arena = bg->name2arena(p->bg_name)) ) { clif->bgqueue_ack(sd,BGQA_FAIL_BGNAME_INVALID,0); return; } - //debug - safestrncpy(arena->name, p->bg_name, sizeof(arena->name)); - + switch( (enum bg_queue_types)p->type ) { case BGQT_INDIVIDUAL: case BGQT_PARTY: @@ -17584,19 +17758,19 @@ void clif_parse_bgqueue_register(int fd, struct map_session_data *sd) { clif->bgqueue_ack(sd,BGQA_FAIL_TYPE_INVALID, arena->id); return; } - + bg->queue_add(sd, arena, (enum bg_queue_types)p->type); } void clif_bgqueue_update_info(struct map_session_data *sd, unsigned char arena_id, int position) { struct packet_bgqueue_update_info p; - + p.PacketType = bgqueue_updateinfoType; safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name)); p.position = position; - + sd->bg_queue.client_has_bg_data = true; // Client creates bg data when this packet arrives - + clif->send(&p,sizeof(p), &sd->bl, SELF); } @@ -17623,7 +17797,7 @@ void clif_parse_bgqueue_battlebegin_ack(int fd, struct map_session_data *sd) { struct bg_arena *arena; if( !bg->queue_on ) return; /* temp, until feature is complete */ - + if( ( arena = bg->name2arena(p->bg_name) ) ) { bg->queue_ready_ack(arena,sd, ( p->result == 1 ) ? true : false); } else { @@ -17633,7 +17807,7 @@ void clif_parse_bgqueue_battlebegin_ack(int fd, struct map_session_data *sd) { void clif_bgqueue_joined(struct map_session_data *sd, int pos) { struct packet_bgqueue_notify_entry p; - + p.PacketType = bgqueue_notify_entryType; safestrncpy(p.name,sd->status.name,sizeof(p.name)); p.position = pos; @@ -17649,26 +17823,26 @@ void clif_bgqueue_pcleft(struct map_session_data *sd) { // Sends BG ready req to all with same bg arena/type as sd void clif_bgqueue_battlebegins(struct map_session_data *sd, unsigned char arena_id, enum send_target target) { struct packet_bgqueue_battlebegins p; - - p.PacketType = bgqueue_battlebegins; + + p.PacketType = bgqueue_battlebeginsType; safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name)); safestrncpy(p.game_name, bg->arena[arena_id]->name, sizeof(p.game_name)); - + clif->send(&p,sizeof(p), &sd->bl, target); } void clif_scriptclear(struct map_session_data *sd, int npcid) { struct packet_script_clear p; - + p.PacketType = script_clearType; p.NpcID = npcid; - + clif->send(&p,sizeof(p), &sd->bl, SELF); } /* Made Possible Thanks to Yommy! */ void clif_package_item_announce(struct map_session_data *sd, unsigned short nameid, unsigned short containerid) { struct packet_package_item_announce p; - + p.PacketType = package_item_announceType; p.PacketLength = 11+NAME_LENGTH; p.type = 0x0; @@ -17677,7 +17851,22 @@ void clif_package_item_announce(struct map_session_data *sd, unsigned short name safestrncpy(p.Name, sd->status.name, sizeof(p.Name)); p.unknown = 0x2; // some strange byte, IDA shows.. BYTE3(BoxItemIDLength) = 2; p.BoxItemID = containerid; - + + clif->send(&p,sizeof(p), &sd->bl, ALL_CLIENT); +} +/* Made Possible Thanks to Yommy! */ +void clif_item_drop_announce(struct map_session_data *sd, unsigned short nameid, char *monsterName) { + struct packet_item_drop_announce p; + + p.PacketType = item_drop_announceType; + p.PacketLength = sizeof(p); + p.type = 0x1; + p.ItemID = nameid; + 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); } /* [Ind/Hercules] special thanks to Yommy~! */ @@ -17688,7 +17877,7 @@ void clif_skill_cooldown_list(int fd, struct skill_cd* cd) { const int offset = 6; #endif int i, count = 0; - + WFIFOHEAD(fd,4+(offset*cd->cursor)); #if PACKETVER >= 20120604 @@ -17696,19 +17885,20 @@ void clif_skill_cooldown_list(int fd, struct skill_cd* cd) { #else WFIFOW(fd,0) = 0x43e; #endif - + for( i = 0; i < cd->cursor; i++ ) { if( cd->entry[i]->duration < 1 ) continue; - - WFIFOW(fd, 4 + (count*offset)) = cd->entry[i]->skill_id; - WFIFOL(fd, 6 + (count*offset)) = cd->entry[i]->duration; + + WFIFOW(fd, 4 + (count*offset)) = cd->entry[i]->skill_id; #if PACKETVER >= 20120604 + WFIFOL(fd, 6 + (count*offset)) = cd->entry[i]->total; WFIFOL(fd, 10 + (count*offset)) = cd->entry[i]->duration; +#else + WFIFOL(fd, 6 + (count*offset)) = cd->entry[i]->duration; #endif - count++; } - + WFIFOW(fd,2) = 4+(offset*count); WFIFOSET(fd,4+(offset*count)); @@ -17719,12 +17909,278 @@ void clif_skill_cooldown_list(int fd, struct skill_cd* cd) { */ void clif_cart_additem_ack(struct map_session_data *sd, int flag) { struct packet_cart_additem_ack p; - + p.PacketType = cart_additem_ackType; p.result = (char)flag; - + + clif->send(&p,sizeof(p), &sd->bl, SELF); +} +/* Bank System [Yommy/Hercules] */ +void clif_parse_BankDeposit(int fd, struct map_session_data* sd) { + struct packet_banking_deposit_req *p = P2PTR(fd); + int money; + + if( !battle_config.feature_banking ) { + clif->colormes(fd,COLOR_RED,msg_txt(1483)); + return; + } + + money = (int)cap_value(p->Money,0,INT_MAX); + + pc->bank_deposit(sd,money); +} + +void clif_parse_BankWithdraw(int fd, struct map_session_data* sd) { + struct packet_banking_withdraw_req *p = P2PTR(fd); + int money; + + if( !battle_config.feature_banking ) { + clif->colormes(fd,COLOR_RED,msg_txt(1483)); + return; + } + + money = (int)cap_value(p->Money,0,INT_MAX); + + pc->bank_withdraw(sd,money); +} + +void clif_parse_BankCheck(int fd, struct map_session_data* sd) { + struct packet_banking_check p; + + if( !battle_config.feature_banking ) { + clif->colormes(fd,COLOR_RED,msg_txt(1483)); + return; + } + + p.PacketType = banking_checkType; + p.Money = (int)sd->status.bank_vault; + p.Reason = (short)0; + + clif->send(&p,sizeof(p), &sd->bl, SELF); +} + +void clif_parse_BankOpen(int fd, struct map_session_data* sd) { + return; +} + +void clif_parse_BankClose(int fd, struct map_session_data* sd) { + return; +} + +void clif_bank_deposit(struct map_session_data *sd, enum e_BANKING_DEPOSIT_ACK reason) { + struct packet_banking_deposit_ack p; + + p.PacketType = banking_deposit_ackType; + p.Balance = sd->status.zeny;/* how much zeny char has after operation */ + p.Money = (int64)sd->status.bank_vault;/* money in the bank */ + p.Reason = (short)reason; + + clif->send(&p,sizeof(p), &sd->bl, SELF); +} +void clif_bank_withdraw(struct map_session_data *sd,enum e_BANKING_WITHDRAW_ACK reason) { + struct packet_banking_withdraw_ack p; + + p.PacketType = banking_withdraw_ackType; + p.Balance = sd->status.zeny;/* how much zeny char has after operation */ + p.Money = (int64)sd->status.bank_vault;/* money in the bank */ + p.Reason = (short)reason; + + clif->send(&p,sizeof(p), &sd->bl, SELF); +} +/* TODO: official response packet (tried 0x8cb/0x97b but the display was quite screwed up.) */ +/* currently mimicing */ +void clif_show_modifiers (struct map_session_data *sd) { + + if( sd->status.mod_exp != 100 || sd->status.mod_drop != 100 || sd->status.mod_death != 100 ) { + char output[128]; + + snprintf(output,128,"Base EXP : %d%% | Base Drop: %d%% | Base Death Penalty: %d%%", + sd->status.mod_exp,sd->status.mod_drop,sd->status.mod_death); + clif->broadcast2(&sd->bl,output, strlen(output) + 1, 0xffbc90, 0x190, 12, 0, 0, SELF); + } + +} + +void clif_notify_bounditem(struct map_session_data *sd, unsigned short index) { + struct packet_notify_bounditem p; + + p.PacketType = notify_bounditemType; + p.index = index+2; + clif->send(&p,sizeof(p), &sd->bl, SELF); } + +/** + * Parses the (GM) right click option 'remove all equipment' + **/ +void clif_parse_GMFullStrip(int fd, struct map_session_data *sd) { + struct map_session_data *tsd = map->id2sd(RFIFOL(fd,2)); + int i; + + /* TODO maybe this could be a new permission? using gm level in the meantime */ + if( !tsd || pc_get_group_level(tsd) >= pc_get_group_level(sd) ) + return; + + for( i = 0; i < EQI_MAX; i++ ) { + if( tsd->equip_index[ i ] >= 0 ) + pc->unequipitem( tsd , tsd->equip_index[ i ] , 2 ); + } +} +/** + * clif_delay_damage timer, sends the stored data and clears the memory afterwards + **/ +int clif_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) { + struct cdelayed_damage *dd = (struct cdelayed_damage *)data; + + clif->send(&dd->p,sizeof(struct packet_damage),&dd->bl,AREA_WOS); + + ers_free(clif->delayed_damage_ers,dd); + + return 0; +} +/** + * Delays sending a damage packet in order to avoid the visual display to overlap + * + * @param tick when to trigger the timer (e.g. timer->gettick() + 500) + * @param src block_list pointer of the src + * @param dst block_list pointer of the damage source + * @param sdelay attack motion usually status_get_amotion() + * @param ddelay damage motion usually status_get_dmotion() + * @param in_damage total damage to be sent + * @param div amount of hits + * @param type action type + * + * @return clif->calc_walkdelay used in further processing + **/ +int clif_delay_damage(int64 tick, struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type) { + struct cdelayed_damage *dd; + struct status_change *sc; +#if PACKETVER < 20071113 + short damage; +#else + int damage; +#endif + + nullpo_ret(src); + nullpo_ret(dst); + + sc = status->get_sc(dst); + + if(sc && sc->count && sc->data[SC_ILLUSION]) { + if(in_damage) in_damage = in_damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; + } + +#if PACKETVER < 20071113 + damage = (short)min(in_damage,INT16_MAX); +#else + damage = (int)min(in_damage,INT_MAX); +#endif + + type = clif_calc_delay(type,div,damage,ddelay); + + dd = ers_alloc(clif->delayed_damage_ers, struct cdelayed_damage); + + dd->p.PacketType = damageType; + dd->p.GID = src->id; + dd->p.targetGID = dst->id; + dd->p.startTime = (uint32)timer->gettick(); + dd->p.attackMT = sdelay; + dd->p.attackedMT = ddelay; + dd->p.count = div; + dd->p.action = type; + dd->p.leftDamage = 0; + + if( battle_config.hide_woe_damage && map_flag_gvg2(src->m) ) + dd->p.damage = damage?div:0; + else + dd->p.damage = damage; + + dd->bl.m = dst->m; + dd->bl.x = dst->x; + dd->bl.y = dst->y; + dd->bl.type = BL_NUL; + + if( tick > timer->gettick() ) + timer->add(tick,clif->delay_damage_sub,0,(intptr_t)dd); + else { + clif->send(&dd->p,sizeof(struct packet_damage),&dd->bl,AREA_WOS); + + ers_free(clif->delayed_damage_ers,dd); + } + + return clif->calc_walkdelay(dst,ddelay,type,damage,div); +} +/* Thanks to Yommy */ +void clif_parse_NPCShopClosed(int fd, struct map_session_data *sd) { + /* TODO track the state <3~ */ + sd->npc_shopid = 0; +} +/* NPC Market (by Ind after an extensive debugging of the packet, only possible thanks to Yommy <3) */ +void clif_npc_market_open(struct map_session_data *sd, struct npc_data *nd) { + struct npc_item_list *shop = nd->u.scr.shop->item; + unsigned short shop_size = nd->u.scr.shop->items, i, c; + struct item_data *id = NULL; + + npcmarket_open.PacketType = npcmarketopenType; + + for(i = 0, c = 0; i < shop_size; i++) { + if( shop[i].nameid && (id = itemdb->exists(shop[i].nameid)) ) { + npcmarket_open.list[c].nameid = shop[i].nameid; + npcmarket_open.list[c].price = shop[i].value; + npcmarket_open.list[c].qty = shop[i].qty; + npcmarket_open.list[c].type = itemtype(id->type); + npcmarket_open.list[c].view = ( id->view_id > 0 ) ? id->view_id : id->nameid; + c++; + } + } + + npcmarket_open.PacketLength = 4 + ( sizeof(npcmarket_open.list[0]) * c ); + + clif->send(&npcmarket_open,npcmarket_open.PacketLength,&sd->bl,SELF); +} +void clif_parse_NPCMarketClosed(int fd, struct map_session_data *sd) { + /* TODO track the state <3~ */ + sd->npc_shopid = 0; +} +void clif_npc_market_purchase_ack(struct map_session_data *sd, struct packet_npc_market_purchase *req, unsigned char response) { + unsigned short c = 0; + + npcmarket_result.PacketType = npcmarketresultackType; + npcmarket_result.result = response == 0 ? 1 : 0;/* find other values */ + + if( npcmarket_result.result ) { + unsigned short i, list_size = (req->PacketLength - 4) / sizeof(req->list[0]), j; + struct npc_data* nd; + struct npc_item_list *shop = NULL; + unsigned short shop_size = 0; + + nd = map->id2nd(sd->npc_shopid); + + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + + for(i = 0; i < list_size; i++) { + + npcmarket_result.list[i].ITID = req->list[i].ITID; + npcmarket_result.list[i].qty = req->list[i].qty; + + ARR_FIND( 0, shop_size, j, req->list[i].ITID == shop[j].nameid ); + + npcmarket_result.list[i].price = (j != shop_size) ? shop[j].value : 0; + + c++; + } + } + + npcmarket_result.PacketLength = 5 + ( sizeof(npcmarket_result.list[0]) * c );; + + clif->send(&npcmarket_result,npcmarket_result.PacketLength,&sd->bl,SELF); +} +void clif_parse_NPCMarketPurchase(int fd, struct map_session_data *sd) { + struct packet_npc_market_purchase *p = P2PTR(fd); + + clif->npc_market_purchase_ack(sd,p,npc->market_buylist(sd,(p->PacketLength - 4) / sizeof(p->list[0]),p)); +} /* */ unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) { if( sd ) { @@ -17735,10 +18191,6 @@ unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) { unsigned short clif_parse_cmd_normal( int fd, struct map_session_data *sd ) { unsigned short cmd = RFIFOW(fd,0); - // filter out invalid / unsupported packets - if( cmd > MAX_PACKET_DB || cmd < MIN_PACKET_DB || packet_db[cmd].len == 0 ) - return 0; - return cmd; } unsigned short clif_parse_cmd_decrypt( int fd, struct map_session_data *sd ) { @@ -17746,10 +18198,6 @@ unsigned short clif_parse_cmd_decrypt( int fd, struct map_session_data *sd ) { cmd = clif->decrypt_cmd(cmd, sd); - // filter out invalid / unsupported packets - if( cmd > MAX_PACKET_DB || cmd < MIN_PACKET_DB || packet_db[cmd].len == 0 ) - return 0; - return cmd; } unsigned short clif_parse_cmd_optional( int fd, struct map_session_data *sd ) { @@ -17774,14 +18222,14 @@ int clif_parse(int fd) { int cmd, packet_len; TBL_PC* sd; int pnum; - + //TODO apply delays or disconnect based on packet throughput [FlavioJS] // Note: "click masters" can do 80+ clicks in 10 seconds - + for( pnum = 0; pnum < 3; ++pnum ) { // Limit max packets per cycle to 3 (delay packet spammers) [FlavioJS] -- This actually aids packet spammers, but stuff like /str+ gets slow without it [Ai4rei] unsigned short (*parse_cmd_func)(int fd, struct map_session_data *sd); // begin main client packet processing loop - + sd = (TBL_PC *)session[fd]->session_data; if (session[fd]->flag.eof) { @@ -17807,7 +18255,7 @@ int clif_parse(int fd) { do_close(fd); return 0; } - + if (RFIFOREST(fd) < 2) return 0; @@ -17818,13 +18266,16 @@ int clif_parse(int fd) { if( r == 2 ) return 0; } } - + if( sd ) parse_cmd_func = sd->parse_cmd_func; else parse_cmd_func = clif->parse_cmd; - if( !( cmd = parse_cmd_func(fd,sd) ) ) { + cmd = parse_cmd_func(fd,sd); + + // filter out invalid / unsupported packets + if( cmd > MAX_PACKET_DB || cmd < MIN_PACKET_DB || packet_db[cmd].len == 0 ) { ShowWarning("clif_parse: Received unsupported packet (packet 0x%04x (0x%04x), %d bytes received), disconnecting session #%d.\n", cmd, RFIFOW(fd,0), RFIFOREST(fd), fd); #ifdef DUMP_INVALID_PACKET ShowDump(RFIFOP(fd,0), RFIFOREST(fd)); @@ -17832,13 +18283,13 @@ int clif_parse(int fd) { set_eof(fd); return 0; } - + // determine real packet length if ( ( packet_len = packet_db[cmd].len ) == -1) { // variable-length packet if (RFIFOREST(fd) < 4) return 0; - + packet_len = RFIFOW(fd,2); if (packet_len < 4 || packet_len > 32768) { ShowWarning("clif_parse: Received packet 0x%04x specifies invalid packet_len (%d), disconnecting session #%d.\n", cmd, packet_len, fd); @@ -17876,36 +18327,36 @@ int clif_parse(int fd) { else { const char* packet_txt = "save/packet.txt"; FILE* fp; - + if( ( fp = fopen( packet_txt , "a" ) ) != NULL ) { if( sd ) { fprintf(fp, "Unknown packet 0x%04X (length %d), %s session #%d, %d/%d (AID/CID)\n", cmd, packet_len, sd->state.active ? "authed" : "unauthed", fd, sd->status.account_id, sd->status.char_id); } else { fprintf(fp, "Unknown packet 0x%04X (length %d), session #%d\n", cmd, packet_len, fd); } - + WriteDump(fp, RFIFOP(fd,0), packet_len); fprintf(fp, "\n"); fclose(fp); } else { ShowError("Failed to write '%s'.\n", packet_txt); - + // Dump on console instead if( sd ) { ShowDebug("Unknown packet 0x%04X (length %d), %s session #%d, %d/%d (AID/CID)\n", cmd, packet_len, sd->state.active ? "authed" : "unauthed", fd, sd->status.account_id, sd->status.char_id); } else { ShowDebug("Unknown packet 0x%04X (length %d), session #%d\n", cmd, packet_len, fd); } - + ShowDump(RFIFOP(fd,0), packet_len); } } #endif - + RFIFOSKIP(fd, packet_len); - + }; // main loop end - + return 0; } @@ -17914,43 +18365,44 @@ static void __attribute__ ((unused)) packetdb_addpacket(short cmd, int len, ...) int i; int pos; pFunc func; - + if (cmd > MAX_PACKET_DB) { ShowError("Packet Error: packet 0x%x is greater than the maximum allowed (0x%x), skipping...\n", cmd, MAX_PACKET_DB); return; } - + packet_db[cmd].len = len; - + va_start(va,len); - + pos = va_arg(va, int); - + if( pos == 0xFFFF ) /* nothing more to do */ return; - + va_end(va); va_start(va,len); - + func = va_arg(va,pFunc); - + packet_db[cmd].func = func; - + for (i = 0; i < MAX_PACKET_POS; i++) { pos = va_arg(va, int); - + if (pos == 0xFFFF) break; - + packet_db[cmd].pos[i] = pos; } + va_end(va); } void packetdb_loaddb(void) { - + memset(packet_db,0,sizeof(packet_db)); - #define packet(id, size, ...) packetdb_addpacket(id, size, ##__VA_ARGS__, 0xFFFF) - #define packetKeys(a,b,c) { clif->cryptKey[0] = a; clif->cryptKey[1] = b; clif->cryptKey[2] = c; } + #define packet(id, size, ...) packetdb_addpacket((id), (size), ##__VA_ARGS__, 0xFFFF) + #define packetKeys(a,b,c) do { clif->cryptKey[0] = (a); clif->cryptKey[1] = (b); clif->cryptKey[2] = (c); } while(0) #include "packets.h" /* load structure data */ #undef packet #undef packetKeys @@ -17960,7 +18412,7 @@ void clif_bc_ready(void) { clif->status_change = clif_status_change; else clif->status_change = clif_status_change_notick; - + switch( battle_config.packet_obfuscation ) { case 0: clif->parse_cmd = clif_parse_cmd_normal; @@ -17977,20 +18429,23 @@ void clif_bc_ready(void) { /*========================================== * *------------------------------------------*/ -int do_init_clif(void) { +int do_init_clif(bool minimal) { const char* colors[COLOR_MAX] = { "0xFF0000", "0x00ff00", "0xffffff" }; int i; + if (minimal) + return 0; + /** * Setup Color Table (saves unnecessary load of strtoul on every call) **/ for(i = 0; i < COLOR_MAX; i++) { - color_table[i] = strtoul(colors[i],NULL,0); + color_table[i] = (unsigned int)strtoul(colors[i],NULL,0); color_table[i] = (color_table[i] & 0x0000FF) << 16 | (color_table[i] & 0x00FF00) | (color_table[i] & 0xFF0000) >> 16;//RGB to BGR } - + packetdb_loaddb(); - + set_defaultparse(clif->parse); if( make_listen_bind(clif->bind_ip,clif->map_port) == -1 ) { ShowFatalError("Failed to bind to port '"CL_WHITE"%d"CL_RESET"'\n",clif->map_port); @@ -18001,11 +18456,12 @@ int do_init_clif(void) { timer->add_func_list(clif->delayquit, "clif_delayquit"); clif->delay_clearunit_ers = ers_new(sizeof(struct block_list),"clif.c::delay_clearunit_ers",ERS_OPT_CLEAR); + clif->delayed_damage_ers = ers_new(sizeof(struct cdelayed_damage),"clif.c::delayed_damage_ers",ERS_OPT_CLEAR); clif->channel_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, HCHSYS_NAME_LENGTH); hChSys.ally = hChSys.local = hChSys.irc = hChSys.ally_autojoin = hChSys.local_autojoin = false; clif->chann_config_read(); - + return 0; } @@ -18013,17 +18469,17 @@ void do_final_clif(void) { DBIterator *iter = db_iterator(clif->channel_db); struct hChSysCh *channel; unsigned char i; - + for( channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter) ) { clif->chsys_delete(channel); } - + dbi_destroy(iter); - + for(i = 0; i < hChSys.colors_count; i++) { aFree(hChSys.colors_name[i]); } - + if( hChSys.colors_count ) { aFree(hChSys.colors_name); aFree(hChSys.colors); @@ -18031,7 +18487,8 @@ void do_final_clif(void) { db_destroy(clif->channel_db); ers_destroy(clif->delay_clearunit_ers); - + ers_destroy(clif->delayed_damage_ers); + for(i = 0; i < CASHSHOP_TAB_MAX; i++) { int k; for( k = 0; k < clif->cs.item_count[i]; k++ ) { @@ -18046,6 +18503,8 @@ void clif_defaults(void) { /* vars */ clif->bind_ip = INADDR_ANY; clif->map_port = 5121; + clif->ally_only = false; + clif->delayed_damage_ers = NULL; /* core */ clif->init = do_init_clif; clif->final = do_final_clif; @@ -18085,6 +18544,7 @@ void clif_defaults(void) { clif->cart_additem_ack = clif_cart_additem_ack; clif->cashshop_load = clif_cashshop_db; clif->package_announce = clif_package_item_announce; + clif->item_drop_announce = clif_item_drop_announce; /* unit-related */ clif->clearunit_single = clif_clearunit_single; clif->clearunit_area = clif_clearunit_area; @@ -18099,7 +18559,6 @@ void clif_defaults(void) { clif->changetraplook = clif_changetraplook; clif->refreshlook = clif_refreshlook; clif->class_change = clif_class_change; - clif->skill_setunit = clif_skill_setunit; clif->skill_delunit = clif_skill_delunit; clif->skillunit_update = clif_skillunit_update; clif->clearunit_delayed_sub = clif_clearunit_delayed_sub; @@ -18113,6 +18572,7 @@ void clif_defaults(void) { clif->getareachar_unit = clif_getareachar_unit; clif->clearchar_skillunit = clif_clearchar_skillunit; clif->getareachar = clif_getareachar; + clif->graffiti_entry = clif_graffiti_entry; /* main unit spawn */ clif->spawn = clif_spawn; /* map-related */ @@ -18204,7 +18664,6 @@ void clif_defaults(void) { clif->partytickack = clif_partytickack; clif->equiptickack = clif_equiptickack; clif->viewequip_ack = clif_viewequip_ack; - clif->viewequip_fail = clif_viewequip_fail; clif->equpcheckbox = clif_equpcheckbox; clif->displayexp = clif_displayexp; clif->font = clif_font; @@ -18287,7 +18746,6 @@ void clif_defaults(void) { clif->changechatstatus = clif_changechatstatus; clif->wis_message = clif_wis_message; clif->wis_end = clif_wis_end; - clif->disp_onlyself = clif_disp_onlyself; clif->disp_message = clif_disp_message; clif->broadcast = clif_broadcast; clif->broadcast2 = clif_broadcast2; @@ -18300,11 +18758,13 @@ void clif_defaults(void) { clif->msgtable_num = clif_msgtable_num; clif->message = clif_displaymessage; clif->messageln = clif_displaymessage2; + clif->messages = clif_displaymessage_sprintf; clif->colormes = clif_colormes; clif->process_message = clif_process_message; clif->wisexin = clif_wisexin; clif->wisall = clif_wisall; clif->PMIgnoreList = clif_PMIgnoreList; + clif->ShowScript = clif_ShowScript; /* trade handling */ clif->traderequest = clif_traderequest; clif->tradestart = clif_tradestart; @@ -18369,7 +18829,6 @@ void clif_defaults(void) { clif->guild_emblem_area = clif_guild_emblem_area; clif->guild_notice = clif_guild_notice; clif->guild_message = clif_guild_message; - clif->guild_skillup = clif_guild_skillup; clif->guild_reqalliance = clif_guild_reqalliance; clif->guild_allianceack = clif_guild_allianceack; clif->guild_delalliance = clif_guild_delalliance; @@ -18523,6 +18982,19 @@ void clif_defaults(void) { clif->chsys_quitg = clif_hercules_chsys_quitg; clif->chsys_gjoin = clif_hercules_chsys_gjoin; clif->chsys_gleave = clif_hercules_chsys_gleave; + /* Bank System [Yommy/Hercules] */ + clif->bank_deposit = clif_bank_deposit; + clif->bank_withdraw = clif_bank_withdraw; + /* */ + clif->show_modifiers = clif_show_modifiers; + /* */ + clif->notify_bounditem = clif_notify_bounditem; + /* */ + clif->delay_damage = clif_delay_damage; + clif->delay_damage_sub = clif_delay_damage_sub; + /* NPC Market */ + clif->npc_market_open = clif_npc_market_open; + clif->npc_market_purchase_ack = clif_npc_market_purchase_ack; /*------------------------ *- Parse Incoming Packet *------------------------*/ @@ -18665,6 +19137,7 @@ void clif_defaults(void) { clif->pGMRc = clif_parse_GMRc; clif->pGMReqAccountName = clif_parse_GMReqAccountName; clif->pGMChangeMapType = clif_parse_GMChangeMapType; + clif->pGMFullStrip = clif_parse_GMFullStrip; clif->pPMIgnore = clif_parse_PMIgnore; clif->pPMIgnoreAll = clif_parse_PMIgnoreAll; clif->pPMIgnoreList = clif_parse_PMIgnoreList; @@ -18745,4 +19218,15 @@ void clif_defaults(void) { clif->pPartyBookingReqVolunteer = clif_parse_PartyBookingReqVolunteer; clif->pPartyBookingRefuseVolunteer = clif_parse_PartyBookingRefuseVolunteer; clif->pPartyBookingCancelVolunteer = clif_parse_PartyBookingCancelVolunteer; + /* Bank System [Yommy/Hercules] */ + clif->pBankDeposit = clif_parse_BankDeposit; + clif->pBankWithdraw = clif_parse_BankWithdraw; + clif->pBankCheck = clif_parse_BankCheck; + clif->pBankOpen = clif_parse_BankOpen; + clif->pBankClose = clif_parse_BankClose; + /* */ + clif->pNPCShopClosed = clif_parse_NPCShopClosed; + /* NPC Market */ + clif->pNPCMarketClosed = clif_parse_NPCMarketClosed; + clif->pNPCMarketPurchase = clif_parse_NPCMarketPurchase; } |