From f5c9f9f42da5889d38104e8b44956a7da461393d Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Tue, 5 Jan 2016 18:56:23 +0300 Subject: Reimpliment packet 0x915 for old clients. --- src/emap/clif.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++ src/emap/clif.h | 4 + src/emap/packets_struct.h | 94 ++++++++++++++++++++++ 3 files changed, 291 insertions(+) create mode 100644 src/emap/packets_struct.h (limited to 'src/emap') diff --git a/src/emap/clif.c b/src/emap/clif.c index b04b3b5..8e81d80 100644 --- a/src/emap/clif.c +++ b/src/emap/clif.c @@ -14,6 +14,7 @@ #include "common/socket.h" #include "common/strlib.h" #include "common/cbasetypes.h" +//#include "common/utils.h" #include "common/timer.h" #include "map/guild.h" #include "map/mob.h" @@ -24,6 +25,7 @@ #include "emap/clif.h" #include "emap/lang.h" #include "emap/map.h" +#include "emap/packets_struct.h" #include "emap/send.h" #include "emap/data/mapd.h" #include "emap/data/session.h" @@ -346,7 +348,37 @@ bool eclif_send(const void* buf __attribute__ ((unused)), enum send_target *type) { if (*type == SELF) + { + if (*len >= 2) + { + const int packet = RBUFW (buf, 0); + if (packet == 0x9dd) + { + struct map_session_data *sd = BL_CAST(BL_PC, bl); + struct SessionExt *data = session_get_bysd(sd); + if (!data) + return true; + if (data->clientVersion < 16) + { // not sending new packet to old clients + hookStop(); + return true; + } + } + if (packet == 0x915) + { + struct map_session_data *sd = BL_CAST(BL_PC, bl); + struct SessionExt *data = session_get_bysd(sd); + if (!data) + return true; + if (data->clientVersion >= 16) + { // not sending old packet to new clients + hookStop(); + return true; + } + } + } return true; + } eclif_handle_invisible_map(bl, *type); return true; } @@ -477,16 +509,177 @@ int eclif_send_actual(int *fd, void *buf, int *len) return 0; } } + if (packet == 0x9dd) + { + struct SessionExt *data = session_get(*fd); + if (!data) + return 0; + if (data->clientVersion < 16) + { // not sending new packets to old clients + hookStop(); + return 0; + } + } + if (packet == 0x915) + { + struct SessionExt *data = session_get(*fd); + if (!data) + return 0; + if (data->clientVersion >= 16) + { // not sending old packets to new clients + hookStop(); + return 0; + } + } } return 0; } +uint16 GetWord(uint32 val, int idx) +{ + switch( idx ) + { + case 0: return (uint16)( (val & 0x0000FFFF) ); + case 1: return (uint16)( (val & 0xFFFF0000) >> 0x10 ); + default: +#if defined(DEBUG) + ShowDebug("GetWord: invalid index (idx=%d)\n", idx); +#endif + return 0; + } +} + +//To make the assignation of the level based on limits clearer/easier. [Skotlex] +static int clif_setlevel_sub(int lv) { + if( lv < battle->bc->max_lv ) { + ; + } else if( lv < battle->bc->aura_lv ) { + lv = battle->bc->max_lv - 1; + } else { + lv = battle->bc->max_lv; + } + + return lv; +} + +static int clif_setlevel(struct block_list* bl) { + int lv = status->get_lv(bl); + nullpo_retr(0, bl); + if( battle->bc->client_limit_unit_lv&bl->type ) + return clif_setlevel_sub(lv); + if (bl->type == BL_NPC || bl->type == BL_PET) + return 0; + return lv; +} + +//To identify disguised characters. +static inline bool disguised(struct block_list* bl) { + return (bool)( bl->type == BL_PC && ((TBL_PC*)bl)->disguise != -1 ); +} + +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)); +} + +static inline unsigned char clif_bl_type_old(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 + } +} + +// this function must be used only by clients version < 16 +void eclif_set_unit_idle_old(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_old p; + int g_id = status->get_guild_id(bl); + + nullpo_retv(bl); + + sd = BL_CAST(BL_PC, bl); + + p.PacketType = 0x915; + p.PacketLength = sizeof(p); + p.objecttype = clif_bl_type_old(bl); +// p.AID = bl->id; +// p.GID = (sd) ? sd->status.char_id : 0; // CCODE + 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) ? sc->option : bl->type == BL_NPC ? ((TBL_NPC*)bl)->option : 0; + p.job = vd->class_; + p.head = vd->hair_style; + p.weapon = vd->weapon; + p.accessory = vd->head_bottom; + 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; + p.robe = vd->robe; + 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); + p.font = (sd) ? sd->status.font : 0; + if (battle->bc->show_monster_hp_bar && bl->type == BL_MOB && status_get_hp(bl) < status_get_max_hp(bl)) { + p.maxHP = status_get_max_hp(bl); + p.HP = status_get_hp(bl); + p.isBoss = ( ((TBL_MOB*)bl)->spawn && ((TBL_MOB*)bl)->spawn->state.boss ) ? 1 : 0; + } else { + p.maxHP = -1; + p.HP = -1; + p.isBoss = 0; + } + + clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); + + if( disguised(bl) ) { + p.objecttype = pc->db_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE + p.GID = -bl->id; + clif->send(&p,sizeof(p),bl,SELF); + } + +} + void eclif_set_unit_idle_post(struct block_list* bl, TBL_PC *tsd, enum send_target *target) { if (!bl || !tsd) return; + eclif_set_unit_idle_old(bl, tsd, *target); + if (bl->type == BL_MOB) send_mob_info(bl, &tsd->bl, *target); else if (bl->type == BL_PC) diff --git a/src/emap/clif.h b/src/emap/clif.h index 64bdaef..32605b0 100644 --- a/src/emap/clif.h +++ b/src/emap/clif.h @@ -37,4 +37,8 @@ void eclif_disp_message(struct block_list* src, const char* mes, size_t *lenPtr, enum send_target *targetPtr); +void eclif_set_unit_idle_old(struct block_list* bl, + struct map_session_data *tsd, + enum send_target target); + #endif // EVOL_MAP_CLIF diff --git a/src/emap/packets_struct.h b/src/emap/packets_struct.h new file mode 100644 index 0000000..1098953 --- /dev/null +++ b/src/emap/packets_struct.h @@ -0,0 +1,94 @@ +/** + * This file is part of Hercules. + * http://herc.ws - http://github.com/HerculesWS/Hercules + * + * Copyright (C) 2013-2015 Hercules Dev Team + * + * 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 . + */ + +/* Hercules Renewal: Phase Two http://herc.ws/board/topic/383-hercules-renewal-phase-two/ */ + +#ifndef EVOL_MAP_PACKETS_STRUCT_H +#define EVOL_MAP_PACKETS_STRUCT_H + +#include "common/cbasetypes.h" +#include "common/mmo.h" + +struct packet_idle_unit_old { + short PacketType; +#if PACKETVER >= 20091103 + short PacketLength; + unsigned char objecttype; +#endif +//#if PACKETVER >= 20131223 +// unsigned int AID; +//#endif + unsigned int GID; + short speed; + short bodyState; + short healthState; +#if PACKETVER < 20080102 + short effectState; +#else + int effectState; +#endif + short job; + short head; +#if PACKETVER < 7 + short weapon; +#else + int weapon; +#endif + short accessory; +#if PACKETVER < 7 + short shield; +#endif + short accessory2; + short accessory3; + short headpalette; + short bodypalette; + short headDir; +#if PACKETVER >= 20101124 + short robe; +#endif + unsigned int GUID; + short GEmblemVer; + short honor; +#if PACKETVER > 7 + int virtue; +#else + short virtue; +#endif + uint8 isPKModeON; + unsigned char sex; + unsigned char PosDir[3]; + unsigned char xSize; + unsigned char ySize; + unsigned char state; + short clevel; +#if PACKETVER >= 20080102 + short font; +#endif +#if PACKETVER >= 20120221 + int maxHP; + int HP; + unsigned char isBoss; +#endif +#if PACKETVER >= 20150513 + short body; +#endif +} __attribute__((packed)); + +#endif /* EVOL_MAP_PACKETS_STRUCT_H */ -- cgit v1.2.3-60-g2f50