aozhiwei b7592f1601 1
2022-12-27 18:05:42 +08:00

488 lines
15 KiB
C++

#include "precompile.h"
#include <a8/list.h>
#include "trigger.h"
#include "creature.h"
#include "skill.h"
#include "room.h"
#include "human.h"
#include "car.h"
#include "bullet.h"
#include "buff.h"
#include "mt/Buff.h"
#include "mt/Skill.h"
#include "mt/SkillNumber.h"
#include "mt/Equip.h"
void Trigger::Init()
{
}
void Trigger::UnInit()
{
for (auto& pair : listeners_hash_) {
while (!list_empty(&pair.second)) {
EventHandler* e = list_first_entry(&pair.second,
EventHandler,
entry);
e->ptr->data = nullptr;
list_del_init(&e->entry);
delete e;
}
}
}
void Trigger::TakeonWeapon(Weapon* old_weapon, Weapon* new_weapon)
{
{
const mt::Equip* weapon_meta = old_weapon ? old_weapon->meta : nullptr;
if (weapon_meta) {
for (int cond = kCondBuffUpdateWeaponId; cond <= kCondBuffUpdateWeaponType; cond++) {
TraverseCondBuffs
(cond,
[this, cond, weapon_meta] (Buff* buff, bool& stop)
{
if (weapon_meta->Match((CondAddBuff_e)cond,
buff->meta->_int_param3,
buff->meta->_int_param5)) {
switch (buff->meta->_int_param2) {
case kWeaponOptTakeoff:
case kWeaponOptKeep:
{
RemoveBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
break;
default:
{
}
break;
}
}
});
}
}
}
{
const mt::Equip* weapon_meta = new_weapon ? new_weapon->meta : nullptr;
if (weapon_meta) {
for (int cond = kCondBuffUpdateWeaponId; cond <= kCondBuffUpdateWeaponType; cond++) {
TraverseCondBuffs
(cond,
[this, cond, weapon_meta] (Buff* buff, bool& stop)
{
if (weapon_meta->Match((CondAddBuff_e)cond,
buff->meta->_int_param3,
buff->meta->_int_param5)) {
switch (buff->meta->_int_param2) {
case kWeaponOptTakeon:
{
AddBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
break;
case kWeaponOptKeep:
{
TryAddBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
break;
default:
{
}
break;
}
}
});
}
}
}
}
void Trigger::Shot(const mt::Equip* weapon_meta)
{
for (int cond = kCondBuffShotWeaponId; cond <= kCondBuffShotWeaponType; ++cond) {
TraverseCondBuffs
(cond,
[this, cond, weapon_meta] (Buff* buff, bool& stop)
{
if (weapon_meta->Match((CondAddBuff_e)cond,
buff->meta->_int_param2,
buff->meta->_int_param5)) {
AddBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
});
}
{
Buff* buff = owner_->GetBuffByEffectId(kBET_MachineGun);
if (buff && buff->meta->_int_param2 == 1) {
auto buff_uniid = buff->buff_uniid;
owner_->room->xtimer.SetTimeoutEx
(buff->meta->_int_param3 / FRAME_RATE_MS,
[this, buff_uniid] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
owner_->RemoveBuffByUniId(buff_uniid);
}
},
&owner_->xtimer_attacher);
}
}
}
void Trigger::Kill(Creature* target, int weapon_id)
{
if (owner_->IsHuman() && target->IsHuman()) {
Human* owner_hum = owner_->AsHuman();
Human* target_hum = target->AsHuman();
owner_hum->CalcAssists(target_hum);
if (target->GetUniId() != owner_->GetUniId()) {
owner_->AsHuman()->stats.kills++;
}
owner_->AsHuman()->stats.last_kill_frameno = owner_->room->GetFrameNo();
owner_->AsHuman()->kill_humans.insert(target->AsHuman());
owner_->AsHuman()->SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
if (owner_->IsCar()) {
owner_->AsCar()->OnKillTarget(target);
}
++kill_num_;
TraverseCondBuffs
(kCondBuffKillTarget,
[this] (Buff* buff, bool& stop)
{
if (buff->meta->_int_param2 > 0 && (kill_num_ % buff->meta->_int_param2) == 0) {
AddBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
});
DispatchEvent(kKillEvent, {kill_num_, target, weapon_id});
}
void Trigger::UseItemAction(int slot_id)
{
TraverseCondBuffs
(kCondBuffEatDrug,
[this, slot_id] (Buff* buff, bool& stop)
{
if (buff->meta->_param2_int_set.find(slot_id) != buff->meta->_param2_int_set.end()) {
AddBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
});
}
void Trigger::UseSkill(Skill* skill)
{
TraverseCondBuffs
(kCondBuffUseSkill,
[this, skill] (Buff* buff, bool& stop)
{
if (buff->meta->_int_param2 == skill->meta->skill_id()) {
AddBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
});
DispatchEvent(kUseSkillEvent, {skill});
}
void Trigger::HpChg()
{
TraverseCondBuffs
(kCondBuffHp,
[this] (Buff* buff, bool& stop)
{
bool match = false;
switch (buff->meta->_int_param2) {
case kHpOptLeAbs:
{
match = owner_->GetHP() < buff->meta->_int_param3;
}
break;
case kHpOptLeRate:
{
//match = (owner_->GetHP() / owner_->GetMaxHP() * 100) < buff->meta->_int_param3;
match = owner_->GetHP() / owner_->GetMaxHP() < buff->meta->_param3;
}
break;
case kHpOptGeAbs:
{
match = owner_->GetHP() > buff->meta->_int_param3;
}
break;
case kHpOptGeRate:
{
//match = (owner_->GetHP() / owner_->GetMaxHP() * 100) > buff->meta->_int_param3;
match = owner_->GetHP() / owner_->GetMaxHP() > buff->meta->_param3;
}
break;
default:
{
}
break;
}
if (match) {
TryAddBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
} else {
RemoveBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
});
}
void Trigger::ReceiveDmg()
{
TriggeCondBuffAll(kCondBuffReceiveDmg);
DispatchEvent(kReceiveDmgEvent, {});
}
void Trigger::PreDie(int killer_id, int weapon_id)
{
DispatchEvent(kPreDieEvent, {killer_id, weapon_id});
}
void Trigger::Die(int killer_id, int weapon_id)
{
{
std::vector<int> list;
owner_->TraverseBuff
(
[&list] (Buff* buff, bool& stop)
{
if (buff->meta->dead_remove()) {
list.push_back(buff->buff_uniid);
}
});
for (int buff_uniid : list) {
owner_->RemoveBuffByUniId(buff_uniid);
}
}
TriggeCondBuffAll(kCondBuffDid);
DispatchEvent(kDieEvent, {killer_id, weapon_id});
}
void Trigger::TraverseCondBuffs(int cond, std::function<void (Buff*, bool&)> func)
{
if (!IsValidCondBuff(cond)) {
A8_ABORT();
}
if (!owner_->room->BattleStarted()) {
return;
}
list_head* pos = nullptr;
list_head* next = nullptr;
list_head* head = &owner_->cond_buffs_[cond];
RemoveBuffCbConext cb;
cb.next = &next;
INIT_LIST_HEAD(&cb.entry);
list_for_each_safe(pos, next, head) {
if (list_empty(next)) {
Buff *next_buff = list_entry(next, Buff, cond_entry);
list_add_tail(&cb.entry, &next_buff->on_remove_contexts);
}
Buff *curr_buff = list_entry(pos, Buff, cond_entry);
bool stop = false;
func(curr_buff, stop);
if (!list_empty(&cb.entry)) {
list_del_init(&cb.entry);
}
if (stop) {
return;
}
}
}
void Trigger::TriggeCondBuffAll(int cond)
{
if (!owner_->room->BattleStarted()) {
return;
}
std::shared_ptr<Ability> old_context_ability = owner_->context_ability;
glm::vec3 old_context_dir = owner_->context_dir;
Position old_context_pos = owner_->context_pos;
owner_->context_dir = owner_->GetAttackDir();
owner_->context_pos = owner_->GetPos();
TraverseCondBuffs
(cond,
[this, cond] (Buff* buff, bool& stop)
{
AddBuffs(cond, buff->meta->_param4_int_list);
});
owner_->context_dir = old_context_dir;
owner_->context_pos = old_context_pos;
owner_->context_ability = old_context_ability;
}
void Trigger::ActiveBuff(const mt::Buff* buff_meta)
{
for (int cond = kCondBuffUpdateBuffId; cond <= kCondBuffUpdateBuffEffect; ++cond) {
TraverseCondBuffs
(cond,
[this, cond, buff_meta] (Buff* buff, bool& stop)
{
if (buff_meta->Match((CondAddBuff_e)cond, buff->meta->_int_param3)) {
switch (buff->meta->_int_param2) {
case kBuffOptActive:
{
AddBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
break;
case kBuffOptKeep:
{
TryAddBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
break;
default:
{
}
break;
}
}
});
}
}
void Trigger::DeactiveBuff(const mt::Buff* buff_meta)
{
for (int cond = kCondBuffUpdateBuffId; cond <= kCondBuffUpdateBuffEffect; ++cond) {
TraverseCondBuffs
(cond,
[this, cond, buff_meta] (Buff* buff, bool& stop)
{
if (buff_meta->Match((CondAddBuff_e)cond, buff->meta->_int_param3)) {
switch (buff->meta->_int_param2) {
case kBuffOptDeactive:
case kBuffOptKeep:
{
RemoveBuffs(buff->meta->_int_param1, buff->meta->_param4_int_list);
}
break;
default:
{
}
break;
}
}
});
}
}
void Trigger::TryAddBuffs(int cond, const std::vector<int>& buffids)
{
for (int buffid : buffids) {
if (!owner_->GetBuffById(buffid)) {
#ifdef DEBUG
owner_->MustBeAddBuff(owner_, buffid);
#else
owner_->TryAddBuff(owner_, buffid);
#endif
}
}
}
void Trigger::AddBuffs(int cond, const std::vector<int>& buffids)
{
for (int buffid : buffids) {
#ifdef DEBUG
owner_->MustBeAddBuff(owner_, buffid);
#else
owner_->TryAddBuff(owner_, buffid);
#endif
}
}
void Trigger::RemoveBuffs(int cond, const std::vector<int>& buffids)
{
for (int buffid : buffids) {
owner_->RemoveBuffById(buffid);
}
}
std::weak_ptr<EventHandlerPtr> Trigger::AddListener(int event_id, a8::CommonCbProc cb)
{
auto itr = listeners_hash_.find(event_id);
if (itr == listeners_hash_.end()) {
listeners_hash_[event_id] = list_head();
itr = listeners_hash_.find(event_id);
INIT_LIST_HEAD(&itr->second);
}
EventHandler* p = new EventHandler();
p->cb = cb;
p->ptr = std::make_shared<EventHandlerPtr>();
p->ptr->data = p;
list_add_tail(&p->entry, &itr->second);
return p->ptr;
}
void Trigger::RemoveEventHandler(std::weak_ptr<EventHandlerPtr> handler)
{
if (!handler.expired()) {
auto p = handler.lock()->data;
EventHandler* e = list_entry(&p->entry, EventHandler, entry);
e->ptr->data = nullptr;
list_del_init(&e->entry);
delete e;
}
}
void Trigger::DispatchEvent(int event_id, const std::vector<std::any>& param)
{
auto itr = listeners_hash_.find(event_id);
if (itr != listeners_hash_.end()) {
struct EventHandler *handle = nullptr, *tmp = nullptr;
list_for_each_entry_safe(handle, tmp, &itr->second, entry) {
handle->cb(param);
}
}
}
void Trigger::BulletHit(IBullet* bullet, Creature* target)
{
if (bullet->GetSender().Get()) {
bullet->GetSender().Get()->GetTrigger()->DispatchEvent(kBulletHitEvent, {bullet, target});
}
}
void Trigger::ShieldDestory()
{
DispatchEvent(kShieldDestoryEvent, {});
}
void Trigger::StartRescue(Human* target)
{
DispatchEvent(kStartRescueEvent, {target});
}
void Trigger::EndRescue(Human* target)
{
DispatchEvent(kEndRescueEvent, {target});
}
void Trigger::YsBuffRemove(Buff* buff)
{
DispatchEvent(kYsRemoveEvent, {buff});
}
void Trigger::SkillBulletPreCreate(int delay_time, const mt::Skill* skill_meta)
{
DispatchEvent(kSkillBulletPreCreateEvent, {delay_time, skill_meta});
}
void Trigger::FlyHookCreate(Bullet* bullet)
{
DispatchEvent(kFlyHookCreateEvent, {bullet});
}
void Trigger::FlyHookDestory()
{
DispatchEvent(kFlyHookDestoryEvent, {});
}
void Trigger::BulletHitBuff(Bullet* bullet)
{
DispatchEvent(kTriggerBulletHitBuffEvent, {bullet});
}
void Trigger::Attacked(Creature* sender)
{
DispatchEvent(kAttacked, {sender});
}