4336 lines
134 KiB
C++
4336 lines
134 KiB
C++
#include "precompile.h"
|
|
|
|
#include <random>
|
|
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
#include <a8/mutable_xobject.h>
|
|
#include <a8/collision.h>
|
|
|
|
#include <f8/udplog.h>
|
|
#include <f8/utils.h>
|
|
#include <f8/timer.h>
|
|
#include <f8/btmgr.h>
|
|
|
|
#include "playermgr.h"
|
|
#include "player.h"
|
|
#include "room.h"
|
|
#include "android.h"
|
|
#include "bullet.h"
|
|
#include "obstacle.h"
|
|
#include "roomobstacle.h"
|
|
#include "loot.h"
|
|
#include "car.h"
|
|
#include "hero.h"
|
|
#include "roommgr.h"
|
|
#include "app.h"
|
|
#include "gamelog.h"
|
|
#include "typeconvert.h"
|
|
#include "entityfactory.h"
|
|
#include "perfmonitor.h"
|
|
#include "mapinstance.h"
|
|
#include "mapmgr.h"
|
|
#include "incubator.h"
|
|
#include "team.h"
|
|
#include "frameeventdata.h"
|
|
#include "pbutils.h"
|
|
#include "movement.h"
|
|
#include "bornpoint.h"
|
|
#include "airdrop.h"
|
|
#include "airraid.h"
|
|
#include "sandtable.h"
|
|
#include "batchsync.h"
|
|
#include "trigger.h"
|
|
#include "custom_battle.h"
|
|
#include "custom_team.h"
|
|
#include "custom_member.h"
|
|
#include "room_agent.h"
|
|
#include "roomob.h"
|
|
#include "ingamevoice.h"
|
|
#include "jsondatamgr.h"
|
|
#include "httpproxy.h"
|
|
#include "netdata.h"
|
|
#include "stats.h"
|
|
#include "boxdrop.h"
|
|
|
|
#include "mt/Param.h"
|
|
#include "mt/Hero.h"
|
|
#include "mt/Equip.h"
|
|
#include "mt/Buff.h"
|
|
#include "mt/Skill.h"
|
|
#include "mt/SkillNumber.h"
|
|
#include "mt/SafeArea.h"
|
|
#include "mt/MapThing.h"
|
|
#include "mt/Text.h"
|
|
#include "mt/Map.h"
|
|
#include "mt/MapMode.h"
|
|
#include "mt/PveGemini.h"
|
|
#include "mt/PveGeminiMode.h"
|
|
#include "mt/RankReward.h"
|
|
#include "mt/RankPoint.h"
|
|
#include "mt/KillReward.h"
|
|
#include "mt/KillPoint.h"
|
|
#include "mt/Drop.h"
|
|
#include "mt/AirLine.h"
|
|
#include "mt/Robot.h"
|
|
#include "mt/SafeAreaPos.h"
|
|
#include "mt/MapThingGroup.h"
|
|
#include "mt/MobaRoom.h"
|
|
|
|
const int SHUA_RANGE = 580;
|
|
|
|
static long long RoomXGetTickCount(void* context)
|
|
{
|
|
Room* room = (Room*)context;
|
|
return room->GetFrameNo();
|
|
}
|
|
|
|
Room::~Room()
|
|
{
|
|
|
|
}
|
|
|
|
void Room::InitData(RoomInitInfo& init_info)
|
|
{
|
|
room_idx_ = init_info.room_idx;
|
|
room_mode_ = init_info.room_mode;
|
|
room_uuid_ = init_info.room_uuid;
|
|
room_type_ = init_info.room_type;
|
|
pve_human_num = init_info.pve_human_num;
|
|
|
|
grid_service = init_info.grid_service;
|
|
map_service = init_info.map_service;
|
|
map_instance = init_info.map_instance;
|
|
map_mode_meta_ = init_info.map_mode_meta;
|
|
map_meta_ = init_info.map_meta;
|
|
poly_ext_datas_ = map_instance->GetPolyExtDatas();
|
|
custom_battle_ = init_info.custom_battle;
|
|
rank_match_conf_ = mt::Param::GetRankModeConfByRoomType(room_type_);
|
|
}
|
|
|
|
void Room::Init()
|
|
{
|
|
xtimer.Init(RoomXGetTickCount, this, 100, 100);
|
|
xtimer_attacher_.SetOwner(&xtimer);
|
|
|
|
frame_event.room = this;
|
|
frame_event_data = std::make_shared<FrameEventData>();
|
|
|
|
ingame_voice_ = std::make_shared<InGameVoice>(this);
|
|
ingame_voice_->Init();
|
|
|
|
air_drop_ = std::make_shared<AirDrop>(this);
|
|
air_raid_ = std::make_shared<AirRaid>(this);
|
|
batch_sync_ = std::make_shared<BatchSync>(this);
|
|
room_agent_ = behaviac::Agent::Create<RoomAgent>();
|
|
room_agent_->SetRoom(this);
|
|
f8::BtMgr::Instance()->BtLoad(room_agent_, "npc/room");
|
|
f8::BtMgr::Instance()->BtSetCurrent(room_agent_, "npc/room");
|
|
|
|
CreateWorldObjects();
|
|
ShuaAndroid();
|
|
incubator_ = std::make_shared<Incubator>();
|
|
incubator_->room = this;
|
|
incubator_->Init();
|
|
sand_table_ = std::make_shared<SandTable>(this);
|
|
box_drop_ = std::make_shared<BoxDrop>(this);
|
|
#ifdef MYDEBUG
|
|
InitDebugInfo();
|
|
#endif
|
|
if (IsMobaModeRoom()) {
|
|
moba_over_timer = xtimer.SetTimeoutWpEx
|
|
(SERVER_FRAME_RATE * GetMapMeta()->GetMobaRoomMeta()->game_time(),
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (!IsGameOver() && !GetVictoryTeam()) {
|
|
if (GetMobaTeamA()->GetKillCount() == GetMobaTeamB()->GetKillCount()) {
|
|
moba_overtime_race_frameno_ = GetFrameNo();
|
|
xtimer.SetTimeoutWpEx
|
|
(SERVER_FRAME_RATE * GetMapMeta()->GetMobaRoomMeta()->game_time(),
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
MobaOver();
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
return;
|
|
}
|
|
MobaOver();
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
xtimer.SetIntervalWpEx
|
|
(SERVER_FRAME_RATE * 1,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (!IsGameOver() && !GetVictoryTeam()) {
|
|
MobaBatterysUpdate();
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
if (GetMapMeta()->GetMobaRoomMeta()->moba_towers.size() == 2) {
|
|
xtimer.SetIntervalWpEx
|
|
(SERVER_FRAME_RATE * GetMapMeta()->GetMobaRoomMeta()->tower_interval(),
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (!IsGameOver() && !GetVictoryTeam()) {
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
const auto side = i + 1;
|
|
auto& tuple = GetMapMeta()->GetMobaRoomMeta()->moba_towers.at(i);
|
|
TraverseTeams
|
|
(
|
|
[&tuple, side] (Team* team) -> bool
|
|
{
|
|
team->TraverseMembers
|
|
(
|
|
[&tuple, side] (Human* hum) -> bool
|
|
{
|
|
if (hum->side != side) {
|
|
return false;
|
|
}
|
|
float distance = hum->GetPos().Distance2D2(std::get<0>(tuple));
|
|
if (distance < std::get<1>(tuple)) {
|
|
if (!hum->dead && !hum->poisoning && !hum->downed) {
|
|
if (hum->GetHP() + 1 < hum->GetMaxHP()) {
|
|
hum->AddHp(hum->GetMaxHP() *
|
|
hum->room->GetMapMeta()->GetMobaRoomMeta()->tower_recover_hp_rate() *
|
|
(1.0f + hum->GetNetData()->GetDrugEfficacyPct()));
|
|
hum->TryAddBuff(hum, kRecoverHpEffectBuffId);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
}
|
|
ob_ = std::make_shared<RoomOb>(this);
|
|
ob_->Init();
|
|
}
|
|
|
|
void Room::UnInit()
|
|
{
|
|
destorying_ = true;
|
|
incubator_->UnInit();
|
|
#ifdef MYDEBUG
|
|
UnInitDebugInfo();
|
|
#endif
|
|
box_drop_->UnInit();
|
|
box_drop_ = nullptr;
|
|
incubator_ = nullptr;
|
|
timer_attacher.ClearTimerList();
|
|
xtimer_attacher_.ClearTimerList();
|
|
grid_service->ClearRoomData(this);
|
|
for (auto& pair : accountid_hash_) {
|
|
PlayerMgr::Instance()->RemovePlayerBySocket(pair.second->GetSocketHandle());
|
|
}
|
|
for (auto& pair : uniid_hash_) {
|
|
delete pair.second;
|
|
}
|
|
uniid_hash_.clear();
|
|
for (auto& pair : later_add_hash_) {
|
|
delete pair.second;
|
|
}
|
|
later_add_hash_.clear();
|
|
for (auto& pair : removed_robot_hash_) {
|
|
delete pair.second;
|
|
}
|
|
removed_robot_hash_.clear();
|
|
f8::BtMgr::Instance()->BtDestory(room_agent_);
|
|
room_agent_ = nullptr;
|
|
team_hash_.clear();
|
|
frame_event_data = nullptr;
|
|
PerfMonitor::Instance()->alive_count -= AliveCount();
|
|
ob_->UnInit();
|
|
ob_ = nullptr;
|
|
ingame_voice_->UnInit();
|
|
ingame_voice_ = nullptr;
|
|
}
|
|
|
|
void Room::Update(int delta_time)
|
|
{
|
|
xtimer.Update();
|
|
if (IsGameOver() && GetFrameNo() - game_over_frameno_ > SERVER_FRAME_RATE * 20) {
|
|
elapsed_time_ += delta_time;
|
|
while (elapsed_time_ >= 50) {
|
|
++frameno_;
|
|
elapsed_time_ -= 50;
|
|
}
|
|
return;
|
|
}
|
|
|
|
elapsed_time_ += delta_time;
|
|
while (elapsed_time_ >= 50) {
|
|
#ifdef MYDEBUG1
|
|
long long begin_tick = a8::XGetTickCount();
|
|
long long end_tick = a8::XGetTickCount();
|
|
#endif
|
|
room_agent_->Exec();
|
|
if (GetFrameNo() % 2 == 0) {
|
|
UpdateGas();
|
|
}
|
|
#ifdef MYDEBUG1
|
|
end_tick = a8::XGetTickCount();
|
|
if (a8::XGetTickCount() - begin_tick > 1000) {
|
|
A8_ABORT();
|
|
}
|
|
begin_tick = a8::XGetTickCount();
|
|
#endif
|
|
for (auto& pair : moveable_hash_) {
|
|
pair.second->Update(50);
|
|
pair.second->LateUpdate(50);
|
|
}
|
|
for (auto& pair : task_hash_) {
|
|
(*pair.second)(nullptr);
|
|
}
|
|
#ifdef MYDEBUG1
|
|
end_tick = a8::XGetTickCount();
|
|
if (a8::XGetTickCount() - begin_tick > 1000) {
|
|
A8_ABORT();
|
|
}
|
|
begin_tick = a8::XGetTickCount();
|
|
#endif
|
|
if (GetFrameNo() % 2 == 0) {
|
|
SyncFrameData();
|
|
}
|
|
#ifdef MYDEBUG1
|
|
end_tick = a8::XGetTickCount();
|
|
if (a8::XGetTickCount() - begin_tick > 1000) {
|
|
A8_ABORT();
|
|
}
|
|
#endif
|
|
++frameno_;
|
|
elapsed_time_ -= 50;
|
|
}
|
|
}
|
|
|
|
bool Room::IsPveRoom()
|
|
{
|
|
return GetMapMeta()->IsPveMap();
|
|
}
|
|
|
|
int Room::GetPlayerNum()
|
|
{
|
|
int num = 0;
|
|
if (BattleStarted()) {
|
|
num = battle_player_count_;
|
|
} else {
|
|
TraversePlayerList
|
|
(
|
|
[&num] (Player* hum) -> bool
|
|
{
|
|
if (!hum->IsOb()) {
|
|
++num;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
return num;
|
|
}
|
|
|
|
int Room::GetHumanNum()
|
|
{
|
|
int num = 0;
|
|
if (BattleStarted()) {
|
|
num = battle_human_count_;
|
|
} else {
|
|
TraverseHumanList
|
|
(
|
|
[&num] (Human* hum) -> bool
|
|
{
|
|
if (!hum->IsOb()) {
|
|
++num;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
return num;
|
|
}
|
|
|
|
Player* Room::GetPlayerByAccountId(const std::string& accountid)
|
|
{
|
|
auto itr = accountid_hash_.find(accountid);
|
|
return itr != accountid_hash_.end() ? itr->second : nullptr;
|
|
}
|
|
|
|
Player* Room::GetPlayerByUniId(int uniid)
|
|
{
|
|
Entity* entity = GetEntityByUniId(uniid);
|
|
if (!entity) {
|
|
return nullptr;
|
|
}
|
|
return entity->IsEntityType(ET_Player) && entity->IsEntitySubType(EST_Player) ?
|
|
(Player*)entity : nullptr;
|
|
}
|
|
|
|
Entity* Room::GetEntityByUniId(int uniid)
|
|
{
|
|
auto itr = uniid_hash_.find(uniid);
|
|
return itr != uniid_hash_.end() ? itr->second : nullptr;
|
|
}
|
|
|
|
Human* Room::GetHumanByUniId(int uniid)
|
|
{
|
|
Entity* entity = GetEntityByUniId(uniid);
|
|
return entity && entity->GetEntityType() == ET_Player ? (Human*)entity : nullptr;
|
|
}
|
|
|
|
int Room::AliveCount()
|
|
{
|
|
return alive_count_;
|
|
}
|
|
|
|
Player* Room::NewPlayer()
|
|
{
|
|
Player* hum = EntityFactory::Instance()->MakePlayer(AllocUniid());
|
|
return hum;
|
|
}
|
|
|
|
void Room::AddPlayer(Player* hum, std::shared_ptr<BornPoint> init_born_point, bool no_matchteam)
|
|
{
|
|
if (GetGasData().GetGasMode() != GasInactive) {
|
|
A8_ABORT();
|
|
}
|
|
if (!hum->IsOb()) {
|
|
while (GetHumanNum() >= GetRoomMaxPlayerNum()) {
|
|
RandRemoveAndroid();
|
|
}
|
|
}
|
|
if (init_born_point) {
|
|
hum->SetBornPoint(init_born_point);
|
|
} else {
|
|
hum->SetBornPoint(AllocBornPoint(hum));
|
|
}
|
|
App::Instance()->verify_set_pos = 1;
|
|
if (!hum->GetBornPoint()) {
|
|
abort();
|
|
} else {
|
|
if (!IsMobaModeRoom() && !IsSandTableRoom()) {
|
|
hum->SetPos(hum->GetBornPoint()->NewRandPoint(hum->room, 10, 100));
|
|
} else {
|
|
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
|
|
}
|
|
}
|
|
App::Instance()->verify_set_pos = 0;
|
|
glm::vec3 attack_dir = hum->GetPos().ToGlmVec3();
|
|
GlmHelper::Normalize(attack_dir);
|
|
GlmHelper::RotateY(attack_dir, a8::RandAngle());
|
|
hum->SetAttackDir(attack_dir);
|
|
hum->SetMoveDir(attack_dir);
|
|
hum->room = this;
|
|
hum->join_frameno = GetFrameNo();
|
|
hum->Initialize();
|
|
AddToEntityHash(hum);
|
|
AddToMoveableHash(hum);
|
|
AddToAccountHash(hum);
|
|
AddToHumanHash(hum);
|
|
if (!hum->IsOb()) {
|
|
AddToAliveHumanHash(hum);
|
|
}
|
|
if (!no_matchteam) {
|
|
MatchTeam(hum);
|
|
}
|
|
hum->PushJoinRoomMsg();
|
|
if (!hum->IsOb()) {
|
|
IncAliveCount();
|
|
}
|
|
grid_service->AddCreature(hum);
|
|
hum->FindLocation();
|
|
hum->RefreshView();
|
|
AddPlayerPostProc(hum);
|
|
NotifyUiUpdate();
|
|
OnAddHuman(hum);
|
|
frame_event.AddEnterGame(hum->GetWeakPtrRef());
|
|
GameLog::Instance()->GameStart(hum);
|
|
if (custom_battle_ && custom_battle_->AllIsJoined()) {
|
|
if (GetGasInactiveReaminTime() > 3) {
|
|
acc_inactive_time_ += GetGasInactiveReaminTime() - 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
int Room::AllocUniid()
|
|
{
|
|
while (GetEntityByUniId(++current_uniid_) ||
|
|
later_add_hash_.find(current_uniid_) != later_add_hash_.end() ||
|
|
current_uniid_ == 0) {}
|
|
return current_uniid_;
|
|
}
|
|
|
|
void Room::ShuaAndroid()
|
|
{
|
|
if (IsCustomBattle()) {
|
|
return;
|
|
}
|
|
if (GetGasData().GetGasMode() != GasInactive) {
|
|
return;
|
|
}
|
|
if (IsMobaModeRoom()) {
|
|
return;
|
|
}
|
|
int robot_num = a8::RandEx(map_meta_->refresh_robot_min_num,
|
|
map_meta_->refresh_robot_max_num);
|
|
int refresh_time = a8::RandEx(map_meta_->refresh_robot_min_time,
|
|
map_meta_->refresh_robot_max_time);
|
|
if (robot_num > 0 && refresh_time > 0) {
|
|
CreateAndroid(robot_num);
|
|
xtimer.SetTimeoutEx
|
|
(SERVER_FRAME_RATE * refresh_time,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
ShuaAndroid();
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
}
|
|
|
|
void Room::CreateAndroid(int robot_num, std::shared_ptr<Team> team)
|
|
{
|
|
for (int i = 0; i < robot_num; ++i) {
|
|
if (GetHumanNum() >= GetRoomMaxPlayerNum()) {
|
|
return;
|
|
}
|
|
const mt::Robot* robot_meta = mt::Robot::RandRobot(refreshed_robot_set_);
|
|
if (!robot_meta) {
|
|
A8_ABORT();
|
|
}
|
|
|
|
Android* hum = EntityFactory::Instance()->MakeAndroid(AllocUniid());
|
|
hum->name = robot_meta->name();
|
|
#if 0
|
|
hum->meta = mt::Hero::GetById(30100);
|
|
#else
|
|
hum->meta = mt::Hero::GetById(robot_meta->hero_id());
|
|
#endif
|
|
hum->robot_meta = robot_meta;
|
|
hum->SetBornPoint(AllocBornPoint(hum));
|
|
App::Instance()->verify_set_pos = 1;
|
|
if (!hum->GetBornPoint()) {
|
|
abort();
|
|
} else {
|
|
if (!IsMobaModeRoom() && !IsSandTableRoom()) {
|
|
hum->SetPos(hum->GetBornPoint()->NewRandPoint(hum->room, 10, 100));
|
|
} else {
|
|
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
|
|
}
|
|
}
|
|
App::Instance()->verify_set_pos = 0;
|
|
glm::vec3 attack_dir = hum->GetPos().ToGlmVec3();
|
|
GlmHelper::Normalize(attack_dir);
|
|
GlmHelper::RotateY(attack_dir, a8::RandAngle());
|
|
hum->SetAttackDir(attack_dir);
|
|
hum->SetMoveDir(attack_dir);
|
|
hum->room = this;
|
|
hum->join_frameno = GetFrameNo();
|
|
hum->Initialize();
|
|
AddToEntityHash(hum);
|
|
AddToHumanHash(hum);
|
|
if (team) {
|
|
team->AddMember(hum);
|
|
} else {
|
|
MatchTeam(hum);
|
|
}
|
|
if (!hum->IsOb()) {
|
|
IncAliveCount();
|
|
}
|
|
refreshed_robot_set_.insert(robot_meta->id());
|
|
if (!CanAddToScene(hum)) {
|
|
a8::SetBitFlag(hum->status, CS_Disable);
|
|
} else {
|
|
AddToAliveHumanHash(hum);
|
|
AddToMoveableHash(hum);
|
|
grid_service->AddCreature(hum);
|
|
hum->FindLocation();
|
|
hum->RefreshView();
|
|
}
|
|
OnAddHuman(hum);
|
|
frame_event.AddEnterGame(hum->GetWeakPtrRef());
|
|
}
|
|
NotifyUiUpdate();
|
|
}
|
|
|
|
Human* Room::CreateAndroidWithCustomMember(std::shared_ptr<CustomMember> custom_member,
|
|
std::shared_ptr<Team> team)
|
|
{
|
|
if (GetHumanNum() >= GetRoomMaxPlayerNum()) {
|
|
return nullptr;
|
|
}
|
|
const mt::Robot* robot_meta = mt::Robot::GetById(custom_member->GetRobotId());
|
|
if (!robot_meta) {
|
|
A8_ABORT();
|
|
}
|
|
|
|
Android* hum = EntityFactory::Instance()->MakeAndroid(AllocUniid());
|
|
hum->name = robot_meta->name();
|
|
hum->meta = mt::Hero::GetById(custom_member->GetNetData()->GetHeroId());
|
|
hum->robot_meta = robot_meta;
|
|
hum->SetBornPoint(AllocBornPoint(hum));
|
|
App::Instance()->verify_set_pos = 1;
|
|
if (!hum->GetBornPoint()) {
|
|
abort();
|
|
} else {
|
|
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
|
|
}
|
|
App::Instance()->verify_set_pos = 0;
|
|
glm::vec3 attack_dir = hum->GetPos().ToGlmVec3();
|
|
GlmHelper::Normalize(attack_dir);
|
|
GlmHelper::RotateY(attack_dir, a8::RandAngle());
|
|
hum->SetAttackDir(attack_dir);
|
|
hum->SetMoveDir(attack_dir);
|
|
hum->room = this;
|
|
hum->join_frameno = GetFrameNo();
|
|
hum->Initialize();
|
|
AddToEntityHash(hum);
|
|
AddToHumanHash(hum);
|
|
if (team) {
|
|
team->AddMember(hum);
|
|
} else {
|
|
MatchTeam(hum);
|
|
}
|
|
if (!hum->IsOb()) {
|
|
IncAliveCount();
|
|
}
|
|
refreshed_robot_set_.insert(robot_meta->id());
|
|
if (!CanAddToScene(hum)) {
|
|
a8::SetBitFlag(hum->status, CS_Disable);
|
|
} else {
|
|
AddToAliveHumanHash(hum);
|
|
AddToMoveableHash(hum);
|
|
grid_service->AddCreature(hum);
|
|
hum->FindLocation();
|
|
hum->RefreshView();
|
|
}
|
|
OnAddHuman(hum);
|
|
frame_event.AddEnterGame(hum->GetWeakPtrRef());
|
|
NotifyUiUpdate();
|
|
return hum;
|
|
}
|
|
|
|
void Room::FillSMJoinedNotify(Human* self_hum, cs::SMJoinedNotify& msg)
|
|
{
|
|
msg.set_team_mode(msg.team_mode());
|
|
msg.set_adjust_bullet(1);
|
|
msg.set_is_newbie_room(IsNewBieBattle());
|
|
}
|
|
|
|
void Room::ScatterDrop(const glm::vec3& center, int drop_id, bool no_adjust, std::vector<int>* items)
|
|
{
|
|
const mt::Drop* drop_meta = mt::Drop::GetById(drop_id);
|
|
if (drop_meta) {
|
|
std::vector<std::tuple<int, int, int>> drop_items;
|
|
drop_meta->RandItems(drop_items);
|
|
for (auto& item : drop_items) {
|
|
glm::vec3 dir = GlmHelper::UP;
|
|
GlmHelper::RotateY(dir, a8::RandAngle());
|
|
const glm::vec3 pos = center;
|
|
const mt::Equip* equip_meta = mt::Equip::GetById(std::get<0>(item));
|
|
if (equip_meta) {
|
|
DropItemEx(center,
|
|
pos,
|
|
std::get<0>(item),
|
|
std::get<1>(item),
|
|
std::get<2>(item),
|
|
true,
|
|
no_adjust,
|
|
items);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::DropItem(const glm::vec3& pos, int item_id, int item_count, int item_lv, bool no_adjust,
|
|
std::vector<int>* items)
|
|
{
|
|
DropItemEx(pos, pos, item_id, item_count, item_lv, false, no_adjust, items);
|
|
}
|
|
|
|
void Room::DropItemEx(const glm::vec3& born_pos, const glm::vec3& pos,
|
|
int item_id, int item_count, int item_lv, bool show_anim, bool no_adjust,
|
|
std::vector<int>* items)
|
|
{
|
|
const mt::Equip* equip_meta = mt::Equip::GetById(item_id);
|
|
if (!equip_meta) {
|
|
return;
|
|
}
|
|
int group_num = equip_meta->group_num();
|
|
if (item_id == mt::Equip::YELLOW_STONE_ID && group_num <= 0) {
|
|
group_num = 1;
|
|
}
|
|
group_num = std::max(group_num, 1);
|
|
if (equip_meta && group_num > 0 && item_count > 0) {
|
|
#if 1
|
|
if (equip_meta->equip_type() == EQUIP_TYPE_BULLET) {
|
|
return;
|
|
}
|
|
#endif
|
|
int total_count = item_count;
|
|
while (total_count > 0) {
|
|
int drop_num = std::min(total_count, group_num);
|
|
if (drop_num < 1) {
|
|
drop_num = 1;
|
|
}
|
|
glm::vec3 dir = GlmHelper::UP;
|
|
GlmHelper::RotateY(dir, a8::RandAngle());
|
|
int obj_uniid = CreateLootEx(item_id,
|
|
born_pos,
|
|
pos + dir * (25.0f + rand() % 50),
|
|
drop_num,
|
|
item_lv,
|
|
show_anim,
|
|
no_adjust);
|
|
if (obj_uniid && items) {
|
|
items->push_back(obj_uniid);
|
|
}
|
|
total_count -= drop_num;
|
|
}
|
|
}
|
|
}
|
|
|
|
RoomObstacle* Room::CreateObstacle(int id, float x, float y, float z,
|
|
std::shared_ptr<a8::Args> init_args)
|
|
{
|
|
RoomObstacle* entity = InternalCreateObstacle(id, x, y, z,
|
|
[] (Obstacle*)
|
|
{
|
|
},
|
|
init_args);
|
|
assert(entity);
|
|
if (entity) {
|
|
entity->BroadcastFullState(this);
|
|
}
|
|
return entity;
|
|
}
|
|
|
|
int Room::CreateLoot(int equip_id, const glm::vec3& born_pos, const glm::vec3& pos, int count,
|
|
int equip_lv, bool no_adjust)
|
|
{
|
|
return CreateLootEx(equip_id, born_pos, pos, count, equip_lv, false, no_adjust);
|
|
}
|
|
|
|
int Room::CreateLootEx(int equip_id, const glm::vec3& born_pos, const glm::vec3& pos, int count,
|
|
int equip_lv, bool show_anim, bool no_adjust)
|
|
{
|
|
glm::vec3 real_pos = pos;
|
|
if (!no_adjust) {
|
|
real_pos = born_pos;
|
|
glm::vec3 dir = pos - born_pos;
|
|
dir.y = 0;
|
|
float distance = GlmHelper::Norm2D(dir);
|
|
if (distance > 10) {
|
|
GlmHelper::Normalize(dir);
|
|
glm::vec3 start = born_pos;
|
|
map_instance->Scale(start);
|
|
for (int i = 0; i < 4; ++i) {
|
|
glm::vec3 end = born_pos + dir * distance;
|
|
glm::vec3 hit_point;
|
|
bool hit_result = false;
|
|
map_instance->Scale(end);
|
|
bool need_adjust = true;
|
|
if (map_instance->Raycast(start,
|
|
end,
|
|
hit_point,
|
|
hit_result,
|
|
map_instance->GetMoveIncludeFlags(),
|
|
map_instance->GetMoveExcludeFlags())) {
|
|
map_instance->UnScale(hit_point);
|
|
if (GlmHelper::Norm2D(hit_point - born_pos) > 5) {
|
|
real_pos = hit_point;
|
|
need_adjust = false;
|
|
break;
|
|
}
|
|
}
|
|
GlmHelper::RotateY(dir, glm::radians(90.0f));
|
|
}
|
|
}
|
|
}
|
|
const mt::Equip* equip_meta = mt::Equip::GetById(equip_id);
|
|
if (equip_meta) {
|
|
Loot* entity = EntityFactory::Instance()->MakeLoot(AllocUniid());
|
|
entity->room = this;
|
|
entity->meta = equip_meta;
|
|
entity->GetMutablePos().FromGlmVec3(real_pos);
|
|
entity->born_pos.FromGlmVec3(born_pos);
|
|
entity->show_anim = show_anim;
|
|
entity->create_frame_no = GetFrameNo();
|
|
#if 1
|
|
{
|
|
if (entity->GetPos().GetX() >= map_meta_->map_width()) {
|
|
entity->GetMutablePos().SetX(map_meta_->map_width() - 1);
|
|
}
|
|
if (entity->GetPos().GetX() < 1.0f) {
|
|
entity->GetMutablePos().SetX(1.0f);
|
|
}
|
|
if (entity->GetPos().GetY() >= map_meta_->map_height()) {
|
|
entity->GetMutablePos().SetY(map_meta_->map_height() - 1);
|
|
}
|
|
if (entity->GetPos().GetY() < 1.0f) {
|
|
entity->GetMutablePos().SetY(1.0f);
|
|
}
|
|
}
|
|
#endif
|
|
entity->item_id = equip_id;
|
|
entity->count = count;
|
|
entity->item_level = equip_lv;
|
|
entity->Initialize();
|
|
AddToEntityHash(entity);
|
|
grid_service->AddRoomEntity(this, entity);
|
|
entity->BroadcastFullState(this);
|
|
return entity->GetUniId();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int Room::CreateBullet(Creature* sender,
|
|
Creature* passenger,
|
|
const mt::Equip* weapon_meta,
|
|
const mt::Equip* bullet_meta,
|
|
const mt::Skill* skill_meta,
|
|
glm::vec3 pos,
|
|
glm::vec3 dir,
|
|
float fly_distance,
|
|
long long weapon_uniid,
|
|
int trace_target_id,
|
|
int hand,
|
|
a8::XTimerWp keep_shot_animi_timer_ptr,
|
|
float shot_animi_time,
|
|
int weapon_buff_id,
|
|
std::shared_ptr<std::set<int>> reporter_list,
|
|
int shot_uniid,
|
|
std::function<void(Bullet*)> on_bullet_exit,
|
|
int duration,
|
|
std::shared_ptr<float> scale)
|
|
{
|
|
int bullet_uniid = 0;
|
|
if (grid_service->CanAdd(pos.x, pos.z)) {
|
|
Bullet* bullet = EntityFactory::Instance()->MakeBullet(AllocUniid());
|
|
bullet->sender.Attach(sender);
|
|
if (passenger) {
|
|
bullet->passenger.Attach(passenger);
|
|
}
|
|
bullet->room = this;
|
|
bullet->weapon_uniid = weapon_uniid;
|
|
bullet->gun_meta = weapon_meta;
|
|
bullet->meta = bullet_meta;
|
|
bullet->skill_meta = skill_meta;
|
|
bullet->GetMutablePos().FromGlmVec3(pos);
|
|
bullet->dir = dir;
|
|
bullet->born_pos.FromGlmVec3(pos);
|
|
bullet->born_dir = dir;
|
|
bullet->fly_distance = fly_distance;
|
|
bullet->trace_target_id = trace_target_id;
|
|
bullet->hand = hand;
|
|
bullet->keep_shot_animi_timer_ptr = keep_shot_animi_timer_ptr;
|
|
bullet->shot_animi_time = shot_animi_time;
|
|
bullet->spec_gun_buff_id = weapon_buff_id;
|
|
bullet->reporter_list = reporter_list;
|
|
bullet->shot_uniid = shot_uniid;
|
|
bullet->on_bullet_exit = on_bullet_exit;
|
|
bullet->duration = duration;
|
|
bullet->Initialize();
|
|
#ifdef MYDEBUG1
|
|
a8::XPrintf("xxxxxxx born_pos:%f,%f,%f curr_pos:%f,%f,%f\n",
|
|
{
|
|
bullet->born_pos.x,
|
|
bullet->born_pos.y,
|
|
bullet->born_pos.z,
|
|
|
|
bullet->GetPos().x,
|
|
bullet->GetPos().y,
|
|
bullet->GetPos().z,
|
|
|
|
});
|
|
#endif
|
|
AddObjectLater(bullet);
|
|
bullet_uniid = bullet->GetUniId();
|
|
}
|
|
return bullet_uniid;
|
|
}
|
|
|
|
Car* Room::CreateCar(Human* driver,
|
|
int car_uniid,
|
|
const mt::Equip* item_meta,
|
|
const glm::vec3& pos,
|
|
int team_id,
|
|
std::set<int>* special_operators)
|
|
{
|
|
Car* car = EntityFactory::Instance()->MakeCar(AllocUniid());
|
|
car->car_uniid = car_uniid;
|
|
car->meta = item_meta;
|
|
car->room = this;
|
|
car->team_id = team_id;
|
|
car->GetMutablePos().FromGlmVec3(pos);
|
|
car->SetAttackDir(GlmHelper::DONW);
|
|
if (special_operators) {
|
|
car->SetSpecialOperators(*special_operators);
|
|
}
|
|
car->Initialize();
|
|
AddToEntityHash(car);
|
|
AddToMoveableHash(car);
|
|
grid_service->AddCreature(car);
|
|
car->RefreshView();
|
|
for (int buff_id : car->hero_meta_->_init_buffs) {
|
|
car->MustBeAddBuff(car, buff_id);
|
|
}
|
|
return car;
|
|
}
|
|
|
|
Hero* Room::CreateHero(Creature* master,
|
|
const mt::Hero* meta,
|
|
const glm::vec3& pos,
|
|
const glm::vec3& dir,
|
|
int team_id,
|
|
int obj_uniid)
|
|
{
|
|
if (obj_uniid > 0) {
|
|
if (GetEntityByUniId(obj_uniid)) {
|
|
abort();
|
|
}
|
|
} else {
|
|
obj_uniid = AllocUniid();
|
|
}
|
|
Hero* hero = EntityFactory::Instance()->MakeHero(obj_uniid);
|
|
hero->meta = meta;
|
|
if (master) {
|
|
hero->master.Attach(master);
|
|
}
|
|
hero->room = this;
|
|
hero->src_pos = pos;
|
|
hero->GetMutablePos().FromGlmVec3(pos);
|
|
hero->SetMoveDir(dir);
|
|
hero->SetAttackDir(dir);
|
|
hero->team_id = team_id;
|
|
hero->Initialize();
|
|
AddToEntityHash(hero);
|
|
AddToMoveableHash(hero);
|
|
grid_service->AddCreature(hero);
|
|
hero->RefreshView();
|
|
for (int buff_id : meta->_init_buffs) {
|
|
hero->MustBeAddBuff(hero, buff_id);
|
|
}
|
|
return hero;
|
|
}
|
|
|
|
void Room::RemoveObjectLater(RoomEntity* entity)
|
|
{
|
|
InternalRemoveObjectLater(entity, entity->xtimer_attacher);
|
|
}
|
|
|
|
void Room::RemoveObjectLater(RoomObstacle* entity)
|
|
{
|
|
InternalRemoveObjectLater(entity, entity->xtimer_attacher);
|
|
}
|
|
|
|
void Room::InternalRemoveObjectLater(Entity* entity, a8::Attacher& xtimer_attacher)
|
|
{
|
|
int entity_uniid = entity->GetUniId();
|
|
auto remove_func =
|
|
[this, entity_uniid] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT != event) {
|
|
return;
|
|
}
|
|
Entity* entity = GetEntityByUniId(entity_uniid);
|
|
if (!entity) {
|
|
return;
|
|
}
|
|
switch (entity->GetEntityType()) {
|
|
case ET_Bullet:
|
|
{
|
|
RemoveFromMoveableHash((Bullet*)entity);
|
|
}
|
|
break;
|
|
case ET_Loot:
|
|
{
|
|
entity->BroadcastDeleteState(this);
|
|
grid_service->DelRoomEntity(this, entity);
|
|
}
|
|
break;
|
|
case ET_Player:
|
|
{
|
|
RemoveFromMoveableHash((Human*)entity);
|
|
RemoveFromHuamnHash((Human*)entity);
|
|
}
|
|
break;
|
|
case ET_Car:
|
|
{
|
|
#if 0
|
|
RemoveFromAroundPlayers(entity->room);
|
|
BroadcastDeleteState(entity->room);
|
|
grid_service->RemoveCreature((Car*)entity);
|
|
#endif
|
|
RemoveFromMoveableHash((Car*)entity);
|
|
}
|
|
break;
|
|
case ET_Hero:
|
|
{
|
|
#if 0
|
|
BroadcastDeleteState(entity->room);
|
|
RemoveFromAroundPlayers(entity->room);
|
|
grid_service->RemoveCreature((Hero*)entity);
|
|
#endif
|
|
RemoveFromMoveableHash((Hero*)entity);
|
|
}
|
|
break;
|
|
case ET_Obstacle:
|
|
{
|
|
entity->BroadcastDeleteState(this);
|
|
grid_service->DelRoomEntity(this, entity);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
A8_ABORT();
|
|
}
|
|
break;
|
|
}
|
|
RemoveFromEntityHash(entity);
|
|
#ifdef MYDEBUG
|
|
#if 0
|
|
f8::UdpLog::Instance()->Debug
|
|
(
|
|
"remove object pointer:%d uniid:%d",
|
|
{
|
|
(long long)entity,
|
|
entity->GetUniId()
|
|
}
|
|
);
|
|
#endif
|
|
#endif
|
|
delete entity;
|
|
};
|
|
if (!entity->removing) {
|
|
entity->removing = true;
|
|
xtimer.SetTimeoutEx
|
|
(NEXT_FRAME_TIMER,
|
|
remove_func,
|
|
&xtimer_attacher);
|
|
}
|
|
}
|
|
|
|
void Room::OnHumanDie(Human* hum)
|
|
{
|
|
if (!hum->IsOb()) {
|
|
DecAliveCount();
|
|
RemoveFromAliveHumanHash(hum);
|
|
NotifyUiUpdate();
|
|
}
|
|
}
|
|
|
|
void Room::OnHumanRevive(Human* hum)
|
|
{
|
|
NotifyUiUpdate();
|
|
}
|
|
|
|
bool Room::OverBorder(const glm::vec3& pos, float radius)
|
|
{
|
|
{
|
|
if (pos.x - radius < 0.0001f) {
|
|
return true;
|
|
}
|
|
if (pos.x + radius > map_meta_->map_width()) {
|
|
return true;
|
|
}
|
|
}
|
|
{
|
|
if (pos.z - radius < 0.0001f) {
|
|
return true;
|
|
}
|
|
if (pos.z + radius > map_meta_->map_height()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Human* Room::GetWatchWarTarget(Human* hum)
|
|
{
|
|
if (!mt::Param::s().watchable) {
|
|
return nullptr;
|
|
}
|
|
if (hum->GetTeam()) {
|
|
Human* member = hum->GetTeam()->RandomOneAliveMember(hum);
|
|
if (member) {
|
|
return member;
|
|
}
|
|
}
|
|
|
|
std::vector<Human*> players;
|
|
std::vector<Human*> humans;
|
|
TraverseHumanList
|
|
(
|
|
[hum, &players, &humans] (Human* ele_hum) -> bool
|
|
{
|
|
if (ele_hum->GetUniId() != hum->GetUniId() &&
|
|
!ele_hum->dead &&
|
|
!a8::HasBitFlag(ele_hum->status, CS_Disable)) {
|
|
if (ele_hum->IsPlayer()) {
|
|
players.push_back(ele_hum);
|
|
} else {
|
|
humans.push_back(ele_hum);
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
|
|
Human* target = nullptr;
|
|
if (!players.empty()) {
|
|
target = players[rand() % players.size()];
|
|
} else if (!humans.empty()) {
|
|
target = humans[rand() % humans.size()];
|
|
#ifdef MYDEBUG1
|
|
{
|
|
std::sort(humans.begin(), humans.end(),
|
|
[hum] (Human* a, Human *b) -> bool
|
|
{
|
|
return (hum->GetPos()-a->GetPos()).Norm() < (hum->GetPos()-b->GetPos()).Norm();
|
|
});
|
|
target = humans[rand() % std::min(humans.size(), (size_t)3)];
|
|
}
|
|
#endif
|
|
}
|
|
if (!target) {
|
|
target = incubator_->ActiveAndroid(hum);
|
|
}
|
|
return target;
|
|
}
|
|
|
|
bool Room::BattleStarted()
|
|
{
|
|
return battle_start_frameno_ != 0 || IsPveRoom();
|
|
}
|
|
|
|
int Room::GetAliveTeamNum()
|
|
{
|
|
int num = 0;
|
|
TraverseTeams
|
|
(
|
|
[&num] (Team* ele_team) -> bool
|
|
{
|
|
if (!ele_team->IsViewTeam() && ele_team->HasAliveMember()) {
|
|
++num;
|
|
}
|
|
return true;
|
|
});
|
|
return num;
|
|
}
|
|
|
|
void Room::TraverseTeams(std::function<bool (Team*)> cb)
|
|
{
|
|
for (auto& pair : team_hash_) {
|
|
if (!pair.second->IsViewTeam() && !cb(pair.second.get())) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseRawTeams(std::function<bool (Team*)> cb)
|
|
{
|
|
for (auto& pair : team_hash_) {
|
|
if (!cb(pair.second.get())) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int Room::GetTeamNum()
|
|
{
|
|
int num = 0;
|
|
if (BattleStarted()) {
|
|
num = battle_team_count_;
|
|
} else {
|
|
TraverseTeams
|
|
(
|
|
[&num] (Team* team) -> bool
|
|
{
|
|
if (!team->IsViewTeam()) {
|
|
++num;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
return num;
|
|
}
|
|
|
|
void Room::OnPlayerOffline(Player* hum)
|
|
{
|
|
if (GetOnlinePlayerNum() <= 0 && game_over_timer.expired()) {
|
|
game_over_timer = xtimer.SetTimeoutWpEx
|
|
(
|
|
SERVER_FRAME_RATE * 15,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (GetOnlinePlayerNum() <= 0 && !added_to_over_room) {
|
|
ForceOver();
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
}
|
|
|
|
void Room::FillSMUiUpdate(cs::SMUiUpdate& msg)
|
|
{
|
|
for (auto& pair : car_hash_) {
|
|
if (!pair.second.taken) {
|
|
auto car = msg.add_car_list();
|
|
car->set_car_id(pair.second.car_id);
|
|
TypeConvert::ToPb(pair.second.pos, car->mutable_pos());
|
|
}
|
|
}
|
|
}
|
|
|
|
Team* Room::GetAliveTeam()
|
|
{
|
|
Team* alive_team = nullptr;
|
|
TraverseTeams
|
|
(
|
|
[&alive_team] (Team* ele_team) -> bool
|
|
{
|
|
if (!ele_team->IsViewTeam() && ele_team->HasAliveMember()) {
|
|
alive_team = ele_team;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
return alive_team;
|
|
}
|
|
|
|
std::shared_ptr<Team> Room::NewTeam()
|
|
{
|
|
auto team = std::make_shared<Team>();
|
|
team->room = this;
|
|
team->SetTeamId(++current_teamid_);
|
|
team_hash_[team->GetTeamId()] = team;
|
|
return team;
|
|
}
|
|
|
|
std::shared_ptr<Team> Room::NewViewTeam()
|
|
{
|
|
auto team = std::make_shared<Team>();
|
|
team->room = this;
|
|
team->SetTeamId(++current_teamid_);
|
|
team->SetViewTeam();
|
|
team_hash_[team->GetTeamId()] = team;
|
|
return team;
|
|
}
|
|
|
|
void Room::TraversePlayerList(std::function<bool (Player*)> cb)
|
|
{
|
|
for (auto& pair : accountid_hash_) {
|
|
if (pair.second && !pair.second->IsOb()) {
|
|
if (!cb(pair.second)){
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseRawPlayerList(std::function<void (Player*)> cb)
|
|
{
|
|
for (auto& pair : accountid_hash_) {
|
|
if (pair.second) {
|
|
cb(pair.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseHumanList(std::function<bool (Human*)> cb)
|
|
{
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second && !pair.second->IsOb()) {
|
|
if (!cb(pair.second)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseRawHumanList(std::function<bool (Human*)> cb)
|
|
{
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second) {
|
|
if (!cb(pair.second)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseAliveHumanList(std::function<bool (Human*)> func)
|
|
{
|
|
for (auto& pair : alive_human_hash_) {
|
|
#ifdef MYDEBUG
|
|
if (pair.second->IsOb()) {
|
|
abort();
|
|
}
|
|
#endif
|
|
if (pair.second) {
|
|
if (!func(pair.second)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseCreatureList(std::function<bool (Creature*)> func)
|
|
{
|
|
for (auto& pair : moveable_hash_) {
|
|
if (pair.second && pair.second->IsCreature(this)) {
|
|
Creature* c = (Creature*)pair.second;
|
|
if (!c->IsOb()) {
|
|
if (!func(c)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseEntityList(std::function<bool (Entity*)> func)
|
|
{
|
|
for (auto& pair : uniid_hash_) {
|
|
if (pair.second) {
|
|
if (!func(pair.second)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseAlivePlayers(std::function<bool (Human*)> func)
|
|
{
|
|
for (auto& pair : alive_player_hash_) {
|
|
#ifdef MYDEBUG
|
|
if (pair.second->IsOb()) {
|
|
abort();
|
|
}
|
|
#endif
|
|
if (!func(pair.second)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::BroadcastDebugMsg(const std::string& debug_msg)
|
|
{
|
|
#ifdef MYDEBUG
|
|
TraverseHumanList
|
|
(
|
|
[debug_msg] (Human* hum) -> bool
|
|
{
|
|
hum->SendDebugMsg(debug_msg);
|
|
return true;
|
|
});
|
|
#endif
|
|
}
|
|
|
|
void Room::UpdateGas()
|
|
{
|
|
switch (GetGasData().GetGasMode()) {
|
|
case GasInactive:
|
|
UpdateGasInactive();
|
|
break;
|
|
case GasJump:
|
|
UpdateGasJump();
|
|
break;
|
|
case GasWaiting:
|
|
UpdateGasWaiting();
|
|
break;
|
|
case GasMoving:
|
|
UpdateGasMoving();
|
|
break;
|
|
}
|
|
if (GetGasData().GetGasMode() != GasInactive && GetGasData().GetGasMode() != GasJump) {
|
|
if (GetGasData().GetGasMode() != GasInactive) {
|
|
if (false) {
|
|
} else if (IsPveRoom()) {
|
|
if (!IsGameOver() &&
|
|
(
|
|
pve_data.pve_kill_boss ||
|
|
IsAllRealDead() ||
|
|
incubator_->IsTimeOut()
|
|
)) {
|
|
game_over_ = true;
|
|
game_over_frameno_ = GetFrameNo();
|
|
OnGameOver();
|
|
}
|
|
} else {
|
|
if (!IsGameOver() &&
|
|
AliveCount() <= GetMaxTeamNum() &&
|
|
GetAliveTeamNum() <= 1) {
|
|
game_over_ = true;
|
|
game_over_frameno_ = GetFrameNo();
|
|
OnGameOver();
|
|
}
|
|
}
|
|
for (auto& pair : moveable_hash_) {
|
|
if (!pair.second->IsCreature(this)) {
|
|
continue;
|
|
}
|
|
Creature* c = (Creature*)pair.second;
|
|
if (c->real_dead ||
|
|
a8::HasBitFlag(c->status, CS_Disable)) {
|
|
continue;
|
|
}
|
|
if (c->IsOb()) {
|
|
continue;
|
|
}
|
|
bool b1 = a8::CircleContainCircle
|
|
(gas_data_.pos_old,
|
|
gas_data_.gas_progress,
|
|
glm::vec2(c->GetPos().GetX(), c->GetPos().GetZ()),
|
|
c->GetRadius()
|
|
);
|
|
bool b2 = a8::CircleContainCircle
|
|
(gas_data_.pos_new,
|
|
gas_data_.rad_new,
|
|
glm::vec2(c->GetPos().GetX(), c->GetPos().GetZ()),
|
|
c->GetRadius()
|
|
);
|
|
if (!b1 && !b2) {
|
|
c->poisoning = true;
|
|
if (!c->GetBuffByEffectId(kBET_Poisoning)) {
|
|
c->TryAddBuff(c, kPoisioningBuffId);
|
|
}
|
|
} else {
|
|
c->poisoning = false;
|
|
c->poisoning_time = false;
|
|
if (c->GetBuffByEffectId(kBET_Poisoning)) {
|
|
c->RemoveBuffByEffectId(kBET_Poisoning);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasInactive()
|
|
{
|
|
if (IsPveRoom()) {
|
|
UpdateGasInactivePve();
|
|
} else if (IsMobaModeRoom()) {
|
|
UpdateGasInactiveMoba();
|
|
} else {
|
|
UpdateGasInactivePvp();
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasInactivePvp()
|
|
{
|
|
bool over = GetFrameNo() - gas_data_.gas_start_frameno >=
|
|
GetGasInactiveTime() * SERVER_FRAME_RATE;
|
|
if (over) {
|
|
long long begin_tick = a8::XGetTickCount();
|
|
if (GetHumanNum() < GetRoomMaxPlayerNum()) {
|
|
if (IsCustomBattle()) {
|
|
} else {
|
|
CreateAndroid(GetRoomMaxPlayerNum() - GetHumanNum());
|
|
}
|
|
NotifyUiUpdate();
|
|
}
|
|
gas_data_.SetGasMode(GasJump);
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
battle_start_frameno_ = GetFrameNo();
|
|
CombineTeam();
|
|
FillTeam();
|
|
ClearPostBattleAutoFreeList();
|
|
OnBattleStart();
|
|
InitAndroidAI();
|
|
RoomMgr::Instance()->ActiveRoom(GetRoomUuid());
|
|
if (IsSandTableRoom()) {
|
|
{
|
|
const mt::SafeArea* first_safearea = mt::SafeArea::GetByType
|
|
(map_meta_->RandSafeArea());
|
|
gas_data_.SetGasMode(GasWaiting);
|
|
gas_data_.old_area_meta = first_safearea;
|
|
gas_data_.new_area_meta = mt::SafeArea::GetById(first_safearea->id() + 1);
|
|
gas_data_.pos_list = mt::SafeAreaPos::RandSafeAreaPos(first_safearea->id());
|
|
gas_data_.gas_progress = gas_data_.old_area_meta->rad();
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
#if 1
|
|
gas_data_.pos_old = glm::vec2(first_safearea->x1(),
|
|
first_safearea->y1());
|
|
#else
|
|
gas_data_.pos_old = map_meta_->first_safearea_center;
|
|
#endif
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
{
|
|
if (gas_data_.pos_list && !gas_data_.pos_list->_poses.empty()) {
|
|
gas_data_.pos_old = glm::vec2(
|
|
gas_data_.pos_list->_poses[0].x,
|
|
gas_data_.pos_list->_poses[0].z
|
|
);
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
}
|
|
bool gen_ok = GenSmallCircle();
|
|
if (!gen_ok) {
|
|
A8_ABORT();
|
|
}
|
|
}
|
|
gas_data_.rad_old = gas_data_.old_area_meta->rad();
|
|
gas_data_.rad_new = gas_data_.new_area_meta->rad();
|
|
if (map_meta_->init_gas_ring() > 0) {
|
|
ForwardGasRing(map_meta_->init_gas_ring());
|
|
}
|
|
}
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* hum) -> bool
|
|
{
|
|
hum->RemoveBuffByEffectId(kBET_ThroughWall);
|
|
hum->OnLand();
|
|
if (hum->GetEntitySubType() == EST_Player) {
|
|
GameLog::Instance()->GameStart((Player*)hum);
|
|
}
|
|
return true;
|
|
});
|
|
NotifyUiUpdate();
|
|
NotifyGameStart();
|
|
sand_table_->OnGameStart();
|
|
if (custom_battle_) {
|
|
|
|
}
|
|
} else {
|
|
if (IsNoPlane()) {
|
|
{
|
|
const mt::SafeArea* first_safearea = mt::SafeArea::GetByType
|
|
(map_meta_->RandSafeArea());
|
|
gas_data_.SetGasMode(GasWaiting);
|
|
gas_data_.old_area_meta = first_safearea;
|
|
gas_data_.new_area_meta = mt::SafeArea::GetById(first_safearea->id() + 1);
|
|
gas_data_.pos_list = mt::SafeAreaPos::RandSafeAreaPos(first_safearea->id());
|
|
gas_data_.gas_progress = gas_data_.old_area_meta->rad();
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
#if 1
|
|
gas_data_.pos_old = glm::vec2(first_safearea->x1(),
|
|
first_safearea->y1());
|
|
#else
|
|
gas_data_.pos_old = map_meta_->first_safearea_center;
|
|
#endif
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
{
|
|
if (gas_data_.pos_list && !gas_data_.pos_list->_poses.empty()) {
|
|
gas_data_.pos_old = glm::vec2(
|
|
gas_data_.pos_list->_poses[0].x,
|
|
gas_data_.pos_list->_poses[0].z
|
|
);
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
}
|
|
bool gen_ok = GenSmallCircle();
|
|
if (!gen_ok) {
|
|
A8_ABORT();
|
|
}
|
|
}
|
|
gas_data_.rad_old = gas_data_.old_area_meta->rad();
|
|
gas_data_.rad_new = gas_data_.new_area_meta->rad();
|
|
if (map_meta_->init_gas_ring() > 0) {
|
|
ForwardGasRing(map_meta_->init_gas_ring());
|
|
}
|
|
}
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* hum) -> bool
|
|
{
|
|
hum->RemoveBuffByEffectId(kBET_ThroughWall);
|
|
hum->OnLand();
|
|
if (hum->GetEntitySubType() == EST_Player) {
|
|
GameLog::Instance()->GameStart((Player*)hum);
|
|
}
|
|
return true;
|
|
});
|
|
NotifyUiUpdate();
|
|
NotifyGameStart();
|
|
sand_table_->OnGameStart();
|
|
if (custom_battle_) {
|
|
|
|
}
|
|
} else {
|
|
ShuaPlane();
|
|
#if 1
|
|
int auto_jump_interval = mt::Param::GetIntParam("auto_jump_interval");
|
|
auto_jump_timer_ = xtimer.SetIntervalWpEx
|
|
(SERVER_FRAME_RATE * auto_jump_interval + SERVER_FRAME_RATE * 3,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
AutoJump();
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
#else
|
|
int auto_jump_interval_delay = mt::Param::GetIntParam("auto_jump_interval_delay");
|
|
xtimer.SetTimeoutEx
|
|
(
|
|
SERVER_FRAME_RATE * auto_jump_interval_delay,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
int auto_jump_interval = mt::Param::GetIntParam("auto_jump_interval");
|
|
auto_jump_timer_ = xtimer.SetIntervalWpEx
|
|
(SERVER_FRAME_RATE * auto_jump_interval,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
AutoJump();
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
},
|
|
&xtimer_attacher_);
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef MYDEBUG
|
|
a8::XPrintf("max_run_delay:%d %d\n", {PerfMonitor::Instance()->max_run_delay_time,
|
|
a8::XGetTickCount() - begin_tick});
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasInactivePve()
|
|
{
|
|
if (GetFrameNo() - gas_data_.gas_start_frameno >=
|
|
GetGasInactiveTime() * SERVER_FRAME_RATE) {
|
|
{
|
|
auto first_safearea = pve_mode_meta->_area[0];
|
|
gas_data_.SetGasMode(GasWaiting);
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
battle_start_frameno_ = GetFrameNo();
|
|
gas_data_.old_area_meta = first_safearea;
|
|
gas_data_.new_area_meta = pve_mode_meta->_area[0];
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
gas_data_.pos_new = glm::vec2(gas_data_.new_area_meta->x1(),
|
|
gas_data_.new_area_meta->y1());
|
|
gas_data_.pos_old = gas_data_.pos_new;
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
gas_data_.rad_old = gas_data_.old_area_meta->rad();
|
|
gas_data_.rad_new = gas_data_.new_area_meta->rad();
|
|
gas_data_.gas_progress = 0;
|
|
}
|
|
NotifyUiUpdate();
|
|
ClearPostBattleAutoFreeList();
|
|
OnBattleStart();
|
|
NotifyGameStart();
|
|
InitAndroidAI();
|
|
incubator_->InitPve();
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasInactiveMoba()
|
|
{
|
|
if (GetFrameNo() - gas_data_.gas_start_frameno >=
|
|
GetGasInactiveTime() * SERVER_FRAME_RATE) {
|
|
{
|
|
const mt::SafeArea* first_safearea = mt::SafeArea::GetByType
|
|
(map_meta_->RandSafeArea());
|
|
gas_data_.SetGasMode(GasWaiting);
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
battle_start_frameno_ = GetFrameNo() + 1;
|
|
gas_data_.old_area_meta = first_safearea;
|
|
gas_data_.new_area_meta = first_safearea;
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
gas_data_.pos_new = glm::vec2(gas_data_.new_area_meta->x1(),
|
|
gas_data_.new_area_meta->y1());
|
|
gas_data_.pos_old = gas_data_.pos_new;
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
gas_data_.rad_old = gas_data_.old_area_meta->rad();
|
|
gas_data_.rad_new = gas_data_.new_area_meta->rad();
|
|
gas_data_.gas_progress = 0;
|
|
}
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* hum) -> bool
|
|
{
|
|
hum->RemoveBuffByEffectId(kBET_ThroughWall);
|
|
hum->OnLand();
|
|
if (hum->GetEntitySubType() == EST_Player) {
|
|
GameLog::Instance()->GameStart((Player*)hum);
|
|
}
|
|
return true;
|
|
});
|
|
NotifyUiUpdate();
|
|
#if 1
|
|
App::Instance()->verify_set_pos = 1;
|
|
TraverseHumanList
|
|
(
|
|
[this] (Human* ele_hum) -> bool
|
|
{
|
|
Human* hum = ele_hum;
|
|
if (!hum->GetBornPoint()) {
|
|
abort();
|
|
} else {
|
|
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
|
|
}
|
|
#ifdef MYDEBUG
|
|
a8::XPrintf("set_pos side:%d %d pos:%f %f %f\n", {
|
|
hum->side,
|
|
hum->GetUniId(),
|
|
hum->GetPos().GetX(),
|
|
hum->GetPos().GetY(),
|
|
hum->GetPos().GetZ(),
|
|
});
|
|
#endif
|
|
hum->GetMovement()->ClearPath();
|
|
grid_service->MoveCreature(hum);
|
|
return true;
|
|
});
|
|
App::Instance()->verify_set_pos = 0;
|
|
TraverseTeams
|
|
(
|
|
[this] (Team* ele_team) -> bool
|
|
{
|
|
if (ele_team->HasPlayer()) {
|
|
batch_sync_->AddTeam(ele_team);
|
|
}
|
|
return true;
|
|
});
|
|
#else
|
|
CombineTeam();
|
|
FillTeam();
|
|
#endif
|
|
ClearPostBattleAutoFreeList();
|
|
OnBattleStart();
|
|
NotifyGameStart();
|
|
InitAndroidAI();
|
|
sand_table_->OnGameStart();
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasWaiting()
|
|
{
|
|
if (IsPveRoom() || IsMobaModeRoom()) {
|
|
|
|
} else {
|
|
if (GetFrameNo() - gas_data_.gas_start_frameno >=
|
|
gas_data_.old_area_meta->wait_time() * SERVER_FRAME_RATE) {
|
|
gas_data_.SetGasMode(GasMoving);
|
|
gas_data_.gas_start_frameno = GetFrameNo();;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasMoving()
|
|
{
|
|
if (GetFrameNo() - gas_data_.gas_start_frameno > 0 && !gas_data_.is_last_gas) {
|
|
float distance = gas_data_.old_area_meta->shrink_speed() *
|
|
((GetFrameNo() - gas_data_.gas_start_frameno) * (1.0 / SERVER_FRAME_RATE));
|
|
gas_data_.gas_progress = std::max(gas_data_.rad_old - distance, gas_data_.rad_new);
|
|
#if 1
|
|
if (std::abs(gas_data_.gas_progress - gas_data_.rad_new) > 0.001f) {
|
|
/*
|
|
移动大圆形的条件:
|
|
两圆形距离:center_distance
|
|
*/
|
|
glm::vec2 p1 = gas_data_.pos_new - gas_data_.pos_old;
|
|
float center_distance = glm::length(p1);
|
|
if (center_distance + gas_data_.rad_new > gas_data_.gas_progress) {
|
|
glm::vec2 dir = glm::normalize(p1);
|
|
gas_data_.pos_old = gas_data_.pos_old + dir *
|
|
(center_distance + gas_data_.rad_new - gas_data_.gas_progress);
|
|
}
|
|
}
|
|
#else
|
|
if (!(gas_data_.pos_new == gas_data_.pos_old)) {
|
|
glm::vec2 p1 = gas_data_.pos_new - gas_data_.pos_old_bk;
|
|
gas_data_.pre_pos_old = gas_data_.pos_old;
|
|
if (glm::length(p1) - distance <= 0.01f) {
|
|
gas_data_.pos_old = gas_data_.pos_new;
|
|
} else {
|
|
glm::vec2 dir = p1;
|
|
dir = glm::normalize(dir);
|
|
gas_data_.pos_old = gas_data_.pos_old_bk + dir * distance;
|
|
}
|
|
if (gas_data_.rad_old - distance <= gas_data_.rad_new) {
|
|
assert(gas_data_.rad_old - distance <= gas_data_.rad_new + 5);
|
|
}
|
|
}
|
|
#endif
|
|
if (std::abs(gas_data_.gas_progress - gas_data_.rad_new) <= 0.001f) {
|
|
if (gas_data_.new_area_meta->IsLastGas()) {
|
|
gas_data_.is_last_gas = true;
|
|
return;
|
|
}
|
|
ForwardGasRing(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasJump()
|
|
{
|
|
|
|
glm::vec3 len_vec = plane.dir *
|
|
((GetFrameNo() - GetGasData().gas_start_frameno)*airline_->plane_speed() / SERVER_FRAME_RATE);
|
|
plane.curr_pos = plane.start_point + len_vec;
|
|
if (GlmHelper::Norm(plane.end_point - plane.start_point) <=
|
|
GlmHelper::Norm(len_vec) + mt::Param::s().early_parachute_jump) {
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* hum) -> bool
|
|
{
|
|
if (hum->HasBuffEffect(kBET_Fly)) {
|
|
hum->DoJump();
|
|
}
|
|
if (hum->GetEntitySubType() == EST_Player) {
|
|
GameLog::Instance()->GameStart((Player*)hum);
|
|
}
|
|
return true;
|
|
});
|
|
const mt::SafeArea* first_safearea = mt::SafeArea::GetByType
|
|
(map_meta_->RandSafeArea());
|
|
gas_data_.SetGasMode(GasWaiting);
|
|
gas_data_.old_area_meta = first_safearea;
|
|
gas_data_.new_area_meta = mt::SafeArea::GetById(first_safearea->id() + 1);
|
|
gas_data_.pos_list = mt::SafeAreaPos::RandSafeAreaPos(first_safearea->id());
|
|
gas_data_.gas_progress = gas_data_.old_area_meta->rad();
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
#if 1
|
|
gas_data_.pos_old = glm::vec2(first_safearea->x1(),
|
|
first_safearea->y1());
|
|
#else
|
|
gas_data_.pos_old = map_meta_->first_safearea_center;
|
|
#endif
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
{
|
|
if (gas_data_.pos_list && !gas_data_.pos_list->_poses.empty()) {
|
|
gas_data_.pos_old = glm::vec2(
|
|
gas_data_.pos_list->_poses[0].x,
|
|
gas_data_.pos_list->_poses[0].z
|
|
);
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
}
|
|
bool gen_ok = GenSmallCircle();
|
|
if (!gen_ok) {
|
|
A8_ABORT();
|
|
}
|
|
}
|
|
gas_data_.rad_old = gas_data_.old_area_meta->rad();
|
|
gas_data_.rad_new = gas_data_.new_area_meta->rad();
|
|
if (map_meta_->init_gas_ring() > 0) {
|
|
ForwardGasRing(map_meta_->init_gas_ring());
|
|
}
|
|
if (!auto_jump_timer_.expired()) {
|
|
xtimer.Delete(auto_jump_timer_);
|
|
}
|
|
air_drop_->Init();
|
|
air_raid_->Init();
|
|
NotifyGameStart();
|
|
NotifyUiUpdate();
|
|
}
|
|
}
|
|
|
|
bool Room::GenSmallCircle()
|
|
{
|
|
if (gas_data_.new_area_meta->rad() >= gas_data_.old_area_meta->rad()) {
|
|
A8_ABORT();
|
|
}
|
|
if (gas_data_.pos_list && gas_data_.gas_count + 1 < gas_data_.pos_list->_poses.size()) {
|
|
gas_data_.pos_new =
|
|
glm::vec2(
|
|
gas_data_.pos_list->_poses[gas_data_.gas_count + 1].x,
|
|
gas_data_.pos_list->_poses[gas_data_.gas_count + 1].z
|
|
);
|
|
} else {
|
|
gas_data_.pos_new = glm::vec2(gas_data_.new_area_meta->x1(),
|
|
gas_data_.new_area_meta->y1());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Room::MatchTeam(Human* hum)
|
|
{
|
|
if (!hum->team_uuid.empty()) {
|
|
{
|
|
bool match_ok = false;
|
|
TraverseHumanList
|
|
(
|
|
[&match_ok, hum] (Human* ele_hum) -> bool
|
|
{
|
|
if (ele_hum != hum) {
|
|
if (ele_hum->team_uuid == hum->team_uuid) {
|
|
if (ele_hum->GetTeam() && !ele_hum->GetTeam()->IsFull()) {
|
|
ele_hum->GetTeam()->AddMember(hum);
|
|
match_ok = true;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
if (match_ok) {
|
|
return;
|
|
}
|
|
}
|
|
if (mt::Param::s().prebattle_combine_team) {
|
|
if (!hum->GetTeam() && hum->auto_fill && combineable_team_hash_.size() > 1) {
|
|
for (auto& pair : combineable_team_hash_) {
|
|
auto team = pair.second;
|
|
if (team->CanCombine(hum)) {
|
|
team->AddMember(hum);
|
|
team->AddCombineMemberNum(hum->init_team_member_num);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}//end if
|
|
}
|
|
|
|
if (!hum->GetTeam()) {
|
|
auto new_team = NewTeam();
|
|
new_team->SetInitTeamMemberNum(hum->init_team_member_num);
|
|
new_team->SetAutoFill(hum->auto_fill);
|
|
new_team->AddMember(hum);
|
|
if (hum->IsPlayer() && hum->auto_fill) {
|
|
combineable_team_hash_[new_team->GetTeamId()] = new_team;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CombineTeam()
|
|
{
|
|
if (!mt::Param::s().prebattle_combine_team) {
|
|
return;
|
|
}
|
|
if (IsCustomBattle()) {
|
|
return;
|
|
}
|
|
std::map<int, size_t> need_combine_teams;
|
|
std::map<int, size_t> need_combine_teams_copy;
|
|
|
|
int first_team_id = 0;
|
|
int total_count = 0;
|
|
TraverseTeams
|
|
(
|
|
[&need_combine_teams, &need_combine_teams_copy, &first_team_id, &total_count]
|
|
(Team* ele_team) -> bool
|
|
{
|
|
if (!ele_team->AllIsRunAway()) {
|
|
ele_team->TraverseMembers
|
|
(
|
|
[ele_team, &first_team_id, &total_count, &need_combine_teams] (Human* member) -> bool
|
|
{
|
|
if (member->auto_fill && !member->team_uuid.empty()) {
|
|
if (first_team_id == 0) {
|
|
first_team_id = ele_team->GetTeamId();
|
|
}
|
|
need_combine_teams[ele_team->GetTeamId()] = ele_team->GetMemberNum();
|
|
total_count += ele_team->GetMemberNum();
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
return true;
|
|
});
|
|
|
|
if (total_count <= 1) {
|
|
return;
|
|
}
|
|
|
|
if (need_combine_teams.size() <= 2) {
|
|
return;
|
|
}
|
|
if (total_count == 3) {
|
|
int del_team_id = 0;
|
|
for (auto& pair : need_combine_teams) {
|
|
if (pair.first != first_team_id) {
|
|
del_team_id = pair.first;
|
|
break;
|
|
}
|
|
}
|
|
if (del_team_id != 0) {
|
|
auto itr = need_combine_teams.find(del_team_id);
|
|
if (itr != need_combine_teams.end()) {
|
|
total_count -= itr->second;
|
|
need_combine_teams.erase(itr);
|
|
}
|
|
}
|
|
if (total_count <= 1) {
|
|
abort();
|
|
}
|
|
}
|
|
|
|
size_t first_team_num = 4;
|
|
switch (total_count) {
|
|
case 3:
|
|
{
|
|
first_team_num = 2;
|
|
break;
|
|
}
|
|
case 4:
|
|
{
|
|
first_team_num = 2;
|
|
break;
|
|
}
|
|
case 5:
|
|
{
|
|
first_team_num = 3;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
first_team_num = 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
need_combine_teams_copy = need_combine_teams;
|
|
int try_count = 0;
|
|
do {
|
|
for (auto& pair1 : need_combine_teams) {
|
|
bool combine_ok = false;
|
|
for (auto& pair2 : need_combine_teams_copy) {
|
|
int team_id1 = pair1.first;
|
|
int team_id2 = pair2.first;
|
|
if (team_id2 == first_team_id) {
|
|
continue;
|
|
}
|
|
if (team_id1 == first_team_id) {
|
|
if (pair1.second + pair2.second > first_team_num) {
|
|
continue;
|
|
}
|
|
}
|
|
if (team_id1 != team_id2) {
|
|
if (pair1.second + pair2.second <= GetMaxTeamNum()) {
|
|
int new_team_num = pair1.second + pair2.second;
|
|
{
|
|
std::shared_ptr<Team> team1 = team_hash_.at(team_id1);
|
|
std::shared_ptr<Team> team2 = team_hash_.at(team_id2);
|
|
if (team1->GetMemberNum() + team2->GetMemberNum() > GetMaxTeamNum()) {
|
|
f8::UdpLog::Instance()->Warning("team_member > 4 :%d",
|
|
{
|
|
team1->GetMemberNum() + team2->GetMemberNum()
|
|
});
|
|
}
|
|
if (pair1.first == first_team_id || pair1.second >= pair2.second) {
|
|
team1->CombineTeam(team2.get());
|
|
team_hash_.erase(pair2.first);
|
|
} else {
|
|
team2->CombineTeam(team1.get());
|
|
team_hash_.erase(pair1.first);
|
|
}
|
|
}
|
|
|
|
if (first_team_id == team_id1) {
|
|
if (pair1.second + pair2.second >= first_team_num) {
|
|
need_combine_teams.erase(team_id1);
|
|
need_combine_teams_copy.erase(team_id1);
|
|
} else {
|
|
pair1.second = new_team_num;
|
|
if (need_combine_teams_copy.find(pair1.first) !=
|
|
need_combine_teams_copy.end()) {
|
|
need_combine_teams_copy[pair1.first] = new_team_num;
|
|
}
|
|
}
|
|
need_combine_teams.erase(team_id2);
|
|
need_combine_teams_copy.erase(team_id2);
|
|
} else {
|
|
if (pair1.second >= pair2.second) {
|
|
if (pair1.second + pair2.second >= GetMaxTeamNum()) {
|
|
need_combine_teams.erase(team_id1);
|
|
need_combine_teams_copy.erase(team_id1);
|
|
} else {
|
|
pair1.second = new_team_num;
|
|
if (need_combine_teams_copy.find(pair1.first) !=
|
|
need_combine_teams_copy.end()) {
|
|
need_combine_teams_copy[pair1.first] = new_team_num;
|
|
}
|
|
}
|
|
need_combine_teams.erase(team_id2);
|
|
need_combine_teams_copy.erase(team_id2);
|
|
} else {
|
|
if (pair1.second + pair2.second >= GetMaxTeamNum()) {
|
|
need_combine_teams.erase(team_id2);
|
|
need_combine_teams_copy.erase(team_id2);
|
|
} else {
|
|
pair2.second = new_team_num;
|
|
if (need_combine_teams.find(pair2.first) !=
|
|
need_combine_teams.end()) {
|
|
need_combine_teams[pair2.first] = new_team_num;
|
|
}
|
|
}
|
|
need_combine_teams.erase(team_id1);
|
|
need_combine_teams_copy.erase(team_id1);
|
|
}
|
|
}
|
|
combine_ok = true;
|
|
break;
|
|
}
|
|
}
|
|
}//end for
|
|
if (combine_ok) {
|
|
break;
|
|
}
|
|
}
|
|
} while (++try_count < 20);
|
|
}
|
|
|
|
void Room::FillTeam()
|
|
{
|
|
std::vector<std::shared_ptr<Team>> free_team_list;
|
|
TraverseTeams
|
|
(
|
|
[&free_team_list] (Team* ele_team) -> bool
|
|
{
|
|
if (ele_team->IsFreeTeam()) {
|
|
free_team_list.push_back(ele_team->shared_from_this());
|
|
}
|
|
return true;
|
|
});
|
|
std::random_shuffle(free_team_list.begin(), free_team_list.end());
|
|
for (auto& pair : accountid_hash_) {
|
|
if (free_team_list.empty()) {
|
|
break;
|
|
}
|
|
if (!pair.second->GetTeam()->IsFull()) {
|
|
for (int i = pair.second->GetTeam()->GetMemberNum(); i < GetMaxTeamNum(); ++i) {
|
|
if (!free_team_list.empty()) {
|
|
std::shared_ptr<Team> b_team = free_team_list.at(free_team_list.size() - 1);
|
|
pair.second->GetTeam()->CombineTeam(b_team.get());
|
|
free_team_list.erase(free_team_list.begin() + free_team_list.size() - 1);
|
|
team_hash_.erase(b_team->GetTeamId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (free_team_list.size() > 1) {
|
|
std::shared_ptr<Team> a_team = free_team_list[0];
|
|
free_team_list.erase(free_team_list.begin());
|
|
for (int i = 1; i < 4; ++i) {
|
|
if (!free_team_list.empty()) {
|
|
std::shared_ptr<Team> b_team = free_team_list.at(0);
|
|
a_team->CombineTeam(b_team.get());
|
|
free_team_list.erase(free_team_list.begin());
|
|
team_hash_.erase(b_team->GetTeamId());
|
|
}
|
|
}
|
|
}
|
|
TraverseTeams
|
|
(
|
|
[this] (Team* ele_team) -> bool
|
|
{
|
|
if (ele_team->HasPlayer()) {
|
|
batch_sync_->AddTeam(ele_team);
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
void Room::ShuaPlane()
|
|
{
|
|
airline_ = mt::AirLine::RandAirLine(map_meta_->map_id());
|
|
if (!airline_) {
|
|
A8_ABORT();
|
|
}
|
|
plane.start_point = airline_->GetStartPoint();
|
|
plane.end_point = airline_->GetEndPoint();
|
|
plane.dir = plane.end_point - plane.start_point;
|
|
GlmHelper::Normalize(plane.dir);
|
|
plane.curr_pos = plane.start_point;
|
|
last_player_jump_pos = plane.curr_pos;
|
|
|
|
TraverseHumanList
|
|
(
|
|
[this] (Human* ele_hum) -> bool
|
|
{
|
|
ele_hum->MustBeAddBuff(ele_hum, FLY_BUFFID);
|
|
ele_hum->ResetAllSkillCd();
|
|
App::Instance()->verify_set_pos = 1;
|
|
ele_hum->GetMutablePos().FromGlmVec3(plane.curr_pos);
|
|
App::Instance()->verify_set_pos = 0;
|
|
ele_hum->GetMovement()->ClearPath();
|
|
ele_hum->SetAttackDir(plane.dir);
|
|
ele_hum->SetMoveDir(plane.dir);
|
|
grid_service->MoveCreature(ele_hum);
|
|
ele_hum->AddToNewObjects(ele_hum);
|
|
ele_hum->ActiveAllSkill();
|
|
return true;
|
|
});
|
|
}
|
|
|
|
RoomObstacle* Room::InternalCreateObstacle(int id, float x, float y, float z,
|
|
std::function<void (Obstacle*)> on_precreate,
|
|
std::shared_ptr<a8::Args> init_args)
|
|
{
|
|
const mt::MapThing* thing = mt::MapThing::GetById(id);
|
|
if (thing) {
|
|
RoomObstacle* entity = EntityFactory::Instance()->MakeRoomObstacle(AllocUniid());
|
|
entity->meta = thing;
|
|
entity->room = this;
|
|
entity->init_args = init_args;
|
|
{
|
|
Position pos;
|
|
pos.SetX(x);
|
|
pos.SetY(y);
|
|
pos.SetZ(z);
|
|
entity->SetPos(pos);
|
|
}
|
|
entity->Initialize();
|
|
if (on_precreate) {
|
|
on_precreate(entity);
|
|
}
|
|
AddToEntityHash(entity);
|
|
grid_service->AddRoomEntity(this, entity);
|
|
return entity;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void Room::AddObjectLater(RoomEntity* entity)
|
|
{
|
|
auto add_func =
|
|
[entity] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (entity->IsEntityType(ET_Bullet)) {
|
|
MoveableEntity* moveableentity = (MoveableEntity*)entity;
|
|
entity->room->AddToMoveableHash(moveableentity);
|
|
|
|
}
|
|
entity->room->AddToEntityHash(entity);
|
|
entity->room->RemoveFromLaterAddHash(entity);
|
|
}
|
|
};
|
|
AddToLaterAddHash(entity);
|
|
xtimer.SetTimeoutEx
|
|
(0,
|
|
add_func,
|
|
&entity->xtimer_attacher);
|
|
}
|
|
|
|
void Room::TryMobaReport(int try_count)
|
|
{
|
|
if (!IsMobaModeRoom()) {
|
|
return;
|
|
}
|
|
if (sending_moba_report_battle_) {
|
|
return;
|
|
}
|
|
if (already_moba_report_battle_) {
|
|
return;;
|
|
}
|
|
sending_moba_report_battle_ = true;
|
|
Player* player = nullptr;
|
|
TraversePlayerList
|
|
(
|
|
[&player] (Player* hum) -> bool
|
|
{
|
|
player = hum;
|
|
return true;
|
|
});
|
|
if (!player) {
|
|
return;
|
|
}
|
|
std::string url;
|
|
JsonDataMgr::Instance()->GetApiUrl(url);
|
|
std::shared_ptr<a8::MutableXObject> params = a8::MutableXObject::CreateObject();
|
|
std::shared_ptr<a8::MutableXObject> post_data = a8::MutableXObject::CreateObject();
|
|
params->SetVal("c", "Battle");
|
|
params->SetVal("a", "mobaTeamReport");
|
|
params->SetVal("account_id", player->account_id);
|
|
params->SetVal("session_id", player->session_id);
|
|
GenBattleMobaReportData(post_data.get());
|
|
std::string content = post_data->ToJsonStr();
|
|
HttpProxy::Instance()->HttpPost
|
|
(
|
|
[room_uuid = GetRoomUuid()]
|
|
(bool ok, a8::XObject* rsp_obj, f8::HttpContext* ctx)
|
|
{
|
|
auto room = RoomMgr::Instance()->GetRoomByUuid(room_uuid);
|
|
if (room) {
|
|
room->already_moba_report_battle_ = true;
|
|
room->sending_moba_report_battle_ = false;
|
|
room->TraverseHumanList
|
|
(
|
|
[] (Human* ele_hum) -> bool
|
|
{
|
|
ele_hum->SendGameOver();
|
|
return true;
|
|
});
|
|
}
|
|
},
|
|
url,
|
|
params,
|
|
content
|
|
);
|
|
#ifdef MYDEBUG
|
|
a8::XPrintf("MobaReportReportLen:%d\n", {params->ToJsonStr().size()});
|
|
#endif
|
|
}
|
|
|
|
void Room::OnGameOver()
|
|
{
|
|
if (IsAlreadyRoomReportBattle() ||
|
|
GetCustomBattle()) {
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* ele_hum) -> bool
|
|
{
|
|
ele_hum->SendGameOver();
|
|
return true;
|
|
});
|
|
return;
|
|
} else {
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* ele_hum) -> bool
|
|
{
|
|
ele_hum->SendGameOver();
|
|
return true;
|
|
});
|
|
CalcMvp();
|
|
if (IsMobaModeRoom()) {
|
|
TryMobaReport(0);
|
|
}
|
|
xtimer.SetIntervalEx
|
|
(SERVER_FRAME_RATE / 0.5,
|
|
[this, frameno = GetFrameNo()] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
bool all_sent = true;
|
|
if (IsMobaModeRoom()) {
|
|
all_sent = already_moba_report_battle_;
|
|
} else {
|
|
TraverseTeams
|
|
(
|
|
[&all_sent] (Team* team) -> bool
|
|
{
|
|
if (team->HasPlayer() && !team->IsViewTeam() &&
|
|
!team->IsAlreadyReportBattle()) {
|
|
all_sent = false;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
if (all_sent) {
|
|
TryRoomReport(0);
|
|
xtimer.DeleteCurrentTimer();
|
|
} else if (GetFrameNo() - frameno > SERVER_FRAME_RATE * 5) {
|
|
TryRoomReport(0);
|
|
xtimer.DeleteCurrentTimer();
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
}
|
|
|
|
void Room::RandRemoveAndroid()
|
|
{
|
|
Human* hum = nullptr;
|
|
if (!hum) {
|
|
TraverseHumanList
|
|
(
|
|
[&hum] (Human* ele_hum) -> bool
|
|
{
|
|
if (ele_hum->IsAndroid() && ele_hum->team_uuid.empty()) {
|
|
hum = ele_hum;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
if (hum) {
|
|
hum->CheckSpecObject(0);
|
|
if (hum->team_id != 0) {
|
|
Team* team = GetTeam(hum->team_id);
|
|
if (team) {
|
|
team->RemoveMember(hum);
|
|
if (team->GetMemberNum() < 1) {
|
|
team_hash_.erase(hum->team_id);
|
|
}
|
|
}
|
|
}
|
|
if (hum->GetBornPoint()) {
|
|
DecBornPointHumanNum(hum->GetBornPoint(), hum);
|
|
}
|
|
if (!hum->IsOb()) {
|
|
DecAliveCount();
|
|
}
|
|
TraverseRawHumanList
|
|
(
|
|
[hum] (Human* ele_hum) -> bool
|
|
{
|
|
ele_hum->RemovePartObjects(hum);
|
|
return true;
|
|
});
|
|
TraverseRawHumanList
|
|
(
|
|
[hum] (Human* ele_hum) -> bool
|
|
{
|
|
ele_hum->RemoveObjects(hum);
|
|
return true;
|
|
});
|
|
frame_event.AddExitGame(hum->GetWeakPtrRef());
|
|
grid_service->DeatchHuman(hum);
|
|
RemoveFromMoveableHash(hum);
|
|
RemoveFromEntityHash(hum);
|
|
RemoveFromHuamnHash(hum);
|
|
RemoveFromAliveHumanHash(hum);
|
|
AddToRemovedRobotHash(hum);
|
|
}
|
|
}
|
|
|
|
void Room::NotifyUiUpdate()
|
|
{
|
|
xtimer.SetTimeoutEx
|
|
(0,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
TraverseHumanList(
|
|
[] (Human * hum) -> bool
|
|
{
|
|
hum->SendUIUpdate();
|
|
return true;
|
|
});
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
|
|
void Room::UpdateCarObject(int old_uniid, int new_uniid, const glm::vec3 pos)
|
|
{
|
|
auto itr = car_hash_.find(old_uniid);
|
|
if (itr != car_hash_.end()) {
|
|
CarObject new_obj = itr->second;
|
|
new_obj.pos = pos;
|
|
car_hash_[new_uniid] = new_obj;
|
|
car_hash_.erase(old_uniid);
|
|
} else {
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
void Room::TakeOnCarObject(int car_uniid)
|
|
{
|
|
auto itr = car_hash_.find(car_uniid);
|
|
if (itr != car_hash_.end()) {
|
|
itr->second.taken = true;
|
|
}
|
|
}
|
|
|
|
void Room::TakeOffCarObject(int car_uniid, glm::vec3 pos)
|
|
{
|
|
auto itr = car_hash_.find(car_uniid);
|
|
if (itr != car_hash_.end()) {
|
|
itr->second.pos = pos;
|
|
itr->second.taken = false;
|
|
}
|
|
}
|
|
|
|
int Room::CreateAndTakeonCar(int car_id, glm::vec3 pos)
|
|
{
|
|
const mt::Equip* item_meta = mt::Equip::GetById(car_id);
|
|
if (!item_meta) {
|
|
return -1;
|
|
}
|
|
int car_uniid = AllocUniid();
|
|
CarObject car;
|
|
car.car_id = car_id;
|
|
car.pos = pos;
|
|
car.taken = true;
|
|
car_hash_[car_uniid] = car;
|
|
return car_uniid;
|
|
}
|
|
|
|
bool Room::HaveMyTeam(const std::string& team_uuid)
|
|
{
|
|
if (team_uuid.empty()) {
|
|
return false;
|
|
}
|
|
for (auto& pair : accountid_hash_) {
|
|
if (pair.second->team_uuid == team_uuid) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::shared_ptr<BornPoint> Room::AllocBornPoint(Human* hum)
|
|
{
|
|
std::shared_ptr<BornPoint> born_point = nullptr;
|
|
if (hum->GetBornPoint()) {
|
|
std::vector<std::shared_ptr<BornPoint>> point_list;
|
|
std::vector<std::shared_ptr<BornPoint>> free_point_list;
|
|
std::shared_ptr<BornPoint> pre_point = nullptr;
|
|
std::shared_ptr<BornPoint> reserve_point = nullptr;
|
|
for (auto& pair : born_point_hash_) {
|
|
if (pair.second != hum->GetBornPoint()) {
|
|
if (pair.second->player_num + pair.second->android_num <
|
|
pair.second->GetNum()) {
|
|
point_list.push_back(pair.second);
|
|
free_point_list.push_back(pair.second);;
|
|
}
|
|
if (!reserve_point || rand() % 100 < 10) {
|
|
reserve_point = pair.second;
|
|
}
|
|
} else {
|
|
pre_point = pair.second;
|
|
}
|
|
}
|
|
if (!free_point_list.empty()) {
|
|
born_point = free_point_list[rand() % free_point_list.size()];
|
|
if (pre_point) {
|
|
DecBornPointHumanNum(pre_point, hum);
|
|
}
|
|
} else {
|
|
if (point_list.empty() && reserve_point) {
|
|
born_point = ForceTakeBornPoint(hum, reserve_point);
|
|
} else {
|
|
born_point = !point_list.empty() ? point_list[rand() % point_list.size()] : nullptr;
|
|
if (pre_point) {
|
|
DecBornPointHumanNum(pre_point, hum);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
std::vector<std::shared_ptr<BornPoint>> free_point_list;
|
|
for (auto& pair : born_point_hash_) {
|
|
if (pair.second->player_num + pair.second->android_num <
|
|
pair.second->GetNum()) {
|
|
free_point_list.push_back(pair.second);
|
|
}
|
|
}
|
|
if (!free_point_list.empty()) {
|
|
born_point = free_point_list[rand() % free_point_list.size()];
|
|
}
|
|
}
|
|
if (born_point) {
|
|
IncBornPointHumanNum(born_point, hum);
|
|
}
|
|
#ifdef MYDEBUG
|
|
if (!born_point) {
|
|
A8_ABORT();
|
|
}
|
|
#endif
|
|
return born_point;
|
|
}
|
|
|
|
std::shared_ptr<BornPoint> Room::GetBornPoint(int point_uniid)
|
|
{
|
|
auto itr = born_point_hash_.find(point_uniid);
|
|
return itr != born_point_hash_.end() ? itr->second : nullptr;
|
|
}
|
|
|
|
void Room::IncBornPointHumanNum(std::shared_ptr<BornPoint> point, Human* hum)
|
|
{
|
|
switch (hum->GetEntitySubType()) {
|
|
case EST_Player:
|
|
{
|
|
++point->player_num;
|
|
}
|
|
break;
|
|
case EST_Android:
|
|
{
|
|
++point->android_num;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Room::DecBornPointHumanNum(std::shared_ptr<BornPoint> point, Human* hum)
|
|
{
|
|
switch (hum->GetEntitySubType()) {
|
|
case EST_Player:
|
|
{
|
|
--point->player_num;
|
|
}
|
|
break;
|
|
case EST_Android:
|
|
{
|
|
--point->android_num;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Room::NotifyGameStart()
|
|
{
|
|
cs::SMGameStart msg;
|
|
for (auto& pair : accountid_hash_) {
|
|
pair.second->SendNotifyMsg(msg);
|
|
}
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* ele_hum) -> bool
|
|
{
|
|
a8::SetBitFlag(ele_hum->status, CS_DisableAttack);
|
|
return true;
|
|
});
|
|
|
|
xtimer.SetTimeoutEx
|
|
(mt::Param::GetIntParam("prepare_time", 3000) / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
TraverseHumanList
|
|
(
|
|
[this] (Human* ele_hum) -> bool
|
|
{
|
|
a8::UnSetBitFlag(ele_hum->status, CS_DisableAttack);
|
|
for (int buff_id : map_meta_->buff_list) {
|
|
const mt::Buff* buff_meta = mt::Buff::GetById(buff_id);
|
|
if (buff_meta) {
|
|
#if 0
|
|
ele_hum->AddBuff(ele_hum,
|
|
buff_meta,
|
|
nullptr);
|
|
#endif
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
|
|
long long Room::GetGasInactiveTime()
|
|
{
|
|
long long inactive_time = 0;
|
|
if (IsPveRoom()) {
|
|
inactive_time = 10;
|
|
} else if (GetCustomBattle()) {
|
|
inactive_time = 15;
|
|
} else {
|
|
if (IsPvpRankModeRoom()) {
|
|
if (IsPvpMasterRankModeRoom()) {
|
|
inactive_time = mt::Param::s().master_rank_gas_inactive_time;
|
|
} else {
|
|
inactive_time = mt::Param::s().rank_gas_inactive_time;
|
|
}
|
|
} else {
|
|
inactive_time = mt::Param::s().gas_inactive_time;
|
|
}
|
|
}
|
|
#ifdef MYDEBUG
|
|
if (!f8::IsTestEnv()) {
|
|
inactive_time = 12;
|
|
}
|
|
#endif
|
|
if (IsMobaModeRoom()) {
|
|
inactive_time = 0;
|
|
}
|
|
inactive_time = std::max((long long)0, inactive_time - acc_inactive_time_);
|
|
if (IsNewerMap()) {
|
|
inactive_time = 10;
|
|
}
|
|
if (IsNewBieBattle()) {
|
|
inactive_time = 10;
|
|
}
|
|
return inactive_time;
|
|
}
|
|
|
|
long long Room::GetGasInactiveReaminTime()
|
|
{
|
|
if (GetGasData().GetGasMode() != GasInactive) {
|
|
return -1;
|
|
}
|
|
long long remain_time = GetGasInactiveTime() -
|
|
(GetFrameNo() - GetGasData().gas_start_frameno) * FRAME_RATE_MS;
|
|
return std::max((int)remain_time, 0);
|
|
}
|
|
|
|
void Room::EnableHuman(Human* target)
|
|
{
|
|
if (!RuningInTimer()) {
|
|
A8_ABORT();
|
|
}
|
|
#ifdef MYDEBUG
|
|
CheckPartObjects();
|
|
#if 0
|
|
f8::UdpLog::Instance()->Debug("enablehuman %d %d",
|
|
{
|
|
(long long)target,
|
|
target->GetUniId()
|
|
});
|
|
#endif
|
|
#endif
|
|
#if 0
|
|
target->OnEnable();
|
|
AddToMoveableHash(target);
|
|
if (!target->real_dead) {
|
|
AddToAliveHumanHash(target);
|
|
}
|
|
#else
|
|
if (a8::HasBitFlag(target->status, CS_Disable)) {
|
|
target->OnEnable();
|
|
AddToMoveableHash(target);
|
|
if (!target->real_dead) {
|
|
AddToAliveHumanHash(target);
|
|
}
|
|
} else {
|
|
A8_ABORT();
|
|
}
|
|
#endif
|
|
#ifdef MYDEBUG
|
|
CheckPartObjects();
|
|
#endif
|
|
}
|
|
|
|
void Room::DisableHuman(Human* target)
|
|
{
|
|
#if 0
|
|
if (!RuningInTimer()) {
|
|
A8_ABORT();
|
|
}
|
|
#endif
|
|
#ifdef MYDEBUG
|
|
CheckPartObjects();
|
|
#if 0
|
|
f8::UdpLog::Instance()->Debug("disablehuman %d %d",
|
|
{
|
|
(long long)target,
|
|
target->GetUniId()
|
|
});
|
|
#endif
|
|
#endif
|
|
if (!a8::HasBitFlag(target->status, CS_Disable)) {
|
|
target->OnDisable();
|
|
RemoveFromMoveableHash(target);
|
|
RemoveFromAliveHumanHash(target);
|
|
}
|
|
#ifdef MYDEBUG
|
|
CheckPartObjects();
|
|
#endif
|
|
}
|
|
|
|
bool Room::HasPlayerInRound(const glm::vec3& pos, float rad)
|
|
{
|
|
for (auto& pair : accountid_hash_) {
|
|
if (std::fabs(pair.second->GetPos().GetX() - pos.x) < rad &&
|
|
std::fabs(pair.second->GetPos().GetZ() - pos.z) < rad) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Room::CheckPartObjects(Human* testa, Human* testb)
|
|
{
|
|
}
|
|
|
|
bool Room::RuningInTimer()
|
|
{
|
|
return xtimer.IsRunning();
|
|
}
|
|
|
|
#ifdef MYDEBUG
|
|
void Room::InitDebugInfo()
|
|
{
|
|
}
|
|
|
|
void Room::UnInitDebugInfo()
|
|
{
|
|
}
|
|
#endif
|
|
|
|
void Room::AddPlayerPostProc(Player* hum)
|
|
{
|
|
}
|
|
|
|
void Room::AddToEntityHash(Entity* entity)
|
|
{
|
|
uniid_hash_[entity->GetUniId()] = entity;
|
|
}
|
|
|
|
void Room::AddToHumanHash(Human* hum)
|
|
{
|
|
human_hash_[hum->GetUniId()] = hum;
|
|
}
|
|
|
|
void Room::AddToAliveHumanHash(Human* hum)
|
|
{
|
|
#ifdef MYDEBUG
|
|
if (hum->IsOb()) {
|
|
abort();
|
|
}
|
|
#endif
|
|
alive_human_hash_[hum->GetUniId()] = hum;
|
|
if (hum->IsPlayer()) {
|
|
alive_player_hash_[hum->GetUniId()] = hum;
|
|
}
|
|
}
|
|
|
|
void Room::AddToMoveableHash(MoveableEntity* entity)
|
|
{
|
|
moveable_hash_[entity->GetUniId()] = entity;
|
|
}
|
|
|
|
void Room::AddToAccountHash(Player* hum)
|
|
{
|
|
accountid_hash_[hum->account_id] = hum;
|
|
}
|
|
|
|
void Room::AddToLaterAddHash(RoomEntity* entity)
|
|
{
|
|
later_add_hash_[entity->GetUniId()] = entity;
|
|
}
|
|
|
|
void Room::AddToRemovedRobotHash(Human* hum)
|
|
{
|
|
removed_robot_hash_[hum->GetUniId()] = hum;
|
|
}
|
|
|
|
void Room::RemoveFromEntityHash(Entity* entity)
|
|
{
|
|
uniid_hash_.erase(entity->GetUniId());
|
|
}
|
|
|
|
void Room::RemoveFromMoveableHash(MoveableEntity* entity)
|
|
{
|
|
moveable_hash_.erase(entity->GetUniId());
|
|
}
|
|
|
|
void Room::RemoveFromHuamnHash(Human* hum)
|
|
{
|
|
human_hash_.erase(hum->GetUniId());
|
|
}
|
|
|
|
void Room::RemoveFromAliveHumanHash(Human* hum)
|
|
{
|
|
alive_human_hash_.erase(hum->GetUniId());
|
|
if (hum->IsPlayer()) {
|
|
alive_player_hash_.erase(hum->GetUniId());
|
|
}
|
|
}
|
|
|
|
void Room::RemoveFromLaterAddHash(RoomEntity* entity)
|
|
{
|
|
later_add_hash_.erase(entity->GetUniId());
|
|
}
|
|
|
|
void Room::ForceSetBornPoint(Human* hum, std::shared_ptr<BornPoint> born_point)
|
|
{
|
|
if (born_point && hum->GetBornPoint() != born_point) {
|
|
if (hum->GetBornPoint()) {
|
|
DecBornPointHumanNum(hum->GetBornPoint(), hum);
|
|
}
|
|
hum->SetBornPoint(born_point);
|
|
if (hum->GetBornPoint()) {
|
|
IncBornPointHumanNum(hum->GetBornPoint(), hum);
|
|
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
|
|
}
|
|
hum->FindLocation();
|
|
hum->RefreshView();
|
|
grid_service->MoveCreature(hum);
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<BornPoint> Room::ForceTakeBornPoint(Human* hum, std::shared_ptr<BornPoint> reserve_born_point)
|
|
{
|
|
if (!reserve_born_point) {
|
|
A8_ABORT();
|
|
}
|
|
if (hum->GetBornPoint() == reserve_born_point) {
|
|
A8_ABORT();
|
|
}
|
|
if (!hum->GetBornPoint()) {
|
|
A8_ABORT();
|
|
}
|
|
std::shared_ptr<BornPoint> pre_point = hum->GetBornPoint();
|
|
if (pre_point) {
|
|
DecBornPointHumanNum(pre_point, hum);
|
|
}
|
|
TraverseHumanList
|
|
(
|
|
[this, reserve_born_point, pre_point] (Human* ele_hum) -> bool
|
|
{
|
|
if (ele_hum->GetBornPoint() == reserve_born_point) {
|
|
ForceSetBornPoint(ele_hum, pre_point);
|
|
}
|
|
return true;
|
|
});
|
|
return reserve_born_point;
|
|
}
|
|
|
|
Human* Room::GetOneCanEnableAndroid()
|
|
{
|
|
std::vector<Human*> humans;
|
|
GetCanEnableAndroids(humans, 1);
|
|
return !humans.empty() ? humans[0] : nullptr;
|
|
}
|
|
|
|
void Room::GetCanEnableAndroids(std::vector<Human*>& humans, size_t num)
|
|
{
|
|
TraverseHumanList
|
|
(
|
|
[&humans, num] (Human* ele_hum) -> bool
|
|
{
|
|
if (ele_hum->IsAndroid() &&
|
|
!ele_hum->real_dead &&
|
|
a8::HasBitFlag(ele_hum->status, CS_Disable)
|
|
) {
|
|
if (humans.size() >= num) {
|
|
return false;
|
|
}
|
|
humans.push_back(ele_hum);
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
Player* Room::GetOneAlivePlayer()
|
|
{
|
|
std::vector<Player*> humans;
|
|
GetAlivePlayers(humans, 1);
|
|
return !humans.empty() ? humans[0] : nullptr;
|
|
}
|
|
|
|
void Room::GetAlivePlayers(std::vector<Player*>& humans, size_t num)
|
|
{
|
|
for (auto& pair : accountid_hash_) {
|
|
if (!pair.second->real_dead) {
|
|
if (humans.size() >= num) {
|
|
break;
|
|
}
|
|
humans.push_back(pair.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
int Room::GetCanShuaNum(int shua_num)
|
|
{
|
|
int real_shua_num = shua_num;
|
|
return real_shua_num;
|
|
}
|
|
|
|
bool Room::CanAddToScene(Human* hum)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void Room::SyncFrameData()
|
|
{
|
|
#ifdef MYDEBUG
|
|
long long begin_tick = a8::XGetTickCount();
|
|
long long end_tick = a8::XGetTickCount();
|
|
#endif
|
|
TraverseHumanList
|
|
(
|
|
#ifdef MYDEBUG
|
|
[&begin_tick, &end_tick] (Human* ele_hum) -> bool
|
|
#else
|
|
[] (Human* ele_hum) -> bool
|
|
#endif
|
|
{
|
|
ele_hum->SendUpdateMsg();
|
|
#ifdef MYDEBUG
|
|
end_tick = a8::XGetTickCount();
|
|
#if 0
|
|
if (a8::XGetTickCount() - begin_tick > 100) {
|
|
A8_ABORT();
|
|
}
|
|
#endif
|
|
begin_tick = a8::XGetTickCount();
|
|
#endif
|
|
return true;
|
|
});
|
|
#ifdef MYDEBUG
|
|
end_tick = a8::XGetTickCount();
|
|
if (a8::XGetTickCount() - begin_tick > 1000) {
|
|
A8_ABORT();
|
|
}
|
|
begin_tick = a8::XGetTickCount();
|
|
#endif
|
|
frame_event.Clear();
|
|
}
|
|
|
|
void Room::RemoveRescue(Human* hum)
|
|
{
|
|
TraverseHumanList
|
|
(
|
|
[this, hum] (Human* ele_hum) -> bool
|
|
{
|
|
if (ele_hum != hum && ele_hum->GetActionType() == AT_Relive &&
|
|
ele_hum->GetActionTargetId() == hum->GetUniId()) {
|
|
ele_hum->CancelAction();
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
void Room::NotifyCountdown(const std::string& msg, int time)
|
|
{
|
|
for (auto& pair : accountid_hash_) {
|
|
pair.second->SendShowCountdown(msg, time);
|
|
}
|
|
}
|
|
|
|
void Room::NotifySysPiao(const std::string& msg, int color, int duration)
|
|
{
|
|
for (auto& pair : accountid_hash_) {
|
|
pair.second->SendSysPiaoMsg(msg, color, duration);
|
|
}
|
|
}
|
|
|
|
int Room::GetOnlinePlayerNum()
|
|
{
|
|
int num = 0;
|
|
for (auto& pair : accountid_hash_) {
|
|
if (pair.second->SocketIsValid()) {
|
|
++num;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
size_t Room::GetRoomMaxPlayerNum()
|
|
{
|
|
if (pve_instance) {
|
|
return pve_human_num;
|
|
}
|
|
if (custom_battle_) {
|
|
return custom_battle_->GetMemberNum();
|
|
}
|
|
return map_meta_->player();
|
|
}
|
|
|
|
void Room::InitAndroidAI()
|
|
{
|
|
}
|
|
|
|
void Room::ForwardGasRing(int n)
|
|
{
|
|
while (n > 0) {
|
|
if (gas_data_.new_area_meta->IsLastGas()) {
|
|
gas_data_.is_last_gas = true;
|
|
return;
|
|
}
|
|
int pre_area_id = gas_data_.new_area_meta->id();
|
|
gas_data_.SetGasMode(GasWaiting);
|
|
glm::vec2 pre_pos = gas_data_.pos_new;
|
|
gas_data_.old_area_meta = mt::SafeArea::GetById(pre_area_id);
|
|
gas_data_.new_area_meta = mt::SafeArea::GetById(pre_area_id + 1);
|
|
gas_data_.gas_progress = gas_data_.old_area_meta->rad();
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
gas_data_.pos_old = pre_pos;
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
{
|
|
bool gen_ok = GenSmallCircle();
|
|
if (!gen_ok) {
|
|
A8_ABORT();
|
|
}
|
|
}
|
|
gas_data_.rad_old = gas_data_.old_area_meta->rad();
|
|
gas_data_.rad_new = gas_data_.new_area_meta->rad();
|
|
gas_data_.gas_count++;
|
|
--n;
|
|
}
|
|
if (gas_data_.old_area_meta) {
|
|
auto boss_tuple = gas_data_.old_area_meta->GetBoss();
|
|
if (boss_tuple && !IsGameOver()) {
|
|
const mt::Hero* hero_meta = mt::Hero::GetById(std::get<2>(*boss_tuple));
|
|
if (hero_meta) {
|
|
int boss_uniid = AllocUniid();
|
|
NotifyNewsTicker
|
|
(2,
|
|
{
|
|
a8::XValue(boss_uniid).GetString(),
|
|
a8::XValue(hero_meta->id()).GetString(),
|
|
a8::XValue(std::get<0>(*boss_tuple).x).GetString(),
|
|
a8::XValue(std::get<0>(*boss_tuple).y).GetString(),
|
|
a8::XValue(std::get<0>(*boss_tuple).z).GetString(),
|
|
a8::XValue(std::get<1>(*boss_tuple)).GetString(),
|
|
});
|
|
xtimer.SetTimeoutEx
|
|
(SERVER_FRAME_RATE * std::get<1>(*boss_tuple),
|
|
[this, boss_tuple, hero_meta, boss_uniid] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
Hero* hero = CreateHero
|
|
(nullptr,
|
|
hero_meta,
|
|
std::get<0>(*boss_tuple),
|
|
GlmHelper::UP,
|
|
666,
|
|
boss_uniid);
|
|
if (hero) {
|
|
batch_sync_->AddGlobalObject(hero);
|
|
hero->GetTrigger()->AddListener
|
|
(
|
|
kDieEvent,
|
|
[this, boss_uniid] (const a8::Args& args) mutable
|
|
{
|
|
if (!IsGameOver()) {
|
|
batch_sync_->RemoveGlobalObject(boss_uniid);
|
|
NotifyKillList({boss_uniid});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::GetPartObjectWatchList(Entity* entity, std::vector<Human*>& watch_list)
|
|
{
|
|
TraverseHumanList
|
|
(
|
|
[&watch_list, entity] (Human* hum) -> bool
|
|
{
|
|
if (hum->InPartObjects(entity)) {
|
|
watch_list.push_back(hum);
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
void Room::SetInfiniteBulletMode()
|
|
{
|
|
infinite_bullet_mode_ = true;
|
|
for (auto& pair : accountid_hash_) {
|
|
pair.second->SetInfiniteBulletMode();
|
|
}
|
|
}
|
|
|
|
void Room::AddToPostBattleAutoFreeList(a8::XTimerWp timer)
|
|
{
|
|
if (BattleStarted()) {
|
|
A8_ABORT();
|
|
}
|
|
if (timer.expired()) {
|
|
A8_ABORT();
|
|
}
|
|
post_battle_auto_free_list_.push_back(timer);
|
|
}
|
|
|
|
void Room::ClearPostBattleAutoFreeList()
|
|
{
|
|
size_t i = 0;
|
|
while (i < post_battle_auto_free_list_.size()) {
|
|
auto timer = post_battle_auto_free_list_[i];
|
|
if (!timer.expired()) {
|
|
xtimer.Delete(timer);
|
|
}
|
|
++i;
|
|
}
|
|
post_battle_auto_free_list_.clear();
|
|
}
|
|
|
|
void Room::OnBattleStart()
|
|
{
|
|
battle_start_frameno_ = GetFrameNo();
|
|
if (IsMobaModeRoom()) {
|
|
++battle_start_frameno_;
|
|
}
|
|
battle_starting_ = true;
|
|
std::vector<EntityWeakPtr> entitys;
|
|
entitys.reserve(uniid_hash_.size());
|
|
for (auto& pair : uniid_hash_) {
|
|
entitys.push_back(pair.second->GetEntityWeakPtrRef());
|
|
}
|
|
for (auto& e : entitys) {
|
|
if (e.Get()) {
|
|
e.Get()->OnBattleStart(this);
|
|
}
|
|
}
|
|
TraverseHumanList
|
|
(
|
|
[this] (Human* ele_hum) -> bool
|
|
{
|
|
++battle_human_count_;
|
|
return true;
|
|
});
|
|
TraversePlayerList
|
|
(
|
|
[this] (Player* ele_hum) -> bool
|
|
{
|
|
++battle_player_count_;
|
|
return true;
|
|
});
|
|
TraverseTeams
|
|
(
|
|
[this] (Team* ele_team) -> bool
|
|
{
|
|
++battle_team_count_;
|
|
return true;
|
|
});
|
|
if (!IsMobaModeRoom() && !IsSandTableRoom()) {
|
|
std::vector<std::shared_ptr<BornPoint>> born_point_list;
|
|
born_point_list.reserve(born_point_hash_.size());
|
|
for (auto& pair : born_point_hash_) {
|
|
pair.second->player_num = 0;
|
|
pair.second->android_num = 0;
|
|
born_point_list.push_back(pair.second);
|
|
}
|
|
if (born_point_list.empty()) {
|
|
A8_ABORT();
|
|
}
|
|
std::shuffle(born_point_list.begin(),
|
|
born_point_list.end(),
|
|
std::default_random_engine(a8::XGetTickCount()));
|
|
size_t cur_point_idx = 0;
|
|
TraverseTeams
|
|
(
|
|
[this, &born_point_list, &cur_point_idx] (Team* ele_team) mutable -> bool
|
|
{
|
|
if (cur_point_idx >= born_point_list.size()) {
|
|
cur_point_idx = 0;
|
|
}
|
|
auto point = born_point_list.at(cur_point_idx++);
|
|
ele_team->TraverseMembers
|
|
(
|
|
[point] (Human* hum) -> bool
|
|
{
|
|
if (hum->IsPlayer()) {
|
|
point->player_num++;
|
|
} else {
|
|
point->android_num++;
|
|
}
|
|
App::Instance()->verify_set_pos = 1;
|
|
hum->SetBornPoint(point);
|
|
hum->SetPos(hum->GetBornPoint()->NewRandPoint(hum->room, 10, 100));
|
|
App::Instance()->verify_set_pos = 0;
|
|
return true;
|
|
});
|
|
return true;
|
|
});
|
|
}
|
|
battle_starting_ = false;
|
|
SendSMTeamFull(nullptr);
|
|
GetBoxDrop()->OnBattleStart();
|
|
}
|
|
|
|
bool Room::CanAddObstacle(const glm::vec3& pos, int obstacle_id)
|
|
{
|
|
const mt::MapThing* thing_meta = mt::MapThing::GetById(obstacle_id);
|
|
if (!thing_meta) {
|
|
return false;
|
|
}
|
|
int rad = std::max(thing_meta->width(), thing_meta->height());
|
|
return map_service->CanAdd(pos, rad);
|
|
}
|
|
|
|
bool Room::IsDestoryRoom()
|
|
{
|
|
return GetMapMeta()->map_id() == 1002;
|
|
}
|
|
|
|
bool Room::IsSurvivalRoom()
|
|
{
|
|
return GetMapMeta()->map_id() == 1003;
|
|
}
|
|
|
|
void Room::OnEnterNewWave(int wave)
|
|
{
|
|
if (IsDestoryRoom() && wave > 0 && wave < pve_mode_meta->_area.size()) {
|
|
gas_data_.SetGasMode(GasWaiting);
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
gas_data_.old_area_meta = pve_mode_meta->_area[wave];
|
|
gas_data_.new_area_meta = pve_mode_meta->_area[wave];
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
gas_data_.pos_new = glm::vec2(gas_data_.new_area_meta->x1(),
|
|
gas_data_.new_area_meta->y1());
|
|
gas_data_.pos_old = gas_data_.pos_new;
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
gas_data_.rad_old = gas_data_.old_area_meta->rad();
|
|
gas_data_.rad_new = gas_data_.new_area_meta->rad();
|
|
gas_data_.gas_progress = 0;
|
|
}
|
|
NotifyUiUpdate();
|
|
#ifdef MYDEBUG
|
|
a8::XPrintf("OnEnternerWave:%d\n", {wave});
|
|
#endif
|
|
}
|
|
|
|
bool Room::IsAllRealDead()
|
|
{
|
|
bool is_all_dead = true;
|
|
TraverseHumanList
|
|
(
|
|
[&is_all_dead] (Human* hum)
|
|
{
|
|
if (!hum->real_dead) {
|
|
is_all_dead = false;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
);
|
|
return is_all_dead;
|
|
}
|
|
|
|
void Room::AddTask(int task_uniid, std::shared_ptr<a8::CommonCbProcEx> cb)
|
|
{
|
|
if (task_hash_.find(task_uniid) != task_hash_.end()) {
|
|
abort();
|
|
}
|
|
task_hash_[task_uniid] = cb;
|
|
}
|
|
|
|
void Room::RemoveTask(int task_uniid)
|
|
{
|
|
task_hash_.erase(task_uniid);
|
|
}
|
|
|
|
void Room::AutoJump()
|
|
{
|
|
int auto_jump_min_num = mt::Param::GetIntParam("auto_jump_min_num");
|
|
int auto_jump_max_num = mt::Param::GetIntParam("auto_jump_max_num");
|
|
int jump_num = a8::RandEx(auto_jump_min_num, auto_jump_max_num);
|
|
if (GlmHelper::Norm(last_player_jump_pos - plane.curr_pos)< 64 * 8) {
|
|
jump_num = 1 + rand() % 2;
|
|
}
|
|
for (int i = 0; i < jump_num; ++i) {
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* hum) -> bool
|
|
{
|
|
if (hum->HasBuffEffect(kBET_Fly) &&
|
|
hum->GetEntitySubType() != EST_Player) {
|
|
hum->DoJump();
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
|
|
int Room::GetPolyExtFlag(int poly_idx)
|
|
{
|
|
if (poly_idx >=0 && poly_idx < poly_ext_datas_.size()) {
|
|
return poly_ext_datas_.at(poly_idx);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Room::CreateWorldObjects()
|
|
{
|
|
if (IsPveRoom()) {
|
|
int uniid = AllocUniid();
|
|
std::shared_ptr<BornPoint> born_point = std::make_shared<BornPoint>();
|
|
std::shared_ptr<mt::WorldObject> wo_meta = std::make_shared<mt::WorldObject>();
|
|
wo_meta->pos = pve_instance->_spawn_point;
|
|
born_point->wo_meta = wo_meta;
|
|
born_point_hash_[uniid] = born_point;
|
|
return;
|
|
}
|
|
for (auto& itr : GetMapMeta()->_world_objects) {
|
|
std::shared_ptr<mt::WorldObject> obj = itr;
|
|
switch ((WorldObjectType_e)obj->object_type) {
|
|
case WorldObjectType_e::kLootType:
|
|
{
|
|
CreateLoot
|
|
(
|
|
obj->object_id,
|
|
obj->pos,
|
|
obj->pos,
|
|
1,
|
|
1,
|
|
true);
|
|
}
|
|
break;
|
|
case WorldObjectType_e::kBoxType:
|
|
{
|
|
CreateObstacle
|
|
(
|
|
obj->object_id,
|
|
obj->pos.x,
|
|
obj->pos.y,
|
|
obj->pos.z,
|
|
std::make_shared<a8::Args>(std::vector<std::any>({obj}))
|
|
);
|
|
}
|
|
break;
|
|
case WorldObjectType_e::kCarType:
|
|
{
|
|
const mt::Equip* equip_meta = mt::Equip::GetById(obj->object_id);
|
|
if (equip_meta) {
|
|
int car_uniid = AllocUniid();
|
|
glm::vec3 pos = obj->pos - obj->size / 2.0f;
|
|
Car* c = CreateCar(nullptr,
|
|
car_uniid,
|
|
equip_meta,
|
|
pos,
|
|
0,
|
|
nullptr);
|
|
if (c) {
|
|
CarObject car;
|
|
car.car_id = equip_meta->id();
|
|
car.pos = c->GetPos().ToGlmVec3();
|
|
car_hash_[c->GetUniId()] = car;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case WorldObjectType_e::kMonsterType:
|
|
{
|
|
const mt::Hero* hero_meta = mt::Hero::GetById(obj->object_id);
|
|
if (hero_meta) {
|
|
glm::vec3 pos = obj->pos - obj->size / 2.0f;
|
|
Hero* hero = CreateHero
|
|
(nullptr,
|
|
hero_meta,
|
|
pos,
|
|
GlmHelper::UP,
|
|
666,
|
|
0);
|
|
}
|
|
}
|
|
break;
|
|
case WorldObjectType_e::kBornPointType:
|
|
{
|
|
int uniid = AllocUniid();
|
|
std::shared_ptr<BornPoint> born_point = std::make_shared<BornPoint>();
|
|
born_point->wo_meta = obj;
|
|
born_point_hash_[uniid] = born_point;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
abort();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
for (auto& itr : GetMapMeta()->_group_world_objects) {
|
|
int ikey = itr.first;
|
|
auto objects = itr.second;
|
|
std::shuffle(objects.begin(), objects.end(), std::default_random_engine(a8::XGetTickCount()));
|
|
const mt::MapThingGroup* group_meta = mt::MapThingGroup::GetById(ikey);
|
|
if (group_meta) {
|
|
int i = 0;
|
|
for (auto& tuple : *group_meta->GetItems()) {
|
|
if (i < objects.size()) {
|
|
switch (std::get<0>(tuple)) {
|
|
case 1:
|
|
{
|
|
const mt::Equip* equip_meta = mt::Equip::GetById(std::get<1>(tuple));
|
|
if (equip_meta) {
|
|
CreateLoot
|
|
(
|
|
std::get<1>(tuple),
|
|
objects[i]->pos,
|
|
objects[i]->pos,
|
|
1,
|
|
1
|
|
);
|
|
} else {
|
|
const mt::MapThing* thing_meta = mt::MapThing::GetById(std::get<1>(tuple));
|
|
if (thing_meta) {
|
|
if (thing_meta->thing_type() == 16) {
|
|
for (int drop_id : thing_meta->RandDrop()) {
|
|
ScatterDrop(objects[i]->pos, drop_id);
|
|
}
|
|
} else {
|
|
CreateObstacle
|
|
(
|
|
std::get<1>(tuple),
|
|
objects[i]->pos.x,
|
|
objects[i]->pos.y,
|
|
objects[i]->pos.z
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
#ifdef MYDEBUG1
|
|
#else
|
|
const mt::Hero* hero_meta = mt::Hero::GetById(std::get<1>(tuple));
|
|
if (hero_meta) {
|
|
Position hero_pos;
|
|
hero_pos.FromGlmVec3(objects[i]->pos);
|
|
|
|
int team_id = 666;
|
|
Creature* master = nullptr;
|
|
|
|
glm::vec3 dir = GlmHelper::UP;
|
|
|
|
Hero* hero = CreateHero(master,
|
|
hero_meta,
|
|
hero_pos.ToGlmVec3(),
|
|
dir,
|
|
team_id);
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
} //end switch
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
if (born_point_hash_.size() < GetRoomMaxPlayerNum() / 4) {
|
|
while (born_point_hash_.size() < GetRoomMaxPlayerNum() / 4) {
|
|
int uniid = AllocUniid();
|
|
std::shared_ptr<BornPoint> born_point = std::make_shared<BornPoint>();
|
|
std::shared_ptr<mt::WorldObject> wo_meta = std::make_shared<mt::WorldObject>();
|
|
wo_meta->pos.x = (60 + rand() % ((int)GetMapMeta()->map_width() - 100));
|
|
wo_meta->pos.y = 6.250846862793;
|
|
wo_meta->pos.z = (60 + rand() % ((int)GetMapMeta()->map_height() - 100));
|
|
born_point->wo_meta = wo_meta;
|
|
born_point_hash_[uniid] = born_point;
|
|
}
|
|
}
|
|
}
|
|
|
|
Team* Room::GetTeam(int team_id)
|
|
{
|
|
auto itr = team_hash_.find(team_id);
|
|
return itr != team_hash_.end() ? itr->second.get() : nullptr;
|
|
}
|
|
|
|
Creature* Room::GetCreatureByUniId(int uniid)
|
|
{
|
|
Entity* e = GetEntityByUniId(uniid);
|
|
return e && e->IsCreature(this) ? (Creature*)e : nullptr;
|
|
}
|
|
|
|
bool Room::RandomSafeAreaPoint(glm::vec3& point)
|
|
{
|
|
glm::vec3 dir = GlmHelper::UP;
|
|
GlmHelper::RotateY(dir, a8::RandAngle());
|
|
float rnd_rad = rand() % std::max(GetGasData().new_area_meta->rad(), 100);
|
|
glm::vec2 center = GetGasData().pos_new + glm::vec2(dir.x, dir.z) * (100.f + rnd_rad);
|
|
point = glm::vec3(center.x, 0.0f, center.y);
|
|
return true;
|
|
}
|
|
|
|
bool Room::FindWalkablePointWithOutHouse(const glm::vec3& center, int try_count, int step, glm::vec3& out_point)
|
|
{
|
|
glm::vec3 ref_point = center;
|
|
map_instance->PtInHouse(center, ref_point);
|
|
map_instance->Scale(ref_point);
|
|
glm::vec3 point;
|
|
bool ok = false;
|
|
for (int i = 0; i < try_count; ++i) {
|
|
ok = map_instance->FindNearestPoint(ref_point, 1.0f + step * i, point);
|
|
if (ok) {
|
|
break;
|
|
}
|
|
}
|
|
if (!ok) {
|
|
return false;
|
|
}
|
|
map_instance->UnScale(point);
|
|
out_point = point;
|
|
return true;
|
|
}
|
|
|
|
void Room::AddReportBullet(int bullet_uniid)
|
|
{
|
|
report_bullet_hash[bullet_uniid] = GetFrameNo();
|
|
xtimer.SetTimeoutEx
|
|
(
|
|
SERVER_FRAME_RATE * 10,
|
|
[this, bullet_uniid] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
report_bullet_hash.erase(bullet_uniid);
|
|
Entity* entity = GetEntityByUniId(bullet_uniid);
|
|
if (entity && entity->GetEntityType() == ET_Bullet) {
|
|
Bullet* bullet = (Bullet*)entity;
|
|
bullet->ForceRemove();
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
|
|
int Room::GetReportRoomMode()
|
|
{
|
|
if (IsPveRoom()) {
|
|
return 1;
|
|
} else if (IsMobaModeRoom()){
|
|
return 2;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int Room::GetPvpMatchMode()
|
|
{
|
|
return GetRoomMode() == kPvpRankMode ? 1 : 0;
|
|
}
|
|
|
|
void Room::ForceOver()
|
|
{
|
|
if (added_to_over_room) {
|
|
return;
|
|
}
|
|
std::vector<Team*> alive_teams;
|
|
TraverseTeams
|
|
(
|
|
[&alive_teams] (Team* team)
|
|
{
|
|
if (team->HasAliveMember()) {
|
|
alive_teams.push_back(team);
|
|
}
|
|
team->HasPlayer();
|
|
return true;
|
|
});
|
|
std::sort(alive_teams.begin(), alive_teams.end(),
|
|
[] (Team* a, Team *b) -> bool
|
|
{
|
|
if (a->HasPlayer() && b->HasPlayer()) {
|
|
return a->GetTeamId() < b->GetTeamId();
|
|
}
|
|
if (a->HasPlayer()) {
|
|
return true;
|
|
}
|
|
if (b->HasPlayer()) {
|
|
return false;
|
|
}
|
|
return a->GetTeamId() < b->GetTeamId();
|
|
});
|
|
for (Team* team : alive_teams) {
|
|
team->TraverseMembers
|
|
(
|
|
[] (Human* member)
|
|
{
|
|
if (!member->dead) {
|
|
member->BeKill(VP_Gas,
|
|
TEXT("battle_server_killer_gas", "毒圈"),
|
|
VW_Gas,
|
|
VP_Gas,
|
|
TEXT("battle_server_killer_gas", "毒圈"));
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
force_over_ = true;
|
|
GameLog::Instance()->ForceOver(this);
|
|
xtimer.SetTimeoutEx
|
|
(SERVER_FRAME_RATE * 5,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (!game_over_) {
|
|
game_over_ = true;
|
|
game_over_frameno_ = GetFrameNo();
|
|
OnGameOver();
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
|
|
bool Room::SupportSandTable()
|
|
{
|
|
return !IsMobaModeRoom() && map_meta_->support_sandtable();
|
|
}
|
|
|
|
void Room::OnAddHuman(Human* hum)
|
|
{
|
|
if (IsSandTableRoom()) {
|
|
hum->TryAddBuff(hum, kThroughWall_BUFFID);
|
|
}
|
|
}
|
|
|
|
bool Room::IsSandTableRoom()
|
|
{
|
|
return !IsPveRoom() &&
|
|
SupportSandTable();
|
|
}
|
|
|
|
bool Room::HasRoomSwitch(int tag)
|
|
{
|
|
return a8::HasBitFlag(room_switch_, tag);
|
|
}
|
|
|
|
void Room::OpenRoomSwitch(int tag)
|
|
{
|
|
a8::SetBitFlag(room_switch_, tag);
|
|
}
|
|
|
|
void Room::CloseRoomSwitch(int tag)
|
|
{
|
|
a8::UnSetBitFlag(room_switch_, tag);
|
|
}
|
|
|
|
void Room::GMFastForward()
|
|
{
|
|
while (GetGasData().new_area_meta->GetSmallRingCount() >= 3) {
|
|
ForwardGasRing(1);
|
|
}
|
|
TraversePlayerList
|
|
(
|
|
[this] (Player* hum) -> bool
|
|
{
|
|
glm::vec3 src_point = glm::vec3(GetGasData().new_area_meta->GetLastArea()->x1(),
|
|
6.0f,
|
|
GetGasData().new_area_meta->GetLastArea()->y1());
|
|
{
|
|
glm::vec3 center = src_point;
|
|
map_instance->Scale(center);
|
|
glm::vec3 point;
|
|
bool ok = false;
|
|
for (int i = 0; i < 10; ++i) {
|
|
ok = map_instance->FindConnectableNearestPoint(center, 1.0f + 10 * i, point);
|
|
if (ok) {
|
|
break;
|
|
}
|
|
}
|
|
if (ok) {
|
|
map_instance->UnScale(point);
|
|
hum->GetMutablePos().FromGlmVec3(point);
|
|
grid_service->MoveCreature(hum);
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
GetIncubator()->Clear(5);
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* ele_hum) -> bool
|
|
{
|
|
if (ele_hum->IsAndroid() &&
|
|
!a8::HasBitFlag(ele_hum->status, CS_Disable)) {
|
|
Human* hum = ele_hum;
|
|
hum->BeKill(VP_Gas,
|
|
TEXT("battle_server_killer_gas", "毒圈"),
|
|
VW_Gas,
|
|
VP_Gas,
|
|
TEXT("battle_server_killer_gas", "毒圈"));
|
|
}
|
|
return true;
|
|
});
|
|
xtimer.SetTimeoutEx
|
|
(
|
|
1,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
GetIncubator()->ShowHand();
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
|
|
void Room::LockRoom()
|
|
{
|
|
lock_room_ = true;
|
|
lock_room_frameno_ = GetFrameNo();
|
|
}
|
|
|
|
bool Room::BulletCanReach(const glm::vec3& start, const glm::vec3& end)
|
|
{
|
|
glm::vec3 a_start = start;
|
|
glm::vec3 a_end = end;
|
|
glm::vec3 hit_point;
|
|
bool hit_result = false;
|
|
|
|
map_instance->Scale(a_start);
|
|
map_instance->Scale(a_end);
|
|
if (map_instance->Raycast(a_start,
|
|
a_end,
|
|
hit_point,
|
|
hit_result,
|
|
map_instance->GetBulletIncludeFlags(),
|
|
map_instance->GetBulletExcludeFlags())) {
|
|
if (!hit_result) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Room::MoveCanReach(const glm::vec3& start, const glm::vec3& end)
|
|
{
|
|
glm::vec3 a_start = start;
|
|
glm::vec3 a_end = end;
|
|
glm::vec3 hit_point;
|
|
bool hit_result = false;
|
|
|
|
map_instance->Scale(a_start);
|
|
map_instance->Scale(a_end);
|
|
if (map_instance->Raycast(a_start,
|
|
a_end,
|
|
hit_point,
|
|
hit_result,
|
|
map_instance->GetMoveIncludeFlags(),
|
|
map_instance->GetMoveExcludeFlags())) {
|
|
if (!hit_result) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Room::IsPvpMasterRankModeRoom()
|
|
{
|
|
return rank_match_conf_ && rank_match_conf_->room_type == RoomType_MasterRank;
|
|
}
|
|
|
|
int Room::GetMaxTeamNum()
|
|
{
|
|
return MAX_TEAM_NUM;
|
|
}
|
|
|
|
bool Room::IsMiniMap()
|
|
{
|
|
return map_instance->map_id == 2002;
|
|
}
|
|
|
|
bool Room::IsNewerMap()
|
|
{
|
|
return map_instance->map_id == 2003;
|
|
}
|
|
|
|
int Room::GetMobaLeftTime()
|
|
{
|
|
if (moba_over_timer.expired()) {
|
|
return 0;
|
|
}
|
|
long long remain_time = xtimer.GetRemainTime(moba_over_timer);
|
|
return (remain_time * FRAME_RATE_MS);
|
|
}
|
|
|
|
Team* Room::GetMobaEnemyTeam(Team* self_team)
|
|
{
|
|
if (self_team == GetMobaTeamA()) {
|
|
return GetMobaTeamB();
|
|
} else {
|
|
return GetMobaTeamA();
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<RoomOb> Room::GetRoomOb()
|
|
{
|
|
return ob_;
|
|
}
|
|
|
|
void Room::IncAliveCount()
|
|
{
|
|
++alive_count_;
|
|
alive_count_chged_frameno_ = GetFrameNo();
|
|
++PerfMonitor::Instance()->alive_count;
|
|
}
|
|
|
|
void Room::DecAliveCount()
|
|
{
|
|
--alive_count_;
|
|
alive_count_chged_frameno_ = GetFrameNo();
|
|
--PerfMonitor::Instance()->alive_count;
|
|
}
|
|
|
|
bool Room::CanJoin(std::shared_ptr<CustomBattle> p)
|
|
{
|
|
if (p->IsMoba()) {
|
|
return false;
|
|
}
|
|
if (!p->IsNormalMode()) {
|
|
return false;
|
|
}
|
|
if (p->GetTeamNum() > 1) {
|
|
return false;
|
|
}
|
|
if (p->GetTeamNum() < 1) {
|
|
return false;
|
|
}
|
|
|
|
if (lock_room_) {
|
|
return false;
|
|
}
|
|
if (IsCustomBattle()) {
|
|
return false;
|
|
}
|
|
if (IsMobaModeRoom()) {
|
|
return false;
|
|
}
|
|
if (room_mode_ != p->GetRoomMode()) {
|
|
return false;
|
|
}
|
|
if (GetGasData().GetGasMode() != GasInactive) {
|
|
return false;
|
|
}
|
|
if (map_meta_->map_id() != p->GetMapId()) {
|
|
return false;
|
|
}
|
|
if (GetMapModeMeta() != p->GetMapModeMeta()) {
|
|
return false;
|
|
}
|
|
|
|
auto p_team = p->GetTeamByIdx(0);
|
|
if (GetPlayerNum() + p_team->GetMemberNum() > GetRoomMaxPlayerNum()) {
|
|
return false;
|
|
}
|
|
int try_count = 0;
|
|
while (GetHumanNum() + p_team->GetMemberNum() > GetRoomMaxPlayerNum() &&
|
|
try_count < 100) {
|
|
++try_count;
|
|
RandRemoveAndroid();
|
|
}
|
|
return GetHumanNum() + p_team->GetMemberNum() <= GetRoomMaxPlayerNum();
|
|
}
|
|
|
|
void Room::MobaBatterysUpdate()
|
|
{
|
|
for (int i = 0; i < GetMapMeta()->GetMobaRoomMeta()->moba_batterys.size(); ++i) {
|
|
auto& tuple = GetMapMeta()->GetMobaRoomMeta()->moba_batterys.at(i);
|
|
|
|
int side = i + 1;
|
|
glm::vec3 center = std::get<0>(tuple);
|
|
CreatureWeakPtr target;
|
|
float last_distance = 0;
|
|
TraverseHumanList
|
|
(
|
|
[side, &target, ¢er, &tuple, &last_distance] (Human* hum) -> bool
|
|
{
|
|
if (hum->side != side &&
|
|
!hum->dead &&
|
|
!a8::HasBitFlag(hum->status, CS_Disable) &&
|
|
!hum->HasBuffEffect(kBET_Hide) &&
|
|
!hum->HasBuffEffect(kBET_Dive) &&
|
|
!hum->HasBuffEffect(kBET_Invincible)
|
|
) {
|
|
float distance = hum->GetPos().Distance2D2(center);
|
|
if (distance < std::get<1>(tuple)) {
|
|
if (!target.Get() || distance < last_distance) {
|
|
target = hum->GetWeakPtrRef();
|
|
last_distance = distance;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
if (!target.Get() ||
|
|
(target.Get() && last_distance <= 0.000001f)) {
|
|
continue;
|
|
}
|
|
|
|
glm::vec3 bullet_dir = target.Get()->GetPos().ToGlmVec3() - center;
|
|
GlmHelper::Normalize(bullet_dir);
|
|
|
|
const mt::Equip* weapon_meta = mt::Equip::GetById(std::get<2>(tuple));
|
|
if (!weapon_meta) {
|
|
#ifdef MYDEBUG
|
|
abort();
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
glm::vec3 bullet_born_pos = std::get<0>(tuple);
|
|
int bullet_uniid = AllocUniid();
|
|
int shot_uniid = 0;
|
|
frame_event.AddBullet
|
|
(bullet_uniid,
|
|
target,
|
|
weapon_meta,
|
|
1,
|
|
bullet_born_pos,
|
|
bullet_dir,
|
|
last_distance,
|
|
target.Get()->GetUniId(),
|
|
0,
|
|
nullptr,
|
|
shot_uniid,
|
|
-1);
|
|
float fly_time = last_distance / weapon_meta->bullet_speed();
|
|
fly_time = 0.1;
|
|
xtimer.SetTimeoutWpEx
|
|
(
|
|
fly_time * SERVER_FRAME_RATE,
|
|
[this, target_pos = target.Get()->GetPos().ToGlmVec3(), side, weapon_meta, target]
|
|
(int event, const a8::Args* args) mutable
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
#if 1
|
|
if (target.Get() &&
|
|
target.Get()->IsHuman() &&
|
|
!target.Get()->dead) {
|
|
target.Get()->AsHuman()->BeKill
|
|
(
|
|
VP_Tower,
|
|
"",
|
|
VW_Tower,
|
|
VP_Tower,
|
|
""
|
|
);
|
|
}
|
|
#else
|
|
TraverseHumanList
|
|
(
|
|
[this, side, target_pos, weapon_meta] (Human* hum) -> bool
|
|
{
|
|
if (hum->side != side &&
|
|
!hum->dead &&
|
|
!a8::HasBitFlag(hum->status, CS_Disable) &&
|
|
!hum->HasBuffEffect(kBET_Hide) &&
|
|
!hum->HasBuffEffect(kBET_Dive) &&
|
|
!hum->HasBuffEffect(kBET_Invincible)
|
|
) {
|
|
if (hum->GetPos().Distance2D2(target_pos) < weapon_meta->bullet_rad()) {
|
|
hum->BeKill(
|
|
VP_Explosion,
|
|
"",
|
|
weapon_meta->id(),
|
|
VP_Explosion,
|
|
""
|
|
);
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
#endif
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
#ifdef MYDEBUG
|
|
a8::XPrintf("MobaBatterysUpdate fly_distance:%f fly_time:%f speed:%f\n",
|
|
{last_distance,
|
|
fly_time,
|
|
weapon_meta->bullet_speed()});
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int Room::GetReportMapMode()
|
|
{
|
|
return GetMapModeMeta()->mapMode();
|
|
}
|
|
|
|
void Room::GenBattleRoomReportData(a8::MutableXObject* params)
|
|
{
|
|
params->SetVal("version", 2023030201);
|
|
params->SetVal("room_uuid", a8::XValue(GetRoomUuid()));
|
|
params->SetVal("room_mode", GetReportRoomMode());
|
|
params->SetVal("map_mode", GetReportMapMode());
|
|
params->SetVal("map_id", GetMapMeta()->map_id());
|
|
auto teams_pb = a8::MutableXObject::CreateArray();
|
|
TraverseTeams
|
|
(
|
|
[&teams_pb] (Team* team) -> bool
|
|
{
|
|
auto team_pb = a8::MutableXObject::CreateObject();
|
|
team->GenRoomReportData(team_pb.get());
|
|
teams_pb->Push(*team_pb);
|
|
return true;
|
|
}
|
|
);
|
|
params->SetVal("team_list", *teams_pb);
|
|
}
|
|
|
|
void Room::GenBattleMobaReportData(a8::MutableXObject* params)
|
|
{
|
|
params->SetVal("version", 2023030201);
|
|
params->SetVal("room_uuid", a8::XValue(GetRoomUuid()));
|
|
params->SetVal("room_mode", GetReportRoomMode());
|
|
params->SetVal("map_mode", GetReportMapMode());
|
|
params->SetVal("map_id", GetMapMeta()->map_id());
|
|
auto teams_pb = a8::MutableXObject::CreateArray();
|
|
TraverseTeams
|
|
(
|
|
[&teams_pb] (Team* team) -> bool
|
|
{
|
|
auto team_pb = a8::MutableXObject::CreateObject();
|
|
team->GenBattleReportData(team_pb.get());
|
|
teams_pb->Push(*team_pb);
|
|
return true;
|
|
}
|
|
);
|
|
params->SetVal("team_list", *teams_pb);
|
|
}
|
|
|
|
void Room::StartOverTimer()
|
|
{
|
|
int param1 = 1;
|
|
xtimer.SetIntervalEx
|
|
(
|
|
SERVER_FRAME_RATE * 6,
|
|
[this, param1] (int event, const a8::Args* args) mutable
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (GetOnlinePlayerNum() <= 0 && !added_to_over_room) {
|
|
RoomMgr::Instance()->AddOverRoom(room_uuid_);
|
|
xtimer.DeleteCurrentTimer();
|
|
return;
|
|
}
|
|
#ifdef MYDEBUG
|
|
if (param1 > 10) {
|
|
#else
|
|
if (param1 > 5) {
|
|
#endif
|
|
RoomMgr::Instance()->AddOverRoom(room_uuid_);
|
|
}
|
|
TraverseHumanList
|
|
(
|
|
[] (Human* ele_hum) -> bool
|
|
{
|
|
ele_hum->SendGameOver();
|
|
return true;
|
|
});
|
|
++param1;
|
|
}
|
|
},
|
|
&xtimer_attacher_);
|
|
}
|
|
|
|
void Room::TryRoomReport(int try_count)
|
|
{
|
|
if (sending_room_report_battle_) {
|
|
return;
|
|
}
|
|
if (already_room_report_battle_) {
|
|
return;;
|
|
}
|
|
sending_room_report_battle_ = true;
|
|
Player* player = nullptr;
|
|
TraversePlayerList
|
|
(
|
|
[&player] (Player* hum) -> bool
|
|
{
|
|
player = hum;
|
|
return true;
|
|
});
|
|
if (!player) {
|
|
return;
|
|
}
|
|
std::string url;
|
|
JsonDataMgr::Instance()->GetApiUrl(url);
|
|
std::shared_ptr<a8::MutableXObject> params = a8::MutableXObject::CreateObject();
|
|
std::shared_ptr<a8::MutableXObject> post_data = a8::MutableXObject::CreateObject();
|
|
GenBattleRoomReportData(post_data.get());
|
|
params->SetVal("c", "Battle");
|
|
params->SetVal("a", "roomReport");
|
|
params->SetVal("account_id", player->account_id);
|
|
params->SetVal("session_id", player->session_id);
|
|
std::string content = post_data->ToJsonStr();
|
|
HttpProxy::Instance()->HttpPost
|
|
(
|
|
[room_uuid = GetRoomUuid()]
|
|
(bool ok, a8::XObject* rsp_obj, f8::HttpContext* ctx)
|
|
{
|
|
auto room = RoomMgr::Instance()->GetRoomByUuid(room_uuid);
|
|
if (room) {
|
|
room->already_room_report_battle_ = true;
|
|
room->sending_room_report_battle_ = false;
|
|
room->TraverseHumanList
|
|
(
|
|
[] (Human* ele_hum) -> bool
|
|
{
|
|
ele_hum->SendGameOver();
|
|
return true;
|
|
});
|
|
room->StartOverTimer();
|
|
}
|
|
},
|
|
url,
|
|
params,
|
|
content
|
|
);
|
|
GetBoxDrop()->RequestReturnBoxNum();
|
|
#ifdef MYDEBUG
|
|
a8::XPrintf("RoomReportLen:%d\n", {params->ToJsonStr().size()});
|
|
#endif
|
|
}
|
|
|
|
bool Room::IsNoPlane()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void Room::CalcMvp()
|
|
{
|
|
float param0 = mt::Param::s().battle_score_param0;
|
|
float param1 = mt::Param::s().battle_score_param1;
|
|
|
|
float max_kill = 0;
|
|
float max_assist = 0;
|
|
float max_damage = 0.0f;
|
|
float max_recover = 0.0f;
|
|
float max_level = 0;
|
|
float max_alive = 0;
|
|
|
|
TraverseHumanList
|
|
(
|
|
[this, &max_kill, &max_assist, &max_damage, &max_recover, &max_level, &max_alive]
|
|
(Human* hum) mutable -> bool
|
|
{
|
|
#if 1
|
|
max_kill = std::max(max_kill, (float)hum->stats->kills);
|
|
max_assist = std::max(max_assist, (float)hum->stats->assist);
|
|
max_damage = std::max(max_damage, (float)hum->stats->damage_amount_out);
|
|
max_recover = std::max(max_recover, (float)hum->stats->heal_amount);
|
|
max_level = std::max(max_level, (float)hum->GetHeroLevel());
|
|
max_alive = std::max(max_alive, (float)hum->stats->alive_time / 1000);
|
|
#else
|
|
max_kill += hum->stats->kills;
|
|
max_assist += hum->stats->assist;
|
|
max_damage += hum->stats->damage_amount_out;
|
|
max_recover += hum->stats->heal_amount;
|
|
max_level += hum->GetHeroLevel();
|
|
max_alive += hum->stats->alive_time / 1000;
|
|
#endif
|
|
return true;
|
|
});
|
|
|
|
TraverseHumanList
|
|
(
|
|
[this, max_kill, max_assist, max_damage, max_recover, max_level, max_alive, param0, param1]
|
|
(Human* hum) -> bool
|
|
{
|
|
float kill_sco = param0;
|
|
{
|
|
if (max_kill > 0) {
|
|
float kill = hum->stats->kills;
|
|
kill_sco = (param1 - param0) / (max_kill - 0) * (kill - 0) + param0;
|
|
}
|
|
}
|
|
float assist_sco = param0;
|
|
{
|
|
if (max_assist > 0) {
|
|
float assist = hum->stats->assist;
|
|
assist_sco = (param1 - param0) / (max_assist - 0) * (assist - 0) + param0;
|
|
}
|
|
}
|
|
float damage_sco = param0;
|
|
{
|
|
if (max_damage > 0) {
|
|
float damage = hum->stats->damage_amount_out;
|
|
damage_sco = (param1 - param0) / (max_damage - 0) * (damage - 0) + param0;
|
|
}
|
|
}
|
|
float recover_sco = param0;
|
|
{
|
|
if (max_recover > 0) {
|
|
float recover = hum->stats->heal_amount;
|
|
recover_sco = (param1 - param0) / (max_recover - 0) * (recover - 0) + param0;
|
|
}
|
|
}
|
|
float level_sco = param0;
|
|
{
|
|
if (max_level > 1.00000) {
|
|
float level = hum->GetHeroLevel();
|
|
level_sco = (param1 - param0) / (max_level - 0) * (level - 0) + param0;
|
|
}
|
|
}
|
|
float alive_sco = param0;
|
|
{
|
|
if (max_alive > 0) {
|
|
float alive = hum->stats->alive_time / 1000;
|
|
alive_sco = (param1 - param0) / (max_alive - 0) * (alive - 0) + param0;
|
|
}
|
|
}
|
|
#ifdef MYDEBUG
|
|
if (hum->IsPlayer()) {
|
|
a8::XPrintf("kill_sco:%f assist_sco:%f damage_sco:%f recover_sco:%f alive_sco:%f "
|
|
"assist:%f max_assist:%f damage:%f max_damage:%f recover:%f max_recover:%f "
|
|
"level:%d max_level:%d""\n",
|
|
{
|
|
kill_sco,
|
|
assist_sco,
|
|
damage_sco,
|
|
recover_sco,
|
|
alive_sco,
|
|
hum->stats->assist,
|
|
max_assist,
|
|
hum->stats->damage_amount_out,
|
|
max_damage,
|
|
hum->stats->heal_amount,
|
|
max_recover,
|
|
hum->GetHeroLevel(),
|
|
max_level
|
|
});
|
|
}
|
|
#endif
|
|
float battle_score = 0.0f;
|
|
if (IsMobaModeRoom()) {
|
|
if (mt::Param::s().performance_score_weight_4V4.size() >= 5) {
|
|
kill_sco *= mt::Param::s().performance_score_weight_4V4.at(0);
|
|
assist_sco *= mt::Param::s().performance_score_weight_4V4.at(1);
|
|
damage_sco *= mt::Param::s().performance_score_weight_4V4.at(2);
|
|
recover_sco *= mt::Param::s().performance_score_weight_4V4.at(3);
|
|
level_sco *= mt::Param::s().performance_score_weight_4V4.at(4);
|
|
}
|
|
battle_score = std::round((kill_sco + assist_sco + damage_sco + recover_sco + level_sco) * 100.0f) / 100.0f;
|
|
} else {
|
|
if (mt::Param::s().performance_score_weight_BR.size() >= 5) {
|
|
kill_sco *= mt::Param::s().performance_score_weight_BR.at(0);
|
|
assist_sco *= mt::Param::s().performance_score_weight_BR.at(1);
|
|
damage_sco *= mt::Param::s().performance_score_weight_BR.at(2);
|
|
recover_sco *= mt::Param::s().performance_score_weight_BR.at(3);
|
|
alive_sco *= mt::Param::s().performance_score_weight_BR.at(4);
|
|
}
|
|
battle_score = std::round((kill_sco + assist_sco + damage_sco + recover_sco + alive_sco) * 100.0f) / 100.0f;
|
|
}
|
|
#ifdef MYDEBUG
|
|
if (hum->IsPlayer()) {
|
|
a8::XPrintf("battle_score:%f\n",
|
|
{
|
|
battle_score
|
|
});
|
|
}
|
|
#endif
|
|
hum->stats->battle_score = battle_score;
|
|
return true;
|
|
});
|
|
}
|
|
|
|
void Room::MobaOver()
|
|
{
|
|
if (!IsGameOver() && !GetVictoryTeam()) {
|
|
game_over_ = true;
|
|
game_over_frameno_ = GetFrameNo();
|
|
if (GetMobaTeamA()->GetKillCount() == GetMobaTeamB()->GetKillCount()) {
|
|
if (GetMobaTeamA()->GetLastKillFrameNo() == GetMobaTeamB()->GetLastKillFrameNo()) {
|
|
if (GetMobaTeamA()->GetTeamId() < GetMobaTeamA()->GetTeamId()) {
|
|
SetVictoryTeam(GetMobaTeamA());
|
|
} else {
|
|
SetVictoryTeam(GetMobaTeamB());
|
|
}
|
|
} else if (GetMobaTeamA()->GetLastKillFrameNo() >
|
|
GetMobaTeamB()->GetLastKillFrameNo()) {
|
|
SetVictoryTeam(GetMobaTeamA());
|
|
} else {
|
|
SetVictoryTeam(GetMobaTeamB());
|
|
}
|
|
} if (GetMobaTeamA()->GetKillCount() > GetMobaTeamB()->GetKillCount()) {
|
|
SetVictoryTeam(GetMobaTeamA());
|
|
} else {
|
|
SetVictoryTeam(GetMobaTeamB());
|
|
}
|
|
if (GetVictoryTeam() == GetMobaTeamA()) {
|
|
GetInGameVoice()->Victory(GetMobaTeamA());
|
|
GetInGameVoice()->Fail(GetMobaTeamB());
|
|
} else {
|
|
GetInGameVoice()->Victory(GetMobaTeamB());
|
|
GetInGameVoice()->Fail(GetMobaTeamA());
|
|
}
|
|
OnGameOver();
|
|
}
|
|
}
|
|
|
|
void Room::SetNewBieBattle(int is_newbie_battle)
|
|
{
|
|
is_newbie_battle_ = is_newbie_battle;
|
|
}
|