318 lines
9.1 KiB
C++
318 lines
9.1 KiB
C++
#include "precompile.h"
|
|
|
|
#include "virtualbullet.h"
|
|
#include "room.h"
|
|
#include "mapservice.h"
|
|
#include "gridservice.h"
|
|
#include "creature.h"
|
|
#include "collision.h"
|
|
#include "roomobstacle.h"
|
|
#include "human.h"
|
|
#include "mt/Param.h"
|
|
#include "mt/Buff.h"
|
|
#include "mt/Skill.h"
|
|
#include "mt/SkillNumber.h"
|
|
#include "mt/Equip.h"
|
|
#include "mt/MapThing.h"
|
|
|
|
float VirtualBullet::GetStrengthenWall()
|
|
{
|
|
return strengthened_;
|
|
}
|
|
|
|
long long VirtualBullet::GetWeaponUniId()
|
|
{
|
|
return weapon_uniid;
|
|
}
|
|
|
|
const mt::Skill* VirtualBullet::GetSkillMeta()
|
|
{
|
|
return skill_meta;
|
|
}
|
|
|
|
const mt::Equip* VirtualBullet::GetGunMeta()
|
|
{
|
|
return gun_meta;
|
|
}
|
|
|
|
const mt::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->bullet_speed() / (float)SERVER_FRAME_RATE;
|
|
do {
|
|
float step_len = move_length - mt::Param::s().bullet_planck_step_length;
|
|
if (step_len <= 0.001f) {
|
|
if (move_length > 0.1f) {
|
|
step_len = move_length;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
move_length -= step_len;
|
|
GetMutablePos().AddGlmVec3(dir * step_len);
|
|
float distance = GetPos().DistanceGlmVec3(born_pos.ToGlmVec3());
|
|
if (room->OverBorder(GetPos(), gun_meta->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)
|
|
{
|
|
BulletCheckResult result;
|
|
result.flyed_distance = distance;
|
|
GetHitThings(result);
|
|
if (result.o_hit_num <= 0) {
|
|
GetHitCreatures(result);
|
|
}
|
|
#if 0
|
|
float bullet_range = gun_meta->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->is_penetrate_thing() && !gun_meta->ispenetrate()) {
|
|
} else {
|
|
if ((!gun_meta->is_penetrate_thing() && (t_hit_num > 0)) ||
|
|
(!gun_meta->ispenetrate() && (c_hit_num > 0))) {
|
|
} else {
|
|
need_remove = false;
|
|
}
|
|
}
|
|
}
|
|
if (need_remove) {
|
|
ForceRemove();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
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;
|
|
glm::vec3 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_);
|
|
}
|
|
|
|
void VirtualBullet::OnStrengthen(Obstacle* ob)
|
|
{
|
|
if (ob->IsRoomObstacle()) {
|
|
RoomObstacle* room_ob = ob->AsRoomObstacle();
|
|
if (room_ob->skill_meta) {
|
|
const mt::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->id(), 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void VirtualBullet::GetHitThings(BulletCheckResult& result)
|
|
{
|
|
#if 0
|
|
std::set<ColliderComponent*> colliders;
|
|
room->map_service->GetColliders(room, GetPos().GetX(), GetPos().GetY(), colliders);
|
|
for (ColliderComponent* collider : colliders) {
|
|
if (collider->owner->IsEntityType(ET_Dummy)) {
|
|
if (a8::HasBitFlag(collider->tag, kHalfWallTag)) {
|
|
continue;
|
|
}
|
|
if (TestCollision(room, collider)) {
|
|
++result.o_hit_num;
|
|
result.objects.insert(collider->owner);
|
|
}
|
|
} else if (collider->owner->IsEntityType(ET_Obstacle)) {
|
|
Obstacle* obstacle = (Obstacle*)collider->owner;
|
|
if (gun_meta->is_penetrate_thing() &&
|
|
hit_objects_.find(obstacle->GetUniId()) != hit_objects_.end()) {
|
|
//穿物件
|
|
continue;
|
|
}
|
|
if (!obstacle->CanThroughable(this)) {
|
|
if (TestCollision(room, collider)) {
|
|
result.objects.insert(collider->owner);
|
|
if (gun_meta->is_penetrate_thing()) {
|
|
++result.t_hit_num;
|
|
++result.o_hit_num;
|
|
hit_objects_.insert(collider->owner->GetUniId());
|
|
}
|
|
}
|
|
} else if (obstacle->meta->thing_type() == kObstacleStrengthenWall) {
|
|
if (!strengthened_ && sender.Get() &&
|
|
sender.Get()->team_id == obstacle->GetTeamId(room)) {
|
|
bool ret = Check2dRotationRectangle
|
|
(GetPos().x,
|
|
GetPos().y,
|
|
gun_meta->bullet_rad(),
|
|
obstacle->GetPos().x,
|
|
obstacle->GetPos().y,
|
|
obstacle->meta->width(),
|
|
obstacle->meta->height(),
|
|
obstacle->GetRotate() * 180.0f
|
|
);
|
|
if (ret) {
|
|
strengthened_ = true;
|
|
OnStrengthen(obstacle);
|
|
#ifdef DEBUG
|
|
a8::XPrintf("命中能量墙\n", {});
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void VirtualBullet::GetHitCreatures(BulletCheckResult& result)
|
|
{
|
|
room->grid_service->TraverseCreatures
|
|
(room->GetRoomIdx(),
|
|
GetGridList(),
|
|
[this, &result] (Creature* c, bool& stop)
|
|
{
|
|
bool no_teammate = false;
|
|
if (sender.Get()->IsProperTarget(c, no_teammate)) {
|
|
if (gun_meta->ispenetrate() &&
|
|
hit_objects_.find(c->GetUniId()) != hit_objects_.end()) {
|
|
//穿人
|
|
return;
|
|
}
|
|
if (c->HasBuffEffect(kBET_BulletThrough)) {
|
|
return;
|
|
}
|
|
if (c->HasBuffEffect(kBET_HoldShield)) {
|
|
c->CheckBulletHitHoldShield(this, result.eat);
|
|
if (result.eat) {
|
|
stop = true;
|
|
return;
|
|
}
|
|
}
|
|
if (c != sender.Get() && !c->dead &&
|
|
Collision::CheckBullet(this, c)) {
|
|
if (bullet_meta->_inventory_slot() == IS_C4) {
|
|
if (!c->IsHuman()) {
|
|
result.objects.insert(c);
|
|
if (gun_meta->ispenetrate()) {
|
|
++result.c_hit_num;
|
|
hit_objects_.insert(c->GetUniId());
|
|
}
|
|
}
|
|
} else {
|
|
result.objects.insert(c);
|
|
if (gun_meta->ispenetrate()) {
|
|
++result.c_hit_num;
|
|
hit_objects_.insert(c->GetUniId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
float VirtualBullet::GetHitRadius()
|
|
{
|
|
return gun_meta->bullet_rad();
|
|
}
|