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:
parent
534bc706d0
commit
4a43856271
@ -37451,7 +37451,7 @@ Body:
|
||||
CastCancel: true
|
||||
AfterCastActDelay: 500
|
||||
Duration1: 180000
|
||||
Duration2: 30000
|
||||
Duration2: 15000
|
||||
Cooldown: 150000
|
||||
FixedCastTime: 2000
|
||||
Requires:
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user