game2006/server/gameserver/roomobstacle.cc
2022-12-12 15:45:35 +08:00

1022 lines
32 KiB
C++

#include "precompile.h"
#include <a8/collision.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"
#include "explosion.h"
#include "entityfactory.h"
#include "player.h"
#include "incubator.h"
#include "skillhelper.h"
RoomObstacle::RoomObstacle():Obstacle()
{
weak_ptr_chunk_.Set(this);
}
RoomObstacle::~RoomObstacle()
{
for (auto& itr : colliders_) {
ColliderComponent* collider = itr;
#ifdef DEBUG
#if 0
a8::UdpLog::Instance()->Debug("OnRemoveCollider %d %d %d",
{
room->GetRoomIdx(),
GetUniId(),
(long long)collider
});
#endif
#endif
room->map_service->RemoveCollider(collider);
}
if (!detached_) {
if (master.Get()) {
master.Get()->SlaveOnRemove(this);
}
detached_ = true;
}
if (!grid_list_) {
A8_SAFE_DELETE(grid_list_);
}
if (!hit_objects_) {
A8_SAFE_DELETE(hit_objects_);
}
if (!temp_pass_objects_) {
A8_SAFE_DELETE(temp_pass_objects_);
}
if (meta->sweep_tags != 0) {
room->mine_objects.erase(GetUniId());
}
}
void RoomObstacle::Initialize()
{
Obstacle::Initialize();
xtimer_attacher.xtimer = &room->xtimer;
if (meta->sweep_tags != 0) {
room->mine_objects[GetUniId()] = GetWeakPtrRef();
}
born_frameno = room->GetFrameNo();
#ifdef DEBUG
{
if (App::Instance()->debug_params.find(118) != App::Instance()->debug_params.end()) {
born_frameno += App::Instance()->debug_params[118] * 2;
}
}
#endif
}
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(),
GetUniId(),
(long long)self_collider_
});
#endif
#endif
}
for (auto collider : colliders_) {
collider->tag = collider_tag;
collider->param1 = collider_param1;
collider->param2 = collider_param2;
if (IsHalfWallCollider()) {
a8::SetBitFlag(collider->tag, kHalfWallTag);
}
}
}
void RoomObstacle::ActiveTimerFunc()
{
if (!master.Get()) {
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
return;
}
if (!grid_list_) {
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)
{
if (master.Get()->team_id == hum->team_id) {
if (TestCollision(room, hum)) {
has_hum = true;
stop = true;
}
}
}
);
if (!has_hum) {
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
);
}
}
}
Die(room);
ProcDieExplosion(room);
BroadcastFullState(room);
if (room->xtimer.GetRunningTimer()) {
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
}
}
} else {
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
}
}
void RoomObstacle::SpecExplosion(int delay_time)
{
++explosion_times_;
#if 1
{
#else
if (meta->i->damage_dia() > 0.01f) {
#endif
if (!grid_list_) {
grid_list_ = new std::set<GridCell*>();
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, *grid_list_);
}
Position bomb_born_offset;
if (pos_list && explosion_times_ <= pos_list->size()) {
bomb_born_offset = pos_list->at(explosion_times_ - 1);
} else {
// 999
#if 1
#else
bomb_born_offset.Rotate(a8::RandAngle());
bomb_born_offset = bomb_born_offset * a8::RandEx(1, std::max(2, meta->i->explosion_float()));
#endif
}
// 999
#if 1
Position bomb_pos = GetPos();
#else
a8::Vec2 bomb_pos = GetPos() + bomb_born_offset;
#endif
if (room->grid_service->CanAdd(bomb_pos.x, bomb_pos.y)) {
std::shared_ptr<Explosion> explosion = EntityFactory::Instance()->MakeExplosion();
explosion->exclude_uniid = GetUniId();
if (delay_time > 0) {
explosion->SetDamageDelay(delay_time);
}
explosion->IndifferenceAttack(
room,
bomb_pos,
meta->i->damage_dia(),
meta->i->explosion_effect(),
meta->i->damage()
);
if (master.Get()) {
std::set<Creature*> target_list;
room->grid_service->TraverseCreatures
(room->GetRoomIdx(),
*grid_list_,
[this, &target_list, &bomb_pos] (Creature* c, bool& stop)
{
if (master.Get()->team_id != c->team_id &&
!c->dead &&
bomb_pos.Distance2D2(c->GetPos()) < meta->i->damage_dia()) {
target_list.insert(c);
}
}
);
if (!target_list.empty()) {
for (Creature* c : target_list) {
for (int buff_id : meta->buff_list) {
#if DEBUG
a8::XPrintf("add thing buff:%d\n", {buff_id});
#endif
c->TryAddBuff(master.Get(),
buff_id
);
}
}
}
}
}
}
if (explosion_times_ >= total_explosion_times_) {
if (room->xtimer.GetRunningTimer()) {
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
}
Die(room);
BroadcastFullState(room);
}
}
void RoomObstacle::Active()
{
switch (meta->i->thing_type()) {
case kObstacleSelfExplosion:
{
ActiveSelfExplosion();
}
break;
case kObstacleMine:
{
ActiveMine();
}
break;
case kObstacleTrap:
{
ActiveTrap();
}
break;
case kObstaclePosionGas:
{
ActivePosionGas();
}
break;
case kObstacleSpring:
{
ActiveSpring();
}
break;
case kObstacleHideHouse:
{
ActiveHideHouse();
}
break;
case kObstacleGully:
{
ActiveGully();
}
break;
case kObstacleAirDropBox:
{
ActiveAirDrop();
}
break;
case kObstacleKeepRangeBuff:
{
ActiveKeepRangeBuff();
}
break;
case kObstacleShield:
{
if (master.Get() && !master.Get()->GetMoveDir().IsZero()) {
SetRotate(master.Get()->GetMoveDir().CalcAngleEx(a8::Vec2::UP));
}
CalcTempPassObjects();
}
break;
case kObstacleStrengthenWall:
{
if (master.Get() && !master.Get()->GetMoveDir().IsZero()) {
SetRotate(master.Get()->GetMoveDir().CalcAngleEx(a8::Vec2::UP));
}
ActiveStrengthenWall();
}
break;
case kObstacleMedicalStation:
{
ActiveMedicalStation();
}
break;
case kObstaclePortal:
{
ActivePortal();
}
break;
default:
{
}
break;
}
if (meta->i->life_time() > 0) {
xtimer_list* timer = room->xtimer.AddDeadLineTimerAndAttach
(
meta->i->life_time() / FRAME_RATE_MS,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
obstacle->DetachFromMaster();
},
&xtimer_attacher.timer_list_
);
life_time_timer = room->xtimer.GetTimerPtr(timer);
}
}
void RoomObstacle::ActiveSelfExplosion()
{
total_explosion_times_ = meta->i->explosion_times();
if (context_ability && context_ability->GetAttrAbs(kHAT_WeaponExplosionContinueTime) > 0.001f) {
total_explosion_times_ += context_ability->GetAttrAbs(kHAT_WeaponExplosionContinueTime) * 1000 /
meta->i->explosion_interval();
}
room->xtimer.AddDeadLineTimerAndAttach
(
meta->i->time() / FRAME_RATE_MS,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
obstacle->InstallPreExplostionSummonTimer();
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->meta->i->explosion_dmg_delay());
},
&obstacle->xtimer_attacher.timer_list_
);
},
&xtimer_attacher.timer_list_
);
}
void RoomObstacle::ActiveMine()
{
room->xtimer.AddRepeatTimerAndAttach
(
1,
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()
{
total_explosion_times_ = meta->i->explosion_times();
if (context_ability && context_ability->GetAttrAbs(kHAT_WeaponExplosionContinueTime) > 0.001f) {
total_explosion_times_ += context_ability->GetAttrAbs(kHAT_WeaponExplosionContinueTime) * 1000 /
meta->i->explosion_interval();
}
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()
{
if (!detached_) {
detached_ = true;
if (master.Get()) {
xtimer_attacher.ClearTimerList();
master.Get()->SlaveOnRemove(this);
room->grid_service->DelRoomEntity(room, this);
if (!IsDead(room)) {
Die(room);
BroadcastFullState(room);
}
room->RemoveObjectLater(this);
}
}
}
void RoomObstacle::Die(Room* room)
{
if (!IsDead(room)) {
Obstacle::Die(room);
DetachFromMaster();
if (meta->sweep_tags != 0) {
room->mine_objects.erase(GetUniId());
}
}
}
void RoomObstacle::ActiveSpring()
{
}
void RoomObstacle::ActiveHideHouse()
{
}
void RoomObstacle::ActiveGully()
{
}
void RoomObstacle::ActiveAirDrop()
{
int delay_time = 0;
int appear_time = 0;
if (meta->param2_list.size() >= 2) {
delay_time = meta->param2_list[0];
appear_time = meta->param2_list[1];
}
room->xtimer.AddDeadLineTimerAndAttach
(
(delay_time + appear_time) / FRAME_RATE_MS,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
obstacle->SummonAirDropBox(obstacle->meta->int_param1);
obstacle->Die(obstacle->room);
obstacle->BroadcastFullState(obstacle->room);
},
&xtimer_attacher.timer_list_,
[] (const a8::XParams& param, bool is_destory)
{
int i = 0;
});
room->xtimer.AddDeadLineTimerAndAttach
(
delay_time / FRAME_RATE_MS,
a8::XParams()
.SetSender(this)
.SetParam1(delay_time)
.SetParam2(appear_time)
.SetParam3(meta->int_param1),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
Position born_pos = obstacle->GetPos();
{
MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(obstacle->meta->int_param1);
if (thing_meta && thing_meta->i->summon_born_rad() > 0) {
a8::Vec2 born_dir = a8::Vec2::UP;
born_dir.Rotate(obstacle->GetUniId());
// 999
#if 1
#else
born_pos = born_pos + born_dir * thing_meta->i->summon_born_rad();
#endif
}
}
obstacle->room->frame_event.AddAirDrop(param.param2,
param.param3,
born_pos);
},
&xtimer_attacher.timer_list_
);
}
bool RoomObstacle::DoInteraction(Human* sender)
{
if (Obstacle::DoInteraction(sender)) {
return true;
}
return true;
}
void RoomObstacle::SummonAirDropBox(int box_id)
{
Position born_pos = GetPos();
MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(box_id);
if (thing_meta && thing_meta->i->summon_born_rad() > 0) {
a8::Vec2 born_dir = a8::Vec2::UP;
born_dir.Rotate(GetUniId());
// 999
#if 1
#else
born_pos = born_pos + born_dir * thing_meta->i->summon_born_rad();
#endif
}
RoomObstacle* obstacle = room->CreateObstacle
(
box_id,
born_pos.x,
born_pos.y
);
if (obstacle) {
obstacle->PushCollisionObjects();
}
}
Entity* RoomObstacle::GetRealObject(Room* room)
{
return room->GetEntityByUniId(real_object_uniid);
}
void RoomObstacle::ActiveKeepRangeBuff()
{
auto check_cb =
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
obstacle->ProcKeepRangeBuff();
};
room->xtimer.AddRepeatTimerAndAttach
(
1,
a8::XParams()
.SetSender(this),
check_cb,
&xtimer_attacher.timer_list_
);
room->xtimer.AddDeadLineTimerAndAttach
(
meta->i->time() / FRAME_RATE_MS,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
obstacle->Destory();
},
&xtimer_attacher.timer_list_
);
}
void RoomObstacle::ProcKeepRangeBuff()
{
if (!grid_list_) {
grid_list_ = new std::set<GridCell*>();
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, *grid_list_);
}
if (!hit_objects_) {
hit_objects_ = new std::map<int, CreatureWeakPtr>();
}
if (grid_list_ && master.Get() && !IsDead(room)) {
std::set<Creature*> target_list;
room->grid_service->TraverseCreatures
(room->GetRoomIdx(),
*grid_list_,
[this, &target_list] (Creature* hum, bool& stop)
{
if (master.Get()->team_id != hum->team_id && TestCollision(room, hum)) {
target_list.insert(hum);
}
}
);
for (Creature* hum : target_list) {
for (int buff_id : meta->buff_list) {
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(buff_id);
if (buff_meta && hum->GetBuffById(buff_id)) {
hum->AddBuff(master.Get(),
buff_meta
);
}
}
if (hit_objects_->find(hum->GetUniId()) == hit_objects_->end()) {
(*hit_objects_)[hum->GetUniId()] = hum->GetWeakPtrRef();
}
}
for (auto& pair : *hit_objects_) {
for (int buff_id : meta->buff_list) {
if (pair.second.Get() && target_list.find(pair.second.Get()) == target_list.end()) {
pair.second.Get()->RemoveBuffById(buff_id);
}
}
}
} else {
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
}
}
RoomObstacleWeakPtr RoomObstacle::AllocWeakPtr()
{
RoomObstacleWeakPtr ptr;
ptr.Attach(this);
return ptr;
}
RoomObstacleWeakPtr& RoomObstacle::GetWeakPtrRef()
{
if (!weak_ptr_.Get()) {
weak_ptr_.Attach(this);
}
return weak_ptr_;
}
void RoomObstacle::OnBattleStart(Room* room)
{
if (master.Get()) {
Destory();
}
}
void RoomObstacle::Destory()
{
#if DEBUG
room->BroadcastDebugMsg(a8::Format("obstacle destory uniid:%d pos:%d,%d",
{
GetUniId(),
GetPos().x,
GetPos().y
}));
#endif
DetachFromMaster();
}
void RoomObstacle::PushCollisionObjects()
{
std::set<GridCell*> grid_list;
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, grid_list);
room->grid_service->TraverseCreatures
(
room->GetRoomIdx(),
grid_list,
[this] (Creature* c, bool& stop)
{
if (TestCollision(room, c)) {
c->room->xtimer.AddDeadLineTimerAndAttach
(1,
a8::XParams()
.SetSender(c),
[] (const a8::XParams& param)
{
Creature* c = (Creature*)param.sender.GetUserData();
c->MustBeAddBuff(c, kPullToWalkableBuffId);
},
&c->xtimer_attacher.timer_list_);
}
});
}
void RoomObstacle::InstallPreExplostionSummonTimer()
{
if (!meta->preexplosion_summon.empty()) {
int base_time = 0;
pos_list = std::make_shared<std::vector<Position>>();
for (int i = 0; i < total_explosion_times_; ++i) {
Position bomb_born_offset;
{
// 999
#if 1
Position bomb_pos = GetPos();
#else
bomb_born_offset.Rotate(a8::RandAngle());
bomb_born_offset = bomb_born_offset * a8::RandEx(1, std::max(2, meta->i->explosion_float()));
Position bomb_pos = GetPos() + bomb_born_offset;
#endif
if (room->grid_service->CanAdd(bomb_pos.x, bomb_pos.y)) {
pos_list->push_back(bomb_born_offset);
} else {
pos_list->push_back(Position());
}
}
for (auto& tuple : meta->preexplosion_summon) {
int time = std::get<0>(tuple);
int obstacle_id = std::get<1>(tuple);
room->xtimer.AddDeadLineTimerAndAttach
(
(base_time + time) / FRAME_RATE_MS,
a8::XParams()
.SetSender(this)
.SetParam1(obstacle_id)
.SetParam2(bomb_born_offset.x)
.SetParam3(bomb_born_offset.y),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
a8::Vec2 pos = a8::Vec2(
obstacle->GetPos().x + param.param2.GetDouble(),
obstacle->GetPos().y + param.param3.GetDouble()
);
if (obstacle->room->CanAddObstacle(pos, param.param1)) {
RoomObstacle* p = obstacle->room->CreateObstacle
(
param.param1,
pos.x,
pos.y
);
if (p) {
p->Active();
}
}
},
&xtimer_attacher.timer_list_
);
}//end for tuple
base_time += meta->i->explosion_interval();
}
}
}
void RoomObstacle::DestoryAt(int time)
{
room->xtimer.AddDeadLineTimerAndAttach
(
time / FRAME_RATE_MS,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
obstacle->DetachFromMaster();
#ifdef DEBUG
obstacle->room->BroadcastDebugMsg
(a8::Format("obstacle destory %d", {obstacle->meta->i->thing_id()}));
#endif
},
&xtimer_attacher.timer_list_
);
}
void RoomObstacle::CalcTempPassObjects()
{
if (!grid_list_) {
grid_list_ = new std::set<GridCell*>();
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, *grid_list_);
}
if (!temp_pass_objects_) {
temp_pass_objects_ = new std::map<int, CreatureWeakPtr>();
}
room->grid_service->TraverseCreatures
(room->GetRoomIdx(),
*grid_list_,
[this] (Creature* hum, bool& stop)
{
if (TestCollision(room, hum)) {
(*temp_pass_objects_)[hum->GetUniId()] = hum->GetWeakPtrRef();
}
}
);
if (!temp_pass_objects_->empty()) {
room->xtimer.AddDeadLineTimerAndAttach
(
200 / FRAME_RATE_MS,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
Room* room = obstacle->room;
std::list<int> del_objs;
for (auto& pair : *obstacle->temp_pass_objects_) {
if (!pair.second.Get() || !obstacle->TestCollision(room, pair.second.Get())) {
del_objs.push_back(pair.first);
}
}
for (int obj_uniid : del_objs) {
obstacle->temp_pass_objects_->erase(obj_uniid);
}
if (obstacle->temp_pass_objects_->empty()) {
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
}
},
&xtimer_attacher.timer_list_
);
}
}
void RoomObstacle::ActiveStrengthenWall()
{
}
void RoomObstacle::ActiveMedicalStation()
{
if (!grid_list_) {
grid_list_ = new std::set<GridCell*>();
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, *grid_list_);
}
if (!skill_meta || !skill_meta->number_meta) {
return;
}
if (skill_meta->GetMagicId() != MAGIC_YLZ) {
return;
}
scale = 1.0f;
if (skill_meta->base_skill_meta) {
float base_range = SkillHelper::GetYlzRange(skill_meta->base_skill_meta);
if (std::abs(base_range) > 0.0001f) {
scale = SkillHelper::GetYlzRange(skill_meta) / base_range;
}
}
room->xtimer.AddRepeatTimerAndAttach
(
meta->int_param1 / FRAME_RATE_MS,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
if (!obstacle->master.Get()) {
return;
}
Room* room = obstacle->room;
std::set<Creature*> target_list;
room->grid_service->TraverseCreatures
(room->GetRoomIdx(),
*obstacle->grid_list_,
[obstacle, &target_list, room] (Creature* hum, bool& stop)
{
if (obstacle->master.Get()->team_id == hum->team_id &&
!hum->dead
) {
if (IntersectCircleCircle(
obstacle->GetPos().ToVec2(),
SkillHelper::GetYlzRange(obstacle->skill_meta),
hum->GetPos().ToVec2(),
hum->GetRadius()
)) {
target_list.insert(hum);
}
}
}
);
for (auto& c : target_list) {
float add_hp = SkillHelper::GetYlzRecoverHp(obstacle->master.Get(),
c,
obstacle->skill_meta);
float old_hp = c->GetHP();
c->AddHp(add_hp);
if (std::abs(c->GetHP() - old_hp) > 0.0001f && obstacle->master.Get()) {
for (int buff_id : obstacle->meta->buff_list) {
c->TryAddBuff(obstacle->master.Get(),
buff_id
);
}
}
#ifdef DEBUG
{
std::string dbg_msg = a8::Format
(
"skill_id:%d 医疗站 human.atk:%f target.extRecoverHp:%f add_hp:%f range2:%f",
{
obstacle->skill_meta->i->skill_id(),
obstacle->master.Get()->GetBattleContext()->GetHeroTotalAtk(),
obstacle->master.Get()->GetBattleContext()->GetExtRecoverHp(),
add_hp,
obstacle->skill_meta->number_meta->float_range2
});
obstacle->master.Get()->SendDebugMsg(dbg_msg);
a8::XPrintf("%s\n", {dbg_msg});
}
#endif
}
},
&xtimer_attacher.timer_list_
);
}
void RoomObstacle::ActivePortal()
{
room->xtimer.AddRepeatTimerAndAttach
(
SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
RoomObstacle* obstacle = (RoomObstacle*)param.sender.GetUserData();
obstacle->ProcPortal();
},
&xtimer_attacher.timer_list_
);
}
void RoomObstacle::ProcPortal()
{
if (room->IsGameOver()) {
return;
}
if (!room->IsPveRoom()) {
return;
}
if (!grid_list_) {
grid_list_ = new std::set<GridCell*>();
room->grid_service->GetAllCellsByXy(room, GetPos().x, GetPos().y, *grid_list_);
}
bool ready = true;
room->TraverseHumanList
(
a8::XParams(),
[this, &ready] (Human* hum, a8::XParams& param)
{
if (!a8::IntersectCircleCircle
(
hum->GetPos().ToVec2(),
hum->GetRadius(),
GetPos().ToVec2(),
meta->i->height()
)) {
ready = false;
return false;
}
return true;
}
);
if (ready) {
room->GetIncubator()->NextWave();
Die(room);
BroadcastFullState(room);
room->xtimer.DeleteTimer(room->xtimer.GetRunningTimer());
}
}