#include "precompile.h" #include "bullet.h" #include "metamgr.h" #include "room.h" #include "collider.h" #include "obstacle.h" #include "player.h" #include "app.h" Bullet::Bullet():Entity() { entity_type = ET_Bullet; ++App::Instance()->perf.entity_num[ET_Bullet]; } Bullet::~Bullet() { --App::Instance()->perf.entity_num[ET_Bullet]; } void Bullet::Initialize() { Entity::Initialize(); RecalcSelfCollider(); } void Bullet::Update(int delta_time) { MapServiceUpdate(); } void Bullet::RecalcSelfCollider() { if (!self_collider_) { self_collider_ = new CircleCollider(); self_collider_->owner = this; AddCollider(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) { switch (target->entity_type) { case ET_Player: { if (App::Instance()->HasFlag(8)) { return; } Human* hum = (Human*)target; if (hum->HasBuffEffect(BET_Invincible)) { continue; } #if 1 if (!hum->dead) { #else if (hum != player && !hum->dead && (hum->team_id == 0 || player->team_id != hum->team_id)) { #endif float dmg = gun_meta->i->atk() * (1 + player->ability.damage_add); float def = hum->def + hum->ability.def_add; float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K); player->stats.damage_amount_out += finaly_dmg; hum->DecHP(finaly_dmg, player->entity_uniid, player->name, gun_meta->i->id()); #if 0 if (a8::HasBitFlag(hum->status, HS_ReflectDamage) && hum->skill_meta) { float reflect_dmg = finaly_dmg * hum->skill_meta->value1; if (reflect_dmg > 1.0f) { player->DecHP(reflect_dmg, hum->entity_uniid, hum->name, gun_meta->i->id()); } } #endif } } break; case ET_Obstacle: { Obstacle* obstacle = (Obstacle*)target; if (!obstacle->dead && obstacle->meta->i->attack_type() == 1) { float dmg = gun_meta->i->atk() * (1 + player->ability.damage_add); float def = 0; float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K); #if 0 player->stats.damage_amount_out += finaly_dmg; #endif obstacle->health = std::max(0.0f, obstacle->health - finaly_dmg); obstacle->dead = obstacle->health <= 0.01f; obstacle->dead_frameno = room->frame_no; if (obstacle->dead) { if (obstacle->meta->i->damage_dia() > 0.01f && obstacle->meta->i->damage() > 0.01f) { obstacle->Explosion(this); } room->ScatterDrop(obstacle->pos, obstacle->meta->i->drop()); } obstacle->BroadcastFullState(); } } break; default: break; } } } void Bullet::ProcBomb() { self_collider_->rad = gun_meta->i->explosion_range(); std::set objects; for (auto& grid : grid_list) { for (Human* hum: grid->human_list) { #if 1 { #else if (hum != player && (hum->team_id == 0 || player->team_id != hum->team_id)) { #endif if (TestCollision(hum)) { objects.insert(hum); } } } for (Entity* entity : grid->entity_list) { switch (entity->entity_type) { case ET_Obstacle: case ET_Building: { if (TestCollision(entity)) { objects.insert(entity); } } break; default: { } break; } } }//end for #if 0 switch (meta->i->_inventory_slot()) { case 4: { //榴弹炮 a8::Vec2 bomb_pos = pos; room->frame_event.AddExplosionEx(player, 0, bomb_pos, 0); OnHit(objects); } break; case 5: { //手雷 a8::Vec2 bomb_pos = pos; room->frame_event.AddExplosion(this, meta->i->id(), bomb_pos); OnHit(objects); } break; case 6: { //烟雾弹 a8::Vec2 bomb_pos = pos; room->frame_event.AddSmoke(this, meta->i->id(), bomb_pos); } break; } #endif room->RemoveObjectLater(this); } bool Bullet::IsBomb() { #if 1 return false; #else return meta->i->_inventory_slot() == 4 || meta->i->_inventory_slot() == 5 || meta->i->_inventory_slot() == 6; #endif } void Bullet::MapServiceUpdate() { pos = pos + dir * gun_meta->i->bullet_speed() / (float)SERVER_FRAME_RATE; float distance = (pos - born_pos).Norm(); if (room->OverBorder(pos, gun_meta->i->bullet_rad())) { if (IsBomb()) { ProcBomb(); } else { room->RemoveObjectLater(this); } } else { room->grid_service.MoveBullet(this); std::set objects; for (auto& grid : grid_list) { for (Human* hum: grid->human_list) { if (hum != player && !hum->dead && (hum->team_id == 0 || player->team_id != hum->team_id)) { if (TestCollision(hum)) { objects.insert(hum); } } } }//end for #if 1 { std::set colliders; room->map_service.GetColliders(pos.x, pos.y, colliders); for (ColliderComponent* collider : colliders) { if (TestCollision(collider)) { objects.insert(collider->owner); } } } #endif float bullet_range = gun_meta->i->range(); if (gun_upgrade_meta && gun_upgrade_meta->GetAttrValue(gun_lv, EA_ShotRange) > 0) { bullet_range += gun_upgrade_meta->GetAttrValue(gun_lv, EA_ShotRange); } #if 1 if (!objects.empty() || distance > bullet_range || (IsBomb() && distance >= fly_distance) #else if (!objects.empty() || distance > bullet_range || (IsBomb() && meta->i->_inventory_slot() != 4 && distance >= fly_distance) #endif ) { if (IsBomb()) { ProcBomb(); } else { deleted = true; if (!objects.empty()) { OnHit(objects); } room->RemoveObjectLater(this); } } } }