#include "precompile.h" #include "virtualbullet.h" #include "metamgr.h" #include "room.h" #include "mapservice.h" #include "gridservice.h" #include "creature.h" #include "collider.h" float VirtualBullet::GetStrengthenWall() { return 0; } long long VirtualBullet::GetWeaponUniId() { return weapon_uniid; } MetaData::Skill* VirtualBullet::GetSkillMeta() { return skill_meta; } MetaData::Equip* VirtualBullet::GetGunMeta() { return gun_meta; } MetaData::Equip* VirtualBullet::GetBulletMeta() { return bullet_meta; } CreatureWeakPtr VirtualBullet::GetSender() { return sender; } CreatureWeakPtr VirtualBullet::GetPassenger() { return passenger; } bool VirtualBullet::IsBomb() { return false; } bool VirtualBullet::IsPreBattleBullet() { return is_pre_battle_bullet; } Room* VirtualBullet::GetRoom() { return room; } void VirtualBullet::Update(int delta_time) { if (sender.Get()) { float move_length = gun_meta->i->bullet_speed() / (float)SERVER_FRAME_RATE; do { float step_len = move_length - MetaMgr::Instance()->bullet_planck_step_length; if (step_len <= 0.001f) { if (move_length > 0.1f) { step_len = move_length; } else { break; } } move_length -= step_len; SetPos(GetPos() + dir * step_len); float distance = (GetPos() - born_pos).Norm(); if (room->OverBorder(GetPos(), gun_meta->i->bullet_rad())) { Check(distance); if (!later_removed_) { ForceRemove(); } } else { #if 0 room->grid_service->MoveBullet(this); #endif Check(distance); } } while(!later_removed_ && move_length >= 0.0001f); } } bool VirtualBullet::IsDone() { return false; } void VirtualBullet::Check(float distance) { int c_hit_num = 0; int t_hit_num = 0; int o_hit_num = 0; std::set objects; { std::set colliders; room->map_service->GetColliders(room, GetPos().x, GetPos().y, colliders); #if 0 for (ColliderComponent* collider : colliders) { if (collider->owner->IsEntityType(ET_Dummy)) { if (a8::HasBitFlag(collider->tag, kHalfWallTag)) { continue; } if (TestCollision(room, collider)) { ++o_hit_num; objects.insert(collider->owner); } } else if (collider->owner->IsEntityType(ET_Obstacle)) { Obstacle* obstacle = (Obstacle*)collider->owner; if (gun_meta->i->is_penetrate_thing() && hit_objects_.find(obstacle->GetUniId()) != hit_objects_.end()) { //穿物件 continue; } if (!obstacle->CanThroughable(this)) { if (TestCollision(room, collider)) { objects.insert(collider->owner); if (gun_meta->i->is_penetrate_thing()) { ++t_hit_num; ++o_hit_num; hit_objects_.insert(collider->owner->GetUniId()); } } } else if (obstacle->meta->i->thing_type() == kObstacleStrengthenWall) { if (!strengthened_ && sender.Get() && sender.Get()->team_id == obstacle->GetTeamId(room)) { bool ret = Check2dRotationRectangle (GetPos().x, GetPos().y, gun_meta->i->bullet_rad(), obstacle->GetPos().x, obstacle->GetPos().y, obstacle->meta->i->width(), obstacle->meta->i->height(), obstacle->GetRotate() * 180.0f ); if (ret) { strengthened_ = true; OnStrengthen(obstacle); #ifdef DEBUG a8::XPrintf("命中能量墙\n", {}); #endif } } } } } #endif } bool eat = false; if (o_hit_num <= 0) { #if 0 room->grid_service->TraverseCreatures (room->GetRoomIdx(), GetGridList(), [this, &objects, &c_hit_num, &eat] (Creature* c, bool& stop) { bool no_teammate = IsFlyHook(); if (sender.Get()->IsProperTarget(c, no_teammate)) { if (gun_meta->i->ispenetrate() && hit_objects_.find(c->GetUniId()) != hit_objects_.end()) { //穿人 return; } if (c->HasBuffEffect(kBET_BulletThrough)) { return; } { Buff* hold_shield_buff = c->GetBuffByEffectId(kBET_HoldShield); if (hold_shield_buff && !IsBomb() && !c->dead && c != sender.Get()) { //param2是距离 param4是宽度 a8::Vec2 shield_pos = c->GetPos() + c->GetAttackDir() * hold_shield_buff->meta->param2; bool ret = Check2dRotationRectangle(GetPos().x, GetPos().y, //10, gun_meta->i->bullet_rad(), shield_pos.x, shield_pos.y, hold_shield_buff->meta->param4, MetaMgr::Instance()->bullet_planck_step_length, c->GetAttackDirRotate() * 180.0f ); if (ret) { float finaly_dmg = c->GetBattleContext()->CalcDmg(c, this); c->shield_hp_ = std::max(0.0f, c->shield_hp_ - finaly_dmg); #ifdef DEBUG a8::XPrintf("命中盾牌 finally_dmg:%f shield_hp:%f\n", { finaly_dmg, c->shield_hp_ }); #endif room->frame_event.AddPropChg(c->GetWeakPtrRef(), kPropShieldHp, c->shield_max_hp_, c->shield_hp_); if (c->shield_hp_ <= 0) { #ifdef DEBUG a8::XPrintf("shiled destory\n", {}); #endif c->GetTrigger()->ShieldDestory(); c->RemoveBuffByUniId(hold_shield_buff->buff_uniid); } eat = true; stop = true; return; } } } 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); if (gun_meta->i->ispenetrate()) { ++c_hit_num; hit_objects_.insert(c->GetUniId()); } } } else { objects.insert(c); if (gun_meta->i->ispenetrate()) { ++c_hit_num; hit_objects_.insert(c->GetUniId()); } } } } }); #endif } float bullet_range = gun_meta->i->range(); if (!objects.empty() || (!IsBomb() && distance > bullet_range) ) { if (IsBomb()) { } else { bool hited = false; if (!eat && !objects.empty()) { hited = true; OnHit(objects); } bool need_remove = true; if (distance < bullet_range) { if (!gun_meta->i->is_penetrate_thing() && !gun_meta->i->ispenetrate()) { } else { if ((!gun_meta->i->is_penetrate_thing() && (t_hit_num > 0)) || (!gun_meta->i->ispenetrate() && (c_hit_num > 0))) { } else { need_remove = false; } } } if (need_remove) { ForceRemove(); } } } } void VirtualBullet::ForceRemove() { } void VirtualBullet::OnHit(std::set& objects) { }