/src/map/clif.c
C | 16765 lines | 11831 code | 2253 blank | 2681 comment | 2543 complexity | fbb9af524a00a9cdade18b3f9c85a296 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0
Large files files are truncated, but you can click here to view the full file
- /**
- * This file is part of Hercules.
- * http://herc.ws - http://github.com/HerculesWS/Hercules
- *
- * Copyright (C) 2012-2015 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
- *
- * Hercules is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #define HERCULES_CORE
- #include "config/core.h" // ANTI_MAYAP_CHEAT, RENEWAL, SECURE_NPCTIMEOUT
- #include "clif.h"
- #include "map/atcommand.h"
- #include "map/battle.h"
- #include "map/battleground.h"
- #include "map/channel.h"
- #include "map/chat.h"
- #include "map/chrif.h"
- #include "map/elemental.h"
- #include "map/guild.h"
- #include "map/homunculus.h"
- #include "map/instance.h"
- #include "map/intif.h"
- #include "map/irc-bot.h"
- #include "map/itemdb.h"
- #include "map/log.h"
- #include "map/mail.h"
- #include "map/map.h"
- #include "map/mercenary.h"
- #include "map/mob.h"
- #include "map/npc.h"
- #include "map/party.h"
- #include "map/pc.h"
- #include "map/pet.h"
- #include "map/quest.h"
- #include "map/script.h"
- #include "map/skill.h"
- #include "map/status.h"
- #include "map/storage.h"
- #include "map/trade.h"
- #include "map/unit.h"
- #include "map/vending.h"
- #include "common/HPM.h"
- #include "common/cbasetypes.h"
- #include "common/conf.h"
- #include "common/ers.h"
- #include "common/grfio.h"
- #include "common/memmgr.h"
- #include "common/mmo.h" // NEW_CARTS
- #include "common/nullpo.h"
- #include "common/random.h"
- #include "common/showmsg.h"
- #include "common/socket.h"
- #include "common/strlib.h"
- #include "common/timer.h"
- #include "common/utils.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
- #include <time.h>
- struct clif_interface clif_s;
- struct clif_interface *clif;
- struct s_packet_db packet_db[MAX_PACKET_DB + 1];
- /* 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;
- #if PACKETVER >= 20131223
- static struct packet_npc_market_result_ack npcmarket_result;
- static struct packet_npc_market_open npcmarket_open;
- #endif
- //#define DUMP_UNKNOWN_PACKET
- //#define DUMP_INVALID_PACKET
- //Converts item type in case of pet eggs.
- static inline int itemtype(int 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;
- }
- }
- static inline void WBUFPOS(uint8* p, unsigned short pos, short x, short y, unsigned char dir) {
- p += pos;
- p[0] = (uint8)(x>>2);
- p[1] = (uint8)((x<<6) | ((y>>4)&0x3f));
- p[2] = (uint8)((y<<4) | (dir&0xf));
- }
- // client-side: x0+=sx0*0.0625-0.5 and y0+=sy0*0.0625-0.5
- static inline void WBUFPOS2(uint8* p, unsigned short pos, short x0, short y0, short x1, short y1, unsigned char sx0, unsigned char sy0) {
- p += pos;
- p[0] = (uint8)(x0>>2);
- p[1] = (uint8)((x0<<6) | ((y0>>4)&0x3f));
- p[2] = (uint8)((y0<<4) | ((x1>>6)&0x0f));
- p[3] = (uint8)((x1<<2) | ((y1>>8)&0x03));
- p[4] = (uint8)y1;
- p[5] = (uint8)((sx0<<4) | (sy0&0x0f));
- }
- #if 0 // Currently unused
- static inline void WFIFOPOS(int fd, unsigned short pos, short x, short y, unsigned char dir) {
- WBUFPOS(WFIFOP(fd,pos), 0, x, y, dir);
- }
- #endif // 0
- static inline void WFIFOPOS2(int fd, unsigned short pos, short x0, short y0, short x1, short y1, unsigned char sx0, unsigned char sy0) {
- WBUFPOS2(WFIFOP(fd,pos), 0, x0, y0, x1, y1, sx0, sy0);
- }
- static inline void RBUFPOS(const uint8* p, unsigned short pos, short* x, short* y, unsigned char* dir) {
- p += pos;
- if( x ) {
- x[0] = ( ( p[0] & 0xff ) << 2 ) | ( p[1] >> 6 );
- }
- if( y ) {
- y[0] = ( ( p[1] & 0x3f ) << 4 ) | ( p[2] >> 4 );
- }
- if( dir ) {
- dir[0] = ( p[2] & 0x0f );
- }
- }
- static inline void RFIFOPOS(int fd, unsigned short pos, short* x, short* y, unsigned char* dir) {
- RBUFPOS(RFIFOP(fd,pos), 0, x, y, dir);
- }
- #if 0 // currently unused
- static inline void RBUFPOS2(const uint8* p, unsigned short pos, short* x0, short* y0, short* x1, short* y1, unsigned char* sx0, unsigned char* sy0) {
- p += pos;
- if( x0 ) {
- x0[0] = ( ( p[0] & 0xff ) << 2 ) | ( p[1] >> 6 );
- }
- if( y0 ) {
- y0[0] = ( ( p[1] & 0x3f ) << 4 ) | ( p[2] >> 4 );
- }
- if( x1 ) {
- x1[0] = ( ( p[2] & 0x0f ) << 6 ) | ( p[3] >> 2 );
- }
- if( y1 ) {
- y1[0] = ( ( p[3] & 0x03 ) << 8 ) | ( p[4] >> 0 );
- }
- if( sx0 ) {
- sx0[0] = ( p[5] & 0xf0 ) >> 4;
- }
- if( sy0 ) {
- sy0[0] = ( p[5] & 0x0f ) >> 0;
- }
- }
- static inline void RFIFOPOS2(int fd, unsigned short pos, short* x0, short* y0, short* x1, short* y1, unsigned char* sx0, unsigned char* sy0) {
- RBUFPOS2(WFIFOP(fd,pos), 0, x0, y0, x1, y1, sx0, sy0);
- }
- #endif // 0
- //To identify disguised characters.
- static inline bool disguised(struct block_list* bl)
- {
- struct map_session_data *sd = BL_CAST(BL_PC, bl);
- if (sd == NULL || sd->disguise == -1)
- return false;
- return true;
- }
- //Guarantees that the given string does not exceeds the allowed size, as well as making sure it's null terminated. [Skotlex]
- static inline unsigned int mes_len_check(char* mes, unsigned int len, unsigned int max) {
- nullpo_retr(0, mes);
- if (len <= 0)
- {
- mes[0] = '\0';
- Assert_retr(0, len > 0);
- }
- if( len > max )
- len = max;
- mes[len-1] = '\0';
- return len;
- }
- /*==========================================
- * Ip setting of map-server
- *------------------------------------------*/
- bool clif_setip(const char* ip) {
- char ip_str[16];
- nullpo_retr(false, ip);
- clif->map_ip = sockt->host2ip(ip);
- if ( !clif->map_ip ) {
- ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip);
- 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, sockt->ip2str(clif->map_ip, ip_str));
- return true;
- }
- bool clif_setbindip(const char* ip) {
- nullpo_retr(false, ip);
- clif->bind_ip = sockt->host2ip(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, sockt->ip2str(clif->bind_ip, ip_str));
- return true;
- }
- ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip);
- return false;
- }
- /*==========================================
- * Sets map port to 'port'
- * is run from map.c upon loading map server configuration
- *------------------------------------------*/
- void clif_setport(uint16 port)
- {
- clif->map_port = port;
- }
- /*==========================================
- * Returns map server IP
- *------------------------------------------*/
- uint32 clif_getip(void)
- {
- return clif->map_ip;
- }
- /*==========================================
- * Returns map port which is set by clif_setport()
- *------------------------------------------*/
- uint16 clif_getport(void)
- {
- return clif->map_port;
- }
- /*==========================================
- * Updates server ip resolution and returns it
- *------------------------------------------*/
- uint32 clif_refresh_ip(void)
- {
- uint32 new_ip = sockt->host2ip(clif->map_ip_str);
- 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) {
- nullpo_retr(0x1, bl);
- switch (bl->type) {
- case BL_PC: return (disguised(bl) && !pc->db_checkid(status->get_viewdata(bl)->class_))? 0x1:0x0; //PC_TYPE
- case BL_ITEM: return 0x2; //ITEM_TYPE
- case BL_SKILL: return 0x3; //SKILL_TYPE
- case BL_CHAT: return 0x4; //UNKNOWN_TYPE
- case BL_MOB: return pc->db_checkid(status->get_viewdata(bl)->class_)?0x0:0x5; //NPC_MOB_TYPE
- case BL_NPC: return pc->db_checkid(status->get_viewdata(bl)->class_)?0x0:0x6; //NPC_EVT_TYPE
- case BL_PET: return pc->db_checkid(status->get_viewdata(bl)->class_)?0x0:0x7; //NPC_PET_TYPE
- case BL_HOM: return 0x8; //NPC_HOM_TYPE
- case BL_MER: return 0x9; //NPC_MERSOL_TYPE
- case BL_ELEM: return 0xa; //NPC_ELEMENTAL_TYPE
- default: return 0x1; //NPC_TYPE
- }
- }
- #endif
- /*==========================================
- * sub process of clif_send
- * Called from a map_foreachinarea (grabs all players in specific area and subjects them to this function)
- * In order to send area-wise packets, such as:
- * - AREA : everyone nearby your area
- * - AREA_WOSC (AREA WITHOUT SAME CHAT) : Not run for people in the same chat as yours
- * - AREA_WOC (AREA WITHOUT CHAT) : Not run for people inside a chat
- * - AREA_WOS (AREA WITHOUT SELF) : Not run for self
- * - AREA_CHAT_WOC : Everyone in the area of your chat without a chat
- *------------------------------------------*/
- int clif_send_sub(struct block_list *bl, va_list ap) {
- struct block_list *src_bl;
- struct map_session_data *sd;
- void *buf;
- int len, type, fd;
- nullpo_ret(bl);
- Assert_ret(bl->type == BL_PC);
- sd = BL_UCAST(BL_PC, bl);
- fd = sd->fd;
- if (!fd || sockt->session[fd] == NULL) //Don't send to disconnected clients.
- return 0;
- buf = va_arg(ap,void*);
- len = va_arg(ap,int);
- nullpo_ret(src_bl = va_arg(ap,struct block_list*));
- type = va_arg(ap,int);
- switch(type) {
- case AREA_WOS:
- if (bl == src_bl)
- return 0;
- break;
- case AREA_WOC:
- if (sd->chatID || bl == src_bl)
- return 0;
- break;
- case AREA_WOSC: {
- if (src_bl->type == BL_PC) {
- const struct map_session_data *ssd = BL_UCCAST(BL_PC, src_bl);
- if (ssd != NULL && sd->chatID != 0 && (sd->chatID == ssd->chatID))
- return 0;
- } else if (src_bl->type == BL_NPC) {
- const struct npc_data *nd = BL_UCCAST(BL_NPC, src_bl);
- if (nd != NULL && sd->chatID != 0 && (sd->chatID == nd->chat_id))
- return 0;
- }
- }
- break;
- /* 0x120 crashes the client when warping for this packetver range [Ind/Hercules], thanks to Judas! */
- #if PACKETVER > 20120418 && PACKETVER < 20130000
- case AREA:
- if( WBUFW(buf, 0) == 0x120 && sd->state.warping )
- return 0;
- break;
- #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;
- return clif->send_actual(fd, buf, len);
- }
- int clif_send_actual(int fd, void *buf, int len)
- {
- nullpo_retr(0, buf);
- WFIFOHEAD(fd, len);
- if (WFIFOP(fd,0) == buf) {
- ShowError("WARNING: Invalid use of clif->send function\n");
- ShowError(" Packet x%4x use a WFIFO of a player instead of to use a buffer.\n", WBUFW(buf,0));
- ShowError(" Please correct your code.\n");
- // don't send to not move the pointer of the packet for next sessions in the loop
- //WFIFOSET(fd,0);//## TODO is this ok?
- //NO. It is not ok. There is the chance WFIFOSET actually sends the buffer data, and shifts elements around, which will corrupt the buffer.
- return 0;
- }
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd,len);
- return 0;
- }
- /*==========================================
- * 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
- *------------------------------------------*/
- 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;
- struct guild *g = NULL;
- struct battleground_data *bgd = NULL;
- int x0 = 0, x1 = 0, y0 = 0, y1 = 0, fd;
- struct s_mapiterator* iter;
- if( type != ALL_CLIENT )
- nullpo_ret(bl);
- sd = BL_CAST(BL_PC, bl);
- switch(type) {
- case ALL_CLIENT: //All player clients.
- iter = mapit_getallusers();
- while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
- WFIFOHEAD(tsd->fd, len);
- memcpy(WFIFOP(tsd->fd,0), buf, len);
- WFIFOSET(tsd->fd,len);
- }
- mapit->free(iter);
- break;
- case ALL_SAMEMAP: //All players on the same map
- iter = mapit_getallusers();
- while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
- if (bl && bl->m == tsd->bl.m) {
- WFIFOHEAD(tsd->fd, len);
- memcpy(WFIFOP(tsd->fd,0), buf, len);
- WFIFOSET(tsd->fd,len);
- }
- }
- mapit->free(iter);
- break;
- case AREA:
- case AREA_WOSC:
- if (sd && bl->prev == NULL) //Otherwise source misses the packet.[Skotlex]
- clif->send (buf, len, bl, SELF);
- /* Fall through */
- case AREA_WOC:
- case AREA_WOS:
- nullpo_retr(true, bl);
- map->foreachinarea(clif->send_sub, bl->m, bl->x-AREA_SIZE, bl->y-AREA_SIZE, bl->x+AREA_SIZE, bl->y+AREA_SIZE,
- BL_PC, buf, len, bl, type);
- break;
- case AREA_CHAT_WOC:
- nullpo_retr(true, bl);
- map->foreachinarea(clif->send_sub, bl->m, bl->x-(AREA_SIZE-5), bl->y-(AREA_SIZE-5),
- bl->x+(AREA_SIZE-5), bl->y+(AREA_SIZE-5), BL_PC, buf, len, bl, AREA_WOC);
- break;
- case CHAT:
- case CHAT_WOS:
- nullpo_retr(true, bl);
- {
- const struct chat_data *cd = NULL;
- if (sd != NULL) {
- cd = map->id2cd(sd->chatID);
- } else {
- cd = BL_CCAST(BL_CHAT, bl);
- }
- if (cd == NULL)
- break;
- for(i = 0; i < cd->users; i++) {
- if (type == CHAT_WOS && cd->usersd[i] == sd)
- continue;
- if ((fd=cd->usersd[i]->fd) >0 && sockt->session[fd]) { // Added check to see if session exists [PoW]
- WFIFOHEAD(fd,len);
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd,len);
- }
- }
- }
- break;
- case PARTY_AREA:
- case PARTY_AREA_WOS:
- nullpo_retr(true, bl);
- x0 = bl->x - AREA_SIZE;
- y0 = bl->y - AREA_SIZE;
- x1 = bl->x + AREA_SIZE;
- y1 = bl->y + AREA_SIZE;
- /* Fall through */
- case PARTY:
- case PARTY_WOS:
- case PARTY_SAMEMAP:
- case PARTY_SAMEMAP_WOS:
- if (sd && sd->status.party_id)
- p = party->search(sd->status.party_id);
- if (p) {
- for(i=0;i<MAX_PARTY;i++){
- if( (sd = p->data[i].sd) == NULL )
- continue;
- if( !(fd=sd->fd) )
- continue;
- if( sd->bl.id == bl->id && (type == PARTY_WOS || type == PARTY_SAMEMAP_WOS || type == PARTY_AREA_WOS) )
- continue;
- if( type != PARTY && type != PARTY_WOS && bl->m != sd->bl.m )
- continue;
- if( (type == PARTY_AREA || type == PARTY_AREA_WOS) && (sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1) )
- continue;
- WFIFOHEAD(fd,len);
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd,len);
- }
- if (!map->enable_spy) //Skip unnecessary parsing. [Skotlex]
- break;
- iter = mapit_getallusers();
- while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
- if( tsd->partyspy == p->party.party_id ) {
- WFIFOHEAD(tsd->fd, len);
- memcpy(WFIFOP(tsd->fd,0), buf, len);
- WFIFOSET(tsd->fd,len);
- }
- }
- mapit->free(iter);
- }
- break;
- case DUEL:
- case DUEL_WOS:
- if (!sd || !sd->duel_group) break; //Invalid usage.
- iter = mapit_getallusers();
- while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
- if( type == DUEL_WOS && bl->id == tsd->bl.id )
- continue;
- if( sd->duel_group == tsd->duel_group ) {
- WFIFOHEAD(tsd->fd, len);
- memcpy(WFIFOP(tsd->fd,0), buf, len);
- WFIFOSET(tsd->fd,len);
- }
- }
- mapit->free(iter);
- break;
- case SELF:
- if (sd && (fd=sd->fd) != 0) {
- WFIFOHEAD(fd,len);
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd,len);
- }
- break;
- // New definitions for guilds [Valaris] - Cleaned up and reorganized by [Skotlex]
- case GUILD_AREA:
- case GUILD_AREA_WOS:
- nullpo_retr(true, bl);
- x0 = bl->x - AREA_SIZE;
- y0 = bl->y - AREA_SIZE;
- x1 = bl->x + AREA_SIZE;
- y1 = bl->y + AREA_SIZE;
- /* Fall through */
- case GUILD_SAMEMAP:
- case GUILD_SAMEMAP_WOS:
- case GUILD:
- case GUILD_WOS:
- case GUILD_NOBG:
- if (sd && sd->status.guild_id)
- g = sd->guild;
- if (g) {
- for(i = 0; i < g->max_member; i++) {
- if( (sd = g->member[i].sd) != NULL ) {
- if( !(fd=sd->fd) )
- continue;
- if( type == GUILD_NOBG && sd->bg_id )
- continue;
- if( sd->bl.id == bl->id && (type == GUILD_WOS || type == GUILD_SAMEMAP_WOS || type == GUILD_AREA_WOS) )
- continue;
- if( type != GUILD && type != GUILD_NOBG && type != GUILD_WOS && sd->bl.m != bl->m )
- continue;
- if( (type == GUILD_AREA || type == GUILD_AREA_WOS) && (sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1) )
- continue;
- WFIFOHEAD(fd,len);
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd,len);
- }
- }
- if (!map->enable_spy) //Skip unnecessary parsing. [Skotlex]
- break;
- iter = mapit_getallusers();
- while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
- if( tsd->guildspy == g->guild_id ) {
- WFIFOHEAD(tsd->fd, len);
- memcpy(WFIFOP(tsd->fd,0), buf, len);
- WFIFOSET(tsd->fd,len);
- }
- }
- mapit->free(iter);
- }
- break;
- case BG_AREA:
- case BG_AREA_WOS:
- nullpo_retr(true, bl);
- x0 = bl->x - AREA_SIZE;
- y0 = bl->y - AREA_SIZE;
- x1 = bl->x + AREA_SIZE;
- y1 = bl->y + AREA_SIZE;
- /* Fall through */
- case BG_SAMEMAP:
- case BG_SAMEMAP_WOS:
- case BG:
- case BG_WOS:
- if( sd && sd->bg_id && (bgd = bg->team_search(sd->bg_id)) != NULL ) {
- for( i = 0; i < MAX_BG_MEMBERS; i++ ) {
- if( (sd = bgd->members[i].sd) == NULL || !(fd = sd->fd) )
- continue;
- if( sd->bl.id == bl->id && (type == BG_WOS || type == BG_SAMEMAP_WOS || type == BG_AREA_WOS) )
- continue;
- if( type != BG && type != BG_WOS && sd->bl.m != bl->m )
- continue;
- if( (type == BG_AREA || type == BG_AREA_WOS) && (sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1) )
- continue;
- WFIFOHEAD(fd,len);
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd,len);
- }
- }
- break;
- case BG_QUEUE:
- if( sd && sd->bg_queue.arena ) {
- struct script_queue *queue = script->queue(sd->bg_queue.arena->queue_id);
- for (i = 0; i < VECTOR_LENGTH(queue->entries); i++) {
- struct map_session_data *qsd = map->id2sd(VECTOR_INDEX(queue->entries, i));
- if (qsd != NULL) {
- 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 false;
- }
- return true;
- }
- /// Notifies the client, that it's connection attempt was accepted.
- /// 0073 <start time>.L <position>.3B <x size>.B <y size>.B (ZC_ACCEPT_ENTER)
- /// 02eb <start time>.L <position>.3B <x size>.B <y size>.B <font>.W (ZC_ACCEPT_ENTER2)
- void clif_authok(struct map_session_data *sd)
- {
- struct packet_authok p;
- nullpo_retv(sd);
- p.PacketType = authokType;
- 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->status.font;
- #endif
- #if PACKETVER >= 20141016
- p.sex = sd->status.sex;
- #endif
- clif->send(&p,sizeof(p),&sd->bl,SELF);
- }
- /// Notifies the client, that it's connection attempt was refused (ZC_REFUSE_ENTER).
- /// 0074 <error code>.B
- /// error code:
- /// 0 = client type mismatch
- /// 1 = ID mismatch
- /// 2 = mobile - out of available time
- /// 3 = mobile - already logged in
- /// 4 = mobile - waiting state
- void clif_authrefuse(int fd, uint8 error_code)
- {
- WFIFOHEAD(fd,packet_len(0x74));
- WFIFOW(fd,0) = 0x74;
- WFIFOB(fd,2) = error_code;
- WFIFOSET(fd,packet_len(0x74));
- }
- /// Notifies the client of a ban or forced disconnect (SC_NOTIFY_BAN).
- /// 0081 <error code>.B
- /// error code:
- /// 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]
- /// 4 = server full -> MsgStringTable[264]
- /// 5 = underaged -> MsgStringTable[305]
- /// 8 = Server sill recognizes last connection -> MsgStringTable[441]
- /// 9 = too many connections from this ip -> MsgStringTable[529]
- /// 10 = out of available time paid for -> MsgStringTable[530]
- /// 11 = BAN_PAY_SUSPEND
- /// 12 = BAN_PAY_CHANGE
- /// 13 = BAN_PAY_WRONGIP
- /// 14 = BAN_PAY_PNGAMEROOM
- /// 15 = disconnected by a GM -> if( servicetype == taiwan ) MsgStringTable[579]
- /// 16 = BAN_JAPAN_REFUSE1
- /// 17 = BAN_JAPAN_REFUSE2
- /// 18 = BAN_INFORMATION_REMAINED_ANOTHER_ACCOUNT
- /// 100 = BAN_PC_IP_UNFAIR
- /// 101 = BAN_PC_IP_COUNT_ALL
- /// 102 = BAN_PC_IP_COUNT
- /// 103 = BAN_GRAVITY_MEM_AGREE
- /// 104 = BAN_GAME_MEM_AGREE
- /// 105 = BAN_HAN_VALID
- /// 106 = BAN_PC_IP_LIMIT_ACCESS
- /// 107 = BAN_OVER_CHARACTER_LIST
- /// 108 = BAN_IP_BLOCK
- /// 109 = BAN_INVALID_PWD_CNT
- /// 110 = BAN_NOT_ALLOWED_JOBCLASS
- /// ? = disconnected -> MsgStringTable[3]
- // TODO: type enum
- void clif_authfail_fd(int fd, int type)
- {
- if (!fd || !sockt->session[fd] || sockt->session[fd]->func_parse != clif->parse) //clif_authfail should only be invoked on players!
- return;
- WFIFOHEAD(fd, packet_len(0x81));
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = type;
- WFIFOSET(fd,packet_len(0x81));
- sockt->eof(fd);
- }
- /// Notifies the client, whether it can disconnect and change servers (ZC_RESTART_ACK).
- /// 00b3 <type>.B
- /// type:
- /// 1 = disconnect, char-select
- /// ? = nothing
- void clif_charselectok(int id, uint8 ok) {
- struct map_session_data* sd;
- int fd;
- if ((sd = map->id2sd(id)) == NULL || !sd->fd)
- return;
- fd = sd->fd;
- WFIFOHEAD(fd,packet_len(0xb3));
- WFIFOW(fd,0) = 0xb3;
- WFIFOB(fd,2) = ok;
- WFIFOSET(fd,packet_len(0xb3));
- }
- /// Makes an item appear on the ground.
- /// 009e <id>.L <name id>.W <identified>.B <x>.W <y>.W <subX>.B <subY>.B <amount>.W (ZC_ITEM_FALL_ENTRY)
- /// 084b (ZC_ITEM_FALL_ENTRY4)
- void clif_dropflooritem(struct flooritem_data* fitem) {
- struct packet_dropflooritem p;
- int view;
- nullpo_retv(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 ? 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);
- }
- /// Makes an item disappear from the ground.
- /// 00a1 <id>.L (ZC_ITEM_DISAPPEAR)
- void clif_clearflooritem(struct flooritem_data *fitem, int fd)
- {
- unsigned char buf[16];
- nullpo_retv(fitem);
- WBUFW(buf,0) = 0xa1;
- WBUFL(buf,2) = fitem->bl.id;
- if (fd == 0) {
- clif->send(buf, packet_len(0xa1), &fitem->bl, AREA);
- } else {
- WFIFOHEAD(fd,packet_len(0xa1));
- memcpy(WFIFOP(fd,0), buf, packet_len(0xa1));
- WFIFOSET(fd,packet_len(0xa1));
- }
- }
- /// Makes a unit (char, npc, mob, homun) disappear to one client (ZC_NOTIFY_VANISH).
- /// 0080 <id>.L <type>.B
- /// type:
- /// 0 = out of sight
- /// 1 = died
- /// 2 = logged out
- /// 3 = teleport
- /// 4 = trickdead
- void clif_clearunit_single(int id, clr_type type, int fd)
- {
- WFIFOHEAD(fd, packet_len(0x80));
- WFIFOW(fd,0) = 0x80;
- WFIFOL(fd,2) = id;
- WFIFOB(fd,6) = type;
- WFIFOSET(fd, packet_len(0x80));
- }
- /// Makes a unit (char, npc, mob, homun) disappear to all clients in area (ZC_NOTIFY_VANISH).
- /// 0080 <id>.L <type>.B
- /// type:
- /// 0 = out of sight
- /// 1 = died
- /// 2 = logged out
- /// 3 = teleport
- /// 4 = trickdead
- void clif_clearunit_area(struct block_list* bl, clr_type type)
- {
- unsigned char buf[8];
- nullpo_retv(bl);
- WBUFW(buf,0) = 0x80;
- WBUFL(buf,2) = bl->id;
- WBUFB(buf,6) = type;
- clif->send(buf, packet_len(0x80), bl, type == CLR_DEAD ? AREA : AREA_WOS);
- if(disguised(bl)) {
- WBUFL(buf,2) = -bl->id;
- clif->send(buf, packet_len(0x80), bl, SELF);
- }
- }
- /// 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, 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, int64 tick) {
- struct block_list *tbl;
- nullpo_retv(bl);
- 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)
- {
- nullpo_retv(sd);
- nullpo_retv(rhand);
- nullpo_retv(lhand);
- if(sd->sc.option&OPTION_COSTUME) {
- *rhand = *lhand = 0;
- return;
- }
- #if PACKETVER < 4
- *rhand = sd->status.weapon;
- *lhand = sd->status.shield;
- #else
- if (sd->equip_index[EQI_HAND_R] >= 0 &&
- sd->inventory_data[sd->equip_index[EQI_HAND_R]])
- {
- struct item_data* id = sd->inventory_data[sd->equip_index[EQI_HAND_R]];
- if (id->view_id > 0)
- *rhand = id->view_id;
- else
- *rhand = id->nameid;
- } else
- *rhand = 0;
- if (sd->equip_index[EQI_HAND_L] >= 0 &&
- sd->equip_index[EQI_HAND_L] != sd->equip_index[EQI_HAND_R] &&
- sd->inventory_data[sd->equip_index[EQI_HAND_L]])
- {
- struct item_data* id = sd->inventory_data[sd->equip_index[EQI_HAND_L]];
- if (id->view_id > 0)
- *lhand = id->view_id;
- else
- *lhand = id->nameid;
- } else
- *lhand = 0;
- #endif
- }
- //To make the assignation of the level based on limits clearer/easier. [Skotlex]
- static int clif_setlevel_sub(int lv) {
- if( lv < battle_config.max_lv ) {
- ;
- } else if( lv < battle_config.aura_lv ) {
- lv = battle_config.max_lv - 1;
- } else {
- lv = battle_config.max_lv;
- }
- return lv;
- }
- static int clif_setlevel(struct block_list* bl) {
- int lv = status->get_lv(bl);
- nullpo_retr(0, bl);
- if( battle_config.client_limit_unit_lv&bl->type )
- return clif_setlevel_sub(lv);
- switch( bl->type ) {
- case BL_NPC:
- case BL_PET:
- // npcs and pets do not have level
- return 0;
- }
- return lv;
- }
- /* for 'packetver < 20091103' 0x78 non-pc-looking unit handling */
- void clif_set_unit_idle2(struct block_list* bl, struct map_session_data *tsd, enum send_target target) {
- #if PACKETVER < 20091103
- struct map_session_data* sd;
- struct status_change* sc = status->get_sc(bl);
- struct view_data* vd = status->get_viewdata(bl);
- struct packet_idle_unit2 p;
- int g_id = status->get_guild_id(bl);
- nullpo_retv(bl);
- sd = BL_CAST(BL_PC, bl);
- p.PacketType = idle_unit2Type;
- #if PACKETVER >= 20071106
- p.objecttype = clif_bl_type(bl);
- #endif
- p.GID = bl->id;
- p.speed = status->get_speed(bl);
- p.bodyState = (sc) ? sc->opt1 : 0;
- p.healthState = (sc) ? sc->opt2 : 0;
- p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
- p.job = vd->class_;
- p.head = vd->hair_style;
- p.weapon = vd->weapon;
- p.accessory = vd->head_bottom;
- p.shield = vd->shield;
- p.accessory2 = vd->head_top;
- p.accessory3 = vd->head_mid;
- if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this?
- p.shield = status->get_emblem_id(bl);
- p.accessory2 = GetWord(g_id, 1);
- p.accessory3 = GetWord(g_id, 0);
- }
- p.headpalette = vd->hair_color;
- p.bodypalette = vd->cloth_color;
- p.headDir = (sd)? sd->head_dir : 0;
- p.GUID = g_id;
- 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) ? 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;
- #endif
- }
- /*==========================================
- * Prepares 'unit standing' packet
- *------------------------------------------*/
- void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enum send_target target) {
- struct map_session_data* sd;
- struct status_change* sc = status->get_sc(bl);
- 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( !pc->db_checkid(vd->class_) ) {
- clif->set_unit_idle2(bl,tsd,target);
- return;
- }
- #endif
- sd = BL_CAST(BL_PC, bl);
- p.PacketType = idle_unitType;
- #if PACKETVER >= 20091103
- p.PacketLength = sizeof(p);
- p.objecttype = clif_bl_type(bl);
- #endif
- #if PACKETVER >= 20131223
- p.AID = bl->id;
- p.GID = (sd) ? sd->status.char_id : 0; // CCODE
- #else
- p.GID = bl->id;
- #endif
- p.speed = status->get_speed(bl);
- p.bodyState = (sc) ? sc->opt1 : 0;
- p.healthState = (sc) ? sc->opt2 : 0;
- p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
- p.job = vd->class_;
- p.head = vd->hair_style;
- p.weapon = vd->weapon;
- p.accessory = vd->head_bottom;
- #if PACKETVER < 7
- p.shield = vd->shield;
- #endif
- p.accessory2 = vd->head_top;
- p.accessory3 = vd->head_mid;
- if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this?
- p.accessory = status->get_emblem_id(bl);
- p.accessory2 = GetWord(g_id, 1);
- p.accessory3 = GetWord(g_id, 0);
- }
- p.headpalette = vd->hair_color;
- p.bodypalette = vd->cloth_color;
- p.headDir = (sd)? sd->head_dir : 0;
- #if PACKETVER >= 20101124
- p.robe = vd->robe;
- #endif
- p.GUID = g_id;
- 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) ? 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->status.font : 0;
- #endif
- #if PACKETVER >= 20120221
- if (battle_config.show_monster_hp_bar && bl->type == BL_MOB && status_get_hp(bl) < status_get_max_hp(bl)) {
- const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
- p.maxHP = status_get_max_hp(bl);
- p.HP = status_get_hp(bl);
- p.isBoss = (md->spawn != NULL && md->spawn->state.boss) ? 1 : 0;
- } else {
- p.maxHP = -1;
- p.HP = -1;
- p.isBoss = 0;
- }
- #endif
- #if PACKETVER >= 20150513
- p.body = vd->body_style;
- #endif
- clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target);
- if( disguised(bl) ) {
- #if PACKETVER >= 20091103
- p.objecttype = pc->db_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE
- p.GID = -bl->id;
- #else
- p.GID = -bl->id;
- #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) {
- #if PACKETVER < 20091103
- struct map_session_data* sd;
- struct status_change* sc = status->get_sc(bl);
- struct view_data* vd = status->get_viewdata(bl);
- struct packet_spawn_unit2 p;
- int g_id = status->get_guild_id(bl);
- nullpo_retv(bl);
- sd = BL_CAST(BL_PC, bl);
- p.PacketType = spawn_unit2Type;
- #if PACKETVER >= 20071106
- p.objecttype = clif_bl_type(bl);
- #endif
- p.GID = bl->id;
- p.speed = status->get_speed(bl);
- p.bodyState = (sc) ? sc->opt1 : 0;
- p.healthState = (sc) ? sc->opt2 : 0;
- p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
- p.head = vd->hair_style;
- p.weapon = vd->weapon;
- p.accessory = vd->head_bottom;
- p.job = vd->class_;
- p.shield = vd->shield;
- p.accessory2 = vd->head_top;
- p.accessory3 = vd->head_mid;
- if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this?
- p.shield = status->get_emblem_id(bl);
- p.accessory2 = GetWord(g_id, 1);
- p.accessory3 = GetWord(g_id, 0);
- }
- p.headpalette = vd->hair_color;
- p.bodypalette = vd->cloth_color;
- p.headDir = (sd)? sd->head_dir : 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;
- clif->send(&p,sizeof(p),bl,target);
- #else
- return;
- #endif
- }
- void clif_spawn_unit(struct block_list* bl, enum send_target target) {
- struct map_session_data* sd;
- struct status_change* sc = status->get_sc(bl);
- struct view_data* vd = status->get_viewdata(bl);
- struct packet_spawn_unit p;
- int g_id = status->get_guild_id(bl);
- nullpo_retv(bl);
- #if PACKETVER < 20091103
- if( !pc->db_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);
- p.objecttype = clif_bl_type(bl);
- #endif
- #if PACKETVER >= 20131223
- p.AID = bl->id;
- p.GID = (sd) ? sd->status.char_id : 0; // CCODE
- #else
- p.GID = bl->id;
- #endif
- p.speed = status->get_speed(bl);
- p.bodyState = (sc) ? sc->opt1 : 0;
- p.healthState = (sc) ? sc->opt2 : 0;
- p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
- p.job = vd->class_;
- p.head = vd->hair_style;
- p.weapon = vd->weapon;
- p.accessory = vd->head_bottom;
- #if PACKETVER < 7
- p.shield = vd->shield;
- #endif
- p.accessory2 = vd->head_top;
- p.accessory3 = vd->head_mid;
- if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this?
- p.accessory = status->get_emblem_id(bl);
- p.accessory2 = GetWord(g_id, 1);
- p.accessory3 = GetWord(g_id, 0);
- }
- p.headpalette = vd->hair_color;
- p.bodypalette = vd->cloth_color;
- p.headDir = (sd)? sd->head_dir : 0;
- #if PACKETVER >= 20101124
- p.robe = vd->robe;
- #endif
- p.GUID = g_id;
- 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) ? 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->status.font : 0;
- #endif
- #if PACKETVER >= 20120221
- if (battle_config.show_monster_hp_bar && bl->type == BL_MOB && status_get_hp(bl) < status_get_max_hp(bl)) {
- const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
- p.maxHP = status_get_max_hp(bl);
- p.HP = status_get_hp(bl);
- p.isBoss = (md->spawn != NULL && md->spawn->state.boss) ? 1 : 0;
- } else {
- p.maxHP = -1;
- p.HP = -1;
- p.isBoss = 0;
- }
- #endif
- #if PACKETVER >= 20150513
- p.body = vd->body_style;
- #endif
- if( disguised(bl) ) {
- nullpo_retv(sd);
- if( sd->status.class_ != sd->disguise )
- clif->send(&p,sizeof(p),bl,target);
- #if PACKETVER >= 20091103
- p.objecttype = pc->db_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE
- p.GID = -bl->id;
- #else
- p.GID = -bl->id;
- #endif
- clif->send(&p,sizeof(p),bl,SELF);
- } else
- clif->send(&p,sizeof(p),bl,target);
- }
- /*==========================================
- * Prepares 'unit walking' packet
- *------------------------------------------*/
- void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, struct unit_data* ud, enum send_target target) {
- struct map_session_data* sd;
- struct status_change* sc = status->get_sc(bl);
- struct view_data* vd = status->get_viewdata(bl);
- struct packet_unit_walking p;
- int g_id = status->get_guild_id(bl);
- nullpo_retv(bl);
- nullpo_retv(ud);
- sd = BL_CAST(BL_PC, bl);
- p.PacketType = unit_walkingType;
- #if PACKETVER >= 20091103
- p.PacketLength = sizeof(p);
- #endif
- #if PACKETVER >= 20071106
- p.objecttype = clif_bl_type(bl);
- #endif
- #if PACKETVER >= 20131223
- p.AID = bl->id;
- p.GID = (tsd) ? tsd->status.char_id : 0; // CCODE
- #else
- p.GID = bl->id;
- #endif
- p.speed = status->get_speed(bl);
- p.bodyState = (sc) ? sc->opt1 : 0;
- p.healthState = (sc) ? sc->opt2 : 0;
- p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
- p.job = vd->class_;
- p.head = vd->hair_style;
- p.weapon = vd->weapon;
- p.accessory = vd->head_bottom;
- p.moveStartTime = (unsigned int)timer->gettick();
- #if PACKETVER < 7
- p.shield = vd->shield;
- #endif
- p.accessory2 = vd->head_top;
- p.accessory3 = vd->head_mid;
- p.headpalette = vd->hair_color;
- p.bodypalette = vd->cloth_color;
- p.headDir = (sd)? sd->head_dir : 0;
- #if PACKETVER >= 20101124
- p.robe = vd->robe;
- #endif
- p.GUID = g_id;
- 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) ? 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->status.font : 0;
- #endif
- #if PACKETVER >= 20120221
- if (battle_config.show_monster_hp_bar && bl->type == BL_MOB && status_get_hp(bl) < status_get_max_hp(bl)) {
- const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
- p.maxHP = status_get_max_hp(bl);
- p.HP = status_get_hp(bl);
- p.isBoss = (md->spawn != NULL && md->spawn->state.boss) ? 1 : 0;
- } else {
- p.maxHP = -1;
- p.HP = -1;
- p.isBoss = 0;
- }
- #endif
- #if PACKETVER >= 20150513
- p.body = vd->body_style;
- #endif
- clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target);
- if( disguised(bl) ) {
- #if PACKETVER >= 20091103
- p.objecttype = pc->db_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE
- p.GID = -bl->id;
- #else
- p.GID = -bl->id;
- #endif
- clif->send(&p,sizeof(p),bl,SELF);
- }
- }
- /// Changes sprite of an NPC object (ZC_NPCSPRITE_CHANGE).
- /// 01b0 <id>.L <type>.B <value>.L
- /// type:
- /// unused
- void clif_class_change(struct block_list *bl, int class_, int type)
- {
- nullpo_retv(bl);
- if(!pc->db_checkid(class_))
- {// player classes yield missing sprites
- unsigned char buf[16];
- WBUFW(buf,0)=0x1b0;
- WBUFL(buf,2)=bl->id;
- WBUFB(buf,6)=type;
- WBUFL(buf,7)=class_;
- clif->send(buf,packet_len(0x1b0),bl,AREA);
- }
- }
- /// Notifies the client of an object's spirits.
- /// 01d0 <id>.L <amount>.W (ZC_SPIRITS)
- /// 01e1 <id>.L <amount>.W (ZC_SPIRITS2)
- void clif_spiritball_single(int fd, struct map_session_data *sd) {
- nullpo_retv(sd);
- WFIFOHEAD(fd, packet_len(0x1e1));
- WFIFOW(fd,0)=0x1e1;
- WFIFOL(fd,2)=sd->bl.id;
- WFIFOW(fd,6)=sd->spiritball;
- WFIFOSET(fd, packet_len(0x1e1));
- }
- /*==========================================
- * Kagerou/Oboro amulet spirit
- *------------------------------------------*/
- void clif_charm_single(int fd, struct map_session_data *sd)
- {
- nullpo_retv(sd);
- WFIFOHEAD(fd, packet_len(0x08cf));
- WFIFOW(fd,0) = 0x08cf;
- WFIFOL(fd,2) = sd->bl.id;
- WFIFOW(fd,6) = sd->charm_type;
- WFIFOW(fd,8) = sd->charm_count;
- WFIFOSET(fd, packet_len(0x08cf));
- }
- /*==========================================
- * Run when player changes map / refreshes
- * Tells its client to display all weather settings being used by this map
- *------------------------------------------*/
- void clif_weather_check(struct map_session_data *sd) {
- int16 m;
- int fd;
- nullpo_retv(sd);
- m = sd->bl.m;
- fd = sd->fd;
- if (map->list[m].flag.snow)
- clif->specialeffect_single(&sd->bl, 162, fd);
- if (map->list[m].flag.clouds)
- clif->specialeffect_single(&sd->bl, 233, fd);
- if (map->list[m].flag.clouds2)
- clif->specialeffect_single(&sd->bl, 516, fd);
- if (map->list[m].flag.fog)
- clif->specialeffect_single(&sd->bl, 515, fd);
- if (map->list[m].flag.fireworks) {
- clif->specialeffect_single(&sd->bl, 297, fd);
- clif->specialeffect_single(&sd->bl, 299, fd);
- clif->specialeffect_single(&sd->bl, 301, fd);
- }
- if (map->list[m].flag.sakura)
- clif->specialeffect_single(&sd->bl, 163, fd);
- if (map->list[m].flag.leaves)
- clif->specialeffect_single(&sd->bl, 333, fd);
- }
- /**
- * Run when the weather on a map changes, throws all players in map id 'm' to clif_weather_check function
- **/
- void clif_weather(int16 m)
- {
- struct s_mapiterator* iter;
- struct map_session_data *sd=NULL;
- iter = mapit_getallusers();
- for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
- if( sd->bl.m == m )
- clif->weather_check(sd);
- }
- mapit->free(iter);
- }
- /**
- * Main function to spawn a unit on the client (player/mob/pet/etc)
- **/
- bool clif_spawn(struct block_list *bl)
- {
- struct view_data *vd;
- nullpo_retr(false, bl);
- vd = status->get_viewdata(bl);
- if( !vd )
- return false;
- if (vd->class_ == INVISIBLE_CLASS)
- return true; // Doesn't need to be spawned, so everything is alright
- if (bl->type == BL_NPC) {
- struct npc_data *nd = BL_UCAST(BL_NPC, bl);
- if (nd->chat_id == 0 && (nd->option&OPTION_INVISIBLE)) // Hide NPC from maya purple card.
- return true; // Doesn't need to be spawned, so everything is alright
- }
- clif->spawn_unit(bl,AREA_WOS);
- if (vd->cloth_color)
- clif->refreshlook(bl,bl->id,LOOK_CLOTHES_COLOR,vd->cloth_color,AREA_WOS);
- if (vd->body_style)
- clif->refreshlook(bl,bl->id,LOOK_BODY2,vd->body_style,AREA_WOS);
- switch (bl->type) {
- case BL_PC:
- {
- struct map_session_data *sd = BL_UCAST(BL_PC, bl);
- int i;
- if (sd->spiritball > 0)
- 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)
- clif->specialeffect(bl,421,AREA);
- if (sd->bg_id != 0 && map->list[sd->bl.m].flag.battleground)
- clif->sendbgemblem_area(sd);
- for (i = 0; i < sd->sc_display_count; i++) {
- clif->sc_load(&sd->bl, sd->bl.id,AREA,status->dbs->IconChangeTable[sd->sc_display[i]->type],sd->sc_display[i]->val1,sd->sc_display[i]->val2,sd->sc_display[i]->val3);
- }
- if (sd->charm_type != CHARM_TYPE_NONE && sd->charm_count > 0)
- clif->spiritcharm(sd);
- if (sd->status.robe)
- clif->refreshlook(bl,bl->id,LOOK_ROBE,sd->status.robe,AREA);
- }
- break;
- case BL_MOB:
- {
- struct mob_data *md = BL_UCAST(BL_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)
- clif->specialeffect(&md->bl,421,AREA);
- }
- break;
- case BL_NPC:
- {
- struct npc_data *nd = BL_UCAST(BL_NPC, bl);
- if (nd->size == SZ_BIG)
- clif->specialeffect(&nd->bl,423,AREA);
- else if (nd->size == SZ_MEDIUM)
- clif->specialeffect(&nd->bl,421,AREA);
- }
- break;
- case BL_PET:
- if (vd->head_bottom)
- clif->send_petdata(NULL, BL_UCAST(BL_PET, bl), 3, vd->head_bottom); // needed to display pet equip properly
- break;
- }
- return true;
- }
- /// Sends information about owned homunculus to the client (ZC_PROPERTY_HOMUN). [orn]
- /// 022e <name>.24B <modified>.B <level>.W <hunger>.W <intimacy>.W <equip id>.W <atk>.W <matk>.W <hit>.W <crit>.W <def>.W <mdef>.W <flee>.W <aspd>.W <hp>.W <max hp>.W <sp>.W <max sp>.W <exp>.L <max exp>.L <skill points>.W <atk range>.W
- void clif_hominfo(struct map_session_data *sd, struct homun_data *hd, int flag) {
- struct status_data *hstatus;
- unsigned char buf[128];
- enum homun_type htype;
- nullpo_retv(sd);
- nullpo_retv(hd);
- hstatus = &hd->battle_status;
- htype = homun->class2type(hd->homunculus.class_);
- memset(buf,0,packet_len(0x22e));
- 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 && hd->homunculus.rename_flag ? 0x1 : 0x0) | (hd->homunculus.vaporize == HOM_ST_REST ? 0x2 : 0) | (hd->homunculus.hp > 0 ? 0x4 : 0);
- WBUFW(buf,27)=hd->homunculus.level;
- WBUFW(buf,29)=hd->homunculus.hunger;
- WBUFW(buf,31)=(unsigned short) (hd->homunculus.intimacy / 100) ;
- WBUFW(buf,33)=0; // equip id
- #ifdef RENEWAL
- WBUFW(buf, 35) = cap_value(hstatus->rhw.atk2, 0, INT16_MAX);
- #else
- WBUFW(buf,35)=cap_value(hstatus->rhw.atk2+hstatus->batk, 0, INT16_MAX);
- #endif
- WBUFW(buf,37)=cap_value(hstatus->matk_max, 0, INT16_MAX);
- WBUFW(buf,39)=hstatus->hit;
- if (battle_config.hom_setting&0x10)
- WBUFW(buf,41)=hstatus->luk/3 + 1; //crit is a +1 decimal value! Just display purpose.[Vicious]
- else
- WBUFW(buf,41)=hstatus->cri/10;
- #ifdef RENEWAL
- WBUFW(buf, 43) = hstatus->def + hstatus->def2;
- WBUFW(buf, 45) = hstatus->mdef + hstatus->mdef2;
- #else
- WBUFW(buf,43)=hstatus->def + hstatus->vit ;
- WBUFW(buf, 45) = hstatus->mdef;
- #endif
- WBUFW(buf,47)=hstatus->flee;
- WBUFW(buf,49)=(flag)?0:hstatus->amotion;
- if (hstatus->max_hp > INT16_MAX) {
- WBUFW(buf,51) = hstatus->hp/(hstatus->max_hp/100);
- WBUFW(buf,53) = 100;
- } else {
- WBUFW(buf,51)=hstatus->hp;
- WBUFW(buf,53)=hstatus->max_hp;
- }
- if (hstatus->max_sp > INT16_MAX) {
- WBUFW(buf,55) = hstatus->sp/(hstatus->max_sp/100);
- WBUFW(buf,57) = 100;
- } else {
- WBUFW(buf,55)=hstatus->sp;
- WBUFW(buf,57)=hstatus->max_sp;
- }
- WBUFL(buf,59)=hd->homunculus.exp;
- WBUFL(buf,63)=hd->exp_next;
- switch( htype ) {
- case HT_REG:
- case HT_EVO:
- if( hd->homunculus.level >= battle_config.hom_max_level )
- WBUFL(buf,63)=0;
- break;
- case HT_S:
- if( hd->homunculus.level >= battle_config.hom_S_max_level )
- WBUFL(buf,63)=0;
- break;
- }
- WBUFW(buf,67)=hd->homunculus.skillpts;
- WBUFW(buf,69)=status_get_range(&hd->bl);
- clif->send(buf,packet_len(0x22e),&sd->bl,SELF);
- }
- /// Notification about a change in homunuculus' state (ZC_CHANGESTATE_MER).
- /// 0230 <type>.B <state>.B <id>.L <data>.L
- /// type:
- /// unused
- /// state:
- /// 0 = pre-init
- /// 1 = intimacy
- /// 2 = hunger
- /// 3 = accessory?
- /// ? = ignored
- void clif_send_homdata(struct map_session_data *sd, int state, int param)
- {
- int fd;
- nullpo_retv(sd);
- nullpo_retv(sd->hd);
- fd = sd->fd;
- if ( (state == SP_INTIMATE) && (param >= 910) && (sd->hd->homunculus.class_ == sd->hd->homunculusDB->evo_class) )
- homun->calc_skilltree(sd->hd, 0);
- WFIFOHEAD(fd, packet_len(0x230));
- WFIFOW(fd,0)=0x230;
- WFIFOB(fd,2)=0;
- WFIFOB(fd,3)=state;
- WFIFOL(fd,4)=sd->hd->bl.id;
- WFIFOL(fd,8)=param;
- WFIFOSET(fd,packet_len(0x230));
- }
- /// Prepares and sends homun related information [orn]
- void clif_homskillinfoblock(struct map_session_data *sd) {
- struct homun_data *hd;
- int fd;
- int i,j;
- int len=4;
- nullpo_retv(sd);
- fd = sd->fd;
- hd = sd->hd;
- if ( !hd )
- return;
- WFIFOHEAD(fd, 4+37*MAX_HOMUNSKILL);
- WFIFOW(fd,0)=0x235;
- for ( i = 0; i < MAX_HOMUNSKILL; i++ ) {
- int id = hd->homunculus.hskill[i].id;
- if ( id != 0 ) {
- j = id - HM_SKILLBASE;
- WFIFOW(fd, len) = id;
- WFIFOW(fd, len + 2) = skill->get_inf(id);
- WFIFOW(fd, len + 4) = 0;
- WFIFOW(fd, len + 6) = hd->homunculus.hskill[j].lv;
- if ( hd->homunculus.hskill[j].lv ) {
- WFIFOW(fd, len + 8) = skill->get_sp(id, hd->homunculus.hskill[j].lv);
- WFIFOW(fd, len + 10) = skill->get_range2(&sd->hd->bl, id, hd->homunculus.hskill[j].lv);
- } else {
- WFIFOW(fd, len + 8) = 0;
- WFIFOW(fd, len + 10) = 0;
- }
- safestrncpy((char*)WFIFOP(fd, len + 12), skill->get_name(id), NAME_LENGTH);
- WFIFOB(fd, len + 36) = (hd->homunculus.hskill[j].lv < homun->skill_tree_get_max(id, hd->homunculus.class_)) ? 1 : 0;
- len += 37;
- }
- }
- WFIFOW(fd,2)=len;
- WFIFOSET(fd,len);
- return;
- }
- void clif_homskillup(struct map_session_data *sd, uint16 skill_id) { //[orn]
- struct homun_data *hd;
- int fd, idx;
- nullpo_retv(sd);
- nullpo_retv(sd->hd);
- idx = skill_id - HM_SKILLBASE;
- fd=sd->fd;
- hd=sd->hd;
- WFIFOHEAD(fd, packet_len(0x239));
- WFIFOW(fd,0) = 0x239;
- WFIFOW(fd,2) = skill_id;
- WFIFOW(fd,4) = hd->homunculus.hskill[idx].lv;
- WFIFOW(fd,6) = skill->get_sp(skill_id,hd->homunculus.hskill[idx].lv);
- WFIFOW(fd,8) = skill->get_range2(&hd->bl, skill_id,hd->homunculus.hskill[idx].lv);
- WFIFOB(fd,10) = (hd->homunculus.hskill[idx].lv < skill->get_max(hd->homunculus.hskill[idx].id)) ? 1 : 0;
- WFIFOSET(fd,packet_len(0x239));
- }
- void clif_hom_food(struct map_session_data *sd,int foodid,int fail)
- {
- 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;
- }
- /// Notifies the client, that it is walking (ZC_NOTIFY_PLAYERMOVE).
- /// 0087 <walk start time>.L <walk data>.6B
- void clif_walkok(struct map_session_data *sd)
- {
- int fd;
- nullpo_retv(sd);
- fd = sd->fd;
- WFIFOHEAD(fd, packet_len(0x87));
- WFIFOW(fd,0)=0x87;
- 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;
- #endif
- nullpo_retv(bl);
- nullpo_retv(vd);
- nullpo_retv(ud);
- #ifdef ANTI_MAYAP_CHEAT
- 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)
- clif->refreshlook(bl,bl->id,LOOK_CLOTHES_COLOR,vd->cloth_color,AREA_WOS);
- if (vd->body_style)
- clif->refreshlook(bl,bl->id,LOOK_BODY2,vd->body_style,AREA_WOS);
- switch(bl->type) {
- case BL_PC:
- {
- struct map_session_data *sd = BL_UCAST(BL_PC, bl);
- //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)
- clif->specialeffect(&sd->bl,421,AREA);
- }
- break;
- case BL_MOB:
- {
- struct mob_data *md = BL_UCAST(BL_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)
- clif->specialeffect(&md->bl,421,AREA);
- }
- break;
- case BL_PET:
- if( vd->head_bottom ) // needed to display pet equip properly
- clif->send_petdata(NULL, BL_UCAST(BL_PET, bl), 3, vd->head_bottom);
- break;
- }
- #ifdef ANTI_MAYAP_CHEAT
- clif->al…
Large files files are truncated, but you can click here to view the full file