#include "precompile.h" #include "explosion.h" #include "creature.h" #include "room.h" enum ExplosionType_e { kExplosionIndifference = 1, kExplosionEnemyAndObstacle = 2 }; Explosion::~Explosion() { int i = 0; } void Explosion::IndifferenceAttack(Room* room, const Position& center, float explosion_range, int explosion_effect, float dmg, long long special_damage_type) { type_ = kExplosionIndifference; room_ = room; explosion_range_ = explosion_range; explosion_effect_ = explosion_effect; dmg_ = dmg; center_ = center; special_damage_type_ = special_damage_type; create_frameno_ = room_->GetFrameNo(); InternalAttack(); } void Explosion::EnemyAndObstacleAttack(CreatureWeakPtr& sender, const Position& center, float explosion_range, int explosion_effect, float dmg, long long special_damage_type) { if (!sender.Get()) { return; } type_ = kExplosionEnemyAndObstacle; room_ = sender.Get()->room; sender_ = sender; explosion_range_ = explosion_range; explosion_effect_ = explosion_effect; dmg_ = dmg; center_ = center; special_damage_type_ = special_damage_type; create_frameno_ = room_->GetFrameNo(); InternalAttack(); } void Explosion::ProcDamage() { std::set grid_list; room_->grid_service->GetAllCellsByXy ( room_, center_.GetX(), center_.GetZ(), grid_list ); std::set objects; room_->grid_service->TraverseCreatures ( room_->GetRoomIdx(), grid_list, [this, &objects] (Creature* c, bool& stop) { if (c->dead) { return; } if (c->GetUniId() == exclude_uniid) { return; } if (!c->Attackable(room_)) { return; } if (!c->ReceiveExplosionDmg(this)) { return; } if (type_ == kExplosionEnemyAndObstacle) { long long ignore_buff_effects = 0; a8::SetBitFlag(ignore_buff_effects, kBET_Hide); if (sender_.Get() && sender_.Get()->IsProperTarget(c, false, ignore_buff_effects)) { if (custom_check_cb_) { bool is_hit = false; custom_check_cb_(a8::Args({&is_hit, (Entity*)c})); if (is_hit) { objects.insert(c); } } else { if (center_.Distance2D2(c->GetPos()) < explosion_range_) { objects.insert(c); } } } } else { if (custom_check_cb_) { bool is_hit = false; custom_check_cb_(a8::Args({&is_hit, (Entity*)c})); if (is_hit) { objects.insert(c); } } else { if (center_.Distance2D2(c->GetPos()) < explosion_range_) { objects.insert(c); } } } } ); room_->grid_service->TraverseAllLayerEntityList ( room_->GetRoomIdx(), grid_list, [this, &objects] (Entity* entity, bool& stop) { if (entity->GetUniId() == exclude_uniid) { return; } if (!entity->Attackable(room_)) { return; } if (!entity->ReceiveExplosionDmg(this)) { return; } if (custom_check_cb_) { bool is_hit = false; custom_check_cb_(a8::Args({&is_hit, entity})); if (is_hit) { objects.insert(entity); } } else { if (center_.Distance2D2(entity->GetPos()) < explosion_range_) { objects.insert(entity); } } } ); if (force_target_.Get() && objects.find(force_target_.Get()) == objects.end()) { objects.insert(force_target_.Get()); } for (auto& target : objects) { if (target->IsCreature(room_) && ((Creature*)target)->HasBuffEffect(kBET_BulletThrough)) { continue; } if (!IsThrough()) { target->OnExplosionHit(this); } if (hit_cb_) { hit_cb_(a8::Args({target})); } } } void Explosion::InternalAttack() { if (explosion_range_ <= 0) { return; } if (!no_sync_) { room_->frame_event.AddExplosionEx (sender_, 0, center_, explosion_effect_, bullet_uniid); } if (explosion_damage_delay_ <= 0) { ProcDamage(); } else { auto self = shared_from_this(); room_->xtimer.SetTimeoutEx (explosion_damage_delay_ / FRAME_RATE_MS, [self] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { self->ProcDamage(); } }, &room_->xtimer_attacher_); } } bool Explosion::IsPreBattleExplosion() { return create_frameno_ <= room_->GetBattleStartFrameNo() || room_->GetBattleStartFrameNo() == 0; } void Explosion::AddForceTarget(CreatureWeakPtr force_target) { force_target_ = force_target; }