1155 lines
38 KiB
C++
1155 lines
38 KiB
C++
#include "precompile.h"
|
|
|
|
#include <float.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 "collision.h"
|
|
#include "shot.h"
|
|
#include "movement.h"
|
|
|
|
#include "mt/Buff.h"
|
|
#include "mt/Skill.h"
|
|
#include "mt/SkillNumber.h"
|
|
#include "mt/Equip.h"
|
|
|
|
static int GetTraceTargetId(Creature* c)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
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_30101_XL:
|
|
{
|
|
Proc30101XL();
|
|
}
|
|
break;
|
|
case MAGIC_30201:
|
|
{
|
|
ProcSSJS();
|
|
}
|
|
break;
|
|
case MAGIC_30301:
|
|
{
|
|
ProcJSHX();
|
|
}
|
|
break;
|
|
case MAGIC_30401:
|
|
{
|
|
ProcSWZB();
|
|
}
|
|
break;
|
|
case MAGIC_30501:
|
|
{
|
|
ProcCMXD();
|
|
}
|
|
break;
|
|
case MAGIC_30601:
|
|
{
|
|
ProcMYXY();
|
|
}
|
|
break;
|
|
case MAGIC_30701:
|
|
{
|
|
ProcGZJS();
|
|
}
|
|
break;
|
|
case MAGIC_30801:
|
|
{
|
|
ProcJYFH();
|
|
}
|
|
break;
|
|
case MAGIC_30901:
|
|
{
|
|
ProcFH();
|
|
}
|
|
break;
|
|
case MAGIC_31001:
|
|
{
|
|
ProcYSHF();
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Skill::Proc30101XL()
|
|
{
|
|
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 0
|
|
if (!owner->GetCurrWeapon()->skill_meta ||
|
|
owner->GetCurrWeapon()->skill_meta->GetMagicId() != MAGIC_20801) {
|
|
return;
|
|
}
|
|
#endif
|
|
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);
|
|
owner->TryAddBuff(owner, 208014);
|
|
#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).phase_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)) {
|
|
Creature* c = (Creature*)e;
|
|
glm::vec3 target_pos = sender.Get()->GetPos().ToGlmVec3();
|
|
target_pos = target_pos + (sender.Get()->GetAttackDir() * (float)SkillHelper::GetCmxdRange(this_skill_meta) / 2.0f);
|
|
bool ret = Collision::Check2dRotationRectangle
|
|
(c->GetPos().x,
|
|
c->GetPos().y,
|
|
20,
|
|
target_pos.x,
|
|
target_pos.y,
|
|
shield_buff_meta->_buff_param4,
|
|
SkillHelper::GetCmxdRange(this_skill_meta),
|
|
sender.Get()->GetAttackDirRotate() * 180.0f
|
|
);
|
|
if (ret) {
|
|
*is_hit = true;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
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();
|
|
if (!GlmHelper::IsZero(dir)) {
|
|
glm::vec3 target_pos = c->GetPos().ToGlmVec3() +
|
|
dir * (float)SkillHelper::GetCmxdDistance(skill_meta);
|
|
c->PullTarget(target_pos);
|
|
}
|
|
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_20201) {
|
|
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_20401) {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
void Skill::ProcSkillPhase(const mt::SkillPhase* phase)
|
|
{
|
|
switch (phase->func_id) {
|
|
case kSkill_TurnOver:
|
|
{
|
|
}
|
|
break;
|
|
case kSkill_JumpTo:
|
|
{
|
|
|
|
}
|
|
break;
|
|
case kSkill_Shot:
|
|
{
|
|
ProcShotPhase(phase);
|
|
}
|
|
break;
|
|
case kSkill_Pull:
|
|
{
|
|
|
|
}
|
|
break;
|
|
case kSkill_HoldShield:
|
|
{
|
|
}
|
|
break;
|
|
case kSkill_ForthBackJump:
|
|
{
|
|
ProcForthBackJumpPhase(phase);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Skill::ProcShotPhase(const mt::SkillPhase* phase)
|
|
{
|
|
if (meta->skill_target() == kST_SpecDir) {
|
|
ProcSpecDirShotPhase(phase);
|
|
} else {
|
|
ProcNormalShotPhase(phase);
|
|
}
|
|
}
|
|
|
|
void Skill::ProcSpecDirShotPhase(const mt::SkillPhase* phase)
|
|
{
|
|
const mt::Equip* weapon_meta = mt::Equip::GetById(phase->phase_param1.GetInt());
|
|
if (!weapon_meta) {
|
|
return;
|
|
}
|
|
const mt::Equip* bullet_meta =
|
|
mt::Equip::GetById(weapon_meta->use_bullet());
|
|
|
|
if (std::abs(owner->skill_dir_.x) > FLT_EPSILON ||
|
|
std::abs(owner->skill_dir_.y) > FLT_EPSILON) {
|
|
float target_distance = 5;
|
|
if (meta->GetMagicId() == MAGIC_20401) {
|
|
target_distance = meta->_number_meta->_float_range;
|
|
}
|
|
if (weapon_meta->equip_type() == EQUIP_TYPE_THROW &&
|
|
weapon_meta->equip_subtype() == THROW_EQUIP_TYPE_ADD_BUFF) {
|
|
target_distance = owner->skill_distance_;
|
|
auto context_pos_p = owner->context_pos;
|
|
owner->room->xtimer.SetTimeoutEx
|
|
(
|
|
(target_distance / weapon_meta->bullet_speed() + 1.5) * 1000.0f / FRAME_RATE_MS,
|
|
[this, context_pos_p, weapon_meta]
|
|
(int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
Position new_context_pos = context_pos_p;
|
|
Position old_context_pos = owner->context_pos;
|
|
owner->context_pos = new_context_pos;
|
|
owner->TryAddBuff(owner, weapon_meta->_int_param1,
|
|
meta);
|
|
owner->context_pos = old_context_pos;
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
if (meta->GetMagicId() == MAGIC_20301) {
|
|
target_distance = std::max(0.0001f, target_distance);
|
|
}
|
|
if (bullet_meta && target_distance > 0.00001f) {
|
|
int target_id = 0;
|
|
if (meta->GetMagicId() == MAGIC_20201) {
|
|
target_distance = 0;
|
|
owner->TryAddBuff(owner, 202013);
|
|
owner->TryAddBuff(owner, 202014);
|
|
target_id = GetTraceTargetId(owner);
|
|
|
|
}
|
|
glm::vec3 old_attack_dir = owner->GetAttackDir();
|
|
glm::vec3 attack_dir = owner->skill_dir_;
|
|
GlmHelper::Normalize(attack_dir);
|
|
owner->SetAttackDir(attack_dir);
|
|
InternalShot
|
|
(
|
|
owner,
|
|
weapon_meta,
|
|
bullet_meta,
|
|
meta,
|
|
target_distance,
|
|
0,
|
|
0);
|
|
owner->SetAttackDir(old_attack_dir);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Skill::ProcNormalShotPhase(const mt::SkillPhase* phase)
|
|
{
|
|
const mt::Equip* weapon_meta = mt::Equip::GetById(phase->phase_param1.GetInt());
|
|
if (!weapon_meta) {
|
|
return;
|
|
}
|
|
const mt::Equip* bullet_meta =
|
|
mt::Equip::GetById(weapon_meta->use_bullet());
|
|
|
|
Entity* entity = owner->room->GetEntityByUniId(owner->skill_target_id_);
|
|
if (entity) {
|
|
float target_distance = entity->GetPos().Distance2D2(owner->GetPos());
|
|
if (bullet_meta && target_distance > 0.00001f) {
|
|
if (meta->GetMagicId() == MAGIC_20201) {
|
|
owner->TryAddBuff(owner, 202013);
|
|
owner->TryAddBuff(owner, 202014);
|
|
}
|
|
glm::vec3 old_attack_dir = owner->GetAttackDir();
|
|
glm::vec3 attack_dir = owner->GetPos().CalcDir(entity->GetPos());
|
|
GlmHelper::Normalize(attack_dir);
|
|
owner->SetAttackDir(attack_dir);
|
|
InternalShot
|
|
(
|
|
owner,
|
|
weapon_meta,
|
|
bullet_meta,
|
|
meta,
|
|
target_distance,
|
|
0,
|
|
0);
|
|
owner->SetAttackDir(old_attack_dir);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Skill::ProcForthBackJumpPhase(const mt::SkillPhase* phase)
|
|
{
|
|
if (GetMinorType() != SMT_NONE) {
|
|
return;
|
|
}
|
|
|
|
glm::vec3 old_dir = owner->GetMoveDir();
|
|
Position old_pos = owner->GetPos();
|
|
|
|
int buff_id1 = phase->phase_param3_ints.size() > 0 ? phase->phase_param3_ints[0] : 0;
|
|
int buff_id2 = phase->phase_param3_ints.size() > 1 ? phase->phase_param3_ints[1] : 0;
|
|
int buff_id3 = phase->phase_param3_ints.size() > 2 ? phase->phase_param3_ints[2] : 0;
|
|
const mt::Skill* skill_meta = meta;
|
|
owner->TryAddBuff(owner, buff_id1);
|
|
int land_effect_buff_uniid = owner->TryAddBuffAndSetTime
|
|
(owner,
|
|
buff_id3,
|
|
skill_meta->_number_meta->_float_time * 1000);
|
|
#ifdef DEBUG
|
|
a8::XPrintf("old_pos:%f,%f\n", {owner->GetPos().x, owner->GetPos().y});
|
|
#endif
|
|
owner->ForwardMove(SkillHelper::GetSjydhxForthDistance(meta));
|
|
float recover_hp = SkillHelper::GetSjydhxRecoverHp(owner, meta);
|
|
owner->AddHp(recover_hp);
|
|
glm::vec3 pre_dir = old_dir;
|
|
Position pre_pos = old_pos;
|
|
#ifdef DEBUG
|
|
a8::XPrintf("new_pos:%f,%f", {owner->GetPos().x, owner->GetPos().y});
|
|
#endif
|
|
AddMinorMode
|
|
(
|
|
SMT_BLINK,
|
|
#if 1
|
|
skill_meta->_number_meta->_float_time * 1000,
|
|
#else
|
|
phase->param2.GetInt() * 1000,
|
|
#endif
|
|
[this, pre_pos, pre_dir, buff_id1, buff_id2, buff_id3, land_effect_buff_uniid,
|
|
skill_meta] () {
|
|
glm::vec3 old_dir = owner->GetMoveDir();
|
|
Position old_pos = owner->GetPos();
|
|
float distance = owner->GetPos().Distance2D2(pre_pos);
|
|
owner->RemoveBuffByUniId(land_effect_buff_uniid);
|
|
if (distance > 0.0001f) {
|
|
glm::vec3 new_dir = owner->GetPos().CalcDir(pre_pos);
|
|
GlmHelper::Normalize(new_dir);
|
|
owner->SetMoveDir(new_dir);
|
|
owner->TryAddBuff(owner, buff_id2);
|
|
#if 1
|
|
Global::Instance()->verify_set_pos = 1;
|
|
owner->SetPos(pre_pos);
|
|
Global::Instance()->verify_set_pos = 0;
|
|
owner->GetMovement()->ClearPath();
|
|
owner->room->grid_service->MoveCreature(owner);
|
|
#else
|
|
owner->ForwardMove(distance);
|
|
#endif
|
|
}
|
|
owner->SetMoveDir(old_dir);
|
|
owner->TryAddBuffAndSetTime(owner,
|
|
skill_meta->_number_meta->buff_id(),
|
|
skill_meta->_number_meta->buff_time() * 1000,
|
|
skill_meta);
|
|
}
|
|
);
|
|
owner->SetMoveDir(old_dir);
|
|
}
|