446 lines
14 KiB
C++
446 lines
14 KiB
C++
#include "precompile.h"
|
|
|
|
#include "metamgr.h"
|
|
#include "room.h"
|
|
#include "collider.h"
|
|
#include "building.h"
|
|
#include "human.h"
|
|
#include "app.h"
|
|
#include "typeconvert.h"
|
|
#include "bullet.h"
|
|
#include "mapservice.h"
|
|
#include "roomobstacle.h"
|
|
|
|
RoomObstacle::RoomObstacle():Obstacle()
|
|
{
|
|
}
|
|
|
|
RoomObstacle::~RoomObstacle()
|
|
{
|
|
for (auto& itr : colliders_) {
|
|
ColliderComponent* collider = itr;
|
|
#ifdef DEBUG
|
|
#if 0
|
|
a8::UdpLog::Instance()->Debug("OnRemoveCollider %d %d %d",
|
|
{
|
|
room->GetRoomIdx(),
|
|
GetEntityUniId(),
|
|
(long long)collider
|
|
});
|
|
#endif
|
|
#endif
|
|
room->map_service->RemoveCollider(collider);
|
|
}
|
|
if (!grid_list_) {
|
|
A8_SAFE_DELETE(grid_list_);
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::Initialize()
|
|
{
|
|
Obstacle::Initialize();
|
|
xtimer_attacher.xtimer = &room->xtimer;
|
|
}
|
|
|
|
void RoomObstacle::RecalcSelfCollider()
|
|
{
|
|
if (!Throughable()){
|
|
switch (meta->i->type()) {
|
|
case 1:
|
|
{
|
|
if (!self_collider_) {
|
|
self_collider_ = new CircleCollider();
|
|
self_collider_->owner = this;
|
|
AddEntityCollider(self_collider_);
|
|
}
|
|
self_collider_->pos = a8::Vec2();
|
|
self_collider_->rad = meta->i->height() / 2.0;
|
|
room->map_service->AddCollider(self_collider_);
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
if (!self_collider2_) {
|
|
self_collider2_ = new AabbCollider();
|
|
self_collider2_->owner = this;
|
|
AddEntityCollider(self_collider2_);
|
|
}
|
|
self_collider2_->_min = a8::Vec2(meta->i->width() / -2.0f, meta->i->height() / -2.0f);
|
|
self_collider2_->_max = a8::Vec2(meta->i->width() / 2.0f, meta->i->height() / 2.0f);
|
|
room->map_service->AddCollider(self_collider2_);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (!self_collider_) {
|
|
#ifdef DEBUG
|
|
#if 0
|
|
a8::UdpLog::Instance()->Debug("OnAddCollider %d %d %d",
|
|
{
|
|
room->GetRoomIdx(),
|
|
GetEntityUniId(),
|
|
(long long)self_collider_
|
|
});
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
bool RoomObstacle::CanThroughable(Human* hum)
|
|
{
|
|
if (master.Get()) {
|
|
return master.Get()->team_id == hum->team_id && temp_through_;
|
|
} else {
|
|
return temp_through_;
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::ActiveTimerFunc()
|
|
{
|
|
if (!master.Get()) {
|
|
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
|
|
return;
|
|
}
|
|
if (!grid_list_) {
|
|
temp_through_ = true;
|
|
grid_list_ = new std::set<GridCell*>();
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, *grid_list_);
|
|
}
|
|
bool has_hum = false;
|
|
room->grid_service->TraverseAllLayerHumanList
|
|
(room->GetRoomIdx(),
|
|
*grid_list_,
|
|
[this, &has_hum] (Human* hum, bool& stop)
|
|
{
|
|
bool old_temp_through = temp_through_;
|
|
temp_through_ = false;
|
|
if (master.Get()->team_id == hum->team_id) {
|
|
if (TestCollision(room, hum)) {
|
|
has_hum = true;
|
|
stop = true;
|
|
}
|
|
}
|
|
temp_through_ = old_temp_through;
|
|
}
|
|
);
|
|
if (!has_hum) {
|
|
temp_through_ = false;
|
|
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::UpdateTimerFunc()
|
|
{
|
|
if (!grid_list_) {
|
|
grid_list_ = new std::set<GridCell*>();
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, *grid_list_);
|
|
}
|
|
if (grid_list_ && master.Get() && !IsDead(room)) {
|
|
std::set<Human*> human_list;
|
|
room->grid_service->TraverseAllLayerHumanList
|
|
(room->GetRoomIdx(),
|
|
*grid_list_,
|
|
[this, &human_list] (Human* hum, bool& stop)
|
|
{
|
|
if (master.Get()->team_id != hum->team_id && TestCollision(room, hum)) {
|
|
human_list.insert(hum);
|
|
}
|
|
}
|
|
);
|
|
if (!human_list.empty()) {
|
|
for (Human* hum : human_list) {
|
|
for (int buff_id : meta->buff_list) {
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(buff_id);
|
|
if (buff_meta) {
|
|
hum->AddBuff(master.Get(),
|
|
buff_meta,
|
|
1);
|
|
}
|
|
}
|
|
}
|
|
Explosion();
|
|
Die(room);
|
|
BroadcastFullState(room);
|
|
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
|
|
}
|
|
} else {
|
|
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::Explosion()
|
|
{
|
|
float old_rad = self_collider_->rad;
|
|
if (self_collider_) {
|
|
self_collider_->rad = meta->i->damage_dia();
|
|
}
|
|
if (meta->i->damage_dia() > 0.01f &&
|
|
meta->i->damage() > 0.01f) {
|
|
std::set<Entity*> objects;
|
|
room->grid_service->TraverseAllLayerHumanList
|
|
(
|
|
room->GetRoomIdx(),
|
|
*grid_list_,
|
|
[this, &objects] (Human* hum, bool& stop)
|
|
{
|
|
if (master.Get()->team_id != hum->team_id && TestCollision(room, hum)) {
|
|
objects.insert(hum);
|
|
}
|
|
});
|
|
room->grid_service->TraverseAllLayerEntityList
|
|
(
|
|
room->GetRoomIdx(),
|
|
*grid_list_,
|
|
[this, &objects] (Entity* entity, bool& stop)
|
|
{
|
|
switch (entity->GetEntityType()) {
|
|
case ET_Obstacle:
|
|
case ET_Building:
|
|
{
|
|
if (entity != this && TestCollision(room, entity)) {
|
|
objects.insert(entity);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
a8::Vec2 bomb_pos = GetPos();
|
|
room->frame_event.AddExplosionEx(master,
|
|
meta->i->thing_id(),
|
|
bomb_pos,
|
|
meta->i->explosion_effect());
|
|
for (auto& target : objects) {
|
|
switch (target->GetEntityType()) {
|
|
case ET_Player:
|
|
{
|
|
Human* hum = (Human*)target;
|
|
if (!hum->dead) {
|
|
float dmg = meta->i->damage();
|
|
float def = hum->ability.def;
|
|
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
|
|
hum->DecHP(finaly_dmg, VP_Mine, TEXT("battle_server_killer_mine", "地雷"), VW_Mine);
|
|
}
|
|
}
|
|
break;
|
|
case ET_Obstacle:
|
|
{
|
|
Obstacle* obstacle = (Obstacle*)target;
|
|
if (!obstacle->IsDead(room) &&
|
|
obstacle->Attackable() &&
|
|
!obstacle->IsTerminatorAirDropBox(room)) {
|
|
float dmg = meta->i->damage();
|
|
float def = 0;
|
|
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
|
|
|
|
obstacle->SetHealth(room,
|
|
std::max(0.0f, obstacle->GetHealth(room) - finaly_dmg));
|
|
if (obstacle->GetHealth(room) <= 0.01f) {
|
|
obstacle->Die(room);
|
|
}
|
|
if (obstacle->IsDead(room)) {
|
|
#if 0
|
|
bullet->player->DropItems(obstacle);
|
|
#endif
|
|
}
|
|
obstacle->BroadcastFullState(room);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (self_collider_) {
|
|
self_collider_->rad = old_rad;
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::SpecExplosion()
|
|
{
|
|
++explosion_times_;
|
|
if (meta->i->damage_dia() > 0.01f &&
|
|
meta->i->damage() > 0.01f) {
|
|
if (!grid_list_) {
|
|
grid_list_ = new std::set<GridCell*>();
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, *grid_list_);
|
|
}
|
|
a8::Vec2 bomb_born_offset = a8::Vec2::UP;
|
|
bomb_born_offset.Rotate(a8::RandAngle());
|
|
bomb_born_offset = bomb_born_offset * a8::RandEx(1, std::max(2, meta->i->explosion_float()));
|
|
a8::Vec2 bomb_pos = GetPos() + bomb_born_offset;
|
|
std::set<Entity*> objects;
|
|
room->grid_service->TraverseAllLayerHumanList
|
|
(
|
|
room->GetRoomIdx(),
|
|
*grid_list_,
|
|
[this, &objects, &bomb_pos] (Human* hum, bool& stop)
|
|
{
|
|
float distance = (hum->GetPos() - bomb_pos).Norm();
|
|
if (master.Get()->team_id != hum->team_id && distance < meta->i->damage_dia()) {
|
|
objects.insert(hum);
|
|
}
|
|
});
|
|
room->frame_event.AddExplosionEx(master,
|
|
meta->i->thing_id(),
|
|
bomb_pos,
|
|
meta->i->explosion_effect());
|
|
for (auto& target : objects) {
|
|
switch (target->GetEntityType()) {
|
|
case ET_Player:
|
|
{
|
|
Human* hum = (Human*)target;
|
|
if (!hum->dead) {
|
|
float dmg = meta->i->damage();
|
|
float def = hum->ability.def;
|
|
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
|
|
hum->DecHP(finaly_dmg, VP_Mine, TEXT("battle_server_killer_mine", "地雷"), VW_Mine);
|
|
|
|
for (int buff_id : meta->buff_list) {
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(buff_id);
|
|
if (buff_meta) {
|
|
hum->AddBuff(master.Get(),
|
|
buff_meta,
|
|
1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (explosion_times_ >= meta->i->explosion_times()) {
|
|
Die(room);
|
|
BroadcastFullState(room);
|
|
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::Active()
|
|
{
|
|
switch (meta->i->thing_type()) {
|
|
case kObstacleSelfExplosion:
|
|
{
|
|
ActiveSelfExplosion();
|
|
}
|
|
break;
|
|
case kObstacleMine:
|
|
{
|
|
ActiveMine();
|
|
}
|
|
break;
|
|
case kObstacleTrap:
|
|
{
|
|
ActiveTrap();
|
|
}
|
|
break;
|
|
case kObstaclePosionGas:
|
|
{
|
|
ActivePosionGas();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::ActiveSelfExplosion()
|
|
{
|
|
room->xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
meta->i->time() / FRAME_RATE_MS,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
|
|
obstacle->room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
obstacle->meta->i->explosion_interval() / FRAME_RATE_MS,
|
|
a8::XParams()
|
|
.SetSender(obstacle),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
|
|
obstacle->SpecExplosion();
|
|
},
|
|
&obstacle->xtimer_attacher.timer_list_
|
|
);
|
|
},
|
|
&xtimer_attacher.timer_list_
|
|
);
|
|
}
|
|
|
|
void RoomObstacle::ActiveMine()
|
|
{
|
|
room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
|
|
obstacle->UpdateTimerFunc();
|
|
},
|
|
&xtimer_attacher.timer_list_
|
|
);
|
|
}
|
|
|
|
void RoomObstacle::ActiveTrap()
|
|
{
|
|
room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
|
|
obstacle->UpdateTimerFunc();
|
|
},
|
|
&xtimer_attacher.timer_list_
|
|
);
|
|
}
|
|
|
|
void RoomObstacle::ActivePosionGas()
|
|
{
|
|
room->xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
meta->i->time() / FRAME_RATE_MS,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
|
|
obstacle->room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
obstacle->meta->i->explosion_interval() / FRAME_RATE_MS,
|
|
a8::XParams()
|
|
.SetSender(obstacle),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
|
|
obstacle->SpecExplosion();
|
|
},
|
|
&obstacle->xtimer_attacher.timer_list_
|
|
);
|
|
},
|
|
&xtimer_attacher.timer_list_
|
|
);
|
|
}
|
|
|
|
void RoomObstacle::DetachFromMaster()
|
|
{
|
|
|
|
}
|