game2006/server/gameserver/explosion.cc
aozhiwei ff6f1cd69f 1
2022-10-06 16:23:21 +08:00

178 lines
5.0 KiB
C++

#include "precompile.h"
#include "explosion.h"
#include "creature.h"
#include "room.h"
enum ExplosionType_e
{
kExplosionIndifference = 1,
kExplosionEnemyAndObstacle = 2
};
Explosion::~Explosion()
{
int i = 0;
}
void Explosion::IndifferenceAttack(Room* room,
const a8::Vec2& center,
float explosion_range,
int explosion_effect,
float dmg,
long long special_damage_type)
{
type_ = kExplosionIndifference;
room_ = room;
explosion_range_ = explosion_range;
explosion_effect_ = explosion_effect;
dmg_ = dmg;
center_ = center;
special_damage_type_ = special_damage_type;
create_frameno_ = room_->GetFrameNo();
InternalAttack();
}
void Explosion::EnemyAndObstacleAttack(CreatureWeakPtr& sender,
const a8::Vec2& center,
float explosion_range,
int explosion_effect,
float dmg,
long long special_damage_type)
{
if (!sender.Get()) {
return;
}
type_ = kExplosionEnemyAndObstacle;
room_ = sender.Get()->room;
sender_ = sender;
explosion_range_ = explosion_range;
explosion_effect_ = explosion_effect;
dmg_ = dmg;
center_ = center;
special_damage_type_ = special_damage_type;
create_frameno_ = room_->GetFrameNo();
InternalAttack();
}
void Explosion::ProcDamage()
{
std::set<GridCell*> grid_list;
room_->grid_service->GetAllCellsByXy
(
room_,
center_.x,
center_.y,
grid_list
);
std::set<Entity*> objects;
room_->grid_service->TraverseCreatures
(
room_->GetRoomIdx(),
grid_list,
[this, &objects] (Creature* c, bool& stop)
{
if (c->dead) {
return;
}
if (c->GetUniId() == exclude_uniid) {
return;
}
if (!c->Attackable(room_)) {
return;
}
if (!c->ReceiveExplosionDmg(this)) {
return;
}
if (type_ == kExplosionEnemyAndObstacle) {
if (sender_.Get() && sender_.Get()->IsProperTarget(c)) {
if (center_.Distance(c->GetPos()) < explosion_range_) {
objects.insert(c);
}
}
} else {
if (center_.Distance(c->GetPos()) < explosion_range_) {
objects.insert(c);
}
}
}
);
room_->grid_service->TraverseAllLayerEntityList
(
room_->GetRoomIdx(),
grid_list,
[this, &objects] (Entity* entity, bool& stop)
{
if (entity->GetUniId() == exclude_uniid) {
return;
}
if (!entity->Attackable(room_)) {
return;
}
if (!entity->ReceiveExplosionDmg(this)) {
return;
}
if (center_.Distance(entity->GetPos()) < explosion_range_) {
objects.insert(entity);
}
}
);
if (force_target_.Get() && objects.find(force_target_.Get()) == objects.end()) {
objects.insert(force_target_.Get());
}
for (auto& target : objects) {
if (target->IsCreature(room_) && ((Creature*)target)->HasBuffEffect(kBET_BulletThrough)) {
continue;
}
target->OnExplosionHit(this);
if (hit_cb_) {
hit_cb_({target});
}
}
}
void Explosion::InternalAttack()
{
if (explosion_range_ <= 0) {
return;
}
room_->frame_event.AddExplosionEx
(sender_,
0,
center_,
explosion_effect_);
if (explosion_damage_delay_ <= 0) {
ProcDamage();
} else {
auto self = new std::shared_ptr<Explosion>();
*self = shared_from_this();
room_->xtimer.AddDeadLineTimerAndAttach
(explosion_damage_delay_ / FRAME_RATE_MS,
a8::XParams()
.SetSender(self),
[] (const a8::XParams& param)
{
auto self = (std::shared_ptr<Explosion>*)param.sender.GetUserData();
(*self)->ProcDamage();
},
&room_->xtimer_attacher_.timer_list_,
[] (const a8::XParams& param)
{
auto self = (std::shared_ptr<Explosion>*)param.sender.GetUserData();
delete self;
});
}
}
bool Explosion::IsPreBattleExplosion()
{
return create_frameno_ <= room_->GetBattleStartFrameNo() ||
room_->GetBattleStartFrameNo() == 0;
}
void Explosion::AddForceTarget(CreatureWeakPtr force_target)
{
force_target_ = force_target;
}