900 lines
27 KiB
C++
900 lines
27 KiB
C++
#include "precompile.h"
|
|
|
|
#include <a8/collision.h>
|
|
|
|
#include "room.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"
|
|
#include "ability.h"
|
|
#include "battledatacontext.h"
|
|
#include "collision.h"
|
|
|
|
#include "mt/MapThing.h"
|
|
#include "mt/Skill.h"
|
|
#include "mt/SkillNumber.h"
|
|
#include "mt/Buff.h"
|
|
|
|
RoomObstacle::RoomObstacle():Obstacle()
|
|
{
|
|
weak_ptr_chunk_.Set(this);
|
|
}
|
|
|
|
RoomObstacle::~RoomObstacle()
|
|
{
|
|
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.SetOwner(&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::ActiveTimerFunc()
|
|
{
|
|
if (!master.Get()) {
|
|
room->xtimer.DeleteCurrentTimer();
|
|
return;
|
|
}
|
|
if (!grid_list_) {
|
|
grid_list_ = new std::set<GridCell*>();
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().GetX(), GetPos().GetY(), *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 (Collision::CheckCB(hum, this)) {
|
|
has_hum = true;
|
|
stop = true;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
if (!has_hum) {
|
|
room->xtimer.DeleteCurrentTimer();
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::UpdateTimerFunc()
|
|
{
|
|
if (!grid_list_) {
|
|
grid_list_ = new std::set<GridCell*>();
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().GetX(), GetPos().GetY(), *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 &&
|
|
Collision::CheckCB(hum, this)) {
|
|
human_list.insert(hum);
|
|
}
|
|
}
|
|
);
|
|
if (!human_list.empty()) {
|
|
for (Human* hum : human_list) {
|
|
for (int buff_id : meta->_buff_list) {
|
|
const mt::Buff* buff_meta = mt::Buff::GetById(buff_id);
|
|
if (buff_meta) {
|
|
hum->AddBuff(master.Get(),
|
|
buff_meta
|
|
);
|
|
}
|
|
}
|
|
}
|
|
Die(room);
|
|
ProcDieExplosion(room);
|
|
BroadcastFullState(room);
|
|
room->xtimer.DeleteCurrentTimer();
|
|
}
|
|
} else {
|
|
room->xtimer.DeleteCurrentTimer();
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::SpecExplosion(int delay_time)
|
|
{
|
|
++explosion_times_;
|
|
#if 1
|
|
{
|
|
#else
|
|
if (meta->damage_dia() > 0.01f) {
|
|
#endif
|
|
if (!grid_list_) {
|
|
grid_list_ = new std::set<GridCell*>();
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().GetX(), GetPos().GetY(), *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->explosion_float()));
|
|
#endif
|
|
}
|
|
Position bomb_pos = GetPos();
|
|
bomb_pos.AddGlmVec3(bomb_born_offset.ToGlmVec3());
|
|
if (room->grid_service->CanAdd(bomb_pos.GetX(), bomb_pos.GetY())) {
|
|
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->damage_dia(),
|
|
meta->explosion_effect(),
|
|
meta->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->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_) {
|
|
room->xtimer.DeleteCurrentTimer();
|
|
Die(room);
|
|
BroadcastFullState(room);
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::Active()
|
|
{
|
|
switch (meta->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 0
|
|
if (master.Get() && !GlmHelper::IsZero(master.Get()->GetMoveDir())) {
|
|
SetRotate(master.Get()->GetMoveDir().CalcAngleEx(GlmHelper::UP));
|
|
}
|
|
CalcTempPassObjects();
|
|
#endif
|
|
}
|
|
break;
|
|
case kObstacleStrengthenWall:
|
|
{
|
|
#if 0
|
|
if (master.Get() && !GlmHelper::IsZero(master.Get()->GetMoveDir())) {
|
|
SetRotate(master.Get()->GetMoveDir().CalcAngleEx(GlmHelper::UP));
|
|
}
|
|
ActiveStrengthenWall();
|
|
#endif
|
|
}
|
|
break;
|
|
case kObstacleMedicalStation:
|
|
{
|
|
ActiveMedicalStation();
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
if (meta->life_time() > 0) {
|
|
life_time_timer = room->xtimer.SetTimeoutWpEx
|
|
(
|
|
meta->life_time() / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
DetachFromMaster();
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::ActiveSelfExplosion()
|
|
{
|
|
total_explosion_times_ = meta->explosion_times();
|
|
if (context_ability && context_ability->GetAttrAbs(kHAT_WeaponExplosionContinueTime) > 0.001f) {
|
|
total_explosion_times_ += context_ability->GetAttrAbs(kHAT_WeaponExplosionContinueTime) * 1000 /
|
|
meta->explosion_interval();
|
|
}
|
|
room->xtimer.SetTimeoutEx
|
|
(
|
|
meta->time() / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
InstallPreExplostionSummonTimer();
|
|
room->xtimer.SetIntervalEx
|
|
(
|
|
meta->explosion_interval() / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
SpecExplosion(meta->explosion_dmg_delay());
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
|
|
void RoomObstacle::ActiveMine()
|
|
{
|
|
room->xtimer.SetIntervalEx
|
|
(
|
|
1,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
UpdateTimerFunc();
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
|
|
void RoomObstacle::ActiveTrap()
|
|
{
|
|
room->xtimer.SetIntervalEx
|
|
(
|
|
SERVER_FRAME_RATE,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
UpdateTimerFunc();
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
|
|
void RoomObstacle::ActivePosionGas()
|
|
{
|
|
total_explosion_times_ = meta->explosion_times();
|
|
if (context_ability && context_ability->GetAttrAbs(kHAT_WeaponExplosionContinueTime) > 0.001f) {
|
|
total_explosion_times_ += context_ability->GetAttrAbs(kHAT_WeaponExplosionContinueTime) * 1000 /
|
|
meta->explosion_interval();
|
|
}
|
|
room->xtimer.SetTimeoutEx
|
|
(
|
|
meta->time() / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
room->xtimer.SetIntervalEx
|
|
(
|
|
meta->explosion_interval() / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
SpecExplosion();
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
|
|
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.SetTimeoutEx
|
|
(
|
|
(delay_time + appear_time) / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
SummonAirDropBox(meta->_int_param1);
|
|
Die(room);
|
|
BroadcastFullState(room);
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
room->xtimer.SetTimeoutEx
|
|
(
|
|
delay_time / FRAME_RATE_MS,
|
|
[this, delay_time, appear_time]
|
|
(int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
Position born_pos = GetPos();
|
|
{
|
|
const mt::MapThing* thing_meta = meta;
|
|
if (thing_meta && thing_meta->summon_born_rad() > 0) {
|
|
glm::vec3 born_dir = GlmHelper::UP;
|
|
GlmHelper::RotateY(born_dir, GetUniId());
|
|
born_pos.AddGlmVec3(born_dir * (float)(thing_meta->summon_born_rad()));
|
|
}
|
|
}
|
|
room->frame_event.AddAirDrop(delay_time,
|
|
appear_time,
|
|
born_pos.ToGlmVec3());
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
|
|
bool RoomObstacle::DoInteraction(Human* sender)
|
|
{
|
|
if (Obstacle::DoInteraction(sender)) {
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void RoomObstacle::SummonAirDropBox(int box_id)
|
|
{
|
|
Position born_pos = GetPos();
|
|
const mt::MapThing* thing_meta = mt::MapThing::GetById(box_id);
|
|
if (thing_meta && thing_meta->summon_born_rad() > 0) {
|
|
glm::vec3 born_dir = GlmHelper::UP;
|
|
GlmHelper::RotateY(born_dir, GetUniId());
|
|
// 999
|
|
#if 1
|
|
#else
|
|
born_pos = born_pos + born_dir * thing_meta->summon_born_rad();
|
|
#endif
|
|
}
|
|
RoomObstacle* obstacle = room->CreateObstacle
|
|
(
|
|
box_id,
|
|
born_pos.GetX(),
|
|
born_pos.GetY(),
|
|
born_pos.GetZ()
|
|
);
|
|
if (obstacle) {
|
|
obstacle->PushCollisionObjects();
|
|
}
|
|
}
|
|
|
|
Entity* RoomObstacle::GetRealObject(Room* room)
|
|
{
|
|
return room->GetEntityByUniId(real_object_uniid);
|
|
}
|
|
|
|
void RoomObstacle::ActiveKeepRangeBuff()
|
|
{
|
|
auto check_cb =
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
ProcKeepRangeBuff();
|
|
}
|
|
};
|
|
room->xtimer.SetIntervalEx
|
|
(
|
|
1,
|
|
check_cb,
|
|
&xtimer_attacher);
|
|
room->xtimer.SetTimeoutEx
|
|
(
|
|
meta->time() / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
Destory();
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
|
|
void RoomObstacle::ProcKeepRangeBuff()
|
|
{
|
|
if (!grid_list_) {
|
|
grid_list_ = new std::set<GridCell*>();
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().GetX(), GetPos().GetY(), *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 &&
|
|
Collision::CheckCB(hum, this)) {
|
|
target_list.insert(hum);
|
|
}
|
|
}
|
|
);
|
|
for (Creature* hum : target_list) {
|
|
for (int buff_id : meta->_buff_list) {
|
|
const mt::Buff* buff_meta = mt::Buff::GetById(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.DeleteCurrentTimer();
|
|
}
|
|
}
|
|
|
|
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().GetX(),
|
|
GetPos().GetY()
|
|
}));
|
|
#endif
|
|
DetachFromMaster();
|
|
}
|
|
|
|
void RoomObstacle::PushCollisionObjects()
|
|
{
|
|
std::set<GridCell*> grid_list;
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().GetX(), GetPos().GetY(), grid_list);
|
|
room->grid_service->TraverseCreatures
|
|
(
|
|
room->GetRoomIdx(),
|
|
grid_list,
|
|
[this] (Creature* c, bool& stop)
|
|
{
|
|
if (Collision::CheckCB(c, this)) {
|
|
c->room->xtimer.SetTimeoutEx
|
|
(1,
|
|
[c] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
c->MustBeAddBuff(c, kPullToWalkableBuffId);
|
|
}
|
|
},
|
|
&c->xtimer_attacher);
|
|
}
|
|
});
|
|
}
|
|
|
|
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->explosion_float()));
|
|
Position bomb_pos = GetPos() + bomb_born_offset;
|
|
#endif
|
|
if (room->grid_service->CanAdd(bomb_pos.GetX(), bomb_pos.GetY())) {
|
|
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.SetTimeoutEx
|
|
(
|
|
(base_time + time) / FRAME_RATE_MS,
|
|
[this, obstacle_id, bomb_born_offset]
|
|
(int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
glm::vec3 pos = glm::vec3(
|
|
GetPos().GetX() + bomb_born_offset.GetX(),
|
|
0.0f,
|
|
GetPos().GetY() + bomb_born_offset.GetY()
|
|
);
|
|
if (room->CanAddObstacle(pos, obstacle_id)) {
|
|
RoomObstacle* p = room->CreateObstacle
|
|
(
|
|
obstacle_id,
|
|
pos.x,
|
|
pos.y,
|
|
pos.z
|
|
);
|
|
if (p) {
|
|
p->Active();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}//end for tuple
|
|
base_time += meta->explosion_interval();
|
|
}
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::DestoryAt(int time)
|
|
{
|
|
room->xtimer.SetTimeoutEx
|
|
(
|
|
time / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
DetachFromMaster();
|
|
#ifdef DEBUG
|
|
room->BroadcastDebugMsg
|
|
(a8::Format("obstacle destory %d", {meta->thing_id()}));
|
|
#endif
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
|
|
void RoomObstacle::CalcTempPassObjects()
|
|
{
|
|
if (!grid_list_) {
|
|
grid_list_ = new std::set<GridCell*>();
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().GetX(), GetPos().GetY(), *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 (Collision::CheckCB(hum, this)) {
|
|
(*temp_pass_objects_)[hum->GetUniId()] = hum->GetWeakPtrRef();
|
|
}
|
|
}
|
|
);
|
|
if (!temp_pass_objects_->empty()) {
|
|
room->xtimer.SetTimeoutEx
|
|
(
|
|
200 / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
std::list<int> del_objs;
|
|
for (auto& pair : *temp_pass_objects_) {
|
|
if (!pair.second.Get() ||
|
|
!Collision::CheckCB(pair.second.Get(), this)) {
|
|
del_objs.push_back(pair.first);
|
|
}
|
|
}
|
|
for (int obj_uniid : del_objs) {
|
|
temp_pass_objects_->erase(obj_uniid);
|
|
}
|
|
if (temp_pass_objects_->empty()) {
|
|
room->xtimer.DeleteCurrentTimer();
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::ActiveStrengthenWall()
|
|
{
|
|
|
|
}
|
|
|
|
void RoomObstacle::ActiveMedicalStation()
|
|
{
|
|
ForceGridList();
|
|
if (!skill_meta || !skill_meta->_number_meta) {
|
|
return;
|
|
}
|
|
if (skill_meta->GetMagicId() != MAGIC_20301_XL) {
|
|
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.SetIntervalEx
|
|
(
|
|
SERVER_FRAME_RATE,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT != event) {
|
|
return;
|
|
}
|
|
if (!master.Get()) {
|
|
return;
|
|
}
|
|
|
|
std::set<Creature*> target_list;
|
|
room->grid_service->TraverseCreatures
|
|
(room->GetRoomIdx(),
|
|
*grid_list_,
|
|
[this, &target_list] (Creature* hum, bool& stop)
|
|
{
|
|
if (!hum->dead) {
|
|
if (Collision::CheckCB
|
|
(
|
|
hum,
|
|
hum->GetRadius(),
|
|
this,
|
|
SkillHelper::GetYlzRange(skill_meta)
|
|
)) {
|
|
target_list.insert(hum);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
bool hit = false;
|
|
for (auto& c : target_list) {
|
|
if (c->team_id == master.Get()->team_id) {
|
|
float add_hp = SkillHelper::GetYlzRecoverHp(master.Get(),
|
|
c,
|
|
skill_meta);
|
|
float old_hp = c->GetHP();
|
|
c->AddHp(add_hp);
|
|
if (std::abs(c->GetHP() - old_hp) > 0.0001f && master.Get()) {
|
|
if (meta->_int_param2) {
|
|
c->TryAddBuff(master.Get(),
|
|
meta->_int_param2
|
|
);
|
|
}
|
|
hit = true;
|
|
#ifdef DEBUG
|
|
{
|
|
std::string dbg_msg = a8::Format
|
|
(
|
|
"skill_id:%d 医疗站 human.atk:%f target.extRecoverHp:%f add_hp:%f range2:%f",
|
|
{
|
|
skill_meta->skill_id(),
|
|
master.Get()->GetBattleContext()->GetHeroTotalAtk(),
|
|
master.Get()->GetBattleContext()->GetExtRecoverHp(),
|
|
add_hp,
|
|
skill_meta->_number_meta->_float_range2
|
|
});
|
|
master.Get()->SendDebugMsg(dbg_msg);
|
|
a8::XPrintf("%s\n", {dbg_msg});
|
|
}
|
|
#endif
|
|
}
|
|
} else if (!c->dead){
|
|
float damage = SkillHelper::GetYlzDamage(master.Get(),
|
|
c,
|
|
skill_meta);
|
|
damage = c->GetBattleContext()->CalcReceiveDmg(master.Get(), damage);
|
|
float dmg_out = 0.0f;
|
|
c->DecHP(damage,
|
|
master.Get()->GetUniId(),
|
|
master.Get()->GetName(),
|
|
VP_Buff,
|
|
master.Get()->GetUniId(),
|
|
master.Get()->GetName(),
|
|
dmg_out);
|
|
|
|
if (meta->_int_param1) {
|
|
c->TryAddBuff(master.Get(),
|
|
meta->_int_param1
|
|
);
|
|
}
|
|
hit = true;
|
|
}
|
|
if (hit) {
|
|
break;
|
|
}
|
|
}//end if
|
|
if (hit) {
|
|
DetachFromMaster();
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
RemoveSameSkillObstacle();
|
|
}
|
|
|
|
void RoomObstacle::ForceGridList()
|
|
{
|
|
if (!grid_list_) {
|
|
grid_list_ = new std::set<GridCell*>();
|
|
room->grid_service->GetAllCellsByXy(room, GetPos().GetX(), GetPos().GetZ(), *grid_list_);
|
|
}
|
|
}
|
|
|
|
void RoomObstacle::RemoveSameSkillObstacle()
|
|
{
|
|
if (master.Get() && skill_meta) {
|
|
master.Get()->RemoveSkillObstacle(skill_meta);
|
|
}
|
|
}
|