528 lines
15 KiB
C++
528 lines
15 KiB
C++
#include "precompile.h"
|
|
|
|
#include "skill.h"
|
|
#include "creature.h"
|
|
#include "room.h"
|
|
#include "metamgr.h"
|
|
#include "trigger.h"
|
|
#include "skillhelper.h"
|
|
#include "entityfactory.h"
|
|
#include "explosion.h"
|
|
#include "buff.h"
|
|
|
|
void Skill::Initialzie()
|
|
{
|
|
curr_times_ = GetMaxTimes();
|
|
switch (meta->i->skill_type()) {
|
|
case kActiveSkill:
|
|
{
|
|
InitActiveSkill();
|
|
}
|
|
break;
|
|
case kPassiveSkill:
|
|
{
|
|
InitPassiveSkill();
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
int Skill::GetCd()
|
|
{
|
|
return meta->i->skill_cd() * 1000;
|
|
}
|
|
|
|
int Skill::GetPassedTime()
|
|
{
|
|
if (!inc_times_timer_) {
|
|
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::FillMFSkill(cs::MFSkill* skill_pb)
|
|
{
|
|
skill_pb->set_skill_id(meta->i->skill_id());
|
|
skill_pb->set_left_time(GetLeftTime());
|
|
skill_pb->set_cd_time(GetCd());
|
|
skill_pb->set_curr_times(GetCurrTimes());
|
|
skill_pb->set_max_times(GetMaxTimes());
|
|
if (minor_type_) {
|
|
int minor_left_time = std::max(0, minor_cd_time_ - (int)(owner->room->GetFrameNo() - minor_frameno_));
|
|
skill_pb->set_minor_type(minor_type_);
|
|
skill_pb->set_minor_left_time(minor_left_time);
|
|
skill_pb->set_minor_cd_time(minor_cd_time_);
|
|
skill_pb->set_left_time(GetCd());
|
|
#ifdef DEBUG
|
|
a8::XPrintf("type: %d, lefttime:%d cd_time:%d\n", {
|
|
minor_type_,
|
|
minor_left_time,
|
|
minor_cd_time_
|
|
});
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Skill::DecTimes()
|
|
{
|
|
if (!inc_times_timer_) {
|
|
A8_ABORT();
|
|
}
|
|
if (GetCurrTimes() >= GetMaxTimes()) {
|
|
owner->room->xtimer.ModifyTimer(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->i->max_times();
|
|
}
|
|
|
|
void Skill::NotifySkillState()
|
|
{
|
|
if (owner->IsHuman()) {
|
|
if (GetCurrTimes() < GetMaxTimes()) {
|
|
owner->room->frame_event.AddSkillCdChg(owner->AllocWeakPtr(), meta->i->skill_id(), GetCd());
|
|
} else {
|
|
owner->room->frame_event.AddSkillCdChg(owner->AllocWeakPtr(), meta->i->skill_id(), 0);
|
|
}
|
|
owner->room->frame_event.AddSkillCurrTimesChg(owner->AllocWeakPtr(), meta->i->skill_id(), GetCurrTimes());
|
|
}
|
|
}
|
|
|
|
void Skill::ResetSkillCd()
|
|
{
|
|
if (!meta->IsTurnOverSkill()) {
|
|
curr_times_ = 0;
|
|
if (inc_times_timer_) {
|
|
owner->room->xtimer.ModifyTimer(inc_times_timer_, GetCd() / FRAME_RATE_MS);
|
|
NotifySkillState();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Skill::Accelerate(int time)
|
|
{
|
|
if (inc_times_timer_) {
|
|
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.ModifyTimer(inc_times_timer_, remain_time / FRAME_RATE_MS);
|
|
NotifySkillState();
|
|
}
|
|
}
|
|
|
|
void Skill::LockCastPhase()
|
|
{
|
|
if (meta->i->cast_time() > 0) {
|
|
int buff_uniid = owner->TryAddBuff(owner, kVertigoBuffId);
|
|
Buff* buff = owner->GetBuffByUniId(buff_uniid);
|
|
if (buff && buff->remover_timer) {
|
|
owner->room->xtimer.ModifyTimer(buff->remover_timer,
|
|
meta->i->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->i->up_exp();
|
|
}
|
|
|
|
void Skill::AddMinorMode(
|
|
int minor_type,
|
|
int minor_cd_time,
|
|
std::function<void()> cb
|
|
)
|
|
{
|
|
if (minor_mode_timer_) {
|
|
owner->room->xtimer.DeleteTimer(minor_mode_timer_);
|
|
minor_mode_timer_ = nullptr;
|
|
}
|
|
minor_type_ = minor_type;
|
|
minor_cd_time_ = minor_cd_time;
|
|
minor_frameno_ = owner->room->GetFrameNo();
|
|
minor_cb_ = cb;
|
|
minor_mode_timer_ = owner->room->xtimer.AddDeadLineTimerAndAttach
|
|
(minor_cd_time / FRAME_RATE_MS,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Skill* skill = (Skill*)param.sender.GetUserData();
|
|
},
|
|
&xtimer_attacher.timer_list_,
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Skill* skill = (Skill*)param.sender.GetUserData();
|
|
skill->minor_type_ = SMT_NONE;
|
|
skill->minor_cd_time_ = 0;
|
|
skill->minor_frameno_ = 0;
|
|
skill->minor_cb_ = nullptr;
|
|
skill->minor_mode_timer_ = nullptr;
|
|
}
|
|
);
|
|
owner->need_sync_active_player = true;
|
|
}
|
|
|
|
void Skill::DoMinorMode()
|
|
{
|
|
if (GetMinorType() != SMT_NONE) {
|
|
minor_cb_();
|
|
minor_type_ = SMT_NONE;
|
|
minor_cd_time_ = 0;
|
|
minor_cb_ = nullptr;
|
|
ResetSkillCd();
|
|
owner->need_sync_active_player = true;
|
|
}
|
|
}
|
|
|
|
void Skill::InitActiveSkill()
|
|
{
|
|
inc_times_timer_ = owner->room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
GetCd() / FRAME_RATE_MS,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Skill* skill = (Skill*)param.sender.GetUserData();
|
|
if (skill->GetCurrTimes() < skill->GetMaxTimes()) {
|
|
skill->curr_times_++;
|
|
skill->NotifySkillState();
|
|
}
|
|
},
|
|
&xtimer_attacher.timer_list_);
|
|
}
|
|
|
|
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 std::vector<std::any>& params) mutable
|
|
{
|
|
++shot_times;
|
|
Bullet* bullet = std::any_cast<Bullet*>(params.at(0));
|
|
Creature* target = std::any_cast<Creature*>(params.at(1));
|
|
if (shot_times % meta->number_meta->int_ratio == 0) {
|
|
if ((rand() % 100) < meta->number_meta->float_probability * 100) {
|
|
bool is_hit = false;
|
|
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, kVertigoBuffId, meta->number_meta->float_cd * 1000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
void Skill::ProcSSJS()
|
|
{
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kReceiveDmgEvent,
|
|
[this] (const std::vector<std::any>& params)
|
|
{
|
|
if (GetLeftTime() <= 0) {
|
|
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
void Skill::ProcJSHX()
|
|
{
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kKillEvent,
|
|
[this] (const std::vector<std::any>& params)
|
|
{
|
|
if (!owner->dead) {
|
|
float add_hp = SkillHelper::GetJshxHp(owner, meta);
|
|
owner->AddHp(add_hp);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
void Skill::ProcSWZB()
|
|
{
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kDieEvent,
|
|
[this] (const std::vector<std::any>& params)
|
|
{
|
|
CreatureWeakPtr sender = owner->GetWeakPtrRef();
|
|
a8::Vec2 center = owner->GetPos();
|
|
std::shared_ptr<Explosion> e = EntityFactory::Instance()->MakeExplosion();
|
|
e->SetHitCb
|
|
(
|
|
[sender, center] (const std::vector<std::any>& params) mutable
|
|
{
|
|
#if 0
|
|
if (sender.Get()) {
|
|
Entity* e = std::any_cast<Entity*>(params.at(0));
|
|
if (e->IsCreature()) {
|
|
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
);
|
|
e->EnemyAndObstacleAttack
|
|
(
|
|
owner->GetWeakPtrRef(),
|
|
owner->GetPos(),
|
|
SkillHelper::GetSwzbRadius(meta),
|
|
SkillHelper::GetSwzbEffect(meta),
|
|
SkillHelper::GetSwzbDmg(meta)
|
|
);
|
|
}
|
|
);
|
|
}
|
|
|
|
void Skill::ProcCMXD()
|
|
{
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kShieldDestoryEvent,
|
|
[this] (const std::vector<std::any>& params)
|
|
{
|
|
Buff* hold_shield_buff = owner->GetBuffByEffectId(kBET_HoldShield);
|
|
if (hold_shield_buff) {
|
|
MetaData::Skill* skill_meta = hold_shield_buff->skill_meta;
|
|
CreatureWeakPtr sender = owner->GetWeakPtrRef();
|
|
|
|
std::shared_ptr<Explosion> e = EntityFactory::Instance()->MakeExplosion();
|
|
e->SetThrough(true);
|
|
e->SetHitCb
|
|
(
|
|
[sender, skill_meta] (const std::vector<std::any>& params) mutable
|
|
{
|
|
if (sender.Get()) {
|
|
Entity* e = std::any_cast<Entity*>(params.at(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));
|
|
a8::Vec2 dir = sender.Get()->GetAttackDir();
|
|
if (!dir.IsZero()) {
|
|
a8::Vec2 target_pos = c->GetPos() +
|
|
dir * SkillHelper::GetCmxdDistance(skill_meta);
|
|
c->PullTarget(target_pos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
);
|
|
e->EnemyAndObstacleAttack
|
|
(
|
|
owner->GetWeakPtrRef(),
|
|
owner->GetPos(),
|
|
SkillHelper::GetCmxdRange(meta),
|
|
SkillHelper::GetCmxdExplosion(meta),
|
|
0
|
|
);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
void Skill::ProcMYXY()
|
|
{
|
|
|
|
}
|
|
|
|
void Skill::ProcGZJS()
|
|
{
|
|
|
|
}
|
|
|
|
void Skill::ProcJYFH()
|
|
{
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kStartRescueEvent,
|
|
[this] (const std::vector<std::any>& params)
|
|
{
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kEndRescueEvent,
|
|
[this] (const std::vector<std::any>& params)
|
|
{
|
|
|
|
}
|
|
);
|
|
}
|
|
);
|
|
}
|
|
|
|
void Skill::ProcFH()
|
|
{
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kDieEvent,
|
|
[] (const std::vector<std::any>& params)
|
|
{
|
|
|
|
}
|
|
);
|
|
}
|
|
|
|
void Skill::ProcYSHF()
|
|
{
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kYsRemoveEvent,
|
|
[this] (const std::vector<std::any>& params)
|
|
{
|
|
Buff* buff = std::any_cast<Buff*>(params.at(0));
|
|
if (buff->remover_timer && !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) {
|
|
owner->room->xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
meta->number_meta->float_time * 1000 / FRAME_RATE_MS,
|
|
a8::XParams()
|
|
.SetSender(owner)
|
|
.SetParam1(buff->meta->i->buff_id())
|
|
.SetParam2(remain_time)
|
|
.SetParam3(buff->skill_meta),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Creature* c = (Creature*)param.sender.GetUserData();
|
|
int buff_id = param.param1;
|
|
int remain_time = param.param2;
|
|
MetaData::Skill* skill_meta = (MetaData::Skill*)param.param3.GetUserData();
|
|
if (!c->HasBuffEffect(kBET_Hide)) {
|
|
c->TryAddBuffAndSetTime(c, buff_id, remain_time, skill_meta);
|
|
}
|
|
},
|
|
&owner->xtimer_attacher.timer_list_);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|