#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" #include "human.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 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 hited_objs; owner->GetTrigger()->AddListener ( kBulletHitEvent, [this, shot_times, hited_objs] (const std::vector& params) mutable { ++shot_times; Bullet* bullet = std::any_cast(params.at(0)); Creature* target = std::any_cast(params.at(1)); int rnd = rand(); bool is_hit = false; if (shot_times % meta->number_meta->int_ratio == 0) { if ((rnd % 100) < meta->number_meta->float_probability * 100) { 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_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", { meta->i->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 }); owner->SendDebugMsg(dbg_msg); a8::XPrintf("%s\n", {dbg_msg}); } #endif } ); } void Skill::ProcSSJS() { std::weak_ptr add_speed_timer; owner->GetTrigger()->AddListener ( kReceiveDmgEvent, [this, add_speed_timer] (const std::vector& params) mutable { int rnd = rand(); MetaData::Skill* skill_meta = meta; float speed_rate = SkillHelper::GetSsjsSpeedRate(skill_meta); bool is_hit = false; if (GetLeftTime() <= 0) { if (owner->GetHPRate() <= SkillHelper::GetSsjsHpRate(skill_meta) && rnd % 100 < SkillHelper::GetSsjsProb(skill_meta) && add_speed_timer.expired()) { owner->GetAbility()->AddSpeedAddition(speed_rate); xtimer_list* timer = owner->room->xtimer.AddDeadLineTimerAndAttach ( SkillHelper::GetSsjsTime(meta) * 1000 / FRAME_RATE_MS, a8::XParams() .SetSender(owner) .SetParam1(skill_meta) .SetParam2(speed_rate), [] (const a8::XParams& param) { Creature* c = (Creature*)param.sender.GetUserData(); MetaData::Skill* skill_meta = (MetaData::Skill*)param.param1.GetUserData(); float speed_rate = param.param2.GetDouble(); c->GetAbility()->DelSpeedAddition(speed_rate); }, &xtimer_attacher.timer_list_ ); add_speed_timer = owner->room->xtimer.GetTimerPtr(timer); is_hit = true; } } #ifdef DEBUG { std::string dbg_msg = a8::Format ( "skill_id:%d 受伤加速 rnd:%d ratio2:%f probability:%f speed:%f time:%f 是否加速:%d", { meta->i->skill_id(), 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 std::vector& 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& params) { CreatureWeakPtr sender = owner->GetWeakPtrRef(); MetaData::Skill* skill_meta = meta; a8::Vec2 center = owner->GetPos(); std::shared_ptr e = EntityFactory::Instance()->MakeExplosion(); e->SetThrough(true); e->SetHitCb ( [sender, center, skill_meta] (const std::vector& params) mutable { if (sender.Get()) { Entity* e = std::any_cast(params.at(0)); 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)); a8::Vec2 dir = sender.Get()->GetAttackDir(); if (!dir.IsZero()) { a8::Vec2 target_pos = c->GetPos() + dir * 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); } } } ); e->EnemyAndObstacleAttack ( owner->GetWeakPtrRef(), owner->GetPos(), SkillHelper::GetSwzbRadius(meta), SkillHelper::GetSwzbEffect(meta), 0 ); } ); } void Skill::ProcCMXD() { owner->GetTrigger()->AddListener ( kShieldDestoryEvent, [this] (const std::vector& 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 e = EntityFactory::Instance()->MakeExplosion(); e->SetThrough(true); e->SetHitCb ( [sender, skill_meta] (const std::vector& params) mutable { if (sender.Get()) { Entity* e = std::any_cast(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() { float speed_rate = SkillHelper::GetMyxySpeedRate(meta); float def_rate = SkillHelper::GetMyxyDefRate(meta); owner->GetTrigger()->AddListener ( kStartSwitchWeaponBuffEvent, [this, speed_rate, def_rate] (const std::vector& params) { Buff* buff = std::any_cast(params.at(0)); if (!buff->skill_meta || buff->skill_meta->GetMagicId() != MAGIC_HJHX) { return; } owner->GetAbility()->AddSpeedAddition(speed_rate); owner->GetAbility()->AddDefAddition(def_rate); owner->GetAbility()->IncImmuneVertigo(); } ); owner->GetTrigger()->AddListener ( kEndSwitchWeaponBuffEvent, [this, speed_rate, def_rate] (const std::vector& params) { Buff* buff = std::any_cast(params.at(0)); if (!buff->skill_meta || buff->skill_meta->GetMagicId() != MAGIC_HJHX) { return; } owner->GetAbility()->DelSpeedAddition(speed_rate); owner->GetAbility()->DelDefAddition(def_rate); owner->GetAbility()->DecImmuneVertigo(); } ); } void Skill::ProcGZJS() { float dmg_ruduce_rate = 0; owner->GetTrigger()->AddListener ( kFlyHookCreateEvent, [this, dmg_ruduce_rate] (const std::vector& params) { Buff* buff = std::any_cast(params.at(0)); if (!buff->skill_meta || buff->skill_meta->GetMagicId() != MAGIC_HJHX) { return; } #if 0 owner->GetAbility()->AddSpeedAddition(speed_rate); owner->GetAbility()->AddDefAddition(def_rate); owner->GetAbility()->IncImmuneVertigo(); #endif } ); owner->GetTrigger()->AddListener ( kFlyHookDestoryEvent, [this, dmg_ruduce_rate] (const std::vector& params) { Buff* buff = std::any_cast(params.at(0)); if (!buff->skill_meta || buff->skill_meta->GetMagicId() != MAGIC_HJHX) { return; } #if 0 owner->GetAbility()->DelSpeedAddition(speed_rate); owner->GetAbility()->DelDefAddition(def_rate); owner->GetAbility()->DecImmuneVertigo(); #endif } ); } void Skill::ProcJYFH() { owner->GetTrigger()->AddListener ( kStartRescueEvent, [this] (const std::vector& params) { Human* target = std::any_cast(params.at(0)); int buff_id = SkillHelper::GetJyfhBuffId(meta); float buff_time = SkillHelper::GetJyfhBuffTime(meta); owner->TryAddBuffAndSetTime(owner, buff_id, buff_time, meta); target->TryAddBuffAndSetTime(owner, buff_id, buff_time, meta); owner->GetTrigger()->AddListener ( kEndRescueEvent, [this, buff_id] (const std::vector& params) { Human* target = std::any_cast(params.at(0)); owner->RemoveBuffById(buff_id); target->RemoveBuffById(buff_id); } ); } ); } void Skill::ProcFH() { owner->GetTrigger()->AddListener ( kDieEvent, [] (const std::vector& params) { } ); } void Skill::ProcYSHF() { owner->GetTrigger()->AddListener ( kYsRemoveEvent, [this] (const std::vector& params) { Buff* buff = std::any_cast(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_); } } } ); }