aozhiwei ed9a61017a 1
2023-04-04 21:31:05 +08:00

375 lines
12 KiB
C++

#include "precompile.h"
#include <a8/holder.h>
#include "buff/cond_add.h"
#include "creature.h"
#include "room.h"
#include "mt/Buff.h"
/*
装备武器
子弹命中
击杀
子弹结束
*/
void CondAddBuff::Activate()
{
switch ((CondAddBuff_e)meta->_int_buff_param1) {
case CondAddBuff_e::kBulletHit:
{
ProcBulletHit();
}
break;
case CondAddBuff_e::kBulletKill:
{
ProcBulletKill();
}
break;
case CondAddBuff_e::kBulletEnd:
{
ProcBulletEnd();
}
break;
case CondAddBuff_e::kDisengageBattle:
{
ProcDisengageBattle();
}
break;
case CondAddBuff_e::kLimitTimeKillTarget:
{
ProcLimitTimeKillTarget();
}
break;
case CondAddBuff_e::kReload:
{
ProcReload();
}
break;
case CondAddBuff_e::kShot:
{
ProcShot();
}
break;
default:
{
}
break;
}
}
void CondAddBuff::Deactivate()
{
}
void CondAddBuff::ProcBulletHit()
{
const bool is_same_target = meta->_int_buff_param5 ? true : false;
const float interval_time = meta->_buff_param6 < 0.01 ? 9999999 : meta->_buff_param6;
const int hit_times = meta->_int_buff_param2;
auto context = A8_MAKE_ANON_STRUCT_SHARED
(
int last_hit_target_id = 0;
int hited_times = 0;
long long last_hit_frameno = 0;
);
event_handlers_.push_back
(
owner->GetTrigger()->AddListener
(
kBulletHitEvent,
[this, context, is_same_target, interval_time, hit_times]
(const a8::Args& args)
{
IBullet* bullet = args.Get<IBullet*>(0);
Creature* c = args.Get<Creature*>(1);
if (context->last_hit_frameno > 0 &&
c->room->GetFrameNo() - context->last_hit_frameno > interval_time * SERVER_FRAME_RATE) {
context->hited_times = 0;
}
if (is_same_target) {
if (context->last_hit_target_id != c->GetUniId()) {
context->hited_times = 0;
}
}
context->last_hit_target_id = c->GetUniId();
++context->hited_times;
context->last_hit_frameno = c->room->GetFrameNo();
if (context->hited_times >= hit_times) {
{
if (!c->dead) {
c->TryAddBuff(owner, meta->_int_buff_param3, skill_meta);
}
if (!owner->dead) {
owner->TryAddBuff(owner, meta->_int_buff_param4, skill_meta);
}
}
context->last_hit_target_id = 0;
context->hited_times = 0;
context->last_hit_frameno = 0;
}
})
);
}
void CondAddBuff::ProcBulletKill()
{
auto context = A8_MAKE_ANON_STRUCT_SHARED
(
);
event_handlers_.push_back
(
owner->GetTrigger()->AddListener
(
kBulletKill,
[this, context]
(const a8::Args& args)
{
IBullet* bullet = args.Get<IBullet*>(0);
Creature* c = args.Get<Creature*>(1);
if (!owner->dead) {
owner->TryAddBuff(owner, meta->_int_buff_param4, skill_meta);
}
})
);
}
void CondAddBuff::ProcBulletEnd()
{
}
void CondAddBuff::ProcDisengageBattle()
{
const float disengate_time = meta->GetBuffParam2(this);
auto context = A8_MAKE_ANON_STRUCT_SHARED
(
std::vector<std::tuple<int, int>> hold_buff_list;
long long last_check_frameno = 0;
bool handled = false;
);
a8::XTimerWp timer = owner->room->xtimer.SetIntervalWpEx
(
disengate_time * SERVER_FRAME_RATE,
[this, context] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (!owner->dead && !context->handled) {
for (int buff_id : meta->_buff_param4_int_list) {
int buff_uniid = owner->TryAddBuff
(
GetCaster().Get(),
buff_id,
skill_meta
);
if (!meta->_buff_param5_int_set.empty()) {
context->hold_buff_list.push_back
(
std::make_tuple(buff_uniid, buff_id)
);
}
}
if (owner->room->GetFrameNo() - context->last_check_frameno > SERVER_FRAME_RATE * 10 &&
!meta->_buff_param5_int_set.empty() &&
context->hold_buff_list.size() > 0) {
for (int i = context->hold_buff_list.size() - 1; i >= 0; --i) {
if (!owner->GetBuffByUniId(std::get<0>(context->hold_buff_list[i]))) {
context->hold_buff_list.erase(context->hold_buff_list.begin() + i);
}
}
}
context->handled = true;
}
}
},
&xtimer_attacher);
auto cb =
[this, timer, context] (const a8::Args& args) mutable
{
if (timer.expired()) {
return;
}
if (!meta->_buff_param5_int_set.empty() &&
!context->hold_buff_list.empty()) {
for (auto& tuple : context->hold_buff_list) {
if (meta->_buff_param5_int_set.find(std::get<1>(tuple)) !=
meta->_buff_param5_int_set.end()) {
owner->RemoveBuffByUniId(std::get<0>(tuple));
}
}
context->hold_buff_list.clear();
}
context->handled = false;
owner->room->xtimer.ResetTimer(timer);
};
event_handlers_.push_back
(owner->GetTrigger()->AddListener
(
kReceiveDmgEvent,
cb
)
);
}
void CondAddBuff::ProcLimitTimeKillTarget()
{
const float time_limit = meta->GetBuffParam2(this);
auto context = A8_MAKE_ANON_STRUCT_SHARED
(
std::map<int, std::tuple<a8::XTimerWp, std::weak_ptr<EventHandlerPtr>>> watch_targets;
);
auto holder = std::make_shared<a8::Holder>
(
[owner = owner->GetWeakPtrRef(), context] (const a8::Args& args) mutable
{
if (owner.Get() && !owner.Get()->room->IsDestorying()) {
for (auto& pair : context->watch_targets) {
owner.Get()->GetTrigger()->RemoveEventHandler(std::get<1>(pair.second));
}
}
});
auto cb =
[this, context, time_limit, holder] (const a8::Args& args) mutable
{
Creature* target = args.Get<Creature*>(0);
if (!target->dead) {
auto itr = context->watch_targets.find(target->GetUniId());
if (itr != context->watch_targets.end()) {
owner->room->xtimer.ResetTimer(std::get<0>(itr->second));
} else {
int target_uniid = target->GetUniId();
auto timer_wp = owner->room->xtimer.SetTimeoutWpEx
(
time_limit * SERVER_FRAME_RATE,
[this, context, target_uniid] (int event, const a8::Args* args)
{
auto itr = context->watch_targets.find(target_uniid);
if (itr != context->watch_targets.end()) {
Entity* e = owner->room->GetEntityByUniId(target_uniid);
if (e && e->IsCreature(owner->room)) {
Creature* c = (Creature*)e;
c->GetTrigger()->RemoveEventHandler(std::get<1>(itr->second));
}
context->watch_targets.erase(itr);
}
},
&xtimer_attacher);
auto handler = target->GetTrigger()->AddListener
(
kDieEvent,
[this, context, target_uniid] (const a8::Args& args)
{
if (owner->dead) {
return;
}
auto itr = context->watch_targets.find(target_uniid);
if (itr != context->watch_targets.end()) {
Entity* e = owner->room->GetEntityByUniId(target_uniid);
if (e && e->IsCreature(owner->room)) {
Creature* c = (Creature*)e;
auto buff_vars = std::make_shared<std::vector<float>>();
buff_vars->push_back(target_uniid);
owner->TryAddBuff(GetCaster().Get(),
meta->_int_buff_param4,
skill_meta,
nullptr,
buff_vars);
std::weak_ptr<EventHandlerPtr> handler = std::get<1>(itr->second);
context->watch_targets.erase(itr);
c->GetTrigger()->RemoveEventHandler(handler);
} else {
context->watch_targets.erase(itr);
}
}
});
event_handlers_.push_back(handler);
context->watch_targets[target->GetUniId()] = std::make_tuple(timer_wp, handler);
}
}
};
event_handlers_.push_back
(owner->GetTrigger()->AddListener
(
kAttackTargetEvent,
cb
)
);
}
void CondAddBuff::ProcReload()
{
auto context = A8_MAKE_ANON_STRUCT_SHARED
(
std::vector<int> buffs;
);
event_handlers_.push_back
(owner->GetTrigger()->AddListener
(
kStartReloadEvent,
[this, context] (const a8::Args& args) mutable
{
if (!owner->dead) {
int buff_uniid = owner->TryAddBuff(GetCaster().Get(),
meta->_int_buff_param4,
skill_meta,
nullptr,
buff_vars);
if (buff_uniid > 0) {
context->buffs.push_back(buff_uniid);
}
}
}
)
);
event_handlers_.push_back
(owner->GetTrigger()->AddListener
(
kEndReloadEvent,
[this, context] (const a8::Args& args) mutable
{
for (int buff_uniid : context->buffs) {
owner->RemoveBuffByUniId(buff_uniid);
}
context->buffs.clear();
}
)
);
}
void CondAddBuff::ProcShot()
{
event_handlers_.push_back
(owner->GetTrigger()->AddListener
(
kShotEvent,
[this] (const a8::Args& args) mutable
{
if (!owner->dead) {
owner->TryAddBuff(GetCaster().Get(),
meta->_int_buff_param4,
skill_meta,
nullptr,
buff_vars);
}
}
)
);
}