Adjusts Enchanting Shadow behavior (#7124)

* Fixes #7104.
* Implements Shadow Scar as a timer on units.
* Implements the official packet for Shadow Scar counter.
* Enchanting Shadow can now be triggered by skills as well as melee.
* Removes the hit count limit.
* Adjusts the damage rate of Shadow Wounds to increase by 3%.
* Adjusts the duration of Shadow Scar from 30 seconds to 15.
Thanks to @eppc0330 and @Lemongrass3110!
Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
This commit is contained in:
Aleos 2022-09-06 17:05:19 -04:00 committed by GitHub
parent 534bc706d0
commit 4a43856271
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 107 additions and 18 deletions

View File

@ -37451,7 +37451,7 @@ Body:
CastCancel: true
AfterCastActDelay: 500
Duration1: 180000
Duration2: 30000
Duration2: 15000
Cooldown: 150000
FixedCastTime: 2000
Requires:

View File

@ -1553,8 +1553,8 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
}
if (sc->data[SC_HOLY_OIL] && (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
damage += damage * 50 / 100;// Need official adjustment. [Rytech]
if (sc->data[SC_SHADOW_SCAR])// Need official adjustment for this too.
damage += damage * (10 * sc->data[SC_SHADOW_SCAR]->val1) / 100;
if (sc->data[SC_SHADOW_SCAR]) // !TODO: Need official adjustment for this too.
damage += damage * (3 * sc->data[SC_SHADOW_SCAR]->val1) / 100;
// Damage reductions
// Assumptio increases DEF on RE mode, otherwise gives a reduction on the final damage. [Igniz]

View File

@ -1580,6 +1580,22 @@ static void clif_spiritcharm_single(int fd, struct map_session_data *sd)
WFIFOSET(fd, packet_len(0x08cf));
}
/*==========================================
* Enchanting Shadow / Shadow Scar Spirit
*------------------------------------------*/
void clif_enchantingshadow_spirit(unit_data &ud) {
#if PACKETVER_MAIN_NUM >= 20191120 || PACKETVER_RE_NUM >= 20191120 || PACKETVER_ZERO_NUM >= 20191127
PACKET_ZC_TARGET_SPIRITS p = {};
p.packetType = HEADER_ZC_TARGET_SPIRITS;
p.GID = ud.bl->id;
p.unknown_val = 0;
p.amount = static_cast<uint16>(ud.shadow_scar_timer.size());
clif_send(&p, sizeof(p), ud.bl, AREA);
#endif
}
/*==========================================
* Run when player changes map / refreshes
* Tells its client to display all weather settings being used by this map

View File

@ -1214,4 +1214,7 @@ void clif_item_reform_open( struct map_session_data& sd, t_itemid item );
// Item Enchant UI
void clif_enchantwindow_open( struct map_session_data& sd, uint64 clientLuaIndex );
// Enchanting Shadow / Shadow Scar Spirit
void clif_enchantingshadow_spirit(unit_data &ud);
#endif /* CLIF_HPP */

View File

@ -321,6 +321,13 @@ struct PACKET_CZ_CLOSE_UI_ENCHANT{
int16 packetType;
} __attribute__((packed));
struct PACKET_ZC_TARGET_SPIRITS {
int16 packetType;
uint32 GID;
uint32 unknown_val;
uint16 amount;
} __attribute__((packed));
// 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 )
@ -371,6 +378,7 @@ DEFINE_PACKET_HEADER(CZ_REQ_STYLE_CHANGE2, 0xafc)
DEFINE_PACKET_HEADER(ZC_REMOVE_EFFECT, 0x0b0d)
DEFINE_PACKET_HEADER(CZ_UNCONFIRMED_TSTATUS_UP, 0x0b24)
DEFINE_PACKET_HEADER(CZ_GUILD_EMBLEM_CHANGE2, 0x0b46)
DEFINE_PACKET_HEADER(ZC_TARGET_SPIRITS, 0xb68)
DEFINE_PACKET_HEADER(ZC_UNCONFIRMED_SPIRITS3, 0xb73)
DEFINE_PACKET_HEADER(CZ_UNCONFIRMED_RODEX_RETURN, 0xb98)
DEFINE_PACKET_HEADER(ZC_SUMMON_HP_INIT, 0xb6b)

View File

@ -1303,6 +1303,16 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
}
}
// Enchanting Shadow gives a chance to inflict Shadow Wounds to the enemy.
if (sc != nullptr) {
status_change_entry *sce = sc->data[SC_SHADOW_WEAPON];
unit_data *ud = unit_bl2ud(bl);
if (sce != nullptr && ud != nullptr && rnd_chance(sce->val1, 100)) {
unit_addshadowscar(*ud, skill_get_time2(SHC_ENCHANTING_SHADOW, sce->val1));
}
}
if( skill_id ) {
// Trigger status effects on skills
for (const auto &it : sd->addeff_onskill) {
@ -1385,18 +1395,6 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
if((sce=sc->data[SC_EDP]))
sc_start4(src,bl,SC_DPOISON,sce->val2, sce->val1,src->id,0,0,
skill_get_time2(ASC_EDP,sce->val1));
// Enchanting Shadow gives a chance to inflict shadow wounds to the enemy.
if ((sce = sc->data[SC_SHADOW_WEAPON]) && rnd() % 100 < sce->val2) {
if (tsc && tsc->data[SC_SHADOW_SCAR]) {
uint16 count = 1 + tsc->data[SC_SHADOW_SCAR]->val1;
// Need official stack limit. [Rytech]
count = min(5, count);
sc_start(src, bl, SC_SHADOW_SCAR, 100, count, skill_get_time2(SHC_ENCHANTING_SHADOW, sce->val1));
} else
sc_start(src, bl, SC_SHADOW_SCAR, 100, 1, skill_get_time2(SHC_ENCHANTING_SHADOW, sce->val1));
}
if ((sce = sc->data[SC_LUXANIMA]) && rnd() % 100 < sce->val2)
skill_castend_nodamage_id(src, bl, RK_STORMBLAST, 1, tick, 0);
}

View File

@ -12231,9 +12231,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_POTENT_VENOM:
val2 = 3 * val1;// Res Pierce Percentage
break;
case SC_SHADOW_WEAPON:
val2 = val1;// Success Chance of Shadow Scar
break;
case SC_A_MACHINE:
val4 = tick / 1000;
tick_time = 1000;

View File

@ -14,6 +14,7 @@
#include "../common/showmsg.hpp"
#include "../common/socket.hpp"
#include "../common/timer.hpp"
#include "../common/utils.hpp"
#include "achievement.hpp"
#include "battle.hpp"
@ -37,6 +38,12 @@
#include "storage.hpp"
#include "trade.hpp"
using namespace rathena;
#ifndef MAX_SHADOW_SCAR
#define MAX_SHADOW_SCAR 100 /// Max Shadow Scars
#endif
// Directions values
// 1 0 7
// 2 . 6
@ -3626,6 +3633,60 @@ int unit_free(struct block_list *bl, clr_type clrtype)
return 0;
}
static TIMER_FUNC(unit_shadowscar_timer) {
block_list *bl = map_id2bl(id);
if (bl == nullptr)
return 1;
unit_data *ud = unit_bl2ud(bl);
if (ud == nullptr)
return 1;
std::vector<int>::iterator it = ud->shadow_scar_timer.begin();
while (it != ud->shadow_scar_timer.end()) {
if (*it == tid) {
ud->shadow_scar_timer.erase(it);
break;
}
it++;
}
if (ud->shadow_scar_timer.empty())
status_change_end(bl, SC_SHADOW_SCAR, INVALID_TIMER);
return 0;
}
/**
* Adds a Shadow Scar to unit for 'interval' ms.
* @param ud: Unit data
* @param interval: Duration
*/
void unit_addshadowscar(unit_data &ud, int interval) {
if (ud.shadow_scar_timer.size() >= MAX_SHADOW_SCAR) {
ShowWarning("unit_addshadowscar: Unit %s (%d) has reached the maximum amount of Shadow Scars (%d).\n", status_get_name(ud.bl), ud.bl->id, MAX_SHADOW_SCAR);
return;
}
ud.shadow_scar_timer.push_back(add_timer(gettick() + interval, unit_shadowscar_timer, ud.bl->id, 0));
status_change *sc = status_get_sc(ud.bl);
if (sc != nullptr) {
if (sc->data[SC_SHADOW_SCAR] != nullptr) {
sc->data[SC_SHADOW_SCAR]->val1 = static_cast<int>(ud.shadow_scar_timer.size());
} else {
sc_start(ud.bl, ud.bl, SC_SHADOW_SCAR, 100, 1, INFINITE_TICK);
}
clif_enchantingshadow_spirit(ud);
}
}
/**
* Initialization function for unit on map start
* called in map::do_init
@ -3638,6 +3699,7 @@ void do_init_unit(void){
add_timer_func_list(unit_delay_walktobl_timer,"unit_delay_walktobl_timer");
add_timer_func_list(unit_teleport_timer,"unit_teleport_timer");
add_timer_func_list(unit_step_timer,"unit_step_timer");
add_timer_func_list(unit_shadowscar_timer, "unit_shadowscar_timer");
}
/**

View File

@ -63,6 +63,8 @@ struct unit_data {
char walk_done_event[EVENT_NAME_LENGTH];
char title[NAME_LENGTH];
int32 group_id;
std::vector<int> shadow_scar_timer;
};
struct view_data {
@ -172,6 +174,9 @@ int unit_free(struct block_list *bl, clr_type clrtype);
int unit_changeviewsize(struct block_list *bl,short size);
int unit_changetarget(struct block_list *bl,va_list ap);
// Shadow Scar
void unit_addshadowscar(unit_data &ud, int interval);
void do_init_unit(void);
void do_final_unit(void);