570 lines
14 KiB
C++
570 lines
14 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 "netdata.h"
|
|
#include "collision.h"
|
|
#include "shot.h"
|
|
#include "movement.h"
|
|
#include "team.h"
|
|
#include "app.h"
|
|
|
|
#include "mt/Buff.h"
|
|
#include "mt/Skill.h"
|
|
#include "mt/SkillNumber.h"
|
|
#include "mt/Equip.h"
|
|
#include "mt/MergeItem.h"
|
|
#include "mt/Hero.h"
|
|
|
|
void Skill::Initialzie()
|
|
{
|
|
curr_times_ = GetMaxTimes();
|
|
switch (GetBaseSkillMeta()->skill_type()) {
|
|
case kActiveSkill:
|
|
{
|
|
InitActiveSkill();
|
|
}
|
|
break;
|
|
case kPassiveSkill:
|
|
{
|
|
InitPassiveSkill();
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
int Skill::GetCd()
|
|
{
|
|
if (GetBaseSkillMeta()->IsTurnOverSkill() ||
|
|
GetBaseSkillMeta()->skill_type() == kPassiveSkill) {
|
|
return GetBaseSkillMeta()->skill_cd() * 1000;
|
|
} else {
|
|
return GetBaseSkillMeta()->skill_cd() * 1000 * (1 - owner->GetNetData()->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 GetBaseSkillMeta()->max_times();
|
|
}
|
|
|
|
void Skill::NotifySkillState()
|
|
{
|
|
if (owner->IsHuman() || owner->IsCar()) {
|
|
if (GetCurrTimes() < GetMaxTimes()) {
|
|
owner->room->frame_event.AddSkillCdChg(owner->AllocWeakPtr(), GetBaseSkillId(), GetCd());
|
|
} else {
|
|
owner->room->frame_event.AddSkillCdChg(owner->AllocWeakPtr(), GetBaseSkillId(), 0);
|
|
}
|
|
owner->room->frame_event.AddSkillCurrTimesChg(owner->AllocWeakPtr(), GetBaseSkillId(), GetCurrTimes());
|
|
}
|
|
}
|
|
|
|
void Skill::ResetSkillCd()
|
|
{
|
|
if (!GetBaseSkillMeta()->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 (GetBaseSkillMeta()->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,
|
|
GetBaseSkillMeta()->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 GetBaseSkillMeta()->up_exp();
|
|
}
|
|
|
|
void Skill::AddMinorMode(
|
|
int minor_type,
|
|
int minor_cd_time,
|
|
std::function<void(int)> cb
|
|
)
|
|
{
|
|
bool is_player = owner->IsPlayer();
|
|
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;
|
|
auto old_cb = minor_cb_;
|
|
minor_cb_ = nullptr;
|
|
if (old_cb) {
|
|
old_cb(kSmaTimeOut);
|
|
}
|
|
ResetSkillCd();
|
|
owner->room->frame_event.AddPropChgEx
|
|
(
|
|
owner->GetWeakPtrRef(),
|
|
kPropSkillMinor,
|
|
minor_type_,
|
|
minor_cd_time_,
|
|
minor_cd_time_,
|
|
GetBaseSkillId(),
|
|
true
|
|
);
|
|
NotifySkillState();
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
{
|
|
owner->room->frame_event.AddPropChgEx
|
|
(
|
|
owner->GetWeakPtrRef(),
|
|
kPropSkillMinor,
|
|
minor_type_,
|
|
minor_cd_time_,
|
|
minor_cd_time_,
|
|
GetBaseSkillId(),
|
|
true
|
|
);
|
|
NotifySkillState();
|
|
#ifdef MYDEBUG
|
|
if (is_player) {
|
|
a8::XPrintf("add minor mode minor_type:%d\n", {minor_type_});
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Skill::DoMinorMode()
|
|
{
|
|
if (GetMinorType() != SMT_NONE &&
|
|
GetMinorType() != SMT_DISABLE) {
|
|
auto old_cb = minor_cb_;
|
|
minor_cb_ = nullptr;
|
|
if (!minor_mode_timer_.expired()) {
|
|
owner->room->xtimer.Delete(minor_mode_timer_);
|
|
}
|
|
if (old_cb) {
|
|
old_cb(kSmaClick);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
actived_ = !owner->GetNetData()->IsMainSkill(this);
|
|
if (owner->IsAndroid() || owner->IsHero() || owner->IsCar()) {
|
|
actived_ = true;
|
|
}
|
|
#if 1
|
|
actived_ = true;
|
|
#if 0
|
|
if (owner->IsPlayer()) {
|
|
owner->AddInventory(IS_BLUE_STONE, 1);
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void Skill::InitPassiveSkill()
|
|
{
|
|
actived_ = true;
|
|
switch (GetBaseSkillMeta()->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 : GetBaseSkillMeta()->_buff_list) {
|
|
hold_buffs_.push_back(owner->TryAddBuff(owner, buff_id, GetCurrSkillMeta()));
|
|
}
|
|
}
|
|
|
|
void Skill::Proc30701BAO()
|
|
{
|
|
}
|
|
|
|
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 (GetBaseSkillMeta()->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 (GetBaseSkillMeta()->GetMagicId() == MAGIC_20401_MAO) {
|
|
target_distance = GetCurrSkillMeta()->_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,
|
|
GetCurrSkillMeta());
|
|
owner->context_pos = old_context_pos;
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
if (GetBaseSkillMeta()->GetMagicId() == MAGIC_20301_XL) {
|
|
target_distance = std::max(0.0001f, target_distance);
|
|
}
|
|
if (bullet_meta && target_distance > 0.00001f) {
|
|
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,
|
|
GetCurrSkillMeta(),
|
|
target_distance,
|
|
0,
|
|
0);
|
|
owner->SetAttackDir(old_attack_dir);
|
|
}
|
|
} else {
|
|
if (GetBaseSkillMeta()->GetMagicId() == MAGIC_20301_XL) {
|
|
owner->TryAddBuff(owner, weapon_meta->_int_param1,
|
|
GetCurrSkillMeta());
|
|
owner->room->frame_event.AddShot(owner->GetWeakPtrRef(), owner->room->GenShotUniid());
|
|
}
|
|
}
|
|
}
|
|
|
|
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) {
|
|
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,
|
|
GetCurrSkillMeta(),
|
|
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();
|
|
App::Instance()->verify_set_pos = 1;
|
|
owner->SetPos(new_pos);
|
|
App::Instance()->verify_set_pos = 0;
|
|
owner->room->grid_service->MoveCreature(owner);
|
|
}
|
|
|
|
void Skill::CancelMinorMode()
|
|
{
|
|
if (GetMinorType() != SMT_NONE) {
|
|
auto old_cb = minor_cb_;
|
|
minor_cb_ = nullptr;
|
|
if (!minor_mode_timer_.expired()) {
|
|
owner->room->xtimer.Delete(minor_mode_timer_);
|
|
}
|
|
if (old_cb) {
|
|
old_cb(kSmaCancel);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Skill::IsMainSkill()
|
|
{
|
|
return owner->GetNetData()->IsMainSkill(this);
|
|
}
|
|
|
|
void Skill::Active()
|
|
{
|
|
actived_ = true;
|
|
}
|
|
|
|
void Skill::Clear()
|
|
{
|
|
for (int buff_uniid : hold_buffs_) {
|
|
owner->RemoveBuffByUniId(buff_uniid);
|
|
}
|
|
hold_buffs_.clear();
|
|
}
|
|
|
|
void Skill::LevelUp()
|
|
{
|
|
if (IsFullLevel()) {
|
|
return;
|
|
}
|
|
const mt::Skill* next_skill_meta = mt::Skill::GetById
|
|
(GetBaseSkillMeta()->_base_skill_meta->skill_id() + level_);
|
|
if (!next_skill_meta) {
|
|
return;
|
|
}
|
|
++level_;
|
|
curr_meta_ = next_skill_meta;
|
|
Clear();
|
|
if (IsPassiveSkill()) {
|
|
for (int buff_id : GetBaseSkillMeta()->_buff_list) {
|
|
hold_buffs_.push_back(owner->TryAddBuff(owner, buff_id, GetCurrSkillMeta()));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Skill::IsFullLevel()
|
|
{
|
|
return level_ == 4;
|
|
}
|
|
|
|
const mt::Skill* Skill::GetCurrSkillMeta()
|
|
{
|
|
return curr_meta_;
|
|
}
|
|
|
|
int Skill::GetSkillId()
|
|
{
|
|
return GetBaseSkillMeta()->skill_id();
|
|
}
|
|
|
|
int Skill::GetBaseSkillId()
|
|
{
|
|
if (GetBaseSkillMeta()->_base_skill_meta) {
|
|
return GetBaseSkillMeta()->_base_skill_meta->skill_id();
|
|
} else {
|
|
return GetSkillId();
|
|
}
|
|
}
|
|
|
|
void Skill::SetMeta(const mt::Skill* meta)
|
|
{
|
|
meta_ = meta;
|
|
curr_meta_ = meta;
|
|
}
|
|
|
|
bool Skill::IsPassiveSkill()
|
|
{
|
|
return GetBaseSkillMeta()->skill_type() == kPassiveSkill;
|
|
}
|