game2006/server/gameserver/virtualbullet.cc
aozhiwei 37edea5346 1
2022-12-16 16:28:10 +08:00

350 lines
12 KiB
C++

#include "precompile.h"
#include "virtualbullet.h"
#include "metamgr.h"
#include "room.h"
#include "mapservice.h"
#include "gridservice.h"
#include "creature.h"
#include "collider.h"
#include "roomobstacle.h"
#include "human.h"
#include "config.h"
float VirtualBullet::GetStrengthenWall()
{
return strengthened_;
}
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 (later_removed_) {
return;
}
if (sender.Get()) {
float move_length = gun_meta->pb->bullet_speed() / (float)SERVER_FRAME_RATE;
do {
float step_len = move_length - Config::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;
// 999
#if 1
#else
SetPos(GetPos() + dir * step_len);
#endif
float distance = GetPos().Distance2D2(born_pos);
if (room->OverBorder(GetPos(), gun_meta->pb->bullet_rad())) {
Check(distance);
if (!later_removed_) {
ForceRemove();
}
} else {
Check(distance);
}
} while(!later_removed_ && move_length >= 0.0001f);
} else {
ForceRemove();
}
}
bool VirtualBullet::IsDone()
{
return later_removed_;
}
void VirtualBullet::Check(float distance)
{
int c_hit_num = 0;
int t_hit_num = 0;
int o_hit_num = 0;
std::set<Entity*> objects;
{
std::set<ColliderComponent*> colliders;
room->map_service->GetColliders(room, GetPos().x, GetPos().y, colliders);
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->pb->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->pb->is_penetrate_thing()) {
++t_hit_num;
++o_hit_num;
hit_objects_.insert(collider->owner->GetUniId());
}
}
} else if (obstacle->meta->pb->thing_type() == kObstacleStrengthenWall) {
if (!strengthened_ && sender.Get() &&
sender.Get()->team_id == obstacle->GetTeamId(room)) {
bool ret = Check2dRotationRectangle
(GetPos().x,
GetPos().y,
gun_meta->pb->bullet_rad(),
obstacle->GetPos().x,
obstacle->GetPos().y,
obstacle->meta->pb->width(),
obstacle->meta->pb->height(),
obstacle->GetRotate() * 180.0f
);
if (ret) {
strengthened_ = true;
OnStrengthen(obstacle);
#ifdef DEBUG
a8::XPrintf("命中能量墙\n", {});
#endif
}
}
}
}
}
}
bool eat = false;
if (o_hit_num <= 0) {
room->grid_service->TraverseCreatures
(room->GetRoomIdx(),
GetGridList(),
[this, &objects, &c_hit_num, &eat] (Creature* c, bool& stop)
{
if (sender.Get()->IsProperTarget(c)) {
if (gun_meta->pb->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()) {
// 999
#if 1
#else
//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->pb->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;
}
#endif
}
}
AabbCollider aabb_box;
c->GetHitAabbBox(aabb_box);
if (c != sender.Get() && !c->dead && TestCollision(room, &aabb_box)) {
if (bullet_meta->pb->_inventory_slot() == IS_C4) {
if (!c->IsHuman()) {
objects.insert(c);
if (gun_meta->pb->ispenetrate()) {
++c_hit_num;
hit_objects_.insert(c->GetUniId());
}
}
} else {
objects.insert(c);
if (gun_meta->pb->ispenetrate()) {
++c_hit_num;
hit_objects_.insert(c->GetUniId());
}
}
}
}
});
}
float bullet_range = gun_meta->pb->range();
if (!objects.empty() || (!IsBomb() && distance > bullet_range)) {
if (IsBomb()) {
ForceRemove();
} else {
bool hited = false;
if (!eat && !objects.empty()) {
hited = true;
OnHit(objects);
}
bool need_remove = true;
if (distance < bullet_range) {
if (!gun_meta->pb->is_penetrate_thing() && !gun_meta->pb->ispenetrate()) {
} else {
if ((!gun_meta->pb->is_penetrate_thing() && (t_hit_num > 0)) ||
(!gun_meta->pb->ispenetrate() && (c_hit_num > 0))) {
} else {
need_remove = false;
}
}
}
if (need_remove) {
ForceRemove();
}
}
}
}
void VirtualBullet::ForceRemove()
{
if (!later_removed_) {
later_removed_ = true;
}
}
void VirtualBullet::OnHit(std::set<Entity*>& objects)
{
std::shared_ptr<Ability> old_context_ability = sender.Get()->context_ability;
a8::Vec2 old_context_dir = sender.Get()->context_dir;
Position old_context_pos = sender.Get()->context_pos;
sender.Get()->context_dir = dir;
sender.Get()->context_pos = GetPos();
for (auto& target : objects) {
bool old_is_dead = target->IsDead(room);
target->OnBulletHit(this);
if (target->IsDead(room) && !old_is_dead) {
OnKillTarget(target);
}
}
sender.Get()->context_dir = old_context_dir;
sender.Get()->context_pos = old_context_pos;
sender.Get()->context_ability = old_context_ability;
}
void VirtualBullet::Init()
{
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, grid_list_);
}
bool VirtualBullet::TestCollision(Room* room, ColliderComponent* b)
{
CircleCollider collider;
collider.rad = gun_meta->pb->bullet_rad();
return b->IntersectEx(GetPos().ToVec2(), &collider);
}
void VirtualBullet::OnStrengthen(Obstacle* ob)
{
if (ob->IsRoomObstacle()) {
RoomObstacle* room_ob = ob->AsRoomObstacle();
if (room_ob->skill_meta) {
MetaData::Skill* skill_meta = room_ob->skill_meta;
if (skill_meta && skill_meta->number_meta) {
switch (skill_meta->GetMagicId()) {
case MAGIC_WLFB:
{
strengthen_wall = skill_meta->number_meta->float_ratio2;
}
break;
default:
{
}
break;
}
}
}
}
}
void VirtualBullet::OnKillTarget(Entity* target)
{
if (target->IsCreature(room)) {
Creature* c = (Creature*)target;
if (c->IsHuman() && sender.Get() && sender.Get()->IsHuman()) {
sender.Get()->AsHuman()->stats.IncWeaponKills(gun_meta->pb->id(), 1);
}
}
}