#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 } }