#include "precompile.h" #include "bullet.h" #include "metamgr.h" #include "room.h" #include "collider.h" #include "obstacle.h" #include "player.h" #include "android.h" #include "android.ai.h" #include "app.h" #include "perfmonitor.h" #include "smoke_mitask.h" #include "frag_mitask.h" #include "creature.h" #include "roomobstacle.h" Bullet::Bullet():MoveableEntity() { ++PerfMonitor::Instance()->entity_num[ET_Bullet]; } Bullet::~Bullet() { --PerfMonitor::Instance()->entity_num[ET_Bullet]; } void Bullet::Initialize() { MoveableEntity::Initialize(); RecalcSelfCollider(); } void Bullet::Update(int delta_time) { MapServiceUpdate(); ++updated_times_; } void Bullet::RecalcSelfCollider() { if (!self_collider_) { self_collider_ = new CircleCollider(); self_collider_->owner = this; AddEntityCollider(self_collider_); } self_collider_->pos = a8::Vec2(); self_collider_->rad = gun_meta->i->bullet_rad(); } void Bullet::OnHit(std::set& objects) { for (auto& target : objects) { target->OnBulletHit(this); } } void Bullet::ProcBomb() { self_collider_->rad = gun_meta->i->explosion_range(); std::set objects; TraverseAllLayerHumanList ( [this, &objects] (Human* hum, bool& stop) { if (!is_tank_skin || sender.Get()->team_id != hum->team_id) { //友军火箭筒伤害取消 if ((meta->i->_inventory_slot() == 4 || meta->i->_inventory_slot() == 5) && sender.Get()->team_id == hum->team_id) { return; } if (meta->i->_inventory_slot() == IS_C4) { if (hum->IsHuman()) { return; } } if (TestCollision(room, hum)) { objects.insert(hum); } } }); TraverseAllLayerEntityList ( [this, &objects] (Entity* entity, bool& stop) { switch (entity->GetEntityType()) { case ET_Obstacle: case ET_Building: { if (TestCollision(room, entity)) { objects.insert(entity); } } break; default: { } break; } }); bool block = false; if (objects.empty()) { float distance = (GetPos() - born_pos).Norm(); if (distance < fly_distance) { block = true; } } int delay_time = 0; if (!block) { delay_time = gun_meta->i->missiles_time(); } switch (meta->i->_inventory_slot()) { case IS_RPG: { //榴弹炮 a8::Vec2 bomb_pos = GetPos(); room->frame_event.AddExplosionEx(sender, meta->i->id(), bomb_pos, gun_meta->i->explosion_effect()); OnHit(objects); } break; case IS_FRAG: { //手雷 ProcFragBomb(delay_time); } break; case IS_SMOKE: { //烟雾弹 a8::Vec2 bomb_pos = GetPos(); room->frame_event.AddSmoke(this, meta->i->id(), bomb_pos); ProcSmokeBomb(); } break; case IS_POSION_GAS_BOMB: { //毒气弹 ProcPosionGasBomb(delay_time); } break; case IS_MOLOTOR_COCKTAIL: { //燃烧瓶 ProcMolotorCocktailBomb(delay_time); } break; case IS_C4: { //c4 delay_time = gun_meta->i->missiles_time(); ProcC4Bomb(delay_time); } break; case IS_SINGAL_GUN: { ProcSignalGunBomb(delay_time); } break; case IS_SHIELD_WALL: { ProcShieldWallBomb(delay_time); } break; default: { } break; } room->RemoveObjectLater(this); later_removed_ = true; } void Bullet::ProcSmokeBomb() { MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(HUNLUAN_BUFFID); if (buff_meta) { SmokeMiTask* task = new SmokeMiTask(); task->room = room; task->bomb_pos = GetPos(); task->buff_meta = buff_meta; task->gun_meta = gun_meta; room->xtimer.AddRepeatTimerAndAttach (SERVER_FRAME_RATE / 2, a8::XParams() .SetSender(task), [] (const a8::XParams& param) { SmokeMiTask* task = (SmokeMiTask*)param.sender.GetUserData(); task->Check(); }, &task->timer_attacher.timer_list_); room->xtimer.AddDeadLineTimerAndAttach (SERVER_FRAME_RATE * MetaMgr::Instance()->GetSysParamAsInt("smoke_duration", 10), a8::XParams() .SetSender(task), [] (const a8::XParams& param) { }, &room->timer_attacher.timer_list_, [] (const a8::XParams& param) { SmokeMiTask* task = (SmokeMiTask*)param.sender.GetUserData(); task->Done(); delete task; } ); } } bool Bullet::IsBomb() { return meta->i->_inventory_slot() == IS_RPG || meta->i->_inventory_slot() == IS_FRAG || meta->i->_inventory_slot() == IS_SMOKE || meta->i->_inventory_slot() == IS_POSION_GAS_BOMB || meta->i->_inventory_slot() == IS_MOLOTOR_COCKTAIL || meta->i->_inventory_slot() == IS_C4 || meta->i->_inventory_slot() == IS_SINGAL_GUN || meta->i->_inventory_slot() == IS_SHIELD_WALL; } void Bullet::MapServiceUpdate() { if (later_removed_) { return; } if (sender.Get()) { SetPos(GetPos() + dir * gun_meta->i->bullet_speed() / (float)SERVER_FRAME_RATE); float distance = (GetPos() - born_pos).Norm(); if (room->OverBorder(GetPos(), gun_meta->i->bullet_rad())) { if (IsBomb()) { ProcBomb(); } else { Check(distance); if (!later_removed_) { room->RemoveObjectLater(this); later_removed_ = true; } } } else { room->grid_service->MoveBullet(this); Check(distance); } } else { room->RemoveObjectLater(this); later_removed_ = true; } } float Bullet::GetAtk() { float atk = gun_meta->i->atk() + (gun_upgrade_meta ? gun_upgrade_meta->GetAttrValue(gun_lv, kHAT_Atk) : 0); if (sender.Get()->IsAndroid()) { Android* android = (Android*)sender.Get(); atk *= android->ai->GetAttackRate(); } return atk; } void Bullet::Check(float distance) { std::set objects; room->grid_service->TraverseCreatures (room->GetRoomIdx(), GetGridList(), [this, &objects] (Creature* c, bool& stop) { if (sender.Get()->IsProperTarget(c)) { AabbCollider aabb_box; c->GetHitAabbBox(aabb_box); if (c != sender.Get() && !c->dead && TestCollision(room, &aabb_box)) { if (meta->i->_inventory_slot() == IS_C4) { if (!c->IsHuman()) { objects.insert(c); } } else { objects.insert(c); } } } }); { std::set colliders; room->map_service->GetColliders(room, GetX(), GetY(), colliders); for (ColliderComponent* collider : colliders) { if (TestCollision(room, collider) && !a8::HasBitFlag(collider->tag, kHalfWallTag)) { objects.insert(collider->owner); } } } float bullet_range = gun_meta->i->range(); if (gun_upgrade_meta && gun_upgrade_meta->GetAttrValue(gun_lv, kHAT_ShotRange) > 0) { bullet_range += gun_upgrade_meta->GetAttrValue(gun_lv, kHAT_ShotRange); } if (!objects.empty() || distance > bullet_range || (IsBomb() && meta->i->_inventory_slot() != IS_RPG && distance >= fly_distance) ) { if (IsBomb()) { ProcBomb(); } else { if (!objects.empty()) { OnHit(objects); } room->RemoveObjectLater(this); later_removed_ = true; } } } void Bullet::ProcFragBomb(int delay_time) { if (sender.Get()) { FragMiTask* task = new FragMiTask(); task->room = room; task->sender.Attach(sender.Get()); task->bomb_pos = GetPos(); task->gun_meta = gun_meta; task->meta = meta; task->atk = GetAtk(); room->xtimer.AddDeadLineTimerAndAttach (std::max(1, (int)(delay_time / FRAME_RATE_MS)), a8::XParams() .SetSender(task), [] (const a8::XParams& param) { FragMiTask* task = (FragMiTask*)param.sender.GetUserData(); task->Done(); }, &task->timer_attacher.timer_list_, [] (const a8::XParams& param) { FragMiTask* task = (FragMiTask*)param.sender.GetUserData(); delete task; } ); } } void Bullet::ProcPosionGasBomb(int delay_time) { if (sender.Get()) { a8::Vec2 old_buff_vec2_param1 = sender.Get()->buff_vec2_param1; sender.Get()->buff_vec2_param1 = GetPos(); MetaData::Buff * buff_meta = MetaMgr::Instance()->GetBuff(gun_meta->i->buffid()); if (buff_meta) { sender.Get()->AddBuff(sender.Get(), buff_meta, 1 ); } sender.Get()->buff_vec2_param1 = old_buff_vec2_param1; } } void Bullet::ProcMolotorCocktailBomb(int delay_time) { if (sender.Get()) { a8::Vec2 old_buff_vec2_param1 = sender.Get()->buff_vec2_param1; sender.Get()->buff_vec2_param1 = GetPos(); MetaData::Buff * buff_meta = MetaMgr::Instance()->GetBuff(gun_meta->i->buffid()); if (buff_meta) { sender.Get()->AddBuff(sender.Get(), buff_meta, 1 ); } sender.Get()->buff_vec2_param1 = old_buff_vec2_param1; } } void Bullet::ProcC4Bomb(int delay_time) { if (sender.Get()) { FragMiTask* task = new FragMiTask(); task->room = room; task->sender.Attach(sender.Get()); task->bomb_pos = GetPos(); task->gun_meta = gun_meta; task->meta = meta; task->atk = GetAtk(); room->xtimer.AddDeadLineTimerAndAttach (std::max(1, (int)(delay_time / FRAME_RATE_MS)), a8::XParams() .SetSender(task), [] (const a8::XParams& param) { FragMiTask* task = (FragMiTask*)param.sender.GetUserData(); task->Done(); }, &task->timer_attacher.timer_list_, [] (const a8::XParams& param) { FragMiTask* task = (FragMiTask*)param.sender.GetUserData(); delete task; } ); } } void Bullet::ProcSignalGunBomb(int delay_time) { if (sender.Get()) { a8::Vec2 old_buff_vec2_param1 = sender.Get()->buff_vec2_param1; sender.Get()->buff_vec2_param1 = GetPos(); MetaData::Buff * buff_meta = MetaMgr::Instance()->GetBuff(gun_meta->i->buffid()); if (buff_meta) { sender.Get()->AddBuff(sender.Get(), buff_meta, 1 ); } sender.Get()->buff_vec2_param1 = old_buff_vec2_param1; } } void Bullet::ProcShieldWallBomb(int delay_time) { if (sender.Get()) { a8::Vec2 old_buff_vec2_param1 = sender.Get()->buff_vec2_param1; sender.Get()->buff_vec2_param1 = GetPos(); MetaData::Buff * buff_meta = MetaMgr::Instance()->GetBuff(gun_meta->i->buffid()); if (buff_meta) { sender.Get()->AddBuff(sender.Get(), buff_meta, 1 ); } sender.Get()->buff_vec2_param1 = old_buff_vec2_param1; } }