2019-04-19 11:24:11 +08:00

170 lines
5.5 KiB
C++

#include "precompile.h"
#include "bullet.h"
#include "metamgr.h"
#include "room.h"
#include "collider.h"
#include "obstacle.h"
#include "player.h"
Bullet::Bullet():Entity()
{
entity_type = ET_Bullet;
}
Bullet::~Bullet()
{
}
void Bullet::Initialize()
{
Entity::Initialize();
RecalcSelfCollider();
}
void Bullet::Update(int delta_time)
{
pos = pos + dir * gun_meta->i->bullet_speed() / 20.0f;
float distance = (pos - born_pos).Norm();
if (meta->i->_inventory_slot() == 5 ||
meta->i->_inventory_slot() == 6) {
std::vector<Entity*> objects;
int detection_flags = 0;
{
a8::SetBitFlag(detection_flags, ET_Obstacle);
a8::SetBitFlag(detection_flags, ET_Building);
}
room->CollisionDetection(this, detection_flags, objects);
if (!objects.empty() || distance >= fly_distance) {
ProcBomb();
}
} else {
std::vector<Entity*> objects;
int detection_flags = 0;
{
a8::SetBitFlag(detection_flags, ET_Obstacle);
a8::SetBitFlag(detection_flags, ET_Player);
}
room->CollisionDetection(this, detection_flags, objects);
if (!objects.empty() || distance > gun_meta->i->range()) {
deleted = true;
if (!objects.empty()) {
OnHit(objects);
}
room->AddDeletedObject(entity_uniid, true);
}
}
}
void Bullet::RecalcSelfCollider()
{
if (!self_collider_) {
self_collider_ = new CircleCollider();
self_collider_->owner = this;
colliders.push_back(self_collider_);
}
self_collider_->pos = Vector2D();
self_collider_->rad = gun_meta->i->bullet_rad();
}
void Bullet::OnHit(std::vector<Entity*>& objects)
{
for (auto& target : objects) {
switch (target->entity_type) {
case ET_Player:
{
Human* hum = (Human*)target;
#if 1
if (!hum->dead) {
#else
if (!hum->dead && (hum->team_id == 0 || hum->team_id != player->team_id)) {
#endif
player->stats.damage_amount += 10;
hum->DecHP(10, player->entity_uniid, player->name);
}
}
break;
case ET_Obstacle:
{
Obstacle* obstacle = (Obstacle*)target;
if (!obstacle->dead && obstacle->meta->i->attack_type() == 1) {
obstacle->health = std::max(0.0f, obstacle->health - 10);
obstacle->dead = obstacle->health <= 0.01f;
obstacle->dead_frameno = room->frame_no;
if (obstacle->dead) {
obstacle->ClearColliders();
room->ScatterDrop(obstacle->pos, obstacle->meta->i->drop());
}
room->TouchPlayerList(a8::XParams()
.SetSender(obstacle),
[] (Player* hum, a8::XParams& param)
{
Obstacle* obstacle = (Obstacle*)param.sender.GetUserData();
hum->AddToNewObjects(obstacle);
});
}
}
break;
default:
break;
}
}
}
void Bullet::ProcBomb()
{
switch (meta->i->_inventory_slot()) {
case 5:
{
//手雷
::google::protobuf::RepeatedPtrField<::cs::MFExplosion>* explosions = nullptr;
{
auto itr = room->frame_data.explosions_hash.find(room->frame_no);
if (itr == room->frame_data.explosions_hash.end()) {
room->frame_data.explosions_hash[room->frame_no] = ::google::protobuf::RepeatedPtrField<::cs::MFExplosion>();
itr = room->frame_data.explosions_hash.find(room->frame_no);
}
explosions = &itr->second;
}
#if 1
Vector2D bomb_pos = pos;
#else
float distance = (pos - born_pos).Norm();
Vector2D bomb_pos = born_pos + born_dir * distance;
#endif
cs::MFExplosion* explosion = explosions->Add();
explosion->set_item_id(meta->i->id());
bomb_pos.ToPB(explosion->mutable_pos());
explosion->set_player_id(player->entity_uniid);
}
break;
case 6:
{
//烟雾弹
::google::protobuf::RepeatedPtrField<::cs::MFSmoke>* smokes = nullptr;
{
auto itr = room->frame_data.smokes_hash.find(room->frame_no);
if (itr == room->frame_data.smokes_hash.end()) {
room->frame_data.smokes_hash[room->frame_no] = ::google::protobuf::RepeatedPtrField<::cs::MFSmoke>();
itr = room->frame_data.smokes_hash.find(room->frame_no);
}
smokes = &itr->second;
}
#if 1
Vector2D bomb_pos = pos;
#else
float distance = (pos - born_pos).Norm();
Vector2D bomb_pos = born_pos + born_dir * distance;
#endif
cs::MFSmoke* smoke = smokes->Add();
smoke->set_item_id(meta->i->id());
bomb_pos.ToPB(smoke->mutable_pos());
smoke->set_player_id(player->entity_uniid);
}
break;
}
room->AddDeletedObject(entity_uniid, true);
}