355 lines
11 KiB
C++
355 lines
11 KiB
C++
#include "precompile.h"
|
|
|
|
#include "incubator.h"
|
|
#include "room.h"
|
|
#include "human.h"
|
|
#include "metamgr.h"
|
|
|
|
void Incubator::Init()
|
|
{
|
|
xtimer_attacher_.xtimer = &room->xtimer;
|
|
room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE * (2 + rand() % 3),
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Incubator* incubator = (Incubator*)param.sender.GetUserData();
|
|
incubator->AutoAllocAndroid();
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
if (room->IsPveRoom()) {
|
|
room->pve_data.max_wave = room->pve_mode_meta->mode_time.size();
|
|
int wave = 0;
|
|
int total_time = 0;
|
|
SpawnWaveMon(0);
|
|
for (int time : room->pve_mode_meta->mode_time) {
|
|
total_time += time;
|
|
xtimer_list* timer = room->xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
total_time * SERVER_FRAME_RATE,
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(wave),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Incubator* incubator = (Incubator*)param.sender.GetUserData();
|
|
incubator->OnEnterNewWave(param.param1.GetInt());
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
wave_timers_.push_back(timer);
|
|
++wave;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Incubator::UnInit()
|
|
{
|
|
|
|
}
|
|
|
|
void Incubator::AllocAndroid(Human* target, int num)
|
|
{
|
|
if (room->xtimer.GetRunningTimer() == nullptr) {
|
|
A8_ABORT();
|
|
}
|
|
int try_count = 0;
|
|
a8::Vec2 dir = a8::Vec2::UP;
|
|
while (num > 0 && try_count < 20 && !hold_humans_.empty()) {
|
|
dir.Rotate(a8::RandAngle());
|
|
int rand_len = rand() % MetaMgr::Instance()->incubator_rand_length;
|
|
Human* hum = hold_humans_[0];
|
|
a8::Vec2 old_pos = hum->GetPos();
|
|
hum->SetPos(target->GetPos() + dir * (MetaMgr::Instance()->incubator_base_length + rand_len));
|
|
if (hum->CollisonDetection() || !CanSee(hum, target)) {
|
|
hum->SetPos(old_pos);
|
|
} else {
|
|
room->EnableHuman(hum);
|
|
#ifdef DEBUG
|
|
#if 0
|
|
if (!target->InNewObjects(hum)) {
|
|
A8_ABORT();
|
|
}
|
|
#endif
|
|
if (hum->dead) {
|
|
A8_ABORT();
|
|
}
|
|
#endif
|
|
hum->MustBeAddBuff(hum, kTraceBuffId);
|
|
hold_humans_.erase(hold_humans_.begin());
|
|
--num;
|
|
#ifdef DEBUG
|
|
room->BroadcastDebugMsg(a8::Format("投放机器人 %d:%s pos:%d,%d pos1:%d,%d %d num:%d",
|
|
{hum->GetUniId(),
|
|
hum->name,
|
|
hum->GetPos().x,
|
|
hum->GetPos().y,
|
|
target->GetPos().x,
|
|
target->GetPos().y,
|
|
hum->GetPos().Distance(target->GetPos()),
|
|
hold_humans_.size()}));
|
|
#endif
|
|
}
|
|
++try_count;
|
|
}
|
|
#ifdef DEBUG
|
|
if (num > 0) {
|
|
room->BroadcastDebugMsg(a8::Format("投放机器人 分配失败 %d", {hold_humans_.size()}));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Incubator::RecycleAndroid(Human* hum)
|
|
{
|
|
Human* nearest_hum = nullptr;
|
|
Human* target = hum;
|
|
float distance = 10000000;
|
|
room->TraverseAlivePlayers
|
|
(
|
|
a8::XParams(),
|
|
[&nearest_hum, target, &distance] (Human* hum, a8::XParams& param) -> bool
|
|
{
|
|
float tmp_distance = hum->GetPos().ManhattanDistance(target->GetPos());
|
|
if (tmp_distance < distance) {
|
|
nearest_hum = hum;
|
|
distance = tmp_distance;
|
|
}
|
|
return true;
|
|
});
|
|
if (hum->dead) {
|
|
#ifdef DEBUG
|
|
room->BroadcastDebugMsg(a8::Format("回收机器人 %d:%s 角色已死亡",
|
|
{hum->GetUniId(),
|
|
hum->name}));
|
|
#endif
|
|
hum->RemoveBuffByEffectId(kBET_BeRecycle);
|
|
return;
|
|
}
|
|
if (distance < MetaMgr::Instance()->incubator_canset_distance) {
|
|
#ifdef DEBUG
|
|
room->BroadcastDebugMsg(a8::Format("回收机器人 %d:%s 距离太近",
|
|
{hum->GetUniId(),
|
|
hum->name}));
|
|
#endif
|
|
hum->RemoveBuffByEffectId(kBET_BeRecycle);
|
|
return;
|
|
}
|
|
if (distance > MetaMgr::Instance()->incubator_canset_distance + 100) {
|
|
hum->RemoveBuffByEffectId(kBET_BeRecycle);
|
|
hold_humans_.push_back(hum);
|
|
room->DisableHuman(hum);
|
|
#ifdef DEBUG
|
|
room->BroadcastDebugMsg(a8::Format("回收机器人 %d:%s:%d 添加到回收列表",
|
|
{hum->GetUniId(),
|
|
hum->name,
|
|
hold_humans_.size()
|
|
}));
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool Incubator::CanSee(Human* hum, Human* exclude_hum)
|
|
{
|
|
Human* target = hum;
|
|
bool can_see = true;
|
|
room->TraverseAlivePlayers
|
|
(
|
|
a8::XParams(),
|
|
[target, exclude_hum, &can_see] (Human* hum, a8::XParams& param) -> bool
|
|
{
|
|
if (hum != exclude_hum) {
|
|
if (target->GetPos().ManhattanDistance(hum->GetPos()) <
|
|
MetaMgr::Instance()->incubator_canset_distance) {
|
|
can_see = false;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
return can_see;
|
|
}
|
|
|
|
void Incubator::AutoAllocAndroid()
|
|
{
|
|
switch (room->GetGasData().gas_mode) {
|
|
case GasWaiting:
|
|
case GasMoving:
|
|
{
|
|
if (!hold_humans_.empty()){
|
|
Human* hum = hold_humans_[0];
|
|
if (room->GetGasData().gas_mode == GasWaiting &&
|
|
hold_humans_.size() > 1 &&
|
|
((rand() % 100) > 40)) {
|
|
Human* killer = nullptr;
|
|
if (hold_humans_.size() == 2) {
|
|
killer = hold_humans_[1];
|
|
} else {
|
|
killer = hold_humans_[1 + (rand() % (hold_humans_.size() - 1))];
|
|
}
|
|
hum->BeKill(killer->GetUniId(),
|
|
killer->name,
|
|
killer->GetCurrWeapon()->weapon_id);
|
|
} else if (room->GetGasData().gas_count > 1) {
|
|
hum->BeKill(VP_Gas,
|
|
TEXT("battle_server_killer_gas", "毒圈"),
|
|
VW_Gas);
|
|
} else {
|
|
return;
|
|
}
|
|
hold_humans_.erase(hold_humans_.begin());
|
|
room->xtimer.ModifyTimer(room->xtimer.GetRunningTimer(), SERVER_FRAME_RATE * (3 + rand() % 5));
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Incubator::ActiveAndroid(Human* hum, Human* android)
|
|
{
|
|
a8::Vec2 center = room->GetGasData().pos_new;
|
|
float start_distance = a8::RandEx(200, 600);
|
|
a8::Vec2 start_dir = a8::Vec2::UP;
|
|
start_dir.Rotate(a8::RandAngle());
|
|
|
|
android->SetPos(hum->GetPos());
|
|
int try_count = 0;
|
|
while (++try_count < 100) {
|
|
android->SetPos(center + start_dir * start_distance);
|
|
if (android->CollisonDetection() && !CanSee(android, hum)) {
|
|
break;
|
|
}
|
|
}
|
|
room->EnableHuman(android);
|
|
for (auto itr = hold_humans_.begin(); itr != hold_humans_.end(); ++itr) {
|
|
if (*itr == android) {
|
|
hold_humans_.erase(itr);
|
|
break;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
room->BroadcastDebugMsg(a8::Format("active android id:%d pos:%d,%d",
|
|
{
|
|
android->GetUniId(),
|
|
android->GetPos().x,
|
|
android->GetPos().y
|
|
}));
|
|
#endif
|
|
}
|
|
|
|
void Incubator::OnEnterNewWave(int wave)
|
|
{
|
|
if (room->IsGameOver()) {
|
|
return;
|
|
}
|
|
room->pve_data.wave = wave + 1;
|
|
room->OnEnterNewWave(wave + 1);
|
|
if (wave < 0) {
|
|
abort();
|
|
}
|
|
if (wave >= room->pve_mode_meta->waves.size()) {
|
|
abort();
|
|
}
|
|
if ((
|
|
room->pve_data.refreshed_mon > 0 &&
|
|
room->pve_data.mon_num > 0 &&
|
|
room->IsDestoryRoom()
|
|
) ||
|
|
(
|
|
room->IsSurvivalRoom() &&
|
|
room->pve_mode_meta->waves.size() == wave + 1)
|
|
){
|
|
timeout_ = true;
|
|
return;
|
|
}
|
|
|
|
if (wave > 0 && room->IsDestoryRoom()) {
|
|
return;
|
|
}
|
|
if (wave + 1 < room->pve_mode_meta->waves.size()) {
|
|
SpawnWaveMon(wave + 1);
|
|
}
|
|
}
|
|
|
|
void Incubator::SpawnWaveMon(int wave)
|
|
{
|
|
auto& mons = room->pve_mode_meta->waves[wave];
|
|
for (MetaData::PveGeminiContent* content : mons) {
|
|
room->xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
room->IsDestoryRoom() ? 0 : SERVER_FRAME_RATE * 2,
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(content)
|
|
.SetParam2(room),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
MetaData::PveGeminiContent* content = (MetaData::PveGeminiContent*)param.param1.GetUserData();
|
|
Room* room = (Room*)param.param2.GetUserData();
|
|
MetaData::Player* hero_meta = MetaMgr::Instance()->GetPlayer(content->pb->enemy_id());
|
|
if (hero_meta) {
|
|
a8::Vec2 hero_pos = content->spawn_point;
|
|
|
|
int team_id = 666;
|
|
Creature* master = nullptr;
|
|
|
|
a8::Vec2 dir = hero_pos;
|
|
dir.Normalize();
|
|
|
|
Hero* hero = room->CreateHero(master,
|
|
hero_meta,
|
|
hero_pos,
|
|
dir,
|
|
team_id);
|
|
if (!hero) {
|
|
A8_ABORT();
|
|
}
|
|
++room->pve_data.mon_num;
|
|
room->NotifyUiUpdate();
|
|
}
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
++room->pve_data.refreshed_mon;
|
|
}
|
|
}
|
|
|
|
int Incubator::GetPveLeftTime()
|
|
{
|
|
if (room->pve_data.wave >= wave_timers_.size() ||
|
|
room->pve_data.wave < 0) {
|
|
return 0;
|
|
}
|
|
xtimer_list* timer = wave_timers_[room->pve_data.wave];
|
|
int remain_time = room->xtimer.GetRemainTime(timer);
|
|
return remain_time * FRAME_RATE_MS;
|
|
}
|
|
|
|
bool Incubator::IsLastWave()
|
|
{
|
|
return room->pve_data.wave >= room->pve_mode_meta->waves.size();
|
|
}
|
|
|
|
|
|
void Incubator::NextWave()
|
|
{
|
|
if (room->pve_data.wave < wave_timers_.size() && room->IsSurvivalRoom()) {
|
|
int acc_time = 0;
|
|
{
|
|
xtimer_list* timer = wave_timers_[room->pve_data.wave];
|
|
int remain_time = room->xtimer.GetRemainTime(timer);
|
|
room->xtimer.ModifyTimer(timer, 0);
|
|
acc_time = remain_time;
|
|
}
|
|
for (int i = room->pve_data.wave; i < wave_timers_.size(); ++i) {
|
|
xtimer_list* timer = wave_timers_[i];
|
|
int remain_time = room->xtimer.GetRemainTime(timer);
|
|
room->xtimer.ModifyTimer(timer, remain_time - acc_time);
|
|
}
|
|
}
|
|
}
|