248 lines
9.8 KiB
C++
248 lines
9.8 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 = kET_Bullet;
|
|
++App::Instance()->perf.entity_num[kET_Bullet];
|
|
}
|
|
|
|
Bullet::~Bullet()
|
|
{
|
|
--App::Instance()->perf.entity_num[kET_Bullet];
|
|
}
|
|
|
|
void Bullet::Initialize()
|
|
{
|
|
Entity::Initialize();
|
|
}
|
|
|
|
void Bullet::Update(int delta_time)
|
|
{
|
|
if (dead) {
|
|
return;
|
|
}
|
|
pos = pos + dir * meta->i->bullet_speed() / (float)kSERVER_FRAME_RATE;
|
|
float distance = (pos - born_pos).Norm();
|
|
if (room->OverBorder(pos, meta->i->bullet_rad())) {
|
|
PostAttack();
|
|
room->RemoveObjectLater(this);
|
|
} else {
|
|
room->grid_service.MoveBullet(this);
|
|
CircleCollider bullet_collider;
|
|
bullet_collider.owner = this;
|
|
bullet_collider.rad = meta->i->bullet_rad();
|
|
std::set<Entity*> objects;
|
|
for (auto& grid : grid_list) {
|
|
for (Human* hum: grid->human_list) {
|
|
if (hum != master && !hum->dead &&
|
|
(hum->team_id == 0 || master->team_id != hum->team_id)) {
|
|
if (hum->TestCollision(&bullet_collider)) {
|
|
if (meta->i->is_through()) {
|
|
//可穿透
|
|
if (hited_humans_.find(hum) == hited_humans_.end()) {
|
|
hited_humans_.insert(hum);
|
|
objects.insert(hum);
|
|
}
|
|
} else {
|
|
objects.insert(hum);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}//end for
|
|
float bullet_range = meta->i->range() + master->ability.shot_range + master->BuffAttrAbs(kHAT_ShotRange);
|
|
if (!meta->i->is_through()) {
|
|
std::set<ColliderComponent*> colliders;
|
|
room->map_service.GetColliders(pos.x, pos.y, colliders);
|
|
for (ColliderComponent* collider : colliders) {
|
|
if (collider->Intersect(&bullet_collider)) {
|
|
objects.insert(collider->owner);
|
|
}
|
|
}
|
|
if (!objects.empty() || distance > bullet_range ) {
|
|
deleted = true;
|
|
if (!objects.empty()) {
|
|
OnHit(objects);
|
|
}
|
|
PostAttack();
|
|
room->RemoveObjectLater(this);
|
|
}
|
|
} else {
|
|
if (!objects.empty()) {
|
|
OnHit(objects);
|
|
}
|
|
if (distance > bullet_range ) {
|
|
deleted = true;
|
|
PostAttack();
|
|
room->RemoveObjectLater(this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Bullet::OnHit(std::set<Entity*>& objects)
|
|
{
|
|
for (auto& target : objects) {
|
|
switch (target->entity_type) {
|
|
case kET_Player:
|
|
{
|
|
Human* hum = (Human*)target;
|
|
if (hum->HasBuffEffect(kBET_Invincible)) {
|
|
continue;
|
|
}
|
|
#if 1
|
|
if (!hum->dead) {
|
|
#else
|
|
if (hum != player && !hum->dead &&
|
|
(hum->team_id == 0 || master->team_id != hum->team_id)) {
|
|
#endif
|
|
float power = meta->i->atk() + master->ability.atk;
|
|
float def = hum->ability.def;
|
|
float finaly_dmg = power * (1 - def/MetaMgr::Instance()->K);
|
|
master->stats.damage_amount_out += finaly_dmg;
|
|
hum->OnHit();
|
|
if (!hum->HasBuffEffect(kBET_Invincible)) {
|
|
if (skill_id != 0) {
|
|
master->TriggerOneObjectBuff(hum, kBTT_SkillHit);
|
|
}
|
|
hum->DecHP(finaly_dmg, master->entity_uniid, master->name, meta->i->id());
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case kET_Obstacle:
|
|
{
|
|
Obstacle* obstacle = (Obstacle*)target;
|
|
if (!obstacle->dead && obstacle->meta->i->attack_type() == 1) {
|
|
float dmg = meta->i->atk() + master->ability.atk;
|
|
float def = 0;
|
|
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
|
|
#if 0
|
|
master->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->frameno;
|
|
if (obstacle->dead) {
|
|
if (obstacle->meta->i->damage_dia() > 0.01f &&
|
|
obstacle->meta->i->damage() > 0.01f) {
|
|
obstacle->Explosion();
|
|
}
|
|
room->ScatterDrop(obstacle->pos, obstacle->meta->i->drop());
|
|
}
|
|
obstacle->BroadcastFullState();
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Bullet::PostAttack()
|
|
{
|
|
dead = true;
|
|
auto fire_func =
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Obstacle* obstacle = (Obstacle*)param.sender.GetUserData();
|
|
Human* sender = (Human*)param.param1.GetUserData();
|
|
if (obstacle->room->IsGameOver()) {
|
|
return;
|
|
}
|
|
std::set<GridCell*> grid_list;
|
|
obstacle->room->grid_service.GetAllCellsByXy(obstacle->pos.x, obstacle->pos.y, grid_list);
|
|
for (auto& grid : grid_list) {
|
|
for (Human* hum: grid->human_list) {
|
|
if (hum->pos.Distance(obstacle->pos) < obstacle->meta->i->damage_dia()) {
|
|
hum->OnHit();
|
|
if (!hum->HasBuffEffect(kBET_Invincible)) {
|
|
float power = obstacle->meta->i->damage() + sender->ability.atk;
|
|
float def = hum->ability.def;
|
|
float finally_dmg = power * (1 - def/MetaMgr::Instance()->K);
|
|
sender->stats.damage_amount_out += finally_dmg;
|
|
hum->DecHP(finally_dmg, sender->entity_uniid, sender->name, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if (meta->i->equip_subtype() == kBulletType_FireBomb) {
|
|
//燃烧弹火墙
|
|
Obstacle* obstacle = room->CreateObstacle(kFIRE_WALL_EQUIP_ID, pos.x, pos.y);
|
|
if (obstacle) {
|
|
room->xtimer.AddDeadLineTimerAndAttach(kSERVER_FRAME_RATE,
|
|
a8::XParams()
|
|
.SetSender(obstacle)
|
|
.SetParam1(master),
|
|
fire_func,
|
|
&obstacle->xtimer_attacher.timer_list_);
|
|
room->xtimer.AddDeadLineTimerAndAttach(meta->i->time() * kSERVER_FRAME_RATE,
|
|
a8::XParams()
|
|
.SetSender(obstacle),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Obstacle* obstacle = (Obstacle*)param.sender.GetUserData();
|
|
obstacle->NotifyDelObject();
|
|
obstacle->room->RemoveObjectLater(obstacle);
|
|
},
|
|
&obstacle->xtimer_attacher.timer_list_);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Bullet::ProcMissible(const a8::XParams& param)
|
|
{
|
|
Human* sender = (Human*)param.sender.GetUserData();
|
|
MetaData::Equip* bullet_meta = MetaMgr::Instance()->GetEquip(param.param1);
|
|
if (sender && bullet_meta && !sender->room->IsGameOver()) {
|
|
a8::Vec2 src_pos(a8::Low32(param.param3.GetInt64()), a8::High32(param.param3.GetInt64()));
|
|
Human* target = sender->room->GetHumanByUniId(param.param2);
|
|
if (target && !target->dead) {
|
|
if (bullet_meta->i->equip_subtype() == kBulletType_Trace) {
|
|
float bullet_range = bullet_meta->i->range() +
|
|
sender->ability.shot_range +
|
|
sender->BuffAttrAbs(kHAT_ShotRange);
|
|
if (src_pos.Distance(target->pos) < bullet_range) {
|
|
target->OnHit();
|
|
if (!target->HasBuffEffect(kBET_Invincible)) {
|
|
float power = bullet_meta->i->atk() + sender->ability.atk;
|
|
float def = target->ability.def;
|
|
float finally_dmg = power * (1 - def/MetaMgr::Instance()->K);
|
|
sender->stats.damage_amount_out += finally_dmg;
|
|
target->DecHP(finally_dmg,
|
|
sender->entity_uniid,
|
|
sender->name,
|
|
bullet_meta->i->id()
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
target->OnHit();
|
|
if (!target->HasBuffEffect(kBET_Invincible)) {
|
|
float power = bullet_meta->i->atk() + sender->ability.atk;
|
|
float def = target->ability.def;
|
|
float finally_dmg = power * (1 - def/MetaMgr::Instance()->K);
|
|
sender->stats.damage_amount_out += finally_dmg;
|
|
target->DecHP(finally_dmg,
|
|
sender->entity_uniid,
|
|
sender->name,
|
|
bullet_meta->i->id()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|