summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/emap/clif.c276
-rw-r--r--src/emap/clif.h3
-rw-r--r--src/emap/init.c2
3 files changed, 281 insertions, 0 deletions
diff --git a/src/emap/clif.c b/src/emap/clif.c
index b2131bc..8177ff1 100644
--- a/src/emap/clif.c
+++ b/src/emap/clif.c
@@ -16,9 +16,15 @@
#include "common/cbasetypes.h"
#include "common/random.h"
#include "common/timer.h"
+#include "map/battle.h"
+#include "map/elemental.h"
+#include "map/homunculus.h"
#include "map/guild.h"
#include "map/mob.h"
#include "map/npc.h"
+#include "map/mercenary.h"
+#include "map/party.h"
+#include "map/pet.h"
#include "map/pc.h"
#include "map/quest.h"
@@ -35,6 +41,8 @@
#include "emap/struct/mapdext.h"
#include "emap/struct/sessionext.h"
+#include <math.h>
+
extern bool isInit;
extern char global_npc_str[1001];
@@ -187,9 +195,265 @@ void eclif_quest_add(TBL_PC *sd,
hookStop();
}
+// legacy eclif_charnameack_legacy start
+// clientVersion <= 24
+//
+
+unsigned int eget_percentage(const unsigned int A, const unsigned int B);
+unsigned int eget_percentage(const unsigned int A, const unsigned int B)
+{
+ double result;
+
+ if( B == 0 )
+ {
+ ShowError("get_percentage(): division by zero! (A=%u,B=%u)\n", A, B);
+ return ~0U;
+ }
+
+ result = 100 * ((double)A / (double)B);
+
+ if( result > UINT_MAX )
+ {
+ ShowError("get_percentage(): result percentage too high! (A=%u,B=%u,result=%g)\n", A, B, result);
+ return UINT_MAX;
+ }
+
+ return (unsigned int)floor(result);
+}
+
+// ZC_ACK_REQNAMEALL / ZC_ACK_REQNAMEALL2
+struct packet_reqnameall_legacy_ack {
+ uint16 packet_id;
+ int32 gid;
+ char name[NAME_LENGTH];
+ char party_name[NAME_LENGTH];
+ char guild_name[NAME_LENGTH];
+ char position_name[NAME_LENGTH];
+} __attribute__((packed));
+
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void eclif_charnameack_legacy(int fd, struct block_list *bl)
+{
+ struct packet_reqnameall_legacy_ack packet = { 0 };
+ int len = sizeof(struct packet_reqnameall_legacy_ack);
+
+ nullpo_retv(bl);
+
+ packet.packet_id = reqName;
+ packet.gid = bl->id;
+
+ switch(bl->type) {
+ case BL_PC:
+ {
+ const struct map_session_data *ssd = BL_UCCAST(BL_PC, bl);
+ const struct party_data *p = NULL;
+ const struct guild *g = NULL;
+ int ps = -1;
+
+ if (ssd->fakename[0] != '\0' || ssd->status.guild_id > 0 || ssd->status.party_id > 0 || ssd->status.title_id > 0) {
+ packet.packet_id = 0x195; //reqNameAllType;
+ }
+
+ //Requesting your own "shadow" name. [Skotlex]
+ if (ssd->fd == fd && ssd->disguise != -1) {
+ packet.gid = -bl->id;
+ }
+
+ if (ssd->fakename[0] != '\0') {
+ memcpy(packet.name, ssd->fakename, NAME_LENGTH);
+ break;
+ }
+
+//#if PACKETVER >= 20150503
+// // Title System [Dastgir/Hercules]
+// if (ssd->status.title_id > 0) {
+// packet.title_id = ssd->status.title_id;
+// }
+//#endif
+
+ memcpy(packet.name, ssd->status.name, NAME_LENGTH);
+
+ if (ssd->status.party_id != 0) {
+ p = party->search(ssd->status.party_id);
+ }
+ if (ssd->status.guild_id != 0) {
+ if ((g = ssd->guild) != NULL) {
+ int i;
+ ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id);
+ if (i < g->max_member)
+ ps = g->member[i].position;
+ }
+ }
+
+ if (!battle->bc->display_party_name && g == NULL) {
+ // do not display party unless the player is also in a guild
+ p = NULL;
+ }
+
+ if (p == NULL && g == NULL)
+ break;
+
+ if (p != NULL) {
+ memcpy(packet.party_name, p->party.name, NAME_LENGTH);
+ }
+
+ if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) {
+ memcpy(packet.guild_name, g->name,NAME_LENGTH);
+ memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH);
+ }
+ }
+ break;
+ //[blackhole89]
+ case BL_HOM:
+ memcpy(packet.name, BL_UCCAST(BL_HOM, bl)->homunculus.name, NAME_LENGTH);
+ break;
+ case BL_MER:
+ memcpy(packet.name, BL_UCCAST(BL_MER, bl)->db->name, NAME_LENGTH);
+ break;
+ case BL_PET:
+ memcpy(packet.name, BL_UCCAST(BL_PET, bl)->pet.name, NAME_LENGTH);
+ break;
+ case BL_NPC:
+ memcpy(packet.name, BL_UCCAST(BL_NPC, bl)->name, NAME_LENGTH);
+ break;
+ case BL_MOB:
+ {
+ const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
+
+ memcpy(packet.name, md->name, NAME_LENGTH);
+ if (md->guardian_data && md->guardian_data->g) {
+ packet.packet_id = 0x195; //reqNameAllType;
+ memcpy(packet.guild_name, md->guardian_data->g->name, NAME_LENGTH);
+ memcpy(packet.position_name, md->guardian_data->castle->castle_name, NAME_LENGTH);
+
+ } else if (battle->bc->show_mob_info) {
+ char mobhp[50], *str_p = mobhp;
+ packet.packet_id = 0x195; //reqNameAllType;
+ if (battle->bc->show_mob_info&4)
+ str_p += sprintf(str_p, "Lv. %d | ", md->level);
+ if (battle->bc->show_mob_info&1)
+ str_p += sprintf(str_p, "HP: %u/%u | ", md->status.hp, md->status.max_hp);
+ if (battle->bc->show_mob_info&2)
+ str_p += sprintf(str_p, "HP: %u%% | ", eget_percentage(md->status.hp, md->status.max_hp));
+ //Even thought mobhp ain't a name, we send it as one so the client
+ //can parse it. [Skotlex]
+ if (str_p != mobhp) {
+ *(str_p-3) = '\0'; //Remove trailing space + pipe.
+ memcpy(packet.party_name, mobhp, NAME_LENGTH);
+ }
+ }
+ }
+ break;
+ case BL_CHAT:
+#if 0 //FIXME: Clients DO request this... what should be done about it? The chat's title may not fit... [Skotlex]
+ memcpy(packet.name, BL_UCCAST(BL_CHAT, bl)->title, NAME_LENGTH);
+ break;
+#endif
+ return;
+ case BL_ELEM:
+ memcpy(packet.name, BL_UCCAST(BL_ELEM, bl)->db->name, NAME_LENGTH);
+ break;
+ default:
+ ShowError("clif_charnameack: bad type %u(%d)\n", bl->type, bl->id);
+ return;
+ }
+
+ if (packet.packet_id == reqName) {
+ len = sizeof(struct packet_reqname_ack);
+ }
+ // if no recipient specified just update nearby clients
+ // if no recipient specified just update nearby clients
+ if (fd == 0) {
+ clif->send(&packet, len, bl, AREA);
+ } else {
+ struct map_session_data *sd = sockt->session_is_valid(fd) ? sockt->session[fd]->session_data : NULL;
+ if (sd != NULL) {
+ clif->send(&packet, len, &sd->bl, SELF);
+ } else {
+ clif->send(&packet, len, bl, SELF);
+ }
+ }
+}
+
+//Used to update when a char leaves a party/guild. [Skotlex]
+//Needed because when you send a 0x95 packet, the client will not remove the cached party/guild info that is not sent.
+static void eclif_charnameupdate_legacy(struct map_session_data *ssd)
+{
+ int ps = -1;
+ struct party_data *p = NULL;
+ struct guild *g = NULL;
+ struct packet_reqnameall_legacy_ack packet = { 0 };
+
+ nullpo_retv(ssd);
+
+ if (ssd->fakename[0])
+ return; //No need to update as the party/guild was not displayed anyway.
+
+ packet.packet_id = 0x195; //reqNameAllType;
+ packet.gid = ssd->bl.id;
+
+ memcpy(packet.name, ssd->status.name, NAME_LENGTH);
+
+ if (!battle->bc->display_party_name) {
+ if (ssd->status.party_id > 0 && ssd->status.guild_id > 0 && (g = ssd->guild) != NULL)
+ p = party->search(ssd->status.party_id);
+ } else {
+ if (ssd->status.party_id > 0)
+ p = party->search(ssd->status.party_id);
+ }
+
+ if (ssd->status.guild_id > 0 && (g = ssd->guild) != NULL) {
+ int i;
+ ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id);
+ if( i < g->max_member ) ps = g->member[i].position;
+ }
+
+ if (p != NULL)
+ memcpy(packet.party_name, p->party.name, NAME_LENGTH);
+
+ if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) {
+ memcpy(packet.guild_name, g->name,NAME_LENGTH);
+ memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH);
+ }
+
+//#if PACKETVER >= 20150503
+// // Achievement System [Dastgir/Hercules]
+// if (ssd->status.title_id > 0) {
+// packet.title_id = ssd->status.title_id;
+// }
+//#endif
+
+ // Update nearby clients
+ clif->send(&packet, sizeof(packet), &ssd->bl, AREA);
+}
+
+//
+// clientVersion <= 24
+// legacy eclif_charnameack_legacy end
+
void eclif_charnameack_pre(int *fdPtr,
struct block_list **blPtr)
{
+ eclif_charnameack_pre_sub(fdPtr, blPtr);
+ if (hookStopped())
+ return;
+
+ struct SessionExt *data = session_get(*fdPtr);
+ if (!data)
+ return;
+ if (data->clientVersion <= 24)
+ {
+ eclif_charnameack_legacy(*fdPtr, *blPtr);
+ hookStop();
+ }
+}
+
+void eclif_charnameack_pre_sub(int *fdPtr,
+ struct block_list **blPtr)
+{
struct block_list *bl = *blPtr;
if (!bl)
{
@@ -297,6 +561,18 @@ void eclif_charnameack_pre(int *fdPtr,
}
}
+void eclif_charnameupdate_pre(struct map_session_data **ssdPtr)
+{
+ struct SessionExt *data = session_get_bysd(*ssdPtr);
+ if (!data)
+ return;
+ if (data->clientVersion <= 24)
+ {
+ eclif_charnameupdate_legacy(*ssdPtr);
+ hookStop();
+ }
+}
+
#define equipPos(index, field) \
equip = sd->equip_index[index]; \
if (equip >= 0) \
diff --git a/src/emap/clif.h b/src/emap/clif.h
index ef09b07..3a563fd 100644
--- a/src/emap/clif.h
+++ b/src/emap/clif.h
@@ -11,6 +11,9 @@ void eclif_quest_add_pre(TBL_PC **sdPtr,
struct quest **qdPtr);
void eclif_charnameack_pre(int *fdPtr,
struct block_list **blPtr);
+void eclif_charnameack_pre_sub(int *fdPtr,
+ struct block_list **blPtr);
+void eclif_charnameupdate_pre(struct map_session_data **ssdPtr);
void eclif_getareachar_unit_post(TBL_PC *sd,
struct block_list *bl);
bool eclif_spawn_post(bool retVal,
diff --git a/src/emap/init.c b/src/emap/init.c
index c670dd4..75da76e 100644
--- a/src/emap/init.c
+++ b/src/emap/init.c
@@ -17,6 +17,7 @@
#include "common/strlib.h"
#include "common/timer.h"
#include "map/achievement.h"
+#include "map/battle.h"
#include "map/channel.h"
#include "map/chat.h"
#include "map/chrif.h"
@@ -254,6 +255,7 @@ HPExport void plugin_init (void)
addHookPre(clif, quest_send_list, eclif_quest_send_list_pre);
addHookPre(clif, quest_add, eclif_quest_add_pre);
addHookPre(clif, charnameack, eclif_charnameack_pre);
+ addHookPre(clif, charnameupdate, eclif_charnameupdate_pre);
addHookPre(clif, getareachar_item, eclif_getareachar_item_pre);
addHookPre(clif, dropflooritem, eclif_dropflooritem_pre);
addHookPre(clif, disp_message, eclif_disp_message_pre);