aozhiwei 46cdd93d4a 1
2024-05-24 13:20:37 +08:00

1990 lines
66 KiB
C++

#include "precompile.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/vec2.hpp>
#include <a8/collision.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 "netdata.h"
#include "hero.h"
#include "obstacle.h"
#include "car.h"
#include "app.h"
#include "bullet.h"
#include "virtualbullet.h"
#include "shot.h"
#include "entityfactory.h"
#include "gridcell.h"
#include "mt/Buff.h"
#include "mt/Equip.h"
#include "mt/Skill.h"
#include "mt/SkillNumber.h"
void CallFuncBuff::Activate()
{
int buff_id = meta->buff_id();
hold_weapon_ = owner->GetCurrWeapon();
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->GetNetData()->CalcSkillReceiveDmg(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,
0,
0
);
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::kAddMaxHp:
{
hold_param2_ = meta->GetBuffParam2(this);
ProcAddMaxHp();
}
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;
case BuffCallFunc_e::kDecSkillCd:
{
DecSkillCd();
}
break;
case BuffCallFunc_e::kRefreshHp:
{
owner->SetMaxHP(owner->GetNetData()->GetMaxHP());
owner->SetHP(owner->GetNetData()->GetMaxHP());
owner->room->frame_event.AddHpChg(owner->GetWeakPtrRef());
}
break;
case BuffCallFunc_e::kSummonCarSpecPoint:
{
SummonCarSpecPoint();
}
break;
case BuffCallFunc_e::kRangeHoldBuff:
{
RangeHoldBuff();
}
break;
case BuffCallFunc_e::kPlayFlyEffect:
{
PlayFlyEffect();
}
break;
case BuffCallFunc_e::kSpecCenterRangeHoldBuff:
{
SpecCenterRangeHoldBuff();
}
break;
case BuffCallFunc_e::kLispEval:
{
LispEval();
}
break;
case BuffCallFunc_e::kThrowKnife:
{
ThrowKnife();
}
break;
case BuffCallFunc_e::kDirectAbsDecHP:
{
hold_param2_ = meta->GetBuffParam2(this);
if (GetCaster().Get()) {
float dmg = hold_param2_;
float dmg_out = 0.0f;
owner->DecHP(dmg,
GetCaster().Get()->GetUniId(),
GetCaster().Get()->GetName(),
VP_Buff,
GetCaster().Get()->GetUniId(),
GetCaster().Get()->GetName(),
dmg_out,
0,
0
);
owner->GetTrigger()->Attacked(GetCaster().Get());
}
}
break;
case BuffCallFunc_e::kAccumulatePower:
{
AccumulatePower();
}
break;
case BuffCallFunc_e::kCallShot:
{
Shot();
}
break;
case BuffCallFunc_e::kBatchRandomPosSummonObstacle:
{
BatchRandomPosSummonObstacle();
}
break;
case BuffCallFunc_e::kOnBreakSkill:
{
OnBreakSkill();
}
break;
case BuffCallFunc_e::kBreakSkill:
{
BreakSkill();
}
break;
case BuffCallFunc_e::kBuffEffectCondAdd:
{
BuffEffectCondAdd();
}
break;
case BuffCallFunc_e::kRandAdd:
{
RandAdd();
}
break;
case BuffCallFunc_e::kShowExplosion:
{
ShowExplosion();
}
break;
case BuffCallFunc_e::kAddArmorShield:
{
hold_param2_ = meta->GetBuffParam2(this);
AddArmorShield();
}
break;
case BuffCallFunc_e::kBulletDmgCalcProc:
{
hold_param2_ = meta->GetBuffParam2(this);
BulletDmgCalcProc();
}
break;
default:
{
}
break;
}
}
void CallFuncBuff::Deactivate()
{
int buff_id = meta->buff_id();
if (deactivate_cb_) {
deactivate_cb_();
}
switch ((BuffCallFunc_e)meta->_int_buff_param1) {
case BuffCallFunc_e::kAddMinorMode:
{
if (skill_meta) {
Skill* skill = owner->GetSkill(skill_meta->_base_skill_meta->skill_id());
skill->CancelMinorMode();
}
}
break;
case BuffCallFunc_e::kSetBulletBornOffset:
{
hold_weapon_->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:
{
hold_weapon_->buff_id = 0;
}
break;
case BuffCallFunc_e::kAddEnergyShield:
{
float dur_time = meta->GetBuffParam3(this);
if (dur_time > 0.00001f) {
owner->ClearEnergyShield();
}
}
break;
case BuffCallFunc_e::kAddArmorShield:
{
float dur_time = meta->GetBuffParam3(this);
if (dur_time > 0.00001f) {
owner->ClearArmorShield();
}
}
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->_base_skill_meta->skill_id());
if (skill) {
auto owner_ptr = owner->GetWeakPtrRef();
auto meta_ptr = meta;
auto skill_meta_ptr = skill_meta;
#ifdef MYDEBUG
if (owner_ptr.Get()->IsPlayer()) {
a8::XPrintf("ProcAddMinorMode buff_uniid:%d buff_id:%d dur_time:%d\n",
{
buff_uniid,
meta->buff_id(),
dur_time});
}
#endif
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 == kSmaClick) {
for (int buff_id : meta_ptr->_buff_param6_int_list) {
owner_ptr.Get()->RemoveBuffById(buff_id);
}
for (int buff_id : meta_ptr->_buff_param4_int_list) {
#ifdef MYDEBUG
if (owner_ptr.Get()->IsPlayer() && meta_ptr->buff_id() == 207041) {
a8::XPrintf("addminor buff_id:%d\n", {buff_id});
}
#endif
if (buff_id > 0) {
owner_ptr.Get()->TryAddBuff(owner_ptr.Get(), buff_id, skill_meta_ptr);
} else {
owner_ptr.Get()->RemoveBuffById(std::abs(buff_id));
}
}
#if 0
} else if (action == kSmaTimeOut) {
#else
} else if (action == kSmaTimeOut || action == kSmaCancel) {
#endif
for (int buff_id : meta_ptr->_buff_param7_int_list) {
owner_ptr.Get()->RemoveBuffById(buff_id);
}
for (int buff_id : meta_ptr->_buff_param5_int_list) {
owner_ptr.Get()->TryAddBuff(owner_ptr.Get(), buff_id, skill_meta_ptr);
}
}
}
},
meta->buff_id());
#ifdef MYDEBUG1
if (owner_ptr.Get()->IsPlayer()) {
a8::XPrintf("ProcAddMinorMode buff_uniid:%d buff_id:%d dur_time:%d frame_no:%d 2222222222222222\n",
{
buff_uniid,
meta->buff_id(),
dur_time,
owner_ptr.Get()->room->GetFrameNo(),
});
}
#endif
}
}
}
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,
owner->room->map_instance->GetMoveIncludeFlags(),
owner->room->map_instance->GetMoveExcludeFlags());
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();
if (GlmHelper::IsEqual2D(hit_point,
owner->GetPos().ToGlmVec3())) {
return;
}
GlmHelper::Normalize(move_dir);
owner->SetMoveDir(move_dir);
owner->SetAttackDir(move_dir);
App::Instance()->verify_set_pos = 1;
owner->SetPos(new_pos);
App::Instance()->verify_set_pos = 0;
owner->room->grid_service->MoveCreature(owner);
if (owner->IsCar()) {
Car* car = owner->AsCar();
if (car->GetDriver()) {
App::Instance()->verify_set_pos = 1;
car->GetDriver()->SetPos(new_pos);
car->SyncPos();
car->GetDriver()->GetMovement()->ClearPath();
App::Instance()->verify_set_pos = 0;
}
}
return;
}
}
owner->context_real_pos = owner->GetPos().ToGlmVec3();
}
void CallFuncBuff::ProcAddEnergyShield()
{
int buff_id = meta->buff_id();
if (!owner->dead && !owner->downed) {
float dur_time = meta->GetBuffParam3(this);
if (dur_time < 0.00001f) {
dur_time = 99999999;
}
if (owner->energy_shield > 0) {
is_valid_ = false;
owner->GetTrigger()->UpdateEnergyShield(hold_param2_, dur_time);
} else {
owner->AddEnergyShield(hold_param2_);
event_handlers_.push_back(owner->GetTrigger()->AddListener
(
kUpdateEnergyShieldEvent,
[this] (const a8::Args& args) mutable
{
int value = args.Get<int>(0);
int new_time = args.Get<int>(1);
owner->AddEnergyShield(value);
}));
event_handlers_.push_back(owner->GetTrigger()->AddListener
(
kDestoryEnergyShieldEvent,
[this] (const a8::Args& args) mutable
{
owner->RemoveBuffByUniId(buff_uniid);
}));
owner->room->xtimer.SetTimeoutWpEx
(
dur_time / FRAME_RATE_MS,
[owner = owner, buff_uniid = buff_uniid] (int event, const a8::Args* args) mutable
{
if (a8::TIMER_DELETE_EVENT == event) {
owner->ClearEnergyShield();
owner->RemoveBuffByUniId(buff_uniid);
}
},
&owner->xtimer_attacher);
}
}
}
void CallFuncBuff::ProcAddHp()
{
int buff_id = meta->buff_id();
if (!owner->dead && !owner->downed) {
if (std::abs(owner->GetMaxHP() - owner->GetHP()) < 0.001f) {
is_valid_ = false;
} else {
owner->AddHp(hold_param2_);
}
}
}
void CallFuncBuff::ProcFlashMoveToPos()
{
float x = meta->GetBuffParam2(this);
float y = meta->GetBuffParam3(this);
float z = meta->GetBuffParam4(this);
owner->GetMovement()->ClearPath();
App::Instance()->verify_set_pos = 1;
owner->GetMutablePos().FromGlmVec3(glm::vec3(x, y, z));
App::Instance()->verify_set_pos = 0;
owner->room->grid_service->MoveCreature(owner);
#if 0
owner->room->frame_event.AddPropChg(owner->GetWeakPtrRef(),
kPropFlyTo,
0,
0,
false);
#endif
}
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);
{
event_handlers_.push_back(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->GetBaseSkillMeta()->GetMagicId() == MAGIC_20601_DJS) {
if (!context->active_skill_timer.expired()) {
return;
}
a8::Args event_args({skill->GetBaseSkillMeta()});
owner->room->xtimer.FireEvent(context->passive_skill_timer,
kActiveDjsSkillTimerEvent,
&event_args);
context->active_skill_timer = owner->room->xtimer.SetTimeoutWpEx
(
skill->GetCurrSkillMeta()->_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);
}
}
));
event_handlers_.push_back(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;
}
}
));
event_handlers_.push_back(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
);
}
if (meta->_int_buff_param8) {
owner->GetTrigger()->AddListener
(
kDieEvent,
[hero_ptr = hero->GetWeakPtrRef(), hero_id] (const a8::Args& args) mutable
{
if (hero_ptr.Get() && hero_ptr.Get()->AsHero()->master.Get()) {
if (!hero_ptr.Get()->room->IsGameOver()) {
hero_ptr.Get()->AsHero()->master.Get()->RemoveSurplusHero(hero_id, 0);
}
}
});
}
}
}
}
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->GetMoveIncludeFlags(),
owner->room->map_instance->GetMoveExcludeFlags()
)) {
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
);
}
if (meta->_int_buff_param8) {
owner->GetTrigger()->AddListener
(
kDieEvent,
[hero_ptr = hero->GetWeakPtrRef(), hero_id] (const a8::Args& args) mutable
{
if (hero_ptr.Get() && hero_ptr.Get()->AsHero()->master.Get()) {
if (!hero_ptr.Get()->room->IsGameOver()) {
hero_ptr.Get()->AsHero()->master.Get()->RemoveSurplusHero(hero_id, 0);
}
}
});
}
}
}
}
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()
{
int 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) {
Obstacle* ob = owner->SummonObstacle(this,
id,
glm::vec3(x, y, z),
owner->GetAttackDir());
if (ob) {
if (meta->has_buff_param7()) {
float rotate = meta->GetBuffParam7(this);
ob->SetRotate(rotate);
}
if (meta->has_buff_param8()) {
float scale = meta->GetBuffParam8(this);
ob->scale = scale;
}
std::shared_ptr<std::vector<float>> vars = std::make_shared<std::vector<float>>();
vars->push_back(ob->GetUniId());
for (int buff_id : meta->_buff_param6_int_list) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
vars
);
}
}
}
}
void CallFuncBuff::SummonObstacleSpecDistance()
{
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->GetMoveIncludeFlags(),
owner->room->map_instance->GetMoveExcludeFlags()
)) {
owner->room->map_instance->UnScale(hit_point);
born_pos = hit_point;
}
Obstacle* ob = owner->SummonObstacle(this,
hero_id,
born_pos,
owner->GetAttackDir());
if (ob) {
std::shared_ptr<std::vector<float>> vars = std::make_shared<std::vector<float>>();
vars->push_back(ob->GetUniId());
for (int buff_id : meta->_buff_param6_int_list) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
vars
);
}
}
}
}
void CallFuncBuff::ClearSummonObstacle()
{
int id = meta->_int_buff_param2;
float num = meta->GetBuffParam3(this);
int obj_uniid = meta->GetBuffParam4(this);
if (obj_uniid > 0) {
owner->RemoveSurplusObstacleByUniid(obj_uniid);
}
if (id > 0) {
owner->RemoveSurplusObstacle(id, num);
}
}
void CallFuncBuff::DecSkillCd()
{
int skill_id = meta->_int_buff_param2;
float rate = meta->GetBuffParam3(this);
Skill* skill = owner->GetSkill(skill_id);
if (skill) {
float cd = skill->GetCd();
float dec_time = skill->GetCd() * rate;
skill->Accelerate(-dec_time);
}
}
void CallFuncBuff::ProcAddMaxHp()
{
if (!owner->dead && !owner->downed) {
owner->SetMaxHP(owner->GetMaxHP() + hold_param2_);
}
}
void CallFuncBuff::SummonCarSpecPoint()
{
float delay_time = meta->GetBuffParam2(this);
int oper_type = meta->GetBuffParam3(this);
int oper = meta->GetBuffParam4(this);
int car_id = meta->GetBuffParam5(this);
float x = meta->GetBuffParam6(this);
float y = meta->GetBuffParam7(this);
float z = meta->GetBuffParam8(this);
std::shared_ptr<std::set<int>> special_operators;
switch (oper_type) {
case 1:
{
special_operators = std::make_shared<std::set<int>>();
special_operators->insert(oper);
}
break;
case 2:
{
Team* team = owner->room->GetTeam(oper);
if (team) {
special_operators = std::make_shared<std::set<int>>();
team->TraverseMembers
(
[special_operators] (Human* hum)
{
special_operators->insert(hum->GetUniId());
return true;
});
}
}
break;
default:
{
}
break;
}
owner->room->xtimer.SetTimeoutWpEx
(
delay_time / FRAME_RATE_MS,
[room = owner->room, car_id, x, y, z, special_operators]
(int event, const a8::Args* args) mutable
{
if (a8::TIMER_DELETE_EVENT == event) {
if (!room->IsGameOver()) {
const mt::Equip* equip_meta = mt::Equip::GetById(car_id);
if (equip_meta && equip_meta->equip_type() == EQUIP_TYPE_CAR) {
int car_uniid = room->AllocUniid();
Car* c = room->CreateCar(nullptr,
car_uniid,
equip_meta,
glm::vec3(x, y, z),
0,
special_operators.get());
}
}
}
},
&owner->room->xtimer_attacher_);
}
void CallFuncBuff::RangeHoldBuff()
{
InternalRangeHoldBuff
(
[this] (glm::vec3& center)
{
center = owner->GetPos().ToGlmVec3();
return true;
});
}
void CallFuncBuff::PlayFlyEffect()
{
if (GetCaster().Get()) {
owner->room->frame_event.AddPropChgEx
(GetCaster(),
kPropFlyEffect,
meta->_int_buff_param2,
owner->GetUniId(),
0,
0,
0);
}
owner->TryAddBuff(GetCaster().Get(), meta->_int_buff_param4, skill_meta);
}
void CallFuncBuff::LispEval()
{
for (int i = 1; i <= 8; ++i) {
switch (i) {
case 1:
{
if (!meta->buff_param1().empty()) {
meta->GetBuffParam1(this);
}
}
break;
case 2:
{
if (!meta->buff_param2().empty()) {
meta->GetBuffParam2(this);
}
}
break;
case 3:
{
if (!meta->buff_param3().empty()) {
meta->GetBuffParam3(this);
}
}
break;
case 4:
{
if (!meta->buff_param4().empty()) {
meta->GetBuffParam4(this);
}
}
break;
case 5:
{
if (!meta->buff_param5().empty()) {
meta->GetBuffParam5(this);
}
}
break;
case 6:
{
if (!meta->buff_param6().empty()) {
meta->GetBuffParam6(this);
}
}
break;
case 7:
{
if (!meta->buff_param7().empty()) {
meta->GetBuffParam7(this);
}
}
break;
case 8:
{
if (!meta->buff_param8().empty()) {
meta->GetBuffParam8(this);
}
}
break;
default:
{
break;
}
}
}
}
void CallFuncBuff::SpecCenterRangeHoldBuff()
{
glm::vec3 init_center = glm::vec3
(
meta->GetBuffParam6(this),
meta->GetBuffParam7(this),
meta->GetBuffParam8(this)
);
#ifdef MYDEBUG
if (owner->IsPlayer()) {
a8::XPrintf("init_center:%f %f %f\n",
{
init_center.x,
init_center.y,
init_center.z,
}
);
}
#endif
InternalRangeHoldBuff
(
[this, init_center] (glm::vec3& center)
{
center = init_center;
return true;
});
}
void CallFuncBuff::InternalRangeHoldBuff(std::function<bool(glm::vec3&)> get_center_func)
{
int buff_id = meta->buff_id();
if (owner->dead && !meta->dead_valid()) {
return;
}
struct InnerObject
{
CreatureWeakPtr c;
std::vector<int> buff_uniids;
void OnEnter()
{
}
void OnLeave()
{
}
};
auto context = A8_MAKE_ANON_STRUCT_SHARED
(
std::map<int, InnerObject> in_human_infos;
);
auto on_enter =
[this, context] (Creature* hum)
{
if (context->in_human_infos.find(hum->GetUniId()) != context->in_human_infos.end()) {
abort();
}
InnerObject o;
o.c = hum->GetWeakPtrRef();
if (meta->buff_id() == 203032) {
int i = 0;
#ifdef MYDEBUG
a8::XPrintf("aaaaaaaaaaaa a_team_id:%d b_team_id:%d\n",
{
owner->team_id,
hum->team_id
});
#endif
}
if (owner->team_id == hum->team_id) {
for (int buff_id : meta->_buff_param4_int_list) {
o.buff_uniids.push_back(hum->TryAddBuff(GetCaster().Get(), buff_id, skill_meta));
}
} else {
for (int buff_id : meta->_buff_param3_int_list) {
o.buff_uniids.push_back(hum->TryAddBuff(GetCaster().Get(), buff_id, skill_meta));
}
}
context->in_human_infos[hum->GetUniId()] = o;
context->in_human_infos[hum->GetUniId()].OnEnter();
};
auto on_stay =
[this, context] (Creature* hum)
{
};
auto on_leave =
[this, context] (Creature* 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, get_center_func]
()
{
float range = meta->GetBuffParam2(this);
std::set<Creature*> hit_humans;
glm::vec3 center;
if (get_center_func(center)) {
std::set<GridCell*> grid_list;
owner->room->grid_service->GetAllCellsByXy
(
owner->room,
center.x,
center.z,
grid_list);
owner->room->grid_service->TraverseCreatures
(owner->room->GetRoomIdx(),
grid_list,
[this, range, &hit_humans, &center] (Creature* c, bool& stop)
{
if (!c->dead && c->IsHuman() && a8::IntersectCylinderCylinder
(
center, owner->GetRadius(), 10,
c->GetPos().ToGlmVec3(), range, 10
)) {
hit_humans.insert(c);
}
});
}
std::vector<Human*> leave_humans;
for (auto& pair : context->in_human_infos) {
if (hit_humans.find(pair.second.c.Get()) == hit_humans.end()) {
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 (Creature* hum : hit_humans) {
if (context->in_human_infos.find(hum->GetUniId()) ==
context->in_human_infos.end()) {
on_enter(hum);
on_stay(hum);
} else {
on_stay(hum);
}
}
};
auto check_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) {
if (meta->buff_id() == 303013) {
int i = 0;
}
check_cb();
}
},
&owner->xtimer_attacher);
auto clear_func =
[this, context, check_timer] () mutable
{
if (!check_timer.expired()) {
owner->room->xtimer.Delete(check_timer);
}
for (auto& pair : context->in_human_infos) {
for (int buff_uniid : pair.second.buff_uniids) {
if (pair.second.c.Get()) {
pair.second.c.Get()->RemoveBuffByUniId(buff_uniid);
}
}
}
context->in_human_infos.clear();
};
{
if (!meta->dead_valid()) {
event_handlers_.push_back(owner->GetTrigger()->AddListener
(
kDieEvent,
[this, clear_func] (const a8::Args& args) mutable
{
clear_func();
}
));
}
deactivate_cb_ =
[this, clear_func] () mutable
{
clear_func();
};
}
}
void CallFuncBuff::ThrowKnife()
{
const mt::Equip* weapon_meta = mt::Equip::GetById(meta->_int_buff_param2);
if (!weapon_meta) {
return;
}
for (int i = 0; i < meta->_buff_param4_int_list.size(); ++i) {
glm::vec3 bullet_dir = GlmHelper::UP;
GlmHelper::RotateY(bullet_dir, glm::radians((float)meta->_buff_param4_int_list[i]));
Position bullet_born_pos = owner->GetPos();
bullet_born_pos.AddGlmVec3(bullet_dir * meta->_buff_param3);
int bullet_uniid = owner->room->AllocUniid();
int shot_uniid = 0;
owner->room->frame_event.AddBullet
(bullet_uniid,
owner->GetWeakPtrRef(),
weapon_meta,
1,
bullet_born_pos.ToGlmVec3(),
bullet_dir,
0,
0,
0,
nullptr,
shot_uniid);
auto p = std::make_shared<VirtualBullet>();
p->bullet_uniid = bullet_uniid;
//p->weapon_uniid = bullet->weapon_uniid;
//p->skill_meta = bullet->skill_meta;
p->gun_meta = weapon_meta;
p->bullet_meta = weapon_meta;
p->sender = owner->GetWeakPtrRef();
//p->passenger = bullet->passenger;
p->room = owner->room;
//p->is_pre_battle_bullet = bullet->IsPreBattleBullet();
p->dir = bullet_dir;
p->born_pos = bullet_born_pos;
p->born_dir = bullet_dir;
p->shot_uniid = shot_uniid;
p->Init();
owner->room->AddTask(bullet_uniid, std::make_shared<a8::CommonCbProcEx>
(
[p] (const a8::Args* args)
{
if (!p->IsDone()) {
p->Update(50);
}
}));
}
}
void CallFuncBuff::AccumulatePower()
{
owner->room->xtimer.SetTimeoutEx
(
std::max((long long)0, owner->room->xtimer.GetRemainTime(remover_timer) - 1),
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
const mt::Equip* equip_meta = mt::Equip::GetById(meta->GetBuffParam2(this));
if (equip_meta) {
if (!owner->dead && owner->downed) {
InternalShot(owner,
owner->GetCurrWeapon()->meta,
equip_meta,
skill_meta,
0,
owner->GetCurrWeapon()->weapon_uniid,
0);
}
}
}
},
&xtimer_attacher);
}
void CallFuncBuff::Shot()
{
int id = meta->GetBuffParam2(this);
float x = meta->GetBuffParam3(this);
float y = meta->GetBuffParam4(this);
float z = meta->GetBuffParam5(this);
int duration = meta->GetBuffParam8(this);
const mt::Equip* gun_meta = mt::Equip::GetById(id);
if (gun_meta) {
const mt::Equip* bullet_meta = mt::Equip::GetById(gun_meta->use_bullet());
if (!bullet_meta) {
return;
}
bool force_client_report = meta->_buff_param6_int_set.find(1) != meta->_buff_param6_int_set.end();
bool spec_target_pos = meta->_buff_param6_int_set.find(2) != meta->_buff_param6_int_set.end();
bool ignore_original_dmg = meta->_buff_param6_int_set.find(3) != meta->_buff_param6_int_set.end();
bool no_adjust_attack_dir = meta->_buff_param6_int_set.find(4) != meta->_buff_param6_int_set.end();
if (force_client_report) {
owner->GetAbility()->IncSwitch(kForceClientReportBullet);
}
if (ignore_original_dmg) {
owner->GetAbility()->IncSwitch(kIgnoreOriginalDmg);
}
CreatureWeakPtr owner_wp = owner->GetWeakPtrRef();
int buff_uniid_copy = buff_uniid;
auto meta_copy = meta;
auto on_bullet_exit =
[owner_wp, buff_uniid_copy, meta_copy] (Bullet* bullet) mutable
{
if (owner_wp.Get() && !owner_wp.Get()->IsDestorying()) {
std::shared_ptr<std::vector<float>> vars = std::make_shared<std::vector<float>>();
vars->push_back(bullet->GetPos().GetX());
vars->push_back(bullet->GetPos().GetY());
vars->push_back(bullet->GetPos().GetZ());
for (int buff_id : meta_copy->_buff_param7_int_list) {
owner_wp.Get()->TryAddBuff(
owner_wp.Get(),
buff_id,
bullet->skill_meta,
nullptr,
vars
);
}
}
};
glm::vec3 old_attack_dir = owner->GetAttackDir();
#ifdef MYDEBUG
a8::XPrintf("buff.call_shot target_pos:%f %f %f attack_dir:%f %f %f\n",
{
x,
y,
z,
owner->GetAttackDir().x,
owner->GetAttackDir().y,
owner->GetAttackDir().z,
});
#endif
if (spec_target_pos) {
glm::vec3 target_pos = glm::vec3(x, y, z);
glm::vec3 attack_dir = target_pos - owner->GetPos().ToGlmVec3();
float fly_distance = 0.0f;
if (GlmHelper::IsZero(attack_dir)) {
if (GlmHelper::IsZero(owner->GetAttackDir())) {
owner->SetAttackDir(GlmHelper::UP);
}
attack_dir = owner->GetAttackDir();
} else {
GlmHelper::Normalize(attack_dir);
fly_distance = GlmHelper::Norm2D(target_pos - owner->GetPos().ToGlmVec3());
owner->SetAttackDir(attack_dir);
}
fly_distance = std::max(200.0f, fly_distance);
fly_distance = std::min(400.0f, fly_distance);
InternalShot(owner,
gun_meta,
bullet_meta,
skill_meta,
fly_distance,
owner->GetCurrWeapon()->weapon_uniid,
0,
on_bullet_exit,
duration);
} else {
InternalShot(owner,
owner->GetCurrWeapon()->meta,
owner->GetCurrWeapon()->bullet_meta,
skill_meta,
0,
owner->GetCurrWeapon()->weapon_uniid,
0,
on_bullet_exit,
duration);
}
if (force_client_report) {
owner->GetAbility()->DecSwitch(kForceClientReportBullet);
}
if (ignore_original_dmg) {
owner->GetAbility()->DecSwitch(kIgnoreOriginalDmg);
}
if (!no_adjust_attack_dir) {
owner->SetAttackDir(old_attack_dir);
}
}
}
void CallFuncBuff::BatchRandomPosSummonObstacle()
{
int id = meta->GetBuffParam2(this);
int num = meta->GetBuffParam3(this);
float x = meta->GetBuffParam4(this);
float y = meta->GetBuffParam5(this);
float z = meta->GetBuffParam6(this);
float range = meta->GetBuffParam7(this);
if (!owner->dead || meta->dead_valid() != 0 && num > 0) {
num = std::min(30, num);
glm::vec3 center = glm::vec3(x, y, z);
for (int i = 0; i < num; ++i) {
glm::vec3 out_point = center;
bool ret = owner->room->map_instance->RandPoint(center, range, out_point);
if (ret) {
Obstacle* ob = owner->SummonObstacle(this,
id,
out_point,
owner->GetAttackDir());
if (ob) {
std::shared_ptr<std::vector<float>> vars = std::make_shared<std::vector<float>>();
vars->push_back(ob->GetUniId());
vars->push_back(ob->GetPos().GetX());
vars->push_back(ob->GetPos().GetY());
vars->push_back(ob->GetPos().GetZ());
for (int buff_id : meta->_buff_param8_int_list) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
vars
);
}
}
}
}
}
}
void CallFuncBuff::OnBreakSkill()
{
}
void CallFuncBuff::BreakSkill()
{
Buff* selected_buff = nullptr;
for (auto buff_id : meta->_buff_param2_int_list) {
selected_buff = owner->GetBuffById(buff_id);
if (selected_buff) {
break;
}
}
if (selected_buff) {
a8::Args args({this});
selected_buff->PreExec(&args);
int buff_uniid = selected_buff->buff_uniid;
for (auto buff_id : meta->_buff_param3_int_list) {
if (buff_id > 0) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
buff_vars
);
} else {
owner->RemoveBuffById(-buff_id);
}
}
if (selected_buff) {
selected_buff->PostExec(&args);
owner->RemoveBuffByUniId(buff_uniid);
}
} else {
for (auto buff_id : meta->_buff_param4_int_list) {
if (buff_id > 0) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
buff_vars
);
} else {
owner->RemoveBuffById(-buff_id);
}
}
}
}
void CallFuncBuff::BuffEffectCondAdd()
{
Buff* selected_buff = nullptr;
for (auto buff_effect : meta->_buff_param2_int_list) {
selected_buff = owner->GetBuffByEffectId(buff_effect);
if (selected_buff) {
break;
}
}
if (selected_buff) {
for (auto buff_id : meta->_buff_param3_int_list) {
if (buff_id > 0) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
buff_vars
);
} else {
owner->RemoveBuffById(-buff_id);
}
}
selected_buff = owner->GetBuffByUniId(buff_uniid);
} else {
for (auto buff_id : meta->_buff_param4_int_list) {
if (buff_id > 0) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
buff_vars
);
} else {
owner->RemoveBuffById(-buff_id);
}
}
}
}
void CallFuncBuff::PreExec(const a8::Args* args)
{
switch ((BuffCallFunc_e)meta->_int_buff_param1) {
case BuffCallFunc_e::kOnBreakSkill:
{
OnBreakSkillPreExec();
}
break;
default:
{
break;
}
}
}
void CallFuncBuff::PostExec(const a8::Args* args)
{
switch ((BuffCallFunc_e)meta->_int_buff_param1) {
case BuffCallFunc_e::kOnBreakSkill:
{
OnBreakSkillPostExec();
}
break;
default:
{
break;
}
}
}
void CallFuncBuff::OnBreakSkillPreExec()
{
for (auto buff_id : meta->_buff_param2_int_list) {
if (buff_id > 0) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
buff_vars
);
} else {
owner->RemoveBuffById(-buff_id);
}
}
}
void CallFuncBuff::OnBreakSkillPostExec()
{
for (auto buff_id : meta->_buff_param3_int_list) {
if (buff_id > 0) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
buff_vars
);
} else {
owner->RemoveBuffById(-buff_id);
}
}
}
void CallFuncBuff::RandAdd()
{
int buff_id = meta->buff_id();
hold_param2_ = meta->GetBuffParam2(this) * 100;
if (hold_param2_ >= a8::RandEx(0, 100)) {
for (auto buff_id : meta->_buff_param3_int_list) {
if (buff_id > 0) {
owner->TryAddBuff(
GetCaster().Get(),
buff_id,
skill_meta,
init_args,
buff_vars
);
} else {
owner->RemoveBuffById(-buff_id);
}
}
}
}
void CallFuncBuff::ShowExplosion()
{
if (owner->dead && !meta->dead_valid()) {
return;
}
int explosion_effect = meta->GetBuffParam2(this);
float x = meta->GetBuffParam3(this);
float y = meta->GetBuffParam4(this);
float z = meta->GetBuffParam5(this);
Position center;
center.FromGlmVec3(glm::vec3(x, y, z));
owner->room->frame_event.AddExplosionEx
(owner->GetWeakPtrRef(),
0,
center,
explosion_effect,
0);
}
void CallFuncBuff::AddArmorShield()
{
if (!owner->dead && !owner->downed) {
float dur_time = meta->GetBuffParam3(this);
if (dur_time < 0.00001f) {
dur_time = 99999999;
}
if (owner->armor_shield > 0) {
is_valid_ = false;
#if 0
owner->GetTrigger()->UpdateArmorShield(hold_param2_, dur_time);
#endif
} else {
owner->AddArmorShield(hold_param2_);
#if 0
event_handlers_.push_back(owner->GetTrigger()->AddListener
(
kUpdateArmorShieldEvent,
[this] (const a8::Args& args) mutable
{
int value = args.Get<int>(0);
int new_time = args.Get<int>(1);
owner->AddArmorShield(value);
}));
event_handlers_.push_back(owner->GetTrigger()->AddListener
(
kDestoryArmorShieldEvent,
[this] (const a8::Args& args) mutable
{
owner->RemoveBuffByUniId(buff_uniid);
}));
#endif
owner->room->xtimer.SetTimeoutWpEx
(
dur_time / FRAME_RATE_MS,
[owner = owner, buff_uniid = buff_uniid] (int event, const a8::Args* args) mutable
{
if (a8::TIMER_EXEC_EVENT == event) {
owner->ClearArmorShield();
owner->RemoveBuffByUniId(buff_uniid);
}
},
&owner->xtimer_attacher);
}
}
}
void CallFuncBuff::BulletDmgCalcProc()
{
int target_type = (int)hold_param2_;
if (target_type == 0 || target_type == 1) {
if (!owner->dead && !owner->downed) {
int attr_id = meta->GetBuffParam3(this);
float attr_val = meta->GetBuffParam4(this);
float cond = meta->GetBuffParam5(this);
AttrHandle attr_handle;
auto clear_func =
[this, target_type, &attr_handle] (Creature* c)
{
if (target_type == 0) {
owner->GetAbility()->RemoveAttr(attr_handle);
} else if (target_type == 1) {
c->GetAbility()->RemoveAttr(attr_handle);
}
};
auto start_handle = owner->GetTrigger()->AddListener
(
kBulletDmgStartEvent,
[this, &attr_handle, target_type, attr_id, attr_val, cond, clear_func]
(const a8::Args& args) mutable
{
Creature* target = args.Get<Creature*>(0);
clear_func(target);
if (IsValidHumanAttr(attr_id) ||
IsValidHumanVirtualAttr(attr_id)) {
if (target->GetMaxHP() > 0.0f) {
bool match = target->GetHP() / target->GetMaxHP() < cond;
if (match) {
if (target_type == 0) {
attr_handle = owner->GetAbility()->AddAttr(attr_id, attr_val);
} else if (target_type == 1) {
attr_handle = target->GetAbility()->AddAttr(attr_id, attr_val);
}
}
}
}
});
auto end_handle = owner->GetTrigger()->AddListener
(
kBulletDmgEndEvent,
[this, clear_func] (const a8::Args& args) mutable
{
Creature* target = args.Get<Creature*>(0);
clear_func(target);
});
deactivate_cb_ =
[this, start_handle, end_handle, clear_func] () mutable
{
owner->GetTrigger()->RemoveEventHandler(start_handle);
owner->GetTrigger()->RemoveEventHandler(end_handle);
};
}
}
}