aozhiwei 8f3f141f55 1
2023-11-03 17:10:22 +08:00

587 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 "netdata.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"
#include "mt/MergeItem.h"
#include "mt/Hero.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->GetBattleContext()->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() || 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 (!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
)
{
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;
if (minor_cb_) {
minor_cb_(0);
}
minor_cb_ = nullptr;
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 DEBUG
if (is_player) {
a8::XPrintf("add minor mode minor_type:%d\n", {minor_type_});
}
#endif
}
}
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);
actived_ = !owner->GetBattleContext()->IsMainSkill(this);
if (owner->IsAndroid() || owner->IsHero() || owner->IsCar()) {
actived_ = true;
}
#if 1
actived_ = true;
if (owner->IsPlayer()) {
owner->AddInventory(IS_BLUE_STONE, 1);
}
#endif
}
void Skill::InitPassiveSkill()
{
actived_ = true;
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()
{
}
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) {
#if 1
target_distance = owner->skill_distance_;
#else
target_distance = 0;
#endif
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_);
}
}
}
bool Skill::IsMainSkill()
{
return owner->GetBattleContext()->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 (owner->GetInventory(IS_BLUE_STONE) % 3 == 0) {
Clear();
auto merge_item_meta = mt::MergeItem::GetById(mt::Equip::BLUE_STONE_ID);
if (merge_item_meta) {
int skill_lv = owner->GetInventory(IS_BLUE_STONE) / 3 + 1;
const mt::Skill* new_skill_meta = mt::Skill::GetById(meta->_base_skill_meta->skill_id());
if (new_skill_meta) {
if (mt::Skill::GetById(new_skill_meta->skill_id() + skill_lv - 1)) {
owner->skill_hash_[new_skill_meta->skill_id() + skill_lv - 1] = owner->skill_hash_[meta->skill_id()];
}
level_ = skill_lv;
}
std::set<int>* buffs = merge_item_meta->GetBuffs(owner->GetInventory(IS_BLUE_STONE));
if (buffs) {
for (int buff_id : *buffs) {
hold_buffs_.push_back(owner->TryAddBuff(owner, buff_id, nullptr));
}
}
}
}
}
void Skill::Reset()
{
Clear();
for (int i = 2; i <= level_; ++i) {
owner->skill_hash_.erase(meta->skill_id() + i - 1);
}
level_ = 1;
}
const mt::Skill* Skill::GetCurrSkillMeta()
{
if (level_ > 1) {
const mt::Skill* new_skill_meta = mt::Skill::GetById(meta->skill_id() + level_ - 1);
if (new_skill_meta) {
return new_skill_meta;
} else {
return meta;
}
} else {
return meta;
}
}
int Skill::GetSkillId()
{
return meta->skill_id();
}
int Skill::GetBaseSkillId()
{
if (meta->_base_skill_meta) {
return meta->_base_skill_meta->skill_id();
} else {
GetSkillId();
}
}