aozhiwei ad54cdf366 1
2023-03-31 18:49:58 +08:00

754 lines
24 KiB
C++

#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 "hero.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;
case BuffCallFunc_e::kSetGunBuffId:
{
owner->GetCurrWeapon()->buff_id = meta->_int_buff_param2;
}
break;
case BuffCallFunc_e::kSummonObstacleSepcPoint:
{
SummonObstacleSpecPoint();
}
break;
case BuffCallFunc_e::kSummonObstacleSpecDistance:
{
SummonObstacleSpecDistance();
}
break;
case BuffCallFunc_e::kClearSummonObstacle:
{
ClearSummonObstacle();
}
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;
case BuffCallFunc_e::kSetGunBuffId:
{
owner->GetCurrWeapon()->buff_id = 0;
}
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<int> 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<int, InnerObject> 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<Human*, MAX_TEAM_NUM> 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<Human*> 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<const mt::Skill*>(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<Skill*>(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) {
Hero* hero = owner->SummonHero(this,
glm::vec3(x, y, z),
owner->GetAttackDir());
if (hero) {
std::shared_ptr<std::vector<float>> vars = std::make_shared<std::vector<float>>();
vars->push_back(hero->GetUniId());
for (int buff_id : meta->_buff_param6_int_list) {
hero->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
vars
);
}
}
}
}
void CallFuncBuff::SummonHeroSpecDistance()
{
int hero_id = meta->_int_buff_param2;
float distance = meta->GetBuffParam3(this);
if (!owner->dead || meta->dead_valid() != 0) {
bool hit_result;
glm::vec3 hit_point;
glm::vec3 start = owner->GetPos().ToGlmVec3();
glm::vec3 end = owner->GetPos().ToGlmVec3() + owner->GetAttackDir() * distance;
glm::vec3 born_pos = owner->GetPos().ToGlmVec3() + owner->GetAttackDir() * distance;
owner->room->map_instance->Scale(start);
owner->room->map_instance->Scale(end);
if (owner->room->map_instance->Raycast
(
start,
end,
hit_point,
hit_result
)) {
owner->room->map_instance->UnScale(hit_point);
born_pos = hit_point;
}
Hero* hero = owner->SummonHero(this,
born_pos,
owner->GetAttackDir());
if (hero) {
std::shared_ptr<std::vector<float>> vars = std::make_shared<std::vector<float>>();
vars->push_back(hero->GetUniId());
for (int buff_id : meta->_buff_param6_int_list) {
hero->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
vars
);
}
}
}
}
void CallFuncBuff::ClearSummonHero()
{
int hero_id = meta->_int_buff_param2;
float hero_num = meta->GetBuffParam3(this);
owner->RemoveSurplusHero(hero_id, hero_num);
}
void CallFuncBuff::SummonObstacleSpecPoint()
{
#if 0
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) {
Hero* hero = owner->SummonHero(this,
glm::vec3(x, y, z),
owner->GetAttackDir());
}
#endif
}
void CallFuncBuff::SummonObstacleSpecDistance()
{
#if 0
int hero_id = meta->_int_buff_param2;
float distance = meta->GetBuffParam3(this);
if (!owner->dead || meta->dead_valid() != 0) {
glm::vec3 born_pos = owner->GetPos().ToGlmVec3();
Hero* hero = owner->SummonHero(this,
born_pos,
owner->GetAttackDir());
if (hero) {
std::shared_ptr<std::vector<float>> vars = std::make_shared<std::vector<float>>();
vars->push_back(hero->GetUniId());
for (int buff_id : meta->_buff_param6_int_list) {
hero->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
vars
);
}
}
}
#endif
}
void CallFuncBuff::ClearSummonObstacle()
{
#if 0
int hero_id = meta->_int_buff_param2;
float hero_num = meta->GetBuffParam3(this);
owner->RemoveSurplusHero(hero_id, hero_num);
#endif
}