2022-12-31 20:52:01 +08:00

934 lines
31 KiB
C++

#include "precompile.h"
#include "skill.h"
#include "creature.h"
#include "room.h"
#include "trigger.h"
#include "skillhelper.h"
#include "entityfactory.h"
#include "explosion.h"
#include "buff.h"
#include "human.h"
#include "bullet.h"
#include "collision.h"
#include "pbutils.h"
#include "ability.h"
#include "battledatacontext.h"
#include "mt/Buff.h"
#include "mt/Skill.h"
#include "mt/SkillNumber.h"
#include "mt/Equip.h"
void Skill::Initialzie()
{
curr_times_ = GetMaxTimes();
switch (meta->skill_type()) {
case kActiveSkill:
{
InitActiveSkill();
}
break;
case kPassiveSkill:
{
InitPassiveSkill();
}
break;
default:
{
}
break;
}
}
int Skill::GetCd()
{
return meta->skill_cd() * 1000;
}
int Skill::GetPassedTime()
{
if (inc_times_timer_.expired()) {
A8_ABORT();
}
if (GetCurrTimes() >= GetMaxTimes()) {
return GetCd();
} else {
int remain_time = owner->room->xtimer.GetRemainTime(inc_times_timer_);
int passed_time = GetCd() - remain_time * FRAME_RATE_MS;
passed_time = std::max(0, passed_time);
return passed_time;
}
}
int Skill::GetLeftTime()
{
int passed_time = GetPassedTime();
int skill_left_time = std::max(0, GetCd() - passed_time);
return skill_left_time;
}
void Skill::DecTimes()
{
if (inc_times_timer_.expired()) {
A8_ABORT();
}
if (GetCurrTimes() >= GetMaxTimes()) {
owner->room->xtimer.ModifyTime(inc_times_timer_, GetCd() / FRAME_RATE_MS);
}
--curr_times_;
if (curr_times_ < 0) {
curr_times_ = 0;
}
}
int Skill::GetCurrTimes()
{
return curr_times_;
}
int Skill::GetMaxTimes()
{
return meta->max_times();
}
void Skill::NotifySkillState()
{
if (owner->IsHuman()) {
if (GetCurrTimes() < GetMaxTimes()) {
owner->room->frame_event.AddSkillCdChg(owner->AllocWeakPtr(), meta->skill_id(), GetCd());
} else {
owner->room->frame_event.AddSkillCdChg(owner->AllocWeakPtr(), meta->skill_id(), 0);
}
owner->room->frame_event.AddSkillCurrTimesChg(owner->AllocWeakPtr(), meta->skill_id(), GetCurrTimes());
}
}
void Skill::ResetSkillCd()
{
if (!meta->IsTurnOverSkill()) {
curr_times_ = 0;
if (!inc_times_timer_.expired()) {
owner->room->xtimer.ModifyTime(inc_times_timer_, GetCd() / FRAME_RATE_MS);
NotifySkillState();
}
}
}
void Skill::Accelerate(int time)
{
if (!inc_times_timer_.expired()) {
int remain_time = owner->room->xtimer.GetRemainTime(inc_times_timer_) * FRAME_RATE_MS;
remain_time += time;
remain_time = std::max(remain_time, 0);
owner->room->xtimer.ModifyTime(inc_times_timer_, remain_time / FRAME_RATE_MS);
NotifySkillState();
}
}
void Skill::LockCastPhase()
{
if (meta->cast_time() > 0) {
int buff_uniid = owner->TryAddBuff(owner, kVertigoBuffId);
Buff* buff = owner->GetBuffByUniId(buff_uniid);
if (buff && !buff->remover_timer.expired()) {
owner->room->xtimer.ModifyTime(buff->remover_timer,
meta->cast_time() / FRAME_RATE_MS);
}
}
}
int Skill::GetCurrExp()
{
return curr_exp_;
}
void Skill::SetCurrExp(int exp)
{
curr_exp_ = std::max(0, exp);
}
int Skill::GetMaxExp()
{
return meta->up_exp();
}
void Skill::AddMinorMode(
int minor_type,
int minor_cd_time,
std::function<void()> cb
)
{
if (!minor_mode_timer_.expired()) {
owner->room->xtimer.Delete(minor_mode_timer_);
}
minor_type_ = minor_type;
minor_cd_time_ = minor_cd_time;
minor_frameno_ = owner->room->GetFrameNo();
minor_cb_ = cb;
minor_mode_timer_ = owner->room->xtimer.SetTimeoutWpEx
(minor_cd_time / FRAME_RATE_MS,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
} else if (a8::TIMER_DELETE_EVENT == event) {
minor_type_ = SMT_NONE;
minor_cd_time_ = 0;
minor_frameno_ = 0;
minor_cb_ = nullptr;
}
},
&xtimer_attacher);
if (owner->IsHuman()) {
Human* hum = owner->AsHuman();
owner->room->frame_event.AddPropChgEx
(
owner->GetWeakPtrRef(),
kPropSkillMinor,
minor_type_,
minor_cd_time_,
minor_cd_time_,
meta->skill_id(),
true
);
NotifySkillState();
}
}
void Skill::DoMinorMode()
{
if (GetMinorType() != SMT_NONE) {
minor_cb_();
minor_type_ = SMT_NONE;
minor_cd_time_ = 0;
minor_cb_ = nullptr;
ResetSkillCd();
if (owner->IsHuman()) {
Human* hum = owner->AsHuman();
owner->room->frame_event.AddPropChgEx
(
owner->GetWeakPtrRef(),
kPropSkillMinor,
minor_type_,
minor_cd_time_,
minor_cd_time_,
meta->skill_id(),
true
);
NotifySkillState();
}
}
}
void Skill::InitActiveSkill()
{
inc_times_timer_ = owner->room->xtimer.SetIntervalWpEx
(
GetCd() / FRAME_RATE_MS,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (GetCurrTimes() < GetMaxTimes()) {
curr_times_++;
NotifySkillState();
}
}
},
&xtimer_attacher);
}
void Skill::InitPassiveSkill()
{
switch (meta->GetMagicId()) {
case MAGIC_SJXY:
{
ProcSJXY();
}
break;
case MAGIC_SSJS:
{
ProcSSJS();
}
break;
case MAGIC_JSHX:
{
ProcJSHX();
}
break;
case MAGIC_SWZB:
{
ProcSWZB();
}
break;
case MAGIC_CMXD:
{
ProcCMXD();
}
break;
case MAGIC_MYXY:
{
ProcMYXY();
}
break;
case MAGIC_GZJS:
{
ProcGZJS();
}
break;
case MAGIC_JYFH:
{
ProcJYFH();
}
break;
case MAGIC_FH:
{
ProcFH();
}
break;
case MAGIC_YSHF:
{
ProcYSHF();
}
break;
default:
{
}
break;
}
}
void Skill::ProcSJXY()
{
int shot_times = 0;
std::map<int, long long> hited_objs;
owner->GetTrigger()->AddListener
(
kBulletHitEvent,
[this, shot_times, hited_objs] (const a8::Args& args) mutable
{
++shot_times;
IBullet* bullet = args.Get<IBullet*>(0);
Creature* target = args.Get<Creature*>(1);
int rnd = rand();
bool is_hit = false;
bool is_immune = false;
if (shot_times % meta->_number_meta->_int_ratio == 0) {
if ((rnd % 100) < meta->_number_meta->_float_probability * 100) {
const mt::Buff* buff_meta = mt::Buff::GetById(kVertigoEffectBuffId);
if (buff_meta && target->GetAbility()->CanImmune(buff_meta->_tags)) {
is_immune = true;
} else {
auto itr = hited_objs.find(target->GetUniId());
if (itr == hited_objs.end()) {
hited_objs[target->GetUniId()] = owner->room->GetFrameNo();
is_hit = true;
} else {
if ((owner->room->GetFrameNo() - itr->second) >=
meta->_number_meta->_float_cd * SERVER_FRAME_RATE) {
itr->second = owner->room->GetFrameNo();
is_hit = true;
}
}//endif itr
if (is_hit) {
target->TryAddBuffAndSetTime(owner,
kVertigoEffectBuffId,
meta->_number_meta->_float_time * 1000);
}
}
}
}
#ifdef DEBUG
{
std::string dbg_msg = a8::Format
(
"skill_id:%d 射击 shot_times:%d ratio:%d rand:%d probability:%f time:%f 是否眩晕:%d 是否被免疫:%d",
{
meta->skill_id(),
shot_times,
meta->_number_meta->_int_ratio,
rnd % 100,
meta->_number_meta->_float_probability,
meta->_number_meta->_float_time,
is_hit ? 1 : 0,
is_immune ? 1 : 0
});
owner->SendDebugMsg(dbg_msg);
a8::XPrintf("%s\n", {dbg_msg});
}
#endif
}
);
}
void Skill::ProcSSJS()
{
a8::XTimerWp add_speed_timer;
owner->GetTrigger()->AddListener
(
kReceiveDmgEvent,
[this, add_speed_timer] (const a8::Args& args) mutable
{
int rnd = rand();
const mt::Skill* skill_meta = meta;
float speed_rate = SkillHelper::GetSsjsSpeedRate(skill_meta);
bool is_hit = false;
#if 1
{
#else
if (GetLeftTime() <= 0) {
#endif
if (owner->GetHPRate() <= SkillHelper::GetSsjsHpRate(skill_meta) &&
rnd % 100 < SkillHelper::GetSsjsProb(skill_meta) * 100 &&
add_speed_timer.expired()) {
owner->GetAbility()->AddSpeedAddition(speed_rate);
add_speed_timer = owner->room->xtimer.SetTimeoutWpEx
(
SkillHelper::GetSsjsTime(meta) * 1000 / FRAME_RATE_MS,
[this, skill_meta, speed_rate]
(int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
owner->GetAbility()->DelSpeedAddition(speed_rate);
}
},
&xtimer_attacher);
is_hit = true;
}
}
#ifdef DEBUG
{
std::string dbg_msg = a8::Format
(
"skill_id:%d 受伤加速 hp_rate:%f rnd:%d ratio2:%f probability:%f speed:%f time:%f 是否加速:%d",
{
meta->skill_id(),
owner->GetHPRate(),
rnd % 100,
meta->_number_meta->_float_ratio2,
meta->_number_meta->_float_probability,
meta->_number_meta->_float_speed,
meta->_number_meta->_float_time,
is_hit ? 1 : 0
});
owner->SendDebugMsg(dbg_msg);
a8::XPrintf("%s\n", {dbg_msg});
}
#endif
}
);
}
void Skill::ProcJSHX()
{
owner->GetTrigger()->AddListener
(
kKillEvent,
[this] (const a8::Args& args)
{
int weapon_id = args.Get<int>(2);
if (owner->GetCurrWeapon()->meta->id() != weapon_id) {
return;
}
if (!owner->GetCurrWeapon()->skill_meta ||
owner->GetCurrWeapon()->skill_meta->GetMagicId() != MAGIC_HLYZ) {
return;
}
if (!owner->dead) {
float add_hp = SkillHelper::GetJshxHp(owner, meta);
float real_add_hp = std::max(0.0f, std::min(owner->GetMaxHP() - owner->GetHP(), add_hp));
owner->AddHp(add_hp);
#ifdef DEBUG
{
std::string dbg_msg = a8::Format
(
"skill_id:%d 击杀回血 add_hp:%f real_add_hp:%f ratio:%f ratio2:%f human.atk:%f human.extRecoverHp:%f",
{
meta->skill_id(),
add_hp,
real_add_hp,
meta->_number_meta->_float_ratio,
meta->_number_meta->_float_ratio2,
owner->GetBattleContext()->GetHeroTotalAtk(),
owner->GetBattleContext()->GetExtRecoverHp()
});
owner->SendDebugMsg(dbg_msg);
a8::XPrintf("%s\n", {dbg_msg});
}
#endif
}
}
);
}
void Skill::ProcSWZB()
{
struct _Nested
{
static void cb(CreatureWeakPtr sender, Entity* e, const mt::Skill* skill_meta)
{
if (sender.Get()) {
if (e->IsCreature(sender.Get()->room)) {
Creature* c = (Creature*)e;
if (c->IsInvincible()) {
return;
}
if (c->dead) {
return;
}
float dmg = SkillHelper::GetSwzbDmg(sender.Get(), skill_meta);
c->DecHP(dmg,
VP_Explosion,
"",
SkillHelper::GetSwzbEffect(skill_meta),
sender.Get()->GetUniId(),
sender.Get()->GetName());
glm::vec3 dir = sender.Get()->GetAttackDir();
if (!GlmHelper::IsZero(dir)) {
// 999
glm::vec3 target_pos = c->GetPos().ToGlmVec3() +
dir * (float)(SkillHelper::GetSwzbPullDistance(skill_meta));
c->PullTarget(target_pos);
}
int buff_id = SkillHelper::GetSwzbBuffId(skill_meta);
float buff_time = SkillHelper::GetSwzbBuffTime(skill_meta);
c->TryAddBuffAndSetTime(sender.Get(), buff_id, buff_time);
}
}
}
};
owner->GetTrigger()->AddListener
(
kPreDieEvent,
[this] (const a8::Args& args)
{
int killer_id = args.Get<int>(0);
CreatureWeakPtr sender = owner->GetWeakPtrRef();
const mt::Skill* skill_meta = meta;
Position center = owner->GetPos();
std::shared_ptr<Explosion> e = EntityFactory::Instance()->MakeExplosion();
e->SetThrough(true);
e->SetNoSync();
e->SetHitCb
(
[sender, center, skill_meta] (const a8::Args& args) mutable
{
Entity* e = args.Get<Entity*>(0);
_Nested::cb(sender, e, skill_meta);
}
);
e->EnemyAndObstacleAttack
(
owner->GetWeakPtrRef(),
owner->GetPos(),
SkillHelper::GetSwzbRadius(meta),
SkillHelper::GetSwzbEffect(meta),
0
);
Entity* killer = owner->room->GetEntityByUniId(killer_id);
if (killer && killer != owner && !meta->_raw_phases.empty()) {
owner->over_delay_time = meta->_raw_phases.at(0).param1;
owner->TryAddBuff(owner, 209016);
}
#ifdef DEBUG
{
std::string dbg_msg = a8::Format
(
"skill_id:%d 死亡自爆 range:%f range2:%f ratio:%f time:%f",
{
meta->skill_id(),
meta->_number_meta->_float_range,
meta->_number_meta->_float_range2,
meta->_number_meta->_float_ratio,
meta->_number_meta->_float_time
});
owner->SendDebugMsg(dbg_msg);
a8::XPrintf("%s\n", {dbg_msg});
}
#endif
}
);
owner->GetTrigger()->AddListener
(
kDieEvent,
[this] (const a8::Args& args)
{
#if 0
int killer_id = std::any_cast<int>(params.at(0));
Entity* killer = owner->room->GetEntityByUniId(killer_id);
if (killer && killer != owner) {
owner->TryAddBuff(owner, 209016);
}
#endif
});
}
void Skill::ProcCMXD()
{
owner->GetTrigger()->AddListener
(
kShieldDestoryEvent,
[this] (const a8::Args& params)
{
Buff* hold_shield_buff = owner->GetBuffByEffectId(kBET_HoldShield);
if (hold_shield_buff) {
const mt::Skill* skill_meta = hold_shield_buff->skill_meta;
const mt::Skill* this_skill_meta = meta;
const mt::Buff* shield_buff_meta = hold_shield_buff->meta;
CreatureWeakPtr sender = owner->GetWeakPtrRef();
std::shared_ptr<Explosion> e = EntityFactory::Instance()->MakeExplosion();
e->SetThrough(true);
e->SetCustomCheckCb
(
[sender, skill_meta, this_skill_meta, shield_buff_meta]
(const a8::Args& args) mutable
{
bool* is_hit = args.Get<bool*>(0);
Entity* e = args.Get<Entity*>(1);
if (sender.Get() && e->IsCreature(sender.Get()->room)) {
// 999
#if 1
#else
Creature* c = (Creature*)e;
a8::Vec2 target_pos = sender.Get()->GetPos() +
sender.Get()->GetAttackDir() * SkillHelper::GetCmxdRange(this_skill_meta) / 2;
bool ret = Check2dRotationRectangle
(c->GetPos().x,
c->GetPos().y,
20,
target_pos.x,
target_pos.y,
shield_buff_meta->param4,
SkillHelper::GetCmxdRange(this_skill_meta),
sender.Get()->GetAttackDirRotate() * 180.0f
);
if (ret) {
*is_hit = true;
}
#endif
}
}
);
e->SetHitCb
(
[sender, skill_meta] (const a8::Args& args) mutable
{
if (sender.Get()) {
Entity* e = args.Get<Entity*>(0);
if (e->IsCreature(sender.Get()->room)) {
Creature* c = (Creature*)e;
if (c->IsInvincible()) {
return;
}
if (c->dead) {
return;
}
float dmg = SkillHelper::GetCmxdDmg(sender.Get(), skill_meta);
c->DecHP(dmg,
VP_Explosion,
"",
SkillHelper::GetCmxdExplosion(skill_meta),
sender.Get()->GetUniId(),
sender.Get()->GetName());
glm::vec3 dir = sender.Get()->GetAttackDir();
// 999
#if 1
#else
if (!dir.IsZero()) {
a8::Vec2 target_pos = c->GetPos() +
dir * SkillHelper::GetCmxdDistance(skill_meta);
c->PullTarget(target_pos);
}
#endif
c->TryAddBuffAndSetTime(sender.Get(),
kVertigoEffectBuffId,
SkillHelper::GetCmxdVertigoTime(skill_meta) * 1000);
}
}
}
);
e->EnemyAndObstacleAttack
(
owner->GetWeakPtrRef(),
owner->GetPos(),
SkillHelper::GetCmxdRange(meta),
SkillHelper::GetCmxdExplosion(meta),
0
);
#ifdef DEBUG
{
std::string dbg_msg = a8::Format
(
"skill_id:%d 此面向 range:%f range2:%f ratio:%f time:%f",
{
meta->skill_id(),
meta->_number_meta->_float_range,
meta->_number_meta->_float_range2,
meta->_number_meta->_float_ratio,
meta->_number_meta->_float_time
});
owner->SendDebugMsg(dbg_msg);
a8::XPrintf("%s\n", {dbg_msg});
}
#endif
}
}
);
}
void Skill::ProcMYXY()
{
float speed_rate = SkillHelper::GetMyxySpeedRate(meta);
float atk_rate = SkillHelper::GetMyxyAtkRate(meta);
std::shared_ptr<int> immune_buff_uniid = std::make_shared<int>(0);
owner->GetTrigger()->AddListener
(
kUseSkillEvent,
[this, speed_rate, atk_rate, immune_buff_uniid]
(const a8::Args& args)
{
Skill* skill = args.Get<Skill*>(0);
if (skill->meta->GetMagicId() != MAGIC_HJHX) {
return;
}
owner->GetAbility()->AddSpeedAddition(speed_rate);
if (*immune_buff_uniid) {
owner->RemoveBuffByUniId(*immune_buff_uniid);
*immune_buff_uniid = 0;
}
owner->TryAddBuff
(owner,
kDispelEffectBuffId,
meta);
*immune_buff_uniid = owner->TryAddBuffAndSetTime
(owner,
kImmuneEffectBuffId,
meta->_number_meta->_float_time * 1000,
meta);
owner->GetAbility()->DelSpeedAddition(speed_rate);
}
);
#ifdef DEBUG
{
std::string dbg_msg = a8::Format
(
"skill_id:%d 免疫眩晕 攻击力:%f 移动提升:%f",
{
meta->skill_id(),
atk_rate,
speed_rate
});
owner->SendDebugMsg(dbg_msg);
a8::XPrintf("%s\n", {dbg_msg});
}
#endif
}
void Skill::ProcGZJS()
{
float dmg_ruduce_rate = meta->_number_meta->_float_ratio2;
a8::XTimerWp dmg_ruduce_timer;
std::shared_ptr<int> immune_buff_uniid = std::make_shared<int>(0);
std::shared_ptr<int> hold_gun_buff_uniid = std::make_shared<int>(0);
owner->GetTrigger()->AddListener
(
kFlyHookCreateEvent,
[this, dmg_ruduce_rate, dmg_ruduce_timer, immune_buff_uniid, hold_gun_buff_uniid]
(const a8::Args& args) mutable
{
Bullet* bullet = args.Get<Bullet*>(0);
if (!bullet->skill_meta || bullet->skill_meta->GetMagicId() != MAGIC_FG) {
return;
}
if (!dmg_ruduce_timer.expired()) {
owner->room->xtimer.Delete(dmg_ruduce_timer);
}
owner->GetAbility()->AddDmgRuduce(dmg_ruduce_rate);
dmg_ruduce_timer = owner->room->xtimer.SetTimeoutWpEx
(
meta->_number_meta->_float_time * 1000 / FRAME_RATE_MS,
[this, dmg_ruduce_rate] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
owner->GetAbility()->DelDmgRuduce(dmg_ruduce_rate);
}
},
&xtimer_attacher);
if (*immune_buff_uniid) {
owner->RemoveBuffByUniId(*immune_buff_uniid);
*immune_buff_uniid = 0;
}
*immune_buff_uniid = owner->TryAddBuffAndSetTime
(owner,
kImmuneEffectBuffId,
meta->_number_meta->_float_time * 1000,
meta);
if (*hold_gun_buff_uniid) {
owner->RemoveBuffByUniId(*hold_gun_buff_uniid);
*hold_gun_buff_uniid = 0;
}
*hold_gun_buff_uniid = owner->TryAddBuffAndSetTime
(owner,
//meta->_number_meta->buff_id(),
204014,
10 * 1000,
meta);
owner->TryAddBuff
(owner,
kDispelEffectBuffId,
meta);
owner->TryAddBuffAndSetTime
(owner,
meta->_number_meta->buff_id(),
meta->_number_meta->_float_time
);
});
owner->GetTrigger()->AddListener
(
kFlyHookDestoryEvent,
[this, dmg_ruduce_rate, immune_buff_uniid, hold_gun_buff_uniid]
(const a8::Args& args)
{
if (*immune_buff_uniid) {
owner->RemoveBuffByUniId(*immune_buff_uniid);
*immune_buff_uniid = 0;
}
if (*hold_gun_buff_uniid) {
owner->RemoveBuffByUniId(*hold_gun_buff_uniid);
*hold_gun_buff_uniid = 0;
}
}
);
}
void Skill::ProcJYFH()
{
int buff_id = SkillHelper::GetJyfhBuffId(meta);
float buff_time = SkillHelper::GetJyfhBuffTime(meta);
owner->GetTrigger()->AddListener
(
kStartRescueEvent,
[this, buff_id, buff_time] (const a8::Args& args)
{
Human* target = args.Get<Human*>(0);
owner->TryAddBuffAndSetTime(owner, buff_id, buff_time * 1000, meta);
target->TryAddBuffAndSetTime(owner, buff_id, buff_time * 1000, meta);
}
);
owner->GetTrigger()->AddListener
(
kEndRescueEvent,
[this, buff_id] (const a8::Args& args)
{
Human* target = args.Get<Human*>(0);
owner->RemoveBuffById(buff_id);
target->RemoveBuffById(buff_id);
}
);
#ifdef DEBUG
{
std::string dbg_msg = a8::Format
(
"skill_id:%d 救援防护 time:%f",
{
meta->skill_id(),
buff_time
});
owner->SendDebugMsg(dbg_msg);
a8::XPrintf("%s\n", {dbg_msg});
}
#endif
}
void Skill::ProcFH()
{
int relive_times = 0;
owner->GetTrigger()->AddListener
(
kDieEvent,
[this, relive_times] (const a8::Args& args) mutable
{
int killer_id = args.Get<int>(0);
if (relive_times <= 0) {
++relive_times;
if (killer_id != owner->GetUniId()) {
owner->real_dead = false;
a8::SetBitFlag(owner->status, CS_DeadNoDrop);
owner->room->xtimer.SetTimeoutEx
(
meta->_number_meta->_float_time * 1000 / FRAME_RATE_MS,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT != event) {
return;
}
owner->dead = false;
owner->real_dead = false;
owner->downed = false;
a8::UnSetBitFlag(owner->status, CS_DeadNoDrop);
owner->SyncAroundPlayers(__FILE__, __LINE__, __func__);
owner->room->frame_event.AddRevive(owner->GetWeakPtrRef());
owner->TryAddBuff(owner,
meta->_number_meta->buff_id(),
meta);
owner->room->xtimer.SetTimeoutEx
(
3 * SERVER_FRAME_RATE,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
owner->SetHP(owner->GetMaxHP() * meta->_number_meta->_float_ratio2);
owner->SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
},
&xtimer_attacher);
},
&xtimer_attacher);
}
}
}
);
}
void Skill::ProcYSHF()
{
owner->GetTrigger()->AddListener
(
kYsRemoveEvent,
[this] (const a8::Args& args)
{
Buff* buff = args.Get<Buff*>(0);
if (!buff->remover_timer.expired() && !buff->owner->dead) {
int buff_time = owner->room->xtimer.GetRemainTime(buff->remover_timer) * FRAME_RATE_MS;
int remain_time = buff_time - meta->_number_meta->_float_time * 1000;
if (remain_time > 100) {
int buff_id = buff->meta->buff_id();
auto skill_meta = buff->skill_meta;
owner->room->xtimer.SetTimeoutEx
(
meta->_number_meta->_float_time * 1000 / FRAME_RATE_MS,
[this, buff_id, remain_time, skill_meta]
(int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (!owner->HasBuffEffect(kBET_Hide)) {
owner->TryAddBuffAndSetTime(owner, buff_id, remain_time, skill_meta);
}
}
},
&owner->xtimer_attacher);
}
}
}
);
}