#include "precompile.h" #include "buff/callfunc.h" #include "creature.h" #include "ability.h" #include "room.h" #include "skill.h" #include "movement.h" #include "mapinstance.h" #include "trigger.h" #include "human.h" #include "team.h" #include "collision.h" #include "battledatacontext.h" #include "mt/Buff.h" #include "mt/Skill.h" #include "mt/SkillNumber.h" void CallFuncBuff::Activate() { switch ((BuffCallFunc_e)meta->_int_buff_param1) { case BuffCallFunc_e::kAddMinorMode: { ProcAddMinorMode(); } break; case BuffCallFunc_e::kInternalRangeAddBuff: { ProcIntervalRangeAddBuffFunc(); } break; case BuffCallFunc_e::kDecHp: { hold_param2_ = meta->GetBuffParam2(this); if (GetCaster().Get()) { float dmg = hold_param2_; dmg = owner->GetBattleContext()->CalcReceiveDmg(GetCaster().Get(), dmg); float dmg_out = 0.0f; owner->DecHP(dmg, GetCaster().Get()->GetUniId(), GetCaster().Get()->GetName(), VP_Buff, GetCaster().Get()->GetUniId(), GetCaster().Get()->GetName(), dmg_out ); owner->GetTrigger()->Attacked(GetCaster().Get()); } } break; case BuffCallFunc_e::kMarkTag: { ProcMarkTag(); } break; case BuffCallFunc_e::kRemoveBuff: { ProcRemoveBuff(); } break; case BuffCallFunc_e::kFlashMove: { hold_param2_ = meta->GetBuffParam2(this); ProcFlashMove(); } break; case BuffCallFunc_e::kAddEnergyShield: { hold_param2_ = meta->GetBuffParam2(this); ProcAddEnergyShield(); } break; case BuffCallFunc_e::kAddHp: { hold_param2_ = meta->GetBuffParam2(this); ProcAddHp(); } break; case BuffCallFunc_e::kFlashMoveToPos: { hold_param2_ = meta->GetBuffParam2(this); ProcFlashMoveToPos(); } break; case BuffCallFunc_e::kLightCircle: { ProcLightCircle(); } break; case BuffCallFunc_e::kSyncProp: { hold_param2_ = meta->GetBuffParam2(this); ProcSyncProp(); } break; case BuffCallFunc_e::kSetBulletBornOffset: { owner->GetCurrWeapon()->bullet_born_offset_ptr = &meta->_bullet_born_offset; } break; case BuffCallFunc_e::kSummonHeroSepcPoint: { SummonHeroSpecPoint(); } break; case BuffCallFunc_e::kSummonHeroSpecDistance: { SummonHeroSpecDistance(); } break; case BuffCallFunc_e::kClearSummonHero: { ClearSummonHero(); } break; case BuffCallFunc_e::kImmuneAllMove: { owner->GetAbility()->IncSwitch(kDisableMoveEffectTimes); } break; case BuffCallFunc_e::kDmgForward: { owner->GetAbility()->IncSwitch(kEnableDmgForwardTimes); } break; default: { } break; } } void CallFuncBuff::Deactivate() { switch ((BuffCallFunc_e)meta->_int_buff_param1) { case BuffCallFunc_e::kAddMinorMode: { if (skill_meta) { Skill* skill = owner->GetSkill(skill_meta->skill_id()); skill->CancelMinorMode(); } } break; case BuffCallFunc_e::kSetBulletBornOffset: { owner->GetCurrWeapon()->bullet_born_offset_ptr = nullptr; } break; case BuffCallFunc_e::kImmuneAllMove: { owner->GetAbility()->DecSwitch(kDisableMoveEffectTimes); } break; case BuffCallFunc_e::kDmgForward: { owner->GetAbility()->DecSwitch(kEnableDmgForwardTimes); } break; default: { } break; } } void CallFuncBuff::ProcIntervalRangeAddBuffFunc() { owner->room->xtimer.SetIntervalEx ( meta->_buff_param4 / FRAME_RATE_MS, [this] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { owner->TraverseCreatures ( [this] (Creature* c, bool& stop) { if (c->dead) { return; } if (owner->GetUniId() == c->GetUniId()) { return; } if (!GetCaster().Get()) { return; } if (GetCaster().Get()->team_id != c->team_id) { if (owner->GetPos().Distance2D2(c->GetPos()) < meta->_buff_param2) { c->TryAddBuff(GetCaster().Get(), meta->_int_buff_param3, skill_meta); } } }); } }, &xtimer_attacher ); } void CallFuncBuff::ProcAddMinorMode() { if (skill_meta) { float dur_time = meta->GetBuffParam3(this); Skill* skill = owner->GetSkill(skill_meta->skill_id()); if (skill) { auto owner_ptr = owner->GetWeakPtrRef(); auto meta_ptr = meta; auto skill_meta_ptr = skill_meta; skill->AddMinorMode ( meta->_int_buff_param2, dur_time * 1000, [owner_ptr, meta_ptr, skill_meta_ptr] (int action) mutable { if (owner_ptr.Get()) { if (action == 1) { owner_ptr.Get()->TryAddBuff(owner_ptr.Get(), meta_ptr->_int_buff_param4, skill_meta_ptr); } else if (action == 0) { owner_ptr.Get()->TryAddBuff(owner_ptr.Get(), meta_ptr->_int_buff_param5, skill_meta_ptr); } } }); } } } void CallFuncBuff::ProcMarkTag() { switch (meta->_int_buff_param2) { case 1: { owner->SetBuffTag(meta->_int_buff_param3, meta->_int_buff_param4); } break; case 2: { owner->IncBuffTag(meta->_int_buff_param3, meta->_int_buff_param4); } break; } } void CallFuncBuff::ProcRemoveBuff() { for (int buff_effect : meta->_buff_param2_int_list) { owner->RemoveBuffByEffectId(buff_effect); } for (int buff_id : meta->_buff_param3_int_list) { owner->RemoveBuffById(buff_id); } } void CallFuncBuff::ProcFlashMove() { float distance = owner->context_pos.Distance2D2(owner->GetPos()); if (distance > 0.00001f) { glm::vec3 move_dir = owner->GetPos().CalcDir(owner->context_pos); GlmHelper::Normalize(move_dir); float move_distance = std::min(distance, hold_param2_); glm::vec3 hit_point = glm::vec3(0.0f, 0.0f, 0.0f); bool hit_result = false; glm::vec3 start = owner->GetPos().ToGlmVec3(); glm::vec3 end = owner->GetPos().ToGlmVec3() + move_dir * move_distance; owner->room->map_instance->Scale(start); owner->room->map_instance->Scale(end); bool ret = owner->room->map_instance->Raycast ( start, end, hit_point, hit_result); if (ret) { owner->room->map_instance->UnScale(hit_point); owner->GetMovement()->ClearPath(); owner->context_real_pos = hit_point; Position new_pos; new_pos.FromGlmVec3(hit_point); glm::vec3 move_dir = hit_point - owner->GetPos().ToGlmVec3(); GlmHelper::Normalize(move_dir); owner->SetMoveDir(move_dir); owner->SetAttackDir(move_dir); Global::Instance()->verify_set_pos = 1; owner->SetPos(new_pos); Global::Instance()->verify_set_pos = 0; owner->room->grid_service->MoveCreature(owner); return; } } owner->context_real_pos = owner->GetPos().ToGlmVec3(); } void CallFuncBuff::ProcAddEnergyShield() { owner->AddEnergyShield(hold_param2_); } void CallFuncBuff::ProcAddHp() { if (!owner->dead) { if (std::abs(owner->GetMaxHP() - owner->GetHP()) < 0.001f) { is_valid_ = false; } else { owner->AddHp(hold_param2_); } } } void CallFuncBuff::ProcFlashMoveToPos() { float x = hold_param2_; float y = meta->GetBuffParam3(this); float z = meta->GetBuffParam4(this); owner->GetMovement()->ClearPath(); Global::Instance()->verify_set_pos = 1; owner->GetMutablePos().FromGlmVec3(glm::vec3(x, y, z)); Global::Instance()->verify_set_pos = 0; owner->room->grid_service->MoveCreature(owner); } void CallFuncBuff::ProcLightCircle() { if (!skill_meta) { return; } if (skill_meta->GetMagicId() != MAGIC_30601_DJS) { return; } struct InnerObject { CreatureWeakPtr c; std::set buff_uniids; void OnEnter() { } void OnLeave() { } }; auto context = A8_MAKE_ANON_STRUCT_SHARED ( a8::XTimerWp passive_skill_timer; a8::XTimerWp active_skill_timer; std::map in_human_infos; const mt::Skill* active_skill_meta = nullptr; int keep_buff_uniid = 0; ); auto on_enter = [this, context] (Human* hum) { if (context->in_human_infos.find(hum->GetUniId()) != context->in_human_infos.end()) { abort(); } const mt::Skill* curr_skill_meta = context->active_skill_meta ? context->active_skill_meta : skill_meta; InnerObject o; o.c = hum->GetWeakPtrRef(); const mt::Skill* old_skill_meta = skill_meta; skill_meta = curr_skill_meta; if (context->active_skill_meta) { for (int buff_id : meta->_buff_param3_int_list) { o.buff_uniids.insert(hum->TryAddBuff(GetCaster().Get(), buff_id, skill_meta)); } } else { for (int buff_id : meta->_buff_param2_int_list) { o.buff_uniids.insert(hum->TryAddBuff(GetCaster().Get(), buff_id, skill_meta)); } } skill_meta = old_skill_meta; context->in_human_infos[hum->GetUniId()] = o; context->in_human_infos[hum->GetUniId()].OnEnter(); }; auto on_stay = [this, context] (Human* hum) { }; auto on_leave = [this, context] (Human* hum) { auto itr = context->in_human_infos.find(hum->GetUniId()); if (itr == context->in_human_infos.end()) { abort(); } for (int buff_uniid : itr->second.buff_uniids) { hum->RemoveBuffByUniId(buff_uniid); } itr->second.OnLeave(); }; auto check_cb = [this, context, on_enter, on_stay, on_leave] () { if (owner->HasBuffEffect(kBET_Fly) || owner->HasBuffEffect(kBET_Jump)) { return; } const mt::Skill* curr_skill_meta = context->active_skill_meta ? context->active_skill_meta : skill_meta; if (!owner->dead) { float range = curr_skill_meta->_number_meta->_float_range2; int size = 0; std::array hit_humans; owner->GetTeam()->TraverseMembers ( [this, range, &hit_humans, &size] (Human* hum) mutable { if (!hum->dead && Collision::CheckCC(owner, owner->GetRadius(), hum, range)) { if (size < MAX_TEAM_NUM) { hit_humans[size++] = hum; } } return true; }); std::vector leave_humans; for (auto& pair : context->in_human_infos) { bool found = false; for (int i = 0; i < size; ++i){ if (hit_humans[i] == pair.second.c.Get()) { found = true; break; } } if (!found) { on_leave(pair.second.c.Get()->AsHuman()); leave_humans.push_back(pair.second.c.Get()->AsHuman()); } } for (Human* hum : leave_humans) { context->in_human_infos.erase(hum->GetUniId()); } for (int i = 0; i < size; ++i){ if (context->in_human_infos.find(hit_humans[i]->GetUniId()) == context->in_human_infos.end()) { on_enter(hit_humans[i]); on_stay(hit_humans[i]); } else { on_stay(hit_humans[i]); } } } else { if (!context->in_human_infos.empty()) { for (auto& pair : context->in_human_infos) { on_leave(pair.second.c.Get()->AsHuman()); } context->in_human_infos.clear(); } } }; context->passive_skill_timer = owner->room->xtimer.SetIntervalWpEx ( SERVER_FRAME_RATE, [this, context, on_enter, on_stay, on_leave, check_cb] (int event, const a8::Args* args) mutable { if (a8::TIMER_EXEC_EVENT == event) { check_cb(); } else if (kActiveDjsSkillTimerEvent == event) { for (auto& pair : context->in_human_infos) { on_leave(pair.second.c.Get()->AsHuman()); } context->in_human_infos.clear(); context->active_skill_meta = args->Get(0); Buff* buff = owner->GetBuffByUniId(context->keep_buff_uniid); if (buff) { buff->res_scale = 2.0f; buff->res_scale_frameno = owner->room->GetFrameNo(); owner->room->frame_event.AddBuff(owner->GetWeakPtrRef(), buff); } check_cb(); } else if (kDeactiveDjsSkillTimerEvent == event) { for (auto& pair : context->in_human_infos) { on_leave(pair.second.c.Get()->AsHuman()); } context->in_human_infos.clear(); context->active_skill_meta = nullptr; Buff* buff = owner->GetBuffByUniId(context->keep_buff_uniid); if (buff) { buff->res_scale = 1.0f; buff->res_scale_frameno = owner->room->GetFrameNo(); owner->room->frame_event.AddBuff(owner->GetWeakPtrRef(), buff); } check_cb(); } }, &xtimer_attacher); { owner->GetTrigger()->AddListener ( kUseSkillEvent, [this, context] (const a8::Args& args) mutable { if (context->passive_skill_timer.expired()) { return; } Skill* skill = args.Get(0); if (skill->meta->GetMagicId() == MAGIC_20601_DJS) { if (!context->active_skill_timer.expired()) { return; } a8::Args event_args({skill->meta}); owner->room->xtimer.FireEvent(context->passive_skill_timer, kActiveDjsSkillTimerEvent, &event_args); context->active_skill_timer = owner->room->xtimer.SetTimeoutWpEx ( skill->meta->_number_meta->_float_time * SERVER_FRAME_RATE, [this, context] (int event, const a8::Args* args) mutable { if (a8::TIMER_DELETE_EVENT == event) { a8::Args event_args({}); owner->room->xtimer.FireEvent(context->passive_skill_timer, kDeactiveDjsSkillTimerEvent, &event_args); } }, &xtimer_attacher); } } ); owner->GetTrigger()->AddListener ( kDieEvent, [this, context] (const a8::Args& args) mutable { if (context->keep_buff_uniid) { owner->RemoveBuffByUniId(context->keep_buff_uniid); context->keep_buff_uniid = 0; } } ); owner->GetTrigger()->AddListener ( kStartJump, [this, context, on_leave] (const a8::Args& args) mutable { if (context->keep_buff_uniid) { for (auto& pair : context->in_human_infos) { on_leave(pair.second.c.Get()->AsHuman()); } context->in_human_infos.clear(); owner->RemoveBuffByUniId(context->keep_buff_uniid); context->keep_buff_uniid = 0; } } ); owner->GetTrigger()->AddListener ( kEndJump, [this, context] (const a8::Args& args) mutable { if (context->keep_buff_uniid) { owner->RemoveBuffByUniId(context->keep_buff_uniid); context->keep_buff_uniid = 0; } context->keep_buff_uniid = owner->TryAddBuff(GetCaster().Get(), meta->_int_buff_param4, skill_meta); } ); } { context->keep_buff_uniid = owner->TryAddBuff(GetCaster().Get(), meta->_int_buff_param4, skill_meta); } } void CallFuncBuff::ProcSyncProp() { float type = meta->GetBuffParam2(this); float sub_type = meta->GetBuffParam3(this); float value = meta->GetBuffParam4(this); int only_self = meta->GetBuffParam6(this); owner->room->frame_event.AddPropChg ( owner->GetWeakPtrRef(), type, sub_type, value, only_self > 0); } void CallFuncBuff::SummonHeroSpecPoint() { int hero_id = meta->_int_buff_param2; float x = meta->GetBuffParam3(this); float y = meta->GetBuffParam4(this); float z = meta->GetBuffParam5(this); if (!owner->dead || meta->dead_valid() != 0) { } } void CallFuncBuff::SummonHeroSpecDistance() { int hero_id = meta->_int_buff_param2; float distance = meta->GetBuffParam3(this); if (!owner->dead || meta->dead_valid() != 0) { } } void CallFuncBuff::ClearSummonHero() { int hero_id = meta->_int_buff_param2; float hero_num = meta->GetBuffParam3(this); }