566 lines
15 KiB
C++
566 lines
15 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 "team.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()
|
|
{
|
|
if (meta->IsTurnOverSkill() ||
|
|
meta->skill_type() == kPassiveSkill) {
|
|
return meta->skill_cd() * 1000;
|
|
} else {
|
|
return meta->skill_cd() * 1000 * (1 + owner->GetBattleConetxt()->GetSkillCdPct());
|
|
}
|
|
}
|
|
|
|
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(int)> 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;
|
|
if (minor_cb_) {
|
|
minor_cb_(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();
|
|
}
|
|
}
|
|
},
|
|
&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_(1);
|
|
minor_cb_ = nullptr;
|
|
if (!minor_mode_timer_.expired()) {
|
|
owner->room->xtimer.Delete(minor_mode_timer_);
|
|
}
|
|
}
|
|
}
|
|
|
|
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_HL:
|
|
{
|
|
}
|
|
break;
|
|
case MAGIC_30201_HX:
|
|
{
|
|
}
|
|
break;
|
|
case MAGIC_30301_XL:
|
|
{
|
|
}
|
|
break;
|
|
case MAGIC_30401_MAO:
|
|
{
|
|
}
|
|
break;
|
|
case MAGIC_30501_TZ:
|
|
{
|
|
}
|
|
break;
|
|
case MAGIC_30601_DJS:
|
|
{
|
|
}
|
|
break;
|
|
case MAGIC_30701_BAO:
|
|
{
|
|
Proc30701BAO();
|
|
}
|
|
break;
|
|
case MAGIC_30801_LONG:
|
|
{
|
|
}
|
|
break;
|
|
case MAGIC_30901_XIONG:
|
|
{
|
|
}
|
|
break;
|
|
case MAGIC_31001_NIU:
|
|
{
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
for (int buff_id : meta->_buff_list) {
|
|
owner->TryAddBuff(owner, buff_id, meta);
|
|
}
|
|
}
|
|
|
|
void Skill::Proc30701BAO()
|
|
{
|
|
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_MAO) {
|
|
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::ProcSkillPhase(const mt::SkillPhase* phase)
|
|
{
|
|
switch (phase->func_id) {
|
|
case kSkill_TurnOver:
|
|
{
|
|
}
|
|
break;
|
|
case kSkill_JumpTo:
|
|
{
|
|
ProcJumpToPhase(phase);
|
|
}
|
|
break;
|
|
case kSkill_Shot:
|
|
{
|
|
ProcShotPhase(phase);
|
|
}
|
|
break;
|
|
case kSkill_Pull:
|
|
{
|
|
|
|
}
|
|
break;
|
|
case kSkill_HoldShield:
|
|
{
|
|
}
|
|
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_.z) > FLT_EPSILON) {
|
|
float target_distance = 5;
|
|
if (meta->GetMagicId() == MAGIC_20401_MAO) {
|
|
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.0) * 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_XL) {
|
|
target_distance = std::max(0.0001f, target_distance);
|
|
}
|
|
if (bullet_meta && target_distance > 0.00001f) {
|
|
int target_id = 0;
|
|
if (meta->GetMagicId() == MAGIC_20201_HX) {
|
|
target_distance = 0;
|
|
owner->TryAddBuff(owner, 202013);
|
|
owner->TryAddBuff(owner, 202014);
|
|
#if 0
|
|
target_id = GetTraceTargetId(owner);
|
|
#endif
|
|
}
|
|
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);
|
|
}
|
|
} else {
|
|
if (meta->GetMagicId() == MAGIC_20301_XL) {
|
|
owner->TryAddBuff(owner, weapon_meta->_int_param1,
|
|
meta);
|
|
owner->room->frame_event.AddShot(owner->GetWeakPtrRef());
|
|
}
|
|
}
|
|
}
|
|
|
|
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_HX) {
|
|
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::ProcJumpToPhase(const mt::SkillPhase* phase)
|
|
{
|
|
Position new_pos;
|
|
new_pos.FromGlmVec3(owner->context_pos.ToGlmVec3());
|
|
owner->GetMovement()->ClearPath();
|
|
Global::Instance()->verify_set_pos = 1;
|
|
owner->SetPos(new_pos);
|
|
Global::Instance()->verify_set_pos = 0;
|
|
owner->room->grid_service->MoveCreature(owner);
|
|
}
|
|
|
|
void Skill::CancelMinorMode()
|
|
{
|
|
if (GetMinorType() != SMT_NONE) {
|
|
minor_cb_(2);
|
|
minor_cb_ = nullptr;
|
|
if (!minor_mode_timer_.expired()) {
|
|
owner->room->xtimer.Delete(minor_mode_timer_);
|
|
}
|
|
}
|
|
}
|