244 lines
7.6 KiB
C++
244 lines
7.6 KiB
C++
#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<Entity*>& objects)
|
|
{
|
|
for (auto& target : objects) {
|
|
switch (target->entity_type) {
|
|
case ET_Player:
|
|
{
|
|
if (App::Instance()->HasFlag(8)) {
|
|
return;
|
|
}
|
|
Human* hum = (Human*)target;
|
|
#if 1
|
|
if (!hum->dead && (IsBomb() || player->team_id != hum->team_id)) {
|
|
#else
|
|
if (hum != player && !hum->dead &&
|
|
(hum->team_id == 0 || player->team_id != hum->team_id)) {
|
|
#endif
|
|
#if 1
|
|
float dmg = gun_meta->i->atk() * (1 + player->atk_add);
|
|
#else
|
|
float dmg = gun_meta->i->atk() * (1 + player->buff.damage_add + player->atk_add);
|
|
#endif
|
|
#if 1
|
|
float def = hum->ability.def;
|
|
#else
|
|
float def = hum->def + hum->buff.def_add;
|
|
#endif
|
|
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) {
|
|
#if 1
|
|
float dmg = gun_meta->i->atk() * (1 + player->atk_add);
|
|
#else
|
|
float dmg = gun_meta->i->atk() * (1 + player->buff.damage_add + player->atk_add);
|
|
#endif
|
|
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->GetPos(), obstacle->meta->i->drop());
|
|
}
|
|
obstacle->BroadcastFullState();
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Bullet::ProcBomb()
|
|
{
|
|
self_collider_->rad = gun_meta->i->explosion_range();
|
|
std::set<Entity*> objects;
|
|
for (auto& grid : grid_list) {
|
|
for (Human* hum: grid->human_list) {
|
|
if (!is_tank_skin || player->team_id != hum->team_id) {
|
|
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
|
|
|
|
switch (meta->i->_inventory_slot()) {
|
|
case 4:
|
|
{
|
|
//榴弹炮
|
|
a8::Vec2 bomb_pos = GetPos();
|
|
room->frame_event.AddExplosionEx(player, 0, bomb_pos, 0);
|
|
OnHit(objects);
|
|
}
|
|
break;
|
|
case 5:
|
|
{
|
|
//手雷
|
|
a8::Vec2 bomb_pos = GetPos();
|
|
room->frame_event.AddExplosion(this, meta->i->id(), bomb_pos);
|
|
OnHit(objects);
|
|
}
|
|
break;
|
|
case 6:
|
|
{
|
|
//烟雾弹
|
|
a8::Vec2 bomb_pos = GetPos();
|
|
room->frame_event.AddSmoke(this, meta->i->id(), bomb_pos);
|
|
}
|
|
break;
|
|
}
|
|
room->RemoveObjectLater(this);
|
|
}
|
|
|
|
bool Bullet::IsBomb()
|
|
{
|
|
return
|
|
meta->i->_inventory_slot() == 4 ||
|
|
meta->i->_inventory_slot() == 5 ||
|
|
meta->i->_inventory_slot() == 6;
|
|
}
|
|
|
|
void Bullet::MapServiceUpdate()
|
|
{
|
|
SetPos(GetPos() + dir * gun_meta->i->bullet_speed() / (float)SERVER_FRAME_RATE);
|
|
float distance = (GetPos() - born_pos).Norm();
|
|
if (room->OverBorder(GetPos(), gun_meta->i->bullet_rad())) {
|
|
if (IsBomb()) {
|
|
ProcBomb();
|
|
} else {
|
|
room->RemoveObjectLater(this);
|
|
}
|
|
} else {
|
|
room->grid_service.MoveBullet(this);
|
|
std::set<Entity*> objects;
|
|
for (auto& grid : grid_list) {
|
|
for (Human* hum: grid->human_list) {
|
|
#if 1
|
|
if (hum != player && !hum->dead && TestCollision(hum)) {
|
|
objects.insert(hum);
|
|
}
|
|
#else
|
|
if (hum != player && !hum->dead &&
|
|
(hum->team_id == 0 || player->team_id != hum->team_id)) {
|
|
if (TestCollision(hum)) {
|
|
objects.insert(hum);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}//end for
|
|
#if 1
|
|
{
|
|
std::set<ColliderComponent*> colliders;
|
|
room->map_service.GetColliders(GetX(), GetY(), 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 (!objects.empty() || distance > bullet_range ||
|
|
(IsBomb() && meta->i->_inventory_slot() != 4 && distance >= fly_distance)
|
|
) {
|
|
if (IsBomb()) {
|
|
ProcBomb();
|
|
} else {
|
|
deleted = true;
|
|
if (!objects.empty()) {
|
|
OnHit(objects);
|
|
}
|
|
room->RemoveObjectLater(this);
|
|
}
|
|
}
|
|
}
|
|
}
|