PageRenderTime 77ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 2ms

/src/map/clif.c

https://gitlab.com/evol/hercules
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

  1. /**
  2. * This file is part of Hercules.
  3. * http://herc.ws - http://github.com/HerculesWS/Hercules
  4. *
  5. * Copyright (C) 2012-2015 Hercules Dev Team
  6. * Copyright (C) Athena Dev Teams
  7. *
  8. * Hercules is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #define HERCULES_CORE
  22. #include "config/core.h" // ANTI_MAYAP_CHEAT, RENEWAL, SECURE_NPCTIMEOUT
  23. #include "clif.h"
  24. #include "map/atcommand.h"
  25. #include "map/battle.h"
  26. #include "map/battleground.h"
  27. #include "map/channel.h"
  28. #include "map/chat.h"
  29. #include "map/chrif.h"
  30. #include "map/elemental.h"
  31. #include "map/guild.h"
  32. #include "map/homunculus.h"
  33. #include "map/instance.h"
  34. #include "map/intif.h"
  35. #include "map/irc-bot.h"
  36. #include "map/itemdb.h"
  37. #include "map/log.h"
  38. #include "map/mail.h"
  39. #include "map/map.h"
  40. #include "map/mercenary.h"
  41. #include "map/mob.h"
  42. #include "map/npc.h"
  43. #include "map/party.h"
  44. #include "map/pc.h"
  45. #include "map/pet.h"
  46. #include "map/quest.h"
  47. #include "map/script.h"
  48. #include "map/skill.h"
  49. #include "map/status.h"
  50. #include "map/storage.h"
  51. #include "map/trade.h"
  52. #include "map/unit.h"
  53. #include "map/vending.h"
  54. #include "common/HPM.h"
  55. #include "common/cbasetypes.h"
  56. #include "common/conf.h"
  57. #include "common/ers.h"
  58. #include "common/grfio.h"
  59. #include "common/memmgr.h"
  60. #include "common/mmo.h" // NEW_CARTS
  61. #include "common/nullpo.h"
  62. #include "common/random.h"
  63. #include "common/showmsg.h"
  64. #include "common/socket.h"
  65. #include "common/strlib.h"
  66. #include "common/timer.h"
  67. #include "common/utils.h"
  68. #include <stdio.h>
  69. #include <stdlib.h>
  70. #include <string.h>
  71. #include <stdarg.h>
  72. #include <time.h>
  73. struct clif_interface clif_s;
  74. struct clif_interface *clif;
  75. struct s_packet_db packet_db[MAX_PACKET_DB + 1];
  76. /* re-usable */
  77. static struct packet_itemlist_normal itemlist_normal;
  78. static struct packet_itemlist_equip itemlist_equip;
  79. static struct packet_storelist_normal storelist_normal;
  80. static struct packet_storelist_equip storelist_equip;
  81. static struct packet_viewequip_ack viewequip_list;
  82. #if PACKETVER >= 20131223
  83. static struct packet_npc_market_result_ack npcmarket_result;
  84. static struct packet_npc_market_open npcmarket_open;
  85. #endif
  86. //#define DUMP_UNKNOWN_PACKET
  87. //#define DUMP_INVALID_PACKET
  88. //Converts item type in case of pet eggs.
  89. static inline int itemtype(int type) {
  90. switch( type ) {
  91. #if PACKETVER >= 20080827
  92. case IT_WEAPON:
  93. return IT_ARMOR;
  94. case IT_ARMOR:
  95. case IT_PETARMOR:
  96. #endif
  97. case IT_PETEGG:
  98. return IT_WEAPON;
  99. default:
  100. return type;
  101. }
  102. }
  103. static inline void WBUFPOS(uint8* p, unsigned short pos, short x, short y, unsigned char dir) {
  104. p += pos;
  105. p[0] = (uint8)(x>>2);
  106. p[1] = (uint8)((x<<6) | ((y>>4)&0x3f));
  107. p[2] = (uint8)((y<<4) | (dir&0xf));
  108. }
  109. // client-side: x0+=sx0*0.0625-0.5 and y0+=sy0*0.0625-0.5
  110. static inline void WBUFPOS2(uint8* p, unsigned short pos, short x0, short y0, short x1, short y1, unsigned char sx0, unsigned char sy0) {
  111. p += pos;
  112. p[0] = (uint8)(x0>>2);
  113. p[1] = (uint8)((x0<<6) | ((y0>>4)&0x3f));
  114. p[2] = (uint8)((y0<<4) | ((x1>>6)&0x0f));
  115. p[3] = (uint8)((x1<<2) | ((y1>>8)&0x03));
  116. p[4] = (uint8)y1;
  117. p[5] = (uint8)((sx0<<4) | (sy0&0x0f));
  118. }
  119. #if 0 // Currently unused
  120. static inline void WFIFOPOS(int fd, unsigned short pos, short x, short y, unsigned char dir) {
  121. WBUFPOS(WFIFOP(fd,pos), 0, x, y, dir);
  122. }
  123. #endif // 0
  124. static inline void WFIFOPOS2(int fd, unsigned short pos, short x0, short y0, short x1, short y1, unsigned char sx0, unsigned char sy0) {
  125. WBUFPOS2(WFIFOP(fd,pos), 0, x0, y0, x1, y1, sx0, sy0);
  126. }
  127. static inline void RBUFPOS(const uint8* p, unsigned short pos, short* x, short* y, unsigned char* dir) {
  128. p += pos;
  129. if( x ) {
  130. x[0] = ( ( p[0] & 0xff ) << 2 ) | ( p[1] >> 6 );
  131. }
  132. if( y ) {
  133. y[0] = ( ( p[1] & 0x3f ) << 4 ) | ( p[2] >> 4 );
  134. }
  135. if( dir ) {
  136. dir[0] = ( p[2] & 0x0f );
  137. }
  138. }
  139. static inline void RFIFOPOS(int fd, unsigned short pos, short* x, short* y, unsigned char* dir) {
  140. RBUFPOS(RFIFOP(fd,pos), 0, x, y, dir);
  141. }
  142. #if 0 // currently unused
  143. static inline void RBUFPOS2(const uint8* p, unsigned short pos, short* x0, short* y0, short* x1, short* y1, unsigned char* sx0, unsigned char* sy0) {
  144. p += pos;
  145. if( x0 ) {
  146. x0[0] = ( ( p[0] & 0xff ) << 2 ) | ( p[1] >> 6 );
  147. }
  148. if( y0 ) {
  149. y0[0] = ( ( p[1] & 0x3f ) << 4 ) | ( p[2] >> 4 );
  150. }
  151. if( x1 ) {
  152. x1[0] = ( ( p[2] & 0x0f ) << 6 ) | ( p[3] >> 2 );
  153. }
  154. if( y1 ) {
  155. y1[0] = ( ( p[3] & 0x03 ) << 8 ) | ( p[4] >> 0 );
  156. }
  157. if( sx0 ) {
  158. sx0[0] = ( p[5] & 0xf0 ) >> 4;
  159. }
  160. if( sy0 ) {
  161. sy0[0] = ( p[5] & 0x0f ) >> 0;
  162. }
  163. }
  164. static inline void RFIFOPOS2(int fd, unsigned short pos, short* x0, short* y0, short* x1, short* y1, unsigned char* sx0, unsigned char* sy0) {
  165. RBUFPOS2(WFIFOP(fd,pos), 0, x0, y0, x1, y1, sx0, sy0);
  166. }
  167. #endif // 0
  168. //To identify disguised characters.
  169. static inline bool disguised(struct block_list* bl)
  170. {
  171. struct map_session_data *sd = BL_CAST(BL_PC, bl);
  172. if (sd == NULL || sd->disguise == -1)
  173. return false;
  174. return true;
  175. }
  176. //Guarantees that the given string does not exceeds the allowed size, as well as making sure it's null terminated. [Skotlex]
  177. static inline unsigned int mes_len_check(char* mes, unsigned int len, unsigned int max) {
  178. nullpo_retr(0, mes);
  179. if (len <= 0)
  180. {
  181. mes[0] = '\0';
  182. Assert_retr(0, len > 0);
  183. }
  184. if( len > max )
  185. len = max;
  186. mes[len-1] = '\0';
  187. return len;
  188. }
  189. /*==========================================
  190. * Ip setting of map-server
  191. *------------------------------------------*/
  192. bool clif_setip(const char* ip) {
  193. char ip_str[16];
  194. nullpo_retr(false, ip);
  195. clif->map_ip = sockt->host2ip(ip);
  196. if ( !clif->map_ip ) {
  197. ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip);
  198. return false;
  199. }
  200. safestrncpy(clif->map_ip_str, ip, sizeof(clif->map_ip_str));
  201. ShowInfo("Map Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, sockt->ip2str(clif->map_ip, ip_str));
  202. return true;
  203. }
  204. bool clif_setbindip(const char* ip) {
  205. nullpo_retr(false, ip);
  206. clif->bind_ip = sockt->host2ip(ip);
  207. if ( clif->bind_ip ) {
  208. char ip_str[16];
  209. 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));
  210. return true;
  211. }
  212. ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip);
  213. return false;
  214. }
  215. /*==========================================
  216. * Sets map port to 'port'
  217. * is run from map.c upon loading map server configuration
  218. *------------------------------------------*/
  219. void clif_setport(uint16 port)
  220. {
  221. clif->map_port = port;
  222. }
  223. /*==========================================
  224. * Returns map server IP
  225. *------------------------------------------*/
  226. uint32 clif_getip(void)
  227. {
  228. return clif->map_ip;
  229. }
  230. /*==========================================
  231. * Returns map port which is set by clif_setport()
  232. *------------------------------------------*/
  233. uint16 clif_getport(void)
  234. {
  235. return clif->map_port;
  236. }
  237. /*==========================================
  238. * Updates server ip resolution and returns it
  239. *------------------------------------------*/
  240. uint32 clif_refresh_ip(void)
  241. {
  242. uint32 new_ip = sockt->host2ip(clif->map_ip_str);
  243. if ( new_ip && new_ip != clif->map_ip ) {
  244. clif->map_ip = new_ip;
  245. ShowInfo("Updating IP resolution of [%s].\n", clif->map_ip_str);
  246. return clif->map_ip;
  247. }
  248. return 0;
  249. }
  250. #if PACKETVER >= 20071106
  251. static inline unsigned char clif_bl_type(struct block_list *bl) {
  252. nullpo_retr(0x1, bl);
  253. switch (bl->type) {
  254. case BL_PC: return (disguised(bl) && !pc->db_checkid(status->get_viewdata(bl)->class_))? 0x1:0x0; //PC_TYPE
  255. case BL_ITEM: return 0x2; //ITEM_TYPE
  256. case BL_SKILL: return 0x3; //SKILL_TYPE
  257. case BL_CHAT: return 0x4; //UNKNOWN_TYPE
  258. case BL_MOB: return pc->db_checkid(status->get_viewdata(bl)->class_)?0x0:0x5; //NPC_MOB_TYPE
  259. case BL_NPC: return pc->db_checkid(status->get_viewdata(bl)->class_)?0x0:0x6; //NPC_EVT_TYPE
  260. case BL_PET: return pc->db_checkid(status->get_viewdata(bl)->class_)?0x0:0x7; //NPC_PET_TYPE
  261. case BL_HOM: return 0x8; //NPC_HOM_TYPE
  262. case BL_MER: return 0x9; //NPC_MERSOL_TYPE
  263. case BL_ELEM: return 0xa; //NPC_ELEMENTAL_TYPE
  264. default: return 0x1; //NPC_TYPE
  265. }
  266. }
  267. #endif
  268. /*==========================================
  269. * sub process of clif_send
  270. * Called from a map_foreachinarea (grabs all players in specific area and subjects them to this function)
  271. * In order to send area-wise packets, such as:
  272. * - AREA : everyone nearby your area
  273. * - AREA_WOSC (AREA WITHOUT SAME CHAT) : Not run for people in the same chat as yours
  274. * - AREA_WOC (AREA WITHOUT CHAT) : Not run for people inside a chat
  275. * - AREA_WOS (AREA WITHOUT SELF) : Not run for self
  276. * - AREA_CHAT_WOC : Everyone in the area of your chat without a chat
  277. *------------------------------------------*/
  278. int clif_send_sub(struct block_list *bl, va_list ap) {
  279. struct block_list *src_bl;
  280. struct map_session_data *sd;
  281. void *buf;
  282. int len, type, fd;
  283. nullpo_ret(bl);
  284. Assert_ret(bl->type == BL_PC);
  285. sd = BL_UCAST(BL_PC, bl);
  286. fd = sd->fd;
  287. if (!fd || sockt->session[fd] == NULL) //Don't send to disconnected clients.
  288. return 0;
  289. buf = va_arg(ap,void*);
  290. len = va_arg(ap,int);
  291. nullpo_ret(src_bl = va_arg(ap,struct block_list*));
  292. type = va_arg(ap,int);
  293. switch(type) {
  294. case AREA_WOS:
  295. if (bl == src_bl)
  296. return 0;
  297. break;
  298. case AREA_WOC:
  299. if (sd->chatID || bl == src_bl)
  300. return 0;
  301. break;
  302. case AREA_WOSC: {
  303. if (src_bl->type == BL_PC) {
  304. const struct map_session_data *ssd = BL_UCCAST(BL_PC, src_bl);
  305. if (ssd != NULL && sd->chatID != 0 && (sd->chatID == ssd->chatID))
  306. return 0;
  307. } else if (src_bl->type == BL_NPC) {
  308. const struct npc_data *nd = BL_UCCAST(BL_NPC, src_bl);
  309. if (nd != NULL && sd->chatID != 0 && (sd->chatID == nd->chat_id))
  310. return 0;
  311. }
  312. }
  313. break;
  314. /* 0x120 crashes the client when warping for this packetver range [Ind/Hercules], thanks to Judas! */
  315. #if PACKETVER > 20120418 && PACKETVER < 20130000
  316. case AREA:
  317. if( WBUFW(buf, 0) == 0x120 && sd->state.warping )
  318. return 0;
  319. break;
  320. #endif
  321. }
  322. /* unless visible, hold it here */
  323. if( clif->ally_only && !sd->sc.data[SC_CLAIRVOYANCE] && !sd->special_state.intravision && battle->check_target( src_bl, &sd->bl, BCT_ENEMY ) > 0 )
  324. return 0;
  325. return clif->send_actual(fd, buf, len);
  326. }
  327. int clif_send_actual(int fd, void *buf, int len)
  328. {
  329. nullpo_retr(0, buf);
  330. WFIFOHEAD(fd, len);
  331. if (WFIFOP(fd,0) == buf) {
  332. ShowError("WARNING: Invalid use of clif->send function\n");
  333. ShowError(" Packet x%4x use a WFIFO of a player instead of to use a buffer.\n", WBUFW(buf,0));
  334. ShowError(" Please correct your code.\n");
  335. // don't send to not move the pointer of the packet for next sessions in the loop
  336. //WFIFOSET(fd,0);//## TODO is this ok?
  337. //NO. It is not ok. There is the chance WFIFOSET actually sends the buffer data, and shifts elements around, which will corrupt the buffer.
  338. return 0;
  339. }
  340. memcpy(WFIFOP(fd,0), buf, len);
  341. WFIFOSET(fd,len);
  342. return 0;
  343. }
  344. /*==========================================
  345. * Packet Delegation (called on all packets that require data to be sent to more than one client)
  346. * functions that are sent solely to one use whose ID it posses use WFIFOSET
  347. *------------------------------------------*/
  348. bool clif_send(const void* buf, int len, struct block_list* bl, enum send_target type) {
  349. int i;
  350. struct map_session_data *sd, *tsd;
  351. struct party_data *p = NULL;
  352. struct guild *g = NULL;
  353. struct battleground_data *bgd = NULL;
  354. int x0 = 0, x1 = 0, y0 = 0, y1 = 0, fd;
  355. struct s_mapiterator* iter;
  356. if( type != ALL_CLIENT )
  357. nullpo_ret(bl);
  358. sd = BL_CAST(BL_PC, bl);
  359. switch(type) {
  360. case ALL_CLIENT: //All player clients.
  361. iter = mapit_getallusers();
  362. while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
  363. WFIFOHEAD(tsd->fd, len);
  364. memcpy(WFIFOP(tsd->fd,0), buf, len);
  365. WFIFOSET(tsd->fd,len);
  366. }
  367. mapit->free(iter);
  368. break;
  369. case ALL_SAMEMAP: //All players on the same map
  370. iter = mapit_getallusers();
  371. while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
  372. if (bl && bl->m == tsd->bl.m) {
  373. WFIFOHEAD(tsd->fd, len);
  374. memcpy(WFIFOP(tsd->fd,0), buf, len);
  375. WFIFOSET(tsd->fd,len);
  376. }
  377. }
  378. mapit->free(iter);
  379. break;
  380. case AREA:
  381. case AREA_WOSC:
  382. if (sd && bl->prev == NULL) //Otherwise source misses the packet.[Skotlex]
  383. clif->send (buf, len, bl, SELF);
  384. /* Fall through */
  385. case AREA_WOC:
  386. case AREA_WOS:
  387. nullpo_retr(true, bl);
  388. map->foreachinarea(clif->send_sub, bl->m, bl->x-AREA_SIZE, bl->y-AREA_SIZE, bl->x+AREA_SIZE, bl->y+AREA_SIZE,
  389. BL_PC, buf, len, bl, type);
  390. break;
  391. case AREA_CHAT_WOC:
  392. nullpo_retr(true, bl);
  393. map->foreachinarea(clif->send_sub, bl->m, bl->x-(AREA_SIZE-5), bl->y-(AREA_SIZE-5),
  394. bl->x+(AREA_SIZE-5), bl->y+(AREA_SIZE-5), BL_PC, buf, len, bl, AREA_WOC);
  395. break;
  396. case CHAT:
  397. case CHAT_WOS:
  398. nullpo_retr(true, bl);
  399. {
  400. const struct chat_data *cd = NULL;
  401. if (sd != NULL) {
  402. cd = map->id2cd(sd->chatID);
  403. } else {
  404. cd = BL_CCAST(BL_CHAT, bl);
  405. }
  406. if (cd == NULL)
  407. break;
  408. for(i = 0; i < cd->users; i++) {
  409. if (type == CHAT_WOS && cd->usersd[i] == sd)
  410. continue;
  411. if ((fd=cd->usersd[i]->fd) >0 && sockt->session[fd]) { // Added check to see if session exists [PoW]
  412. WFIFOHEAD(fd,len);
  413. memcpy(WFIFOP(fd,0), buf, len);
  414. WFIFOSET(fd,len);
  415. }
  416. }
  417. }
  418. break;
  419. case PARTY_AREA:
  420. case PARTY_AREA_WOS:
  421. nullpo_retr(true, bl);
  422. x0 = bl->x - AREA_SIZE;
  423. y0 = bl->y - AREA_SIZE;
  424. x1 = bl->x + AREA_SIZE;
  425. y1 = bl->y + AREA_SIZE;
  426. /* Fall through */
  427. case PARTY:
  428. case PARTY_WOS:
  429. case PARTY_SAMEMAP:
  430. case PARTY_SAMEMAP_WOS:
  431. if (sd && sd->status.party_id)
  432. p = party->search(sd->status.party_id);
  433. if (p) {
  434. for(i=0;i<MAX_PARTY;i++){
  435. if( (sd = p->data[i].sd) == NULL )
  436. continue;
  437. if( !(fd=sd->fd) )
  438. continue;
  439. if( sd->bl.id == bl->id && (type == PARTY_WOS || type == PARTY_SAMEMAP_WOS || type == PARTY_AREA_WOS) )
  440. continue;
  441. if( type != PARTY && type != PARTY_WOS && bl->m != sd->bl.m )
  442. continue;
  443. if( (type == PARTY_AREA || type == PARTY_AREA_WOS) && (sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1) )
  444. continue;
  445. WFIFOHEAD(fd,len);
  446. memcpy(WFIFOP(fd,0), buf, len);
  447. WFIFOSET(fd,len);
  448. }
  449. if (!map->enable_spy) //Skip unnecessary parsing. [Skotlex]
  450. break;
  451. iter = mapit_getallusers();
  452. while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
  453. if( tsd->partyspy == p->party.party_id ) {
  454. WFIFOHEAD(tsd->fd, len);
  455. memcpy(WFIFOP(tsd->fd,0), buf, len);
  456. WFIFOSET(tsd->fd,len);
  457. }
  458. }
  459. mapit->free(iter);
  460. }
  461. break;
  462. case DUEL:
  463. case DUEL_WOS:
  464. if (!sd || !sd->duel_group) break; //Invalid usage.
  465. iter = mapit_getallusers();
  466. while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
  467. if( type == DUEL_WOS && bl->id == tsd->bl.id )
  468. continue;
  469. if( sd->duel_group == tsd->duel_group ) {
  470. WFIFOHEAD(tsd->fd, len);
  471. memcpy(WFIFOP(tsd->fd,0), buf, len);
  472. WFIFOSET(tsd->fd,len);
  473. }
  474. }
  475. mapit->free(iter);
  476. break;
  477. case SELF:
  478. if (sd && (fd=sd->fd) != 0) {
  479. WFIFOHEAD(fd,len);
  480. memcpy(WFIFOP(fd,0), buf, len);
  481. WFIFOSET(fd,len);
  482. }
  483. break;
  484. // New definitions for guilds [Valaris] - Cleaned up and reorganized by [Skotlex]
  485. case GUILD_AREA:
  486. case GUILD_AREA_WOS:
  487. nullpo_retr(true, bl);
  488. x0 = bl->x - AREA_SIZE;
  489. y0 = bl->y - AREA_SIZE;
  490. x1 = bl->x + AREA_SIZE;
  491. y1 = bl->y + AREA_SIZE;
  492. /* Fall through */
  493. case GUILD_SAMEMAP:
  494. case GUILD_SAMEMAP_WOS:
  495. case GUILD:
  496. case GUILD_WOS:
  497. case GUILD_NOBG:
  498. if (sd && sd->status.guild_id)
  499. g = sd->guild;
  500. if (g) {
  501. for(i = 0; i < g->max_member; i++) {
  502. if( (sd = g->member[i].sd) != NULL ) {
  503. if( !(fd=sd->fd) )
  504. continue;
  505. if( type == GUILD_NOBG && sd->bg_id )
  506. continue;
  507. if( sd->bl.id == bl->id && (type == GUILD_WOS || type == GUILD_SAMEMAP_WOS || type == GUILD_AREA_WOS) )
  508. continue;
  509. if( type != GUILD && type != GUILD_NOBG && type != GUILD_WOS && sd->bl.m != bl->m )
  510. continue;
  511. if( (type == GUILD_AREA || type == GUILD_AREA_WOS) && (sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1) )
  512. continue;
  513. WFIFOHEAD(fd,len);
  514. memcpy(WFIFOP(fd,0), buf, len);
  515. WFIFOSET(fd,len);
  516. }
  517. }
  518. if (!map->enable_spy) //Skip unnecessary parsing. [Skotlex]
  519. break;
  520. iter = mapit_getallusers();
  521. while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) {
  522. if( tsd->guildspy == g->guild_id ) {
  523. WFIFOHEAD(tsd->fd, len);
  524. memcpy(WFIFOP(tsd->fd,0), buf, len);
  525. WFIFOSET(tsd->fd,len);
  526. }
  527. }
  528. mapit->free(iter);
  529. }
  530. break;
  531. case BG_AREA:
  532. case BG_AREA_WOS:
  533. nullpo_retr(true, bl);
  534. x0 = bl->x - AREA_SIZE;
  535. y0 = bl->y - AREA_SIZE;
  536. x1 = bl->x + AREA_SIZE;
  537. y1 = bl->y + AREA_SIZE;
  538. /* Fall through */
  539. case BG_SAMEMAP:
  540. case BG_SAMEMAP_WOS:
  541. case BG:
  542. case BG_WOS:
  543. if( sd && sd->bg_id && (bgd = bg->team_search(sd->bg_id)) != NULL ) {
  544. for( i = 0; i < MAX_BG_MEMBERS; i++ ) {
  545. if( (sd = bgd->members[i].sd) == NULL || !(fd = sd->fd) )
  546. continue;
  547. if( sd->bl.id == bl->id && (type == BG_WOS || type == BG_SAMEMAP_WOS || type == BG_AREA_WOS) )
  548. continue;
  549. if( type != BG && type != BG_WOS && sd->bl.m != bl->m )
  550. continue;
  551. if( (type == BG_AREA || type == BG_AREA_WOS) && (sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1) )
  552. continue;
  553. WFIFOHEAD(fd,len);
  554. memcpy(WFIFOP(fd,0), buf, len);
  555. WFIFOSET(fd,len);
  556. }
  557. }
  558. break;
  559. case BG_QUEUE:
  560. if( sd && sd->bg_queue.arena ) {
  561. struct script_queue *queue = script->queue(sd->bg_queue.arena->queue_id);
  562. for (i = 0; i < VECTOR_LENGTH(queue->entries); i++) {
  563. struct map_session_data *qsd = map->id2sd(VECTOR_INDEX(queue->entries, i));
  564. if (qsd != NULL) {
  565. WFIFOHEAD(qsd->fd,len);
  566. memcpy(WFIFOP(qsd->fd,0), buf, len);
  567. WFIFOSET(qsd->fd,len);
  568. }
  569. }
  570. }
  571. break;
  572. default:
  573. ShowError("clif_send: Unrecognized type %d\n",type);
  574. return false;
  575. }
  576. return true;
  577. }
  578. /// Notifies the client, that it's connection attempt was accepted.
  579. /// 0073 <start time>.L <position>.3B <x size>.B <y size>.B (ZC_ACCEPT_ENTER)
  580. /// 02eb <start time>.L <position>.3B <x size>.B <y size>.B <font>.W (ZC_ACCEPT_ENTER2)
  581. void clif_authok(struct map_session_data *sd)
  582. {
  583. struct packet_authok p;
  584. nullpo_retv(sd);
  585. p.PacketType = authokType;
  586. p.startTime = (unsigned int)timer->gettick();
  587. WBUFPOS(&p.PosDir[0],0,sd->bl.x,sd->bl.y,sd->ud.dir); /* do the stupid client math */
  588. p.xSize = p.ySize = 5; /* not-used */
  589. #if PACKETVER >= 20080102
  590. p.font = sd->status.font;
  591. #endif
  592. #if PACKETVER >= 20141016
  593. p.sex = sd->status.sex;
  594. #endif
  595. clif->send(&p,sizeof(p),&sd->bl,SELF);
  596. }
  597. /// Notifies the client, that it's connection attempt was refused (ZC_REFUSE_ENTER).
  598. /// 0074 <error code>.B
  599. /// error code:
  600. /// 0 = client type mismatch
  601. /// 1 = ID mismatch
  602. /// 2 = mobile - out of available time
  603. /// 3 = mobile - already logged in
  604. /// 4 = mobile - waiting state
  605. void clif_authrefuse(int fd, uint8 error_code)
  606. {
  607. WFIFOHEAD(fd,packet_len(0x74));
  608. WFIFOW(fd,0) = 0x74;
  609. WFIFOB(fd,2) = error_code;
  610. WFIFOSET(fd,packet_len(0x74));
  611. }
  612. /// Notifies the client of a ban or forced disconnect (SC_NOTIFY_BAN).
  613. /// 0081 <error code>.B
  614. /// error code:
  615. /// 0 = BAN_UNFAIR -> "disconnected from server" -> MsgStringTable[3]
  616. /// 1 = server closed -> MsgStringTable[4]
  617. /// 2 = ID already logged in -> MsgStringTable[5]
  618. /// 3 = timeout/too much lag -> MsgStringTable[241]
  619. /// 4 = server full -> MsgStringTable[264]
  620. /// 5 = underaged -> MsgStringTable[305]
  621. /// 8 = Server sill recognizes last connection -> MsgStringTable[441]
  622. /// 9 = too many connections from this ip -> MsgStringTable[529]
  623. /// 10 = out of available time paid for -> MsgStringTable[530]
  624. /// 11 = BAN_PAY_SUSPEND
  625. /// 12 = BAN_PAY_CHANGE
  626. /// 13 = BAN_PAY_WRONGIP
  627. /// 14 = BAN_PAY_PNGAMEROOM
  628. /// 15 = disconnected by a GM -> if( servicetype == taiwan ) MsgStringTable[579]
  629. /// 16 = BAN_JAPAN_REFUSE1
  630. /// 17 = BAN_JAPAN_REFUSE2
  631. /// 18 = BAN_INFORMATION_REMAINED_ANOTHER_ACCOUNT
  632. /// 100 = BAN_PC_IP_UNFAIR
  633. /// 101 = BAN_PC_IP_COUNT_ALL
  634. /// 102 = BAN_PC_IP_COUNT
  635. /// 103 = BAN_GRAVITY_MEM_AGREE
  636. /// 104 = BAN_GAME_MEM_AGREE
  637. /// 105 = BAN_HAN_VALID
  638. /// 106 = BAN_PC_IP_LIMIT_ACCESS
  639. /// 107 = BAN_OVER_CHARACTER_LIST
  640. /// 108 = BAN_IP_BLOCK
  641. /// 109 = BAN_INVALID_PWD_CNT
  642. /// 110 = BAN_NOT_ALLOWED_JOBCLASS
  643. /// ? = disconnected -> MsgStringTable[3]
  644. // TODO: type enum
  645. void clif_authfail_fd(int fd, int type)
  646. {
  647. if (!fd || !sockt->session[fd] || sockt->session[fd]->func_parse != clif->parse) //clif_authfail should only be invoked on players!
  648. return;
  649. WFIFOHEAD(fd, packet_len(0x81));
  650. WFIFOW(fd,0) = 0x81;
  651. WFIFOB(fd,2) = type;
  652. WFIFOSET(fd,packet_len(0x81));
  653. sockt->eof(fd);
  654. }
  655. /// Notifies the client, whether it can disconnect and change servers (ZC_RESTART_ACK).
  656. /// 00b3 <type>.B
  657. /// type:
  658. /// 1 = disconnect, char-select
  659. /// ? = nothing
  660. void clif_charselectok(int id, uint8 ok) {
  661. struct map_session_data* sd;
  662. int fd;
  663. if ((sd = map->id2sd(id)) == NULL || !sd->fd)
  664. return;
  665. fd = sd->fd;
  666. WFIFOHEAD(fd,packet_len(0xb3));
  667. WFIFOW(fd,0) = 0xb3;
  668. WFIFOB(fd,2) = ok;
  669. WFIFOSET(fd,packet_len(0xb3));
  670. }
  671. /// Makes an item appear on the ground.
  672. /// 009e <id>.L <name id>.W <identified>.B <x>.W <y>.W <subX>.B <subY>.B <amount>.W (ZC_ITEM_FALL_ENTRY)
  673. /// 084b (ZC_ITEM_FALL_ENTRY4)
  674. void clif_dropflooritem(struct flooritem_data* fitem) {
  675. struct packet_dropflooritem p;
  676. int view;
  677. nullpo_retv(fitem);
  678. if (fitem->item_data.nameid <= 0)
  679. return;
  680. p.PacketType = dropflooritemType;
  681. p.ITAID = fitem->bl.id;
  682. p.ITID = ((view = itemdb_viewid(fitem->item_data.nameid)) > 0) ? view : fitem->item_data.nameid;
  683. #if PACKETVER >= 20130000 /* not sure date */
  684. p.type = itemtype(itemdb_type(fitem->item_data.nameid));
  685. #endif
  686. p.IsIdentified = fitem->item_data.identify ? 1 : 0;
  687. p.xPos = fitem->bl.x;
  688. p.yPos = fitem->bl.y;
  689. p.subX = fitem->subx;
  690. p.subY = fitem->suby;
  691. p.count = fitem->item_data.amount;
  692. clif->send(&p, sizeof(p), &fitem->bl, AREA);
  693. }
  694. /// Makes an item disappear from the ground.
  695. /// 00a1 <id>.L (ZC_ITEM_DISAPPEAR)
  696. void clif_clearflooritem(struct flooritem_data *fitem, int fd)
  697. {
  698. unsigned char buf[16];
  699. nullpo_retv(fitem);
  700. WBUFW(buf,0) = 0xa1;
  701. WBUFL(buf,2) = fitem->bl.id;
  702. if (fd == 0) {
  703. clif->send(buf, packet_len(0xa1), &fitem->bl, AREA);
  704. } else {
  705. WFIFOHEAD(fd,packet_len(0xa1));
  706. memcpy(WFIFOP(fd,0), buf, packet_len(0xa1));
  707. WFIFOSET(fd,packet_len(0xa1));
  708. }
  709. }
  710. /// Makes a unit (char, npc, mob, homun) disappear to one client (ZC_NOTIFY_VANISH).
  711. /// 0080 <id>.L <type>.B
  712. /// type:
  713. /// 0 = out of sight
  714. /// 1 = died
  715. /// 2 = logged out
  716. /// 3 = teleport
  717. /// 4 = trickdead
  718. void clif_clearunit_single(int id, clr_type type, int fd)
  719. {
  720. WFIFOHEAD(fd, packet_len(0x80));
  721. WFIFOW(fd,0) = 0x80;
  722. WFIFOL(fd,2) = id;
  723. WFIFOB(fd,6) = type;
  724. WFIFOSET(fd, packet_len(0x80));
  725. }
  726. /// Makes a unit (char, npc, mob, homun) disappear to all clients in area (ZC_NOTIFY_VANISH).
  727. /// 0080 <id>.L <type>.B
  728. /// type:
  729. /// 0 = out of sight
  730. /// 1 = died
  731. /// 2 = logged out
  732. /// 3 = teleport
  733. /// 4 = trickdead
  734. void clif_clearunit_area(struct block_list* bl, clr_type type)
  735. {
  736. unsigned char buf[8];
  737. nullpo_retv(bl);
  738. WBUFW(buf,0) = 0x80;
  739. WBUFL(buf,2) = bl->id;
  740. WBUFB(buf,6) = type;
  741. clif->send(buf, packet_len(0x80), bl, type == CLR_DEAD ? AREA : AREA_WOS);
  742. if(disguised(bl)) {
  743. WBUFL(buf,2) = -bl->id;
  744. clif->send(buf, packet_len(0x80), bl, SELF);
  745. }
  746. }
  747. /// Used to make monsters with player-sprites disappear after dying
  748. /// like normal monsters, because the client does not remove those
  749. /// automatically.
  750. int clif_clearunit_delayed_sub(int tid, int64 tick, int id, intptr_t data) {
  751. struct block_list *bl = (struct block_list *)data;
  752. clif->clearunit_area(bl, (clr_type) id);
  753. ers_free(clif->delay_clearunit_ers,bl);
  754. return 0;
  755. }
  756. void clif_clearunit_delayed(struct block_list* bl, clr_type type, int64 tick) {
  757. struct block_list *tbl;
  758. nullpo_retv(bl);
  759. tbl = ers_alloc(clif->delay_clearunit_ers, struct block_list);
  760. memcpy (tbl, bl, sizeof (struct block_list));
  761. timer->add(tick, clif->clearunit_delayed_sub, (int)type, (intptr_t)tbl);
  762. }
  763. /// Gets weapon view info from sd's inventory_data and points (*rhand,*lhand)
  764. void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, unsigned short *lhand)
  765. {
  766. nullpo_retv(sd);
  767. nullpo_retv(rhand);
  768. nullpo_retv(lhand);
  769. if(sd->sc.option&OPTION_COSTUME) {
  770. *rhand = *lhand = 0;
  771. return;
  772. }
  773. #if PACKETVER < 4
  774. *rhand = sd->status.weapon;
  775. *lhand = sd->status.shield;
  776. #else
  777. if (sd->equip_index[EQI_HAND_R] >= 0 &&
  778. sd->inventory_data[sd->equip_index[EQI_HAND_R]])
  779. {
  780. struct item_data* id = sd->inventory_data[sd->equip_index[EQI_HAND_R]];
  781. if (id->view_id > 0)
  782. *rhand = id->view_id;
  783. else
  784. *rhand = id->nameid;
  785. } else
  786. *rhand = 0;
  787. if (sd->equip_index[EQI_HAND_L] >= 0 &&
  788. sd->equip_index[EQI_HAND_L] != sd->equip_index[EQI_HAND_R] &&
  789. sd->inventory_data[sd->equip_index[EQI_HAND_L]])
  790. {
  791. struct item_data* id = sd->inventory_data[sd->equip_index[EQI_HAND_L]];
  792. if (id->view_id > 0)
  793. *lhand = id->view_id;
  794. else
  795. *lhand = id->nameid;
  796. } else
  797. *lhand = 0;
  798. #endif
  799. }
  800. //To make the assignation of the level based on limits clearer/easier. [Skotlex]
  801. static int clif_setlevel_sub(int lv) {
  802. if( lv < battle_config.max_lv ) {
  803. ;
  804. } else if( lv < battle_config.aura_lv ) {
  805. lv = battle_config.max_lv - 1;
  806. } else {
  807. lv = battle_config.max_lv;
  808. }
  809. return lv;
  810. }
  811. static int clif_setlevel(struct block_list* bl) {
  812. int lv = status->get_lv(bl);
  813. nullpo_retr(0, bl);
  814. if( battle_config.client_limit_unit_lv&bl->type )
  815. return clif_setlevel_sub(lv);
  816. switch( bl->type ) {
  817. case BL_NPC:
  818. case BL_PET:
  819. // npcs and pets do not have level
  820. return 0;
  821. }
  822. return lv;
  823. }
  824. /* for 'packetver < 20091103' 0x78 non-pc-looking unit handling */
  825. void clif_set_unit_idle2(struct block_list* bl, struct map_session_data *tsd, enum send_target target) {
  826. #if PACKETVER < 20091103
  827. struct map_session_data* sd;
  828. struct status_change* sc = status->get_sc(bl);
  829. struct view_data* vd = status->get_viewdata(bl);
  830. struct packet_idle_unit2 p;
  831. int g_id = status->get_guild_id(bl);
  832. nullpo_retv(bl);
  833. sd = BL_CAST(BL_PC, bl);
  834. p.PacketType = idle_unit2Type;
  835. #if PACKETVER >= 20071106
  836. p.objecttype = clif_bl_type(bl);
  837. #endif
  838. p.GID = bl->id;
  839. p.speed = status->get_speed(bl);
  840. p.bodyState = (sc) ? sc->opt1 : 0;
  841. p.healthState = (sc) ? sc->opt2 : 0;
  842. p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
  843. p.job = vd->class_;
  844. p.head = vd->hair_style;
  845. p.weapon = vd->weapon;
  846. p.accessory = vd->head_bottom;
  847. p.shield = vd->shield;
  848. p.accessory2 = vd->head_top;
  849. p.accessory3 = vd->head_mid;
  850. if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this?
  851. p.shield = status->get_emblem_id(bl);
  852. p.accessory2 = GetWord(g_id, 1);
  853. p.accessory3 = GetWord(g_id, 0);
  854. }
  855. p.headpalette = vd->hair_color;
  856. p.bodypalette = vd->cloth_color;
  857. p.headDir = (sd)? sd->head_dir : 0;
  858. p.GUID = g_id;
  859. p.GEmblemVer = status->get_emblem_id(bl);
  860. p.honor = (sd) ? sd->status.manner : 0;
  861. p.virtue = (sc) ? sc->opt3 : 0;
  862. p.isPKModeON = (sd && sd->status.karma) ? 1 : 0;
  863. p.sex = vd->sex;
  864. WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl));
  865. p.xSize = p.ySize = (sd) ? 5 : 0;
  866. p.state = vd->dead_sit;
  867. p.clevel = clif_setlevel(bl);
  868. clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target);
  869. #else
  870. return;
  871. #endif
  872. }
  873. /*==========================================
  874. * Prepares 'unit standing' packet
  875. *------------------------------------------*/
  876. void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enum send_target target) {
  877. struct map_session_data* sd;
  878. struct status_change* sc = status->get_sc(bl);
  879. struct view_data* vd = status->get_viewdata(bl);
  880. struct packet_idle_unit p;
  881. int g_id = status->get_guild_id(bl);
  882. nullpo_retv(bl);
  883. #if PACKETVER < 20091103
  884. if( !pc->db_checkid(vd->class_) ) {
  885. clif->set_unit_idle2(bl,tsd,target);
  886. return;
  887. }
  888. #endif
  889. sd = BL_CAST(BL_PC, bl);
  890. p.PacketType = idle_unitType;
  891. #if PACKETVER >= 20091103
  892. p.PacketLength = sizeof(p);
  893. p.objecttype = clif_bl_type(bl);
  894. #endif
  895. #if PACKETVER >= 20131223
  896. p.AID = bl->id;
  897. p.GID = (sd) ? sd->status.char_id : 0; // CCODE
  898. #else
  899. p.GID = bl->id;
  900. #endif
  901. p.speed = status->get_speed(bl);
  902. p.bodyState = (sc) ? sc->opt1 : 0;
  903. p.healthState = (sc) ? sc->opt2 : 0;
  904. p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
  905. p.job = vd->class_;
  906. p.head = vd->hair_style;
  907. p.weapon = vd->weapon;
  908. p.accessory = vd->head_bottom;
  909. #if PACKETVER < 7
  910. p.shield = vd->shield;
  911. #endif
  912. p.accessory2 = vd->head_top;
  913. p.accessory3 = vd->head_mid;
  914. if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this?
  915. p.accessory = status->get_emblem_id(bl);
  916. p.accessory2 = GetWord(g_id, 1);
  917. p.accessory3 = GetWord(g_id, 0);
  918. }
  919. p.headpalette = vd->hair_color;
  920. p.bodypalette = vd->cloth_color;
  921. p.headDir = (sd)? sd->head_dir : 0;
  922. #if PACKETVER >= 20101124
  923. p.robe = vd->robe;
  924. #endif
  925. p.GUID = g_id;
  926. p.GEmblemVer = status->get_emblem_id(bl);
  927. p.honor = (sd) ? sd->status.manner : 0;
  928. p.virtue = (sc) ? sc->opt3 : 0;
  929. p.isPKModeON = (sd && sd->status.karma) ? 1 : 0;
  930. p.sex = vd->sex;
  931. WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl));
  932. p.xSize = p.ySize = (sd) ? 5 : 0;
  933. p.state = vd->dead_sit;
  934. p.clevel = clif_setlevel(bl);
  935. #if PACKETVER >= 20080102
  936. p.font = (sd) ? sd->status.font : 0;
  937. #endif
  938. #if PACKETVER >= 20120221
  939. if (battle_config.show_monster_hp_bar && bl->type == BL_MOB && status_get_hp(bl) < status_get_max_hp(bl)) {
  940. const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
  941. p.maxHP = status_get_max_hp(bl);
  942. p.HP = status_get_hp(bl);
  943. p.isBoss = (md->spawn != NULL && md->spawn->state.boss) ? 1 : 0;
  944. } else {
  945. p.maxHP = -1;
  946. p.HP = -1;
  947. p.isBoss = 0;
  948. }
  949. #endif
  950. #if PACKETVER >= 20150513
  951. p.body = vd->body_style;
  952. #endif
  953. clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target);
  954. if( disguised(bl) ) {
  955. #if PACKETVER >= 20091103
  956. p.objecttype = pc->db_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE
  957. p.GID = -bl->id;
  958. #else
  959. p.GID = -bl->id;
  960. #endif
  961. clif->send(&p,sizeof(p),bl,SELF);
  962. }
  963. }
  964. /* for 'packetver < 20091103' 0x7c non-pc-looking unit handling */
  965. void clif_spawn_unit2(struct block_list* bl, enum send_target target) {
  966. #if PACKETVER < 20091103
  967. struct map_session_data* sd;
  968. struct status_change* sc = status->get_sc(bl);
  969. struct view_data* vd = status->get_viewdata(bl);
  970. struct packet_spawn_unit2 p;
  971. int g_id = status->get_guild_id(bl);
  972. nullpo_retv(bl);
  973. sd = BL_CAST(BL_PC, bl);
  974. p.PacketType = spawn_unit2Type;
  975. #if PACKETVER >= 20071106
  976. p.objecttype = clif_bl_type(bl);
  977. #endif
  978. p.GID = bl->id;
  979. p.speed = status->get_speed(bl);
  980. p.bodyState = (sc) ? sc->opt1 : 0;
  981. p.healthState = (sc) ? sc->opt2 : 0;
  982. p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
  983. p.head = vd->hair_style;
  984. p.weapon = vd->weapon;
  985. p.accessory = vd->head_bottom;
  986. p.job = vd->class_;
  987. p.shield = vd->shield;
  988. p.accessory2 = vd->head_top;
  989. p.accessory3 = vd->head_mid;
  990. if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this?
  991. p.shield = status->get_emblem_id(bl);
  992. p.accessory2 = GetWord(g_id, 1);
  993. p.accessory3 = GetWord(g_id, 0);
  994. }
  995. p.headpalette = vd->hair_color;
  996. p.bodypalette = vd->cloth_color;
  997. p.headDir = (sd)? sd->head_dir : 0;
  998. p.isPKModeON = (sd && sd->status.karma) ? 1 : 0;
  999. p.sex = vd->sex;
  1000. WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl));
  1001. p.xSize = p.ySize = (sd) ? 5 : 0;
  1002. clif->send(&p,sizeof(p),bl,target);
  1003. #else
  1004. return;
  1005. #endif
  1006. }
  1007. void clif_spawn_unit(struct block_list* bl, enum send_target target) {
  1008. struct map_session_data* sd;
  1009. struct status_change* sc = status->get_sc(bl);
  1010. struct view_data* vd = status->get_viewdata(bl);
  1011. struct packet_spawn_unit p;
  1012. int g_id = status->get_guild_id(bl);
  1013. nullpo_retv(bl);
  1014. #if PACKETVER < 20091103
  1015. if( !pc->db_checkid(vd->class_) ) {
  1016. clif->spawn_unit2(bl,target);
  1017. return;
  1018. }
  1019. #endif
  1020. sd = BL_CAST(BL_PC, bl);
  1021. p.PacketType = spawn_unitType;
  1022. #if PACKETVER >= 20091103
  1023. p.PacketLength = sizeof(p);
  1024. p.objecttype = clif_bl_type(bl);
  1025. #endif
  1026. #if PACKETVER >= 20131223
  1027. p.AID = bl->id;
  1028. p.GID = (sd) ? sd->status.char_id : 0; // CCODE
  1029. #else
  1030. p.GID = bl->id;
  1031. #endif
  1032. p.speed = status->get_speed(bl);
  1033. p.bodyState = (sc) ? sc->opt1 : 0;
  1034. p.healthState = (sc) ? sc->opt2 : 0;
  1035. p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
  1036. p.job = vd->class_;
  1037. p.head = vd->hair_style;
  1038. p.weapon = vd->weapon;
  1039. p.accessory = vd->head_bottom;
  1040. #if PACKETVER < 7
  1041. p.shield = vd->shield;
  1042. #endif
  1043. p.accessory2 = vd->head_top;
  1044. p.accessory3 = vd->head_mid;
  1045. if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this?
  1046. p.accessory = status->get_emblem_id(bl);
  1047. p.accessory2 = GetWord(g_id, 1);
  1048. p.accessory3 = GetWord(g_id, 0);
  1049. }
  1050. p.headpalette = vd->hair_color;
  1051. p.bodypalette = vd->cloth_color;
  1052. p.headDir = (sd)? sd->head_dir : 0;
  1053. #if PACKETVER >= 20101124
  1054. p.robe = vd->robe;
  1055. #endif
  1056. p.GUID = g_id;
  1057. p.GEmblemVer = status->get_emblem_id(bl);
  1058. p.honor = (sd) ? sd->status.manner : 0;
  1059. p.virtue = (sc) ? sc->opt3 : 0;
  1060. p.isPKModeON = (sd && sd->status.karma) ? 1 : 0;
  1061. p.sex = vd->sex;
  1062. WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl));
  1063. p.xSize = p.ySize = (sd) ? 5 : 0;
  1064. p.clevel = clif_setlevel(bl);
  1065. #if PACKETVER >= 20080102
  1066. p.font = (sd) ? sd->status.font : 0;
  1067. #endif
  1068. #if PACKETVER >= 20120221
  1069. if (battle_config.show_monster_hp_bar && bl->type == BL_MOB && status_get_hp(bl) < status_get_max_hp(bl)) {
  1070. const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
  1071. p.maxHP = status_get_max_hp(bl);
  1072. p.HP = status_get_hp(bl);
  1073. p.isBoss = (md->spawn != NULL && md->spawn->state.boss) ? 1 : 0;
  1074. } else {
  1075. p.maxHP = -1;
  1076. p.HP = -1;
  1077. p.isBoss = 0;
  1078. }
  1079. #endif
  1080. #if PACKETVER >= 20150513
  1081. p.body = vd->body_style;
  1082. #endif
  1083. if( disguised(bl) ) {
  1084. nullpo_retv(sd);
  1085. if( sd->status.class_ != sd->disguise )
  1086. clif->send(&p,sizeof(p),bl,target);
  1087. #if PACKETVER >= 20091103
  1088. p.objecttype = pc->db_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE
  1089. p.GID = -bl->id;
  1090. #else
  1091. p.GID = -bl->id;
  1092. #endif
  1093. clif->send(&p,sizeof(p),bl,SELF);
  1094. } else
  1095. clif->send(&p,sizeof(p),bl,target);
  1096. }
  1097. /*==========================================
  1098. * Prepares 'unit walking' packet
  1099. *------------------------------------------*/
  1100. void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, struct unit_data* ud, enum send_target target) {
  1101. struct map_session_data* sd;
  1102. struct status_change* sc = status->get_sc(bl);
  1103. struct view_data* vd = status->get_viewdata(bl);
  1104. struct packet_unit_walking p;
  1105. int g_id = status->get_guild_id(bl);
  1106. nullpo_retv(bl);
  1107. nullpo_retv(ud);
  1108. sd = BL_CAST(BL_PC, bl);
  1109. p.PacketType = unit_walkingType;
  1110. #if PACKETVER >= 20091103
  1111. p.PacketLength = sizeof(p);
  1112. #endif
  1113. #if PACKETVER >= 20071106
  1114. p.objecttype = clif_bl_type(bl);
  1115. #endif
  1116. #if PACKETVER >= 20131223
  1117. p.AID = bl->id;
  1118. p.GID = (tsd) ? tsd->status.char_id : 0; // CCODE
  1119. #else
  1120. p.GID = bl->id;
  1121. #endif
  1122. p.speed = status->get_speed(bl);
  1123. p.bodyState = (sc) ? sc->opt1 : 0;
  1124. p.healthState = (sc) ? sc->opt2 : 0;
  1125. p.effectState = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
  1126. p.job = vd->class_;
  1127. p.head = vd->hair_style;
  1128. p.weapon = vd->weapon;
  1129. p.accessory = vd->head_bottom;
  1130. p.moveStartTime = (unsigned int)timer->gettick();
  1131. #if PACKETVER < 7
  1132. p.shield = vd->shield;
  1133. #endif
  1134. p.accessory2 = vd->head_top;
  1135. p.accessory3 = vd->head_mid;
  1136. p.headpalette = vd->hair_color;
  1137. p.bodypalette = vd->cloth_color;
  1138. p.headDir = (sd)? sd->head_dir : 0;
  1139. #if PACKETVER >= 20101124
  1140. p.robe = vd->robe;
  1141. #endif
  1142. p.GUID = g_id;
  1143. p.GEmblemVer = status->get_emblem_id(bl);
  1144. p.honor = (sd) ? sd->status.manner : 0;
  1145. p.virtue = (sc) ? sc->opt3 : 0;
  1146. p.isPKModeON = (sd && sd->status.karma) ? 1 : 0;
  1147. p.sex = vd->sex;
  1148. WBUFPOS2(&p.MoveData[0],0,bl->x,bl->y,ud->to_x,ud->to_y,8,8);
  1149. p.xSize = p.ySize = (sd) ? 5 : 0;
  1150. p.clevel = clif_setlevel(bl);
  1151. #if PACKETVER >= 20080102
  1152. p.font = (sd) ? sd->status.font : 0;
  1153. #endif
  1154. #if PACKETVER >= 20120221
  1155. if (battle_config.show_monster_hp_bar && bl->type == BL_MOB && status_get_hp(bl) < status_get_max_hp(bl)) {
  1156. const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
  1157. p.maxHP = status_get_max_hp(bl);
  1158. p.HP = status_get_hp(bl);
  1159. p.isBoss = (md->spawn != NULL && md->spawn->state.boss) ? 1 : 0;
  1160. } else {
  1161. p.maxHP = -1;
  1162. p.HP = -1;
  1163. p.isBoss = 0;
  1164. }
  1165. #endif
  1166. #if PACKETVER >= 20150513
  1167. p.body = vd->body_style;
  1168. #endif
  1169. clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target);
  1170. if( disguised(bl) ) {
  1171. #if PACKETVER >= 20091103
  1172. p.objecttype = pc->db_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE
  1173. p.GID = -bl->id;
  1174. #else
  1175. p.GID = -bl->id;
  1176. #endif
  1177. clif->send(&p,sizeof(p),bl,SELF);
  1178. }
  1179. }
  1180. /// Changes sprite of an NPC object (ZC_NPCSPRITE_CHANGE).
  1181. /// 01b0 <id>.L <type>.B <value>.L
  1182. /// type:
  1183. /// unused
  1184. void clif_class_change(struct block_list *bl, int class_, int type)
  1185. {
  1186. nullpo_retv(bl);
  1187. if(!pc->db_checkid(class_))
  1188. {// player classes yield missing sprites
  1189. unsigned char buf[16];
  1190. WBUFW(buf,0)=0x1b0;
  1191. WBUFL(buf,2)=bl->id;
  1192. WBUFB(buf,6)=type;
  1193. WBUFL(buf,7)=class_;
  1194. clif->send(buf,packet_len(0x1b0),bl,AREA);
  1195. }
  1196. }
  1197. /// Notifies the client of an object's spirits.
  1198. /// 01d0 <id>.L <amount>.W (ZC_SPIRITS)
  1199. /// 01e1 <id>.L <amount>.W (ZC_SPIRITS2)
  1200. void clif_spiritball_single(int fd, struct map_session_data *sd) {
  1201. nullpo_retv(sd);
  1202. WFIFOHEAD(fd, packet_len(0x1e1));
  1203. WFIFOW(fd,0)=0x1e1;
  1204. WFIFOL(fd,2)=sd->bl.id;
  1205. WFIFOW(fd,6)=sd->spiritball;
  1206. WFIFOSET(fd, packet_len(0x1e1));
  1207. }
  1208. /*==========================================
  1209. * Kagerou/Oboro amulet spirit
  1210. *------------------------------------------*/
  1211. void clif_charm_single(int fd, struct map_session_data *sd)
  1212. {
  1213. nullpo_retv(sd);
  1214. WFIFOHEAD(fd, packet_len(0x08cf));
  1215. WFIFOW(fd,0) = 0x08cf;
  1216. WFIFOL(fd,2) = sd->bl.id;
  1217. WFIFOW(fd,6) = sd->charm_type;
  1218. WFIFOW(fd,8) = sd->charm_count;
  1219. WFIFOSET(fd, packet_len(0x08cf));
  1220. }
  1221. /*==========================================
  1222. * Run when player changes map / refreshes
  1223. * Tells its client to display all weather settings being used by this map
  1224. *------------------------------------------*/
  1225. void clif_weather_check(struct map_session_data *sd) {
  1226. int16 m;
  1227. int fd;
  1228. nullpo_retv(sd);
  1229. m = sd->bl.m;
  1230. fd = sd->fd;
  1231. if (map->list[m].flag.snow)
  1232. clif->specialeffect_single(&sd->bl, 162, fd);
  1233. if (map->list[m].flag.clouds)
  1234. clif->specialeffect_single(&sd->bl, 233, fd);
  1235. if (map->list[m].flag.clouds2)
  1236. clif->specialeffect_single(&sd->bl, 516, fd);
  1237. if (map->list[m].flag.fog)
  1238. clif->specialeffect_single(&sd->bl, 515, fd);
  1239. if (map->list[m].flag.fireworks) {
  1240. clif->specialeffect_single(&sd->bl, 297, fd);
  1241. clif->specialeffect_single(&sd->bl, 299, fd);
  1242. clif->specialeffect_single(&sd->bl, 301, fd);
  1243. }
  1244. if (map->list[m].flag.sakura)
  1245. clif->specialeffect_single(&sd->bl, 163, fd);
  1246. if (map->list[m].flag.leaves)
  1247. clif->specialeffect_single(&sd->bl, 333, fd);
  1248. }
  1249. /**
  1250. * Run when the weather on a map changes, throws all players in map id 'm' to clif_weather_check function
  1251. **/
  1252. void clif_weather(int16 m)
  1253. {
  1254. struct s_mapiterator* iter;
  1255. struct map_session_data *sd=NULL;
  1256. iter = mapit_getallusers();
  1257. for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
  1258. if( sd->bl.m == m )
  1259. clif->weather_check(sd);
  1260. }
  1261. mapit->free(iter);
  1262. }
  1263. /**
  1264. * Main function to spawn a unit on the client (player/mob/pet/etc)
  1265. **/
  1266. bool clif_spawn(struct block_list *bl)
  1267. {
  1268. struct view_data *vd;
  1269. nullpo_retr(false, bl);
  1270. vd = status->get_viewdata(bl);
  1271. if( !vd )
  1272. return false;
  1273. if (vd->class_ == INVISIBLE_CLASS)
  1274. return true; // Doesn't need to be spawned, so everything is alright
  1275. if (bl->type == BL_NPC) {
  1276. struct npc_data *nd = BL_UCAST(BL_NPC, bl);
  1277. if (nd->chat_id == 0 && (nd->option&OPTION_INVISIBLE)) // Hide NPC from maya purple card.
  1278. return true; // Doesn't need to be spawned, so everything is alright
  1279. }
  1280. clif->spawn_unit(bl,AREA_WOS);
  1281. if (vd->cloth_color)
  1282. clif->refreshlook(bl,bl->id,LOOK_CLOTHES_COLOR,vd->cloth_color,AREA_WOS);
  1283. if (vd->body_style)
  1284. clif->refreshlook(bl,bl->id,LOOK_BODY2,vd->body_style,AREA_WOS);
  1285. switch (bl->type) {
  1286. case BL_PC:
  1287. {
  1288. struct map_session_data *sd = BL_UCAST(BL_PC, bl);
  1289. int i;
  1290. if (sd->spiritball > 0)
  1291. clif->spiritball(&sd->bl);
  1292. if (sd->state.size == SZ_BIG) // tiny/big players [Valaris]
  1293. clif->specialeffect(bl,423,AREA);
  1294. else if (sd->state.size == SZ_MEDIUM)
  1295. clif->specialeffect(bl,421,AREA);
  1296. if (sd->bg_id != 0 && map->list[sd->bl.m].flag.battleground)
  1297. clif->sendbgemblem_area(sd);
  1298. for (i = 0; i < sd->sc_display_count; i++) {
  1299. 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);
  1300. }
  1301. if (sd->charm_type != CHARM_TYPE_NONE && sd->charm_count > 0)
  1302. clif->spiritcharm(sd);
  1303. if (sd->status.robe)
  1304. clif->refreshlook(bl,bl->id,LOOK_ROBE,sd->status.robe,AREA);
  1305. }
  1306. break;
  1307. case BL_MOB:
  1308. {
  1309. struct mob_data *md = BL_UCAST(BL_MOB, bl);
  1310. if (md->special_state.size==SZ_BIG) // tiny/big mobs [Valaris]
  1311. clif->specialeffect(&md->bl,423,AREA);
  1312. else if (md->special_state.size==SZ_MEDIUM)
  1313. clif->specialeffect(&md->bl,421,AREA);
  1314. }
  1315. break;
  1316. case BL_NPC:
  1317. {
  1318. struct npc_data *nd = BL_UCAST(BL_NPC, bl);
  1319. if (nd->size == SZ_BIG)
  1320. clif->specialeffect(&nd->bl,423,AREA);
  1321. else if (nd->size == SZ_MEDIUM)
  1322. clif->specialeffect(&nd->bl,421,AREA);
  1323. }
  1324. break;
  1325. case BL_PET:
  1326. if (vd->head_bottom)
  1327. clif->send_petdata(NULL, BL_UCAST(BL_PET, bl), 3, vd->head_bottom); // needed to display pet equip properly
  1328. break;
  1329. }
  1330. return true;
  1331. }
  1332. /// Sends information about owned homunculus to the client (ZC_PROPERTY_HOMUN). [orn]
  1333. /// 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
  1334. void clif_hominfo(struct map_session_data *sd, struct homun_data *hd, int flag) {
  1335. struct status_data *hstatus;
  1336. unsigned char buf[128];
  1337. enum homun_type htype;
  1338. nullpo_retv(sd);
  1339. nullpo_retv(hd);
  1340. hstatus = &hd->battle_status;
  1341. htype = homun->class2type(hd->homunculus.class_);
  1342. memset(buf,0,packet_len(0x22e));
  1343. WBUFW(buf,0)=0x22e;
  1344. memcpy(WBUFP(buf,2),hd->homunculus.name,NAME_LENGTH);
  1345. // Bit field, bit 0 : rename_flag (1 = already renamed), bit 1 : homunc vaporized (1 = true), bit 2 : homunc dead (1 = true)
  1346. 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);
  1347. WBUFW(buf,27)=hd->homunculus.level;
  1348. WBUFW(buf,29)=hd->homunculus.hunger;
  1349. WBUFW(buf,31)=(unsigned short) (hd->homunculus.intimacy / 100) ;
  1350. WBUFW(buf,33)=0; // equip id
  1351. #ifdef RENEWAL
  1352. WBUFW(buf, 35) = cap_value(hstatus->rhw.atk2, 0, INT16_MAX);
  1353. #else
  1354. WBUFW(buf,35)=cap_value(hstatus->rhw.atk2+hstatus->batk, 0, INT16_MAX);
  1355. #endif
  1356. WBUFW(buf,37)=cap_value(hstatus->matk_max, 0, INT16_MAX);
  1357. WBUFW(buf,39)=hstatus->hit;
  1358. if (battle_config.hom_setting&0x10)
  1359. WBUFW(buf,41)=hstatus->luk/3 + 1; //crit is a +1 decimal value! Just display purpose.[Vicious]
  1360. else
  1361. WBUFW(buf,41)=hstatus->cri/10;
  1362. #ifdef RENEWAL
  1363. WBUFW(buf, 43) = hstatus->def + hstatus->def2;
  1364. WBUFW(buf, 45) = hstatus->mdef + hstatus->mdef2;
  1365. #else
  1366. WBUFW(buf,43)=hstatus->def + hstatus->vit ;
  1367. WBUFW(buf, 45) = hstatus->mdef;
  1368. #endif
  1369. WBUFW(buf,47)=hstatus->flee;
  1370. WBUFW(buf,49)=(flag)?0:hstatus->amotion;
  1371. if (hstatus->max_hp > INT16_MAX) {
  1372. WBUFW(buf,51) = hstatus->hp/(hstatus->max_hp/100);
  1373. WBUFW(buf,53) = 100;
  1374. } else {
  1375. WBUFW(buf,51)=hstatus->hp;
  1376. WBUFW(buf,53)=hstatus->max_hp;
  1377. }
  1378. if (hstatus->max_sp > INT16_MAX) {
  1379. WBUFW(buf,55) = hstatus->sp/(hstatus->max_sp/100);
  1380. WBUFW(buf,57) = 100;
  1381. } else {
  1382. WBUFW(buf,55)=hstatus->sp;
  1383. WBUFW(buf,57)=hstatus->max_sp;
  1384. }
  1385. WBUFL(buf,59)=hd->homunculus.exp;
  1386. WBUFL(buf,63)=hd->exp_next;
  1387. switch( htype ) {
  1388. case HT_REG:
  1389. case HT_EVO:
  1390. if( hd->homunculus.level >= battle_config.hom_max_level )
  1391. WBUFL(buf,63)=0;
  1392. break;
  1393. case HT_S:
  1394. if( hd->homunculus.level >= battle_config.hom_S_max_level )
  1395. WBUFL(buf,63)=0;
  1396. break;
  1397. }
  1398. WBUFW(buf,67)=hd->homunculus.skillpts;
  1399. WBUFW(buf,69)=status_get_range(&hd->bl);
  1400. clif->send(buf,packet_len(0x22e),&sd->bl,SELF);
  1401. }
  1402. /// Notification about a change in homunuculus' state (ZC_CHANGESTATE_MER).
  1403. /// 0230 <type>.B <state>.B <id>.L <data>.L
  1404. /// type:
  1405. /// unused
  1406. /// state:
  1407. /// 0 = pre-init
  1408. /// 1 = intimacy
  1409. /// 2 = hunger
  1410. /// 3 = accessory?
  1411. /// ? = ignored
  1412. void clif_send_homdata(struct map_session_data *sd, int state, int param)
  1413. {
  1414. int fd;
  1415. nullpo_retv(sd);
  1416. nullpo_retv(sd->hd);
  1417. fd = sd->fd;
  1418. if ( (state == SP_INTIMATE) && (param >= 910) && (sd->hd->homunculus.class_ == sd->hd->homunculusDB->evo_class) )
  1419. homun->calc_skilltree(sd->hd, 0);
  1420. WFIFOHEAD(fd, packet_len(0x230));
  1421. WFIFOW(fd,0)=0x230;
  1422. WFIFOB(fd,2)=0;
  1423. WFIFOB(fd,3)=state;
  1424. WFIFOL(fd,4)=sd->hd->bl.id;
  1425. WFIFOL(fd,8)=param;
  1426. WFIFOSET(fd,packet_len(0x230));
  1427. }
  1428. /// Prepares and sends homun related information [orn]
  1429. void clif_homskillinfoblock(struct map_session_data *sd) {
  1430. struct homun_data *hd;
  1431. int fd;
  1432. int i,j;
  1433. int len=4;
  1434. nullpo_retv(sd);
  1435. fd = sd->fd;
  1436. hd = sd->hd;
  1437. if ( !hd )
  1438. return;
  1439. WFIFOHEAD(fd, 4+37*MAX_HOMUNSKILL);
  1440. WFIFOW(fd,0)=0x235;
  1441. for ( i = 0; i < MAX_HOMUNSKILL; i++ ) {
  1442. int id = hd->homunculus.hskill[i].id;
  1443. if ( id != 0 ) {
  1444. j = id - HM_SKILLBASE;
  1445. WFIFOW(fd, len) = id;
  1446. WFIFOW(fd, len + 2) = skill->get_inf(id);
  1447. WFIFOW(fd, len + 4) = 0;
  1448. WFIFOW(fd, len + 6) = hd->homunculus.hskill[j].lv;
  1449. if ( hd->homunculus.hskill[j].lv ) {
  1450. WFIFOW(fd, len + 8) = skill->get_sp(id, hd->homunculus.hskill[j].lv);
  1451. WFIFOW(fd, len + 10) = skill->get_range2(&sd->hd->bl, id, hd->homunculus.hskill[j].lv);
  1452. } else {
  1453. WFIFOW(fd, len + 8) = 0;
  1454. WFIFOW(fd, len + 10) = 0;
  1455. }
  1456. safestrncpy((char*)WFIFOP(fd, len + 12), skill->get_name(id), NAME_LENGTH);
  1457. WFIFOB(fd, len + 36) = (hd->homunculus.hskill[j].lv < homun->skill_tree_get_max(id, hd->homunculus.class_)) ? 1 : 0;
  1458. len += 37;
  1459. }
  1460. }
  1461. WFIFOW(fd,2)=len;
  1462. WFIFOSET(fd,len);
  1463. return;
  1464. }
  1465. void clif_homskillup(struct map_session_data *sd, uint16 skill_id) { //[orn]
  1466. struct homun_data *hd;
  1467. int fd, idx;
  1468. nullpo_retv(sd);
  1469. nullpo_retv(sd->hd);
  1470. idx = skill_id - HM_SKILLBASE;
  1471. fd=sd->fd;
  1472. hd=sd->hd;
  1473. WFIFOHEAD(fd, packet_len(0x239));
  1474. WFIFOW(fd,0) = 0x239;
  1475. WFIFOW(fd,2) = skill_id;
  1476. WFIFOW(fd,4) = hd->homunculus.hskill[idx].lv;
  1477. WFIFOW(fd,6) = skill->get_sp(skill_id,hd->homunculus.hskill[idx].lv);
  1478. WFIFOW(fd,8) = skill->get_range2(&hd->bl, skill_id,hd->homunculus.hskill[idx].lv);
  1479. WFIFOB(fd,10) = (hd->homunculus.hskill[idx].lv < skill->get_max(hd->homunculus.hskill[idx].id)) ? 1 : 0;
  1480. WFIFOSET(fd,packet_len(0x239));
  1481. }
  1482. void clif_hom_food(struct map_session_data *sd,int foodid,int fail)
  1483. {
  1484. int fd;
  1485. nullpo_retv(sd);
  1486. fd = sd->fd;
  1487. WFIFOHEAD(fd,packet_len(0x22f));
  1488. WFIFOW(fd,0)=0x22f;
  1489. WFIFOB(fd,2)=fail;
  1490. WFIFOW(fd,3)=foodid;
  1491. WFIFOSET(fd,packet_len(0x22f));
  1492. return;
  1493. }
  1494. /// Notifies the client, that it is walking (ZC_NOTIFY_PLAYERMOVE).
  1495. /// 0087 <walk start time>.L <walk data>.6B
  1496. void clif_walkok(struct map_session_data *sd)
  1497. {
  1498. int fd;
  1499. nullpo_retv(sd);
  1500. fd = sd->fd;
  1501. WFIFOHEAD(fd, packet_len(0x87));
  1502. WFIFOW(fd,0)=0x87;
  1503. WFIFOL(fd,2)=(unsigned int)timer->gettick();
  1504. WFIFOPOS2(fd,6,sd->bl.x,sd->bl.y,sd->ud.to_x,sd->ud.to_y,8,8);
  1505. WFIFOSET(fd,packet_len(0x87));
  1506. }
  1507. void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *ud) {
  1508. #ifdef ANTI_MAYAP_CHEAT
  1509. struct status_change *sc = NULL;
  1510. #endif
  1511. nullpo_retv(bl);
  1512. nullpo_retv(vd);
  1513. nullpo_retv(ud);
  1514. #ifdef ANTI_MAYAP_CHEAT
  1515. if( (sc = status->get_sc(bl)) && sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE|OPTION_CHASEWALK) )
  1516. clif->ally_only = true;
  1517. #endif
  1518. clif->set_unit_walking(bl,NULL,ud,AREA_WOS);
  1519. if(vd->cloth_color)
  1520. clif->refreshlook(bl,bl->id,LOOK_CLOTHES_COLOR,vd->cloth_color,AREA_WOS);
  1521. if (vd->body_style)
  1522. clif->refreshlook(bl,bl->id,LOOK_BODY2,vd->body_style,AREA_WOS);
  1523. switch(bl->type) {
  1524. case BL_PC:
  1525. {
  1526. struct map_session_data *sd = BL_UCAST(BL_PC, bl);
  1527. //clif_movepc(sd);
  1528. if(sd->state.size==SZ_BIG) // tiny/big players [Valaris]
  1529. clif->specialeffect(&sd->bl,423,AREA);
  1530. else if(sd->state.size==SZ_MEDIUM)
  1531. clif->specialeffect(&sd->bl,421,AREA);
  1532. }
  1533. break;
  1534. case BL_MOB:
  1535. {
  1536. struct mob_data *md = BL_UCAST(BL_MOB, bl);
  1537. if (md->special_state.size == SZ_BIG) // tiny/big mobs [Valaris]
  1538. clif->specialeffect(&md->bl,423,AREA);
  1539. else if (md->special_state.size == SZ_MEDIUM)
  1540. clif->specialeffect(&md->bl,421,AREA);
  1541. }
  1542. break;
  1543. case BL_PET:
  1544. if( vd->head_bottom ) // needed to display pet equip properly
  1545. clif->send_petdata(NULL, BL_UCAST(BL_PET, bl), 3, vd->head_bottom);
  1546. break;
  1547. }
  1548. #ifdef ANTI_MAYAP_CHEAT
  1549. clif->al

Large files files are truncated, but you can click here to view the full file