diff --git a/src/map/clif.cpp b/src/map/clif.cpp index ae160f66dc..1b5f6d9fc0 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -1749,6 +1749,36 @@ int clif_spawn( struct block_list *bl, bool walking ){ return 0; } +/// Notifies client of a change in an elemental's status parameter. +/// 0x7db .W .L (ZC_HO_PAR_CHANGE) +/// 0xba5 .W .Q (ZC_HO_PAR_CHANGE2) +void clif_homunculus_updatestatus(map_session_data& sd, _sp type) { +#if PACKETVER >= 20090610 + if( !hom_is_active(sd.hd) ) + return; + + PACKET_ZC_HO_PAR_CHANGE p = {}; + + p.packetType = HEADER_ZC_HO_PAR_CHANGE; + p.type = static_cast(type); + status_data* status = &sd.hd->battle_status; + + switch (type) { + case SP_BASEEXP: + p.value = static_cast(sd.hd->homunculus.exp); + break; + case SP_HP: + p.value = static_cast(status->hp); + break; + case SP_SP: + p.value = static_cast(status->sp); + break; + } + + clif_send(&p, sizeof(p), &sd.bl, SELF); +#endif +} + /// Sends information about owned homunculus to the client . [orn] /// 022e .24B .B .W .W .W .W .W .W .W .W .W .W .W .W .W .W .W .W .L .L .W .W (ZC_PROPERTY_HOMUN) /// 09f7 .24B .B .W .W .W .W .W .W .W .W .W .W .W .W .L .L .W .W .L .L .W .W (ZC_PROPERTY_HOMUN_2) @@ -10803,6 +10833,8 @@ void clif_parse_LoadEndAck(int fd,map_session_data *sd) clif_send_homdata( *sd->hd, SP_ACK ); clif_hominfo(sd,sd->hd,1); clif_hominfo(sd,sd->hd,0); //for some reason, at least older clients want this sent twice + clif_homunculus_updatestatus(*sd, SP_HP); + clif_homunculus_updatestatus(*sd, SP_SP); clif_homskillinfoblock( *sd->hd ); status_calc_bl(&sd->hd->bl, { SCB_SPEED }); if( !(battle_config.hom_setting&HOMSET_NO_INSTANT_LAND_SKILL) ) diff --git a/src/map/clif.hpp b/src/map/clif.hpp index 7ef89d1703..7e1c51ecd1 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -1160,6 +1160,7 @@ void clif_homskillinfoblock( homun_data& hd ); void clif_homskillup( homun_data& hd, uint16 skill_id ); void clif_hom_food( map_session_data& sd, int32 foodid, bool success ); void clif_send_homdata( homun_data& hd, e_hom_state2 state ); +void clif_homunculus_updatestatus(map_session_data& sd, _sp type); void clif_configuration( map_session_data* sd, enum e_config_type type, bool enabled ); void clif_viewequip_ack( map_session_data& sd, map_session_data& tsd ); diff --git a/src/map/homunculus.cpp b/src/map/homunculus.cpp index c8cdef0079..e78b6929ef 100644 --- a/src/map/homunculus.cpp +++ b/src/map/homunculus.cpp @@ -226,15 +226,6 @@ void hom_delspiritball(TBL_HOM *hd, int count, int type) { clif_spiritball(&hd->bl); } -/** -* Update homunculus info to its master after receiving damage -* @param hd -*/ -void hom_damage(struct homun_data *hd) { - if (hd->master) - clif_hominfo(hd->master,hd,0); -} - /** * Set homunculus's dead status * @param hd @@ -306,11 +297,9 @@ int hom_vaporize(map_session_data *sd, int flag) /** * Delete a homunculus, completely "killing it". -* Emote is the emotion the master should use, send negative to disable. * @param hd -* @param emote */ -int hom_delete(struct homun_data *hd, int emote) +int hom_delete(struct homun_data *hd) { map_session_data *sd; nullpo_ret(hd); @@ -319,9 +308,6 @@ int hom_delete(struct homun_data *hd, int emote) if (!sd) return unit_free(&hd->bl,CLR_DEAD); - if (emote >= 0) - clif_emotion(&sd->bl, emote); - //This makes it be deleted right away. hd->homunculus.intimacy = 0; // Send homunculus_dead to client @@ -573,6 +559,7 @@ int hom_levelup(struct homun_data *hd) // Needed to update skill list for mutated homunculus so unlocked skills will appear when the needed level is reached. status_calc_homunculus(hd,SCO_NONE); clif_hominfo(hd->master,hd,0); + clif_homunculus_updatestatus(*hd->master, SP_BASEEXP); clif_homskillinfoblock( *hd ); if ( hd->master && battle_config.homunculus_show_growth ) { @@ -615,7 +602,7 @@ int hom_evolution(struct homun_data *hd) nullpo_ret(hd); if(!hd->homunculusDB->evo_class || hd->homunculus.class_ == hd->homunculusDB->evo_class) { - clif_emotion(&hd->bl, ET_SWEAT); + clif_emotion(&hd->bl, ET_SCRATCH); return 0 ; } @@ -644,21 +631,15 @@ int hom_evolution(struct homun_data *hd) hom->luk += 10*rnd_value(min->luk, max->luk); hom->intimacy = battle_config.homunculus_evo_intimacy_reset; - hom_calc_skilltree(hd); - - unit_remove_map(&hd->bl, CLR_OUTSIGHT); - if (map_addblock(&hd->bl)) - return 0; - - clif_spawn(&hd->bl); - clif_emotion(&sd->bl, ET_BEST); - clif_specialeffect(&hd->bl,EF_HO_UP,AREA); + clif_class_change(&hd->bl, hd->homunculusDB->evo_class, 0); //status_Calc flag&1 will make current HP/SP be reloaded from hom structure hom->hp = hd->battle_status.hp; hom->sp = hd->battle_status.sp; status_calc_homunculus(hd, SCO_FIRST); + clif_hominfo(sd, hd, 0); + if (!(battle_config.hom_setting&HOMSET_NO_INSTANT_LAND_SKILL)) skill_unit_move(&sd->hd->bl,gettick(),1); // apply land skills immediately @@ -682,7 +663,7 @@ int hom_mutate(struct homun_data *hd, int homun_id) m_id = hom_class2mapid(homun_id); if( m_class == -1 || m_id == -1 || !(m_class&HOM_EVO) || !(m_id&HOM_S) ) { - clif_emotion(&hd->bl, ET_SWEAT); + clif_emotion(&hd->bl, ET_SCRATCH); return 0; } @@ -697,15 +678,7 @@ int hom_mutate(struct homun_data *hd, int homun_id) return 0; } - hom_calc_skilltree(hd); - - unit_remove_map(&hd->bl, CLR_OUTSIGHT); - if(map_addblock(&hd->bl)) - return 0; - - clif_spawn(&hd->bl); - clif_emotion(&sd->bl, ET_BEST); - clif_specialeffect(&hd->bl,EF_HO_UP,AREA); + clif_class_change(&hd->bl, homun_id, 0); //status_Calc flag&1 will make current HP/SP be reloaded from hom structure hom = &hd->homunculus; @@ -714,6 +687,8 @@ int hom_mutate(struct homun_data *hd, int homun_id) hom->prev_class = prev_class; status_calc_homunculus(hd, SCO_FIRST); + clif_hominfo(sd, hd, 0); + if (!(battle_config.hom_setting&HOMSET_NO_INSTANT_LAND_SKILL)) skill_unit_move(&sd->hd->bl,gettick(),1); // apply land skills immediately @@ -750,7 +725,7 @@ void hom_gainexp(struct homun_data *hd,t_exp exp) hd->homunculus.exp += exp; if (hd->master && hd->homunculus.exp < hd->exp_next) { - clif_hominfo(hd->master,hd,0); + clif_homunculus_updatestatus(*hd->master, SP_BASEEXP); return; } @@ -807,12 +782,19 @@ int hom_decrease_intimacy(struct homun_data * hd, unsigned int value) } /** -* Update homunculus info to master after healing -* @param hd +* Update homunculus status after healing/damage +* @param hd Homunculus data +* @param hp HP amount +* @param sp SP amount */ -void hom_heal(struct homun_data *hd) { - if (hd->master) - clif_hominfo(hd->master,hd,0); +void hom_heal(struct homun_data *hd, int hp, int sp) { + if (hd->master == nullptr) + return; + + if (hp) + clif_homunculus_updatestatus(*hd->master, SP_HP); + if (sp) + clif_homunculus_updatestatus(*hd->master, SP_SP); } /** @@ -853,7 +835,7 @@ void hom_menu(map_session_data *sd, int type) hom_food(sd, sd->hd); break; case 2: - hom_delete(sd->hd, -1); + hom_delete(sd->hd); break; default: ShowError("hom_menu : unknown menu choice : %d\n", type); @@ -914,7 +896,7 @@ int hom_food(map_session_data *sd, struct homun_data *hd) // Too much food :/ if(hd->homunculus.intimacy == 0) - return hom_delete(sd->hd, ET_HUK); + return hom_delete(sd->hd); return 0; } @@ -957,7 +939,7 @@ static TIMER_FUNC(hom_hungry){ hd->homunculus.hunger = 0; // Delete the homunculus if intimacy <= 100 if (!hom_decrease_intimacy(hd, 100)) - return hom_delete(hd, ET_HUK); + return hom_delete(hd); clif_send_homdata( *hd, SP_INTIMATE ); } @@ -1025,8 +1007,9 @@ void hom_change_name_ack(map_session_data *sd, char* name, int flag) return; } safestrncpy(hd->homunculus.name,name,NAME_LENGTH); - clif_name_area(&hd->bl); hd->homunculus.rename_flag = 1; + clif_hominfo(sd,hd,1); + clif_name_area(&hd->bl); clif_hominfo(sd,hd,0); } @@ -1138,6 +1121,8 @@ bool hom_call(map_session_data *sd) clif_send_homdata( *hd, SP_ACK ); clif_hominfo(sd,hd,1); clif_hominfo(sd,hd,0); // send this x2. dunno why, but kRO does that [blackhole89] + clif_homunculus_updatestatus(*sd, SP_HP); + clif_homunculus_updatestatus(*sd, SP_SP); clif_homskillinfoblock( *hd ); status_calc_bl(&hd->bl, { SCB_SPEED }); hom_save(hd); @@ -1201,6 +1186,8 @@ int hom_recv_data(uint32 account_id, struct s_homunculus *sh, int flag) clif_send_homdata( *hd, SP_ACK ); clif_hominfo(sd,hd,1); clif_hominfo(sd,hd,0); // send this x2. dunno why, but kRO does that [blackhole89] + clif_homunculus_updatestatus(*sd, SP_HP); + clif_homunculus_updatestatus(*sd, SP_SP); clif_homskillinfoblock( *hd ); hom_init_timers(hd); @@ -1319,6 +1306,8 @@ void hom_revive(struct homun_data *hd, unsigned int hp, unsigned int sp) clif_send_homdata( *hd, SP_ACK ); clif_hominfo(sd,hd,1); clif_hominfo(sd,hd,0); + clif_homunculus_updatestatus(*sd, SP_HP); + clif_homunculus_updatestatus(*sd, SP_SP); clif_homskillinfoblock( *hd ); if( hd->homunculus.class_ == MER_ELEANOR ){ diff --git a/src/map/homunculus.hpp b/src/map/homunculus.hpp index fee46cf51d..6d749f9861 100644 --- a/src/map/homunculus.hpp +++ b/src/map/homunculus.hpp @@ -207,7 +207,6 @@ int hom_recv_data(uint32 account_id, struct s_homunculus *sh, int flag); //albat struct view_data* hom_get_viewdata(int class_); int hom_class2mapid(int hom_class); enum homun_type hom_class2type(int class_); -void hom_damage(struct homun_data *hd); int hom_dead(struct homun_data *hd); void hom_skillup(struct homun_data *hd,uint16 skill_id); void hom_calc_skilltree(homun_data *hd); @@ -217,7 +216,7 @@ void hom_gainexp(struct homun_data *hd,t_exp exp); int hom_levelup(struct homun_data *hd); int hom_evolution(struct homun_data *hd); int hom_mutate(struct homun_data *hd,int homun_id); -void hom_heal(struct homun_data *hd); +void hom_heal(struct homun_data* hd, int hp, int sp); int hom_vaporize(map_session_data *sd, int flag); int hom_ressurect(map_session_data *sd, unsigned char per, short x, short y); void hom_revive(struct homun_data *hd, unsigned int hp, unsigned int sp); diff --git a/src/map/packets.hpp b/src/map/packets.hpp index 5a55cb88c0..74f20f28b7 100644 --- a/src/map/packets.hpp +++ b/src/map/packets.hpp @@ -1154,6 +1154,23 @@ struct PACKET_CZ_PARTY_JOIN_REQ_ACK{ } __attribute__((packed)); DEFINE_PACKET_HEADER(CZ_PARTY_JOIN_REQ_ACK, 0x2c7); +#if PACKETVER_MAIN_NUM >= 20210000 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20210217 +// PACKET_ZC_HO_PAR_CHANGE2 +struct PACKET_ZC_HO_PAR_CHANGE { + int16 packetType; + uint16 type; + uint64 value; +} __attribute__((packed)); +DEFINE_PACKET_HEADER(ZC_HO_PAR_CHANGE, 0xba5); +#else +struct PACKET_ZC_HO_PAR_CHANGE { + int16 packetType; + uint16 type; + int32 value; +} __attribute__((packed)); +DEFINE_PACKET_HEADER(ZC_HO_PAR_CHANGE, 0x7db); +#endif + // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 ) #pragma pack( pop ) diff --git a/src/map/status.cpp b/src/map/status.cpp index 29ecc77fa4..bbf96954ae 100644 --- a/src/map/status.cpp +++ b/src/map/status.cpp @@ -1582,11 +1582,20 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in // Need to pass original HP damage for the mob damage log dhp = cap_value(dhp, INT_MIN, INT_MAX); switch (target->type) { - case BL_PC: pc_damage((TBL_PC*)target,src,hp,sp,ap); break; - case BL_MOB: mob_damage((TBL_MOB*)target, src, (int)dhp); break; - case BL_HOM: hom_damage((TBL_HOM*)target); break; - case BL_MER: mercenary_heal((TBL_MER*)target,hp,sp); break; - case BL_ELEM: elemental_heal((TBL_ELEM*)target,hp,sp); break; + case BL_PC: + pc_damage(reinterpret_cast(target), src, hp, sp, ap); break; + case BL_MOB: + mob_damage(reinterpret_cast(target), src, (int)dhp); + break; + case BL_HOM: + hom_heal(reinterpret_cast(target), hp, sp); + break; + case BL_MER: + mercenary_heal(reinterpret_cast(target), hp, sp); + break; + case BL_ELEM: + elemental_heal(reinterpret_cast(target), hp, sp); + break; } if( src && target->type == BL_PC && ((TBL_PC*)target)->disguise ) { // Stop walking when attacked in disguise to prevent walk-delay bug @@ -1795,11 +1804,21 @@ int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int64 hap, int flag) // Send HP update to client switch(bl->type) { - case BL_PC: pc_heal((TBL_PC*)bl,hp,sp,ap,flag); break; - case BL_MOB: mob_heal((TBL_MOB*)bl,hp); break; - case BL_HOM: hom_heal((TBL_HOM*)bl); break; - case BL_MER: mercenary_heal((TBL_MER*)bl,hp,sp); break; - case BL_ELEM: elemental_heal((TBL_ELEM*)bl,hp,sp); break; + case BL_PC: + pc_heal(reinterpret_cast(bl), hp, sp, ap, flag); + break; + case BL_MOB: + mob_heal(reinterpret_cast(bl), hp); + break; + case BL_HOM: + hom_heal(reinterpret_cast(bl), hp, sp); + break; + case BL_MER: + mercenary_heal(reinterpret_cast(bl), hp, sp); + break; + case BL_ELEM: + elemental_heal(reinterpret_cast(bl), hp, sp); + break; } return (int)hp+sp+ap; diff --git a/src/map/unit.cpp b/src/map/unit.cpp index 8f5d4820d0..35fc10e8d3 100644 --- a/src/map/unit.cpp +++ b/src/map/unit.cpp @@ -3353,7 +3353,6 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, if( !hd->homunculus.intimacy && !(hd->master && !hd->master->state.active) ) { // If logging out, this is deleted on unit_free - clif_emotion(bl, ET_CRY); clif_clearunit_area( *bl, clrtype ); map_delblock(bl); unit_free(bl,CLR_OUTSIGHT);