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

459 lines
15 KiB
C++

#include "precompile.h"
#include "incubator.h"
#include "room.h"
#include "human.h"
#include "metamgr.h"
#include "hero.h"
#include "player.h"
#include "cs_proto.pb.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_);
}
void Incubator::InitPve()
{
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_,
[] (const a8::XParams& param, bool is_destory)
{
int wave = param.param1.GetInt();
Incubator* incubator = (Incubator*)param.sender.GetUserData();
if (wave < incubator->wave_timers_.size()) {
incubator->wave_timers_[wave] = nullptr;
}
});
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];
Position old_pos = hum->GetPos();
// 999
#if 1
#else
hum->SetPos(target->GetPos() + dir * (MetaMgr::Instance()->incubator_base_length + rand_len));
#endif
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().Distance2D2(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().ManhattanDistance2D(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().ManhattanDistance2D(hum->GetPos()) <
MetaMgr::Instance()->incubator_canset_distance) {
can_see = false;
return false;
}
}
return true;
});
return can_see;
}
void Incubator::AutoAllocAndroid()
{
switch (room->GetGasData().GetGasMode()) {
case GasWaiting:
case GasMoving:
{
if (!hold_humans_.empty()){
Human* hum = hold_humans_[0];
if (room->GetGasData().GetGasMode() == 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,
killer->GetUniId(),
killer->name);
} else if (room->GetGasData().gas_count > 1) {
hum->BeKill(VP_Gas,
TEXT("battle_server_killer_gas", "毒圈"),
VW_Gas,
VP_Gas,
TEXT("battle_server_killer_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;
// 999
#if 1
#else
while (++try_count < 100) {
android->SetPos(center + start_dir * start_distance);
if (android->CollisonDetection() && !CanSee(android, hum)) {
break;
}
}
#endif
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)
{
#ifdef DEBUG
a8::XPrintf("OnEnterNewWave2 wave:%d \n", {wave + 1});
#endif
if (room->IsGameOver()) {
return;
}
if (timeout_) {
return;
}
if (
room->pve_data.refreshed_mon > 0 &&
room->pve_data.mon_num > 0
) {
timeout_ = true;
return;
}
room->pve_data.SetWave(wave + 1);
room->OnEnterNewWave(wave + 1);
if (wave < 0) {
abort();
}
if (wave >= room->pve_mode_meta->waves.size()) {
abort();
}
if (wave + 1 < room->pve_mode_meta->waves.size()) {
SpawnWaveMon(wave + 1);
}
}
void Incubator::SpawnWaveMon(int wave)
{
#ifdef DEBUG
a8::XPrintf("SpawnWaveMon wave:%d \n", {wave});
#endif
auto cb =
[] (const a8::XParams& param)
{
Incubator* incubator = (Incubator*)param.sender.GetUserData();
MetaData::PveGeminiContent* content = (MetaData::PveGeminiContent*)param.param1.GetUserData();
Room* room = incubator->room;
int wave = param.param2.GetInt();
int monIdx = param.param3.GetInt();
#ifdef DEBUG
a8::XPrintf("wave i:%d enemys_size:%d\n", {wave, content->enemys.size()});
#endif
if (monIdx < content->enemys.size()) {
int enemy_id = content->enemys[monIdx];
MetaData::Player* hero_meta = MetaMgr::Instance()->GetPlayer(enemy_id);
if (hero_meta) {
// 999
#if 1
Position hero_pos;
hero_pos.x = content->spawn_point.x;
hero_pos.y = content->spawn_point.y;
#else
Position hero_pos = content->spawn_point;
#endif
int team_id = 666;
Creature* master = nullptr;
// 999
#if 1
a8::Vec2 dir = a8::Vec2::UP;
#else
a8::Vec2 dir = hero_pos;
dir.Normalize();
#endif
Hero* hero = room->CreateHero(master,
hero_meta,
hero_pos,
dir,
team_id);
if (!hero) {
A8_ABORT();
}
#ifdef DEBUG1
{
room->xtimer.AddDeadLineTimerAndAttach
(
SERVER_FRAME_RATE * (rand() % 3),
a8::XParams()
.SetSender(hero),
[] (const a8::XParams& param)
{
Hero* hero = (Hero*)param.sender.GetUserData();
Human* hum = hero->room->GetOneAlivePlayer();
if (hum) {
hum->room->pve_data.AddDamageInfo(hum->GetUniId(), hero->GetUniId(), 1);
hero->BeKill(hum->GetUniId(), hum->name, hum->GetCurrWeapon()->weapon_id);
} else {
hero->BeKill(VP_Gas, TEXT("battle_server_killer_gas", "毒圈"), VW_Gas);
}
},
&hero->xtimer_attacher.timer_list_);
}
#endif
if (wave + 1 == room->pve_mode_meta->waves.size()) {
hero->is_pve_boss = true;
room->pve_data.boss_state = 1;
#ifdef DEBGU
a8::XPrintf("pve_boss appear\n", {});
#endif
}
++room->pve_data.mon_num;
room->NotifyUiUpdate();
}
}
};
auto& mons = room->pve_mode_meta->waves[wave];
for (MetaData::PveGeminiContent* content : mons) {
for (int i = 0; i < content->enemys.size(); ++i) {
room->xtimer.AddDeadLineTimerAndAttach
(
i == 0 ? 0 : (1000 + room->pve_mode_meta->pb->wave_prepare_time() * 1000) / FRAME_RATE_MS,
a8::XParams()
.SetSender(this)
.SetParam1(content)
.SetParam2(wave)
.SetParam3(i),
cb,
&xtimer_attacher_.timer_list_);
}
room->pve_data.refreshed_mon += content->enemys.size();
}
}
int Incubator::GetPveLeftTime()
{
if (room->pve_data.GetWave() >= wave_timers_.size() ||
room->pve_data.GetWave() < 0) {
return 0;
}
xtimer_list* timer = wave_timers_[room->pve_data.GetWave()];
if (!timer) {
return 0;
}
int remain_time = room->xtimer.GetRemainTime(timer);
return remain_time * FRAME_RATE_MS;
}
void Incubator::NextWave()
{
if (room->pve_data.GetWave() < wave_timers_.size()) {
#ifdef DEBUG
a8::XPrintf("NextWave wait_time:%d\n", {room->pve_mode_meta->pb->wave_prepare_time()});
#endif
int acc_time = 0;
{
xtimer_list* timer = wave_timers_[room->pve_data.GetWave()];
if (timer) {
int remain_time = room->xtimer.GetRemainTime(timer);
room->xtimer.ModifyTimer
(timer, room->pve_mode_meta->pb->wave_prepare_time() * SERVER_FRAME_RATE);
acc_time = remain_time;
}
}
acc_time -= room->pve_mode_meta->pb->wave_prepare_time() * SERVER_FRAME_RATE;
for (int i = room->pve_data.GetWave() + 1; 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);
}
#if 1
room->TraversePlayerList
(
a8::XParams(),
[this] (Player* hum, a8::XParams& param)
{
cs::SMPvePassWave notify_msg;
int next_wave = hum->room->pve_data.GetWave() + 1 + 1;
int max_wave = room->pve_data.max_wave;
next_wave = std::min(next_wave, max_wave);
notify_msg.set_new_wave(next_wave);
notify_msg.set_wait_time(hum->room->pve_mode_meta->pb->wave_prepare_time());
notify_msg.set_pve_max_wave(max_wave);
hum->SendNotifyMsg(notify_msg);
return true;
});
#endif
}
}