#include "precompile.h" #include #include "trigger.h" #include "creature.h" #include "metamgr.h" #include "skill.h" #include "room.h" #include "human.h" #include "car.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) { { MetaData::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; } } }); } } } { MetaData::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(MetaData::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) { owner_->room->xtimer.AddDeadLineTimerAndAttach (buff->meta->int_param3 / FRAME_RATE_MS, a8::XParams() .SetSender(owner_) .SetParam1(buff->buff_uniid), [] (const a8::XParams& param) { Creature* c = (Creature*)param.sender.GetUserData(); c->RemoveBuffByUniId(param.param1); }, &owner_->xtimer_attacher.timer_list_, [] (const a8::XParams& param) { }); } } } void Trigger::Kill(Creature* target) { if (owner_->IsHuman() && target->IsHuman()) { 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); } }); } 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->i->skill_id()) { AddBuffs(buff->meta->int_param1, buff->meta->param4_int_list); } }); } 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); } void Trigger::Die() { { std::vector list; owner_->TraverseBuff ( [&list] (Buff* buff, bool& stop) { if (buff->meta->i->dead_remove()) { list.push_back(buff->buff_uniid); } }); for (int buff_uniid : list) { owner_->RemoveBuffByUniId(buff_uniid); } } TriggeCondBuffAll(kCondBuffDid); } void Trigger::TraverseCondBuffs(int cond, std::function 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 old_context_ability = owner_->context_ability; a8::Vec2 old_context_dir = owner_->context_dir; a8::Vec2 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(MetaData::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(MetaData::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, std::vector& 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, std::vector& buffids) { for (int buffid : buffids) { #ifdef DEBUG owner_->MustBeAddBuff(owner_, buffid); #else owner_->TryAddBuff(owner_, buffid); #endif } } void Trigger::RemoveBuffs(int cond, std::vector& buffids) { for (int buffid : buffids) { owner_->RemoveBuffById(buffid); } } std::weak_ptr Trigger::AddListener(int event_id, std::function 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(); p->ptr->data = p; list_add_tail(&p->entry, &itr->second); return p->ptr; } void Trigger::RemoveEventHandler(std::weak_ptr 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 a8::XParams& param) { }