4060 lines
130 KiB
C++
4060 lines
130 KiB
C++
#include "precompile.h"
|
|
|
|
#include <random>
|
|
|
|
#include <a8/mutable_xobject.h>
|
|
#include <a8/timer.h>
|
|
#include <a8/udplog.h>
|
|
#include <a8/collision.h>
|
|
|
|
#include "framework/cpp/utils.h"
|
|
|
|
#include "playermgr.h"
|
|
#include "player.h"
|
|
#include "cs_proto.pb.h"
|
|
#include "room.h"
|
|
#include "android.h"
|
|
#include "metamgr.h"
|
|
#include "bullet.h"
|
|
#include "collider.h"
|
|
#include "obstacle.h"
|
|
#include "roomobstacle.h"
|
|
#include "building.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"
|
|
|
|
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;
|
|
creator_game_times_ = init_info.creator_game_times;
|
|
creator_register_time_ = init_info.creator_register_time;
|
|
creator_proto_version_ = init_info.creator_proto_version;
|
|
creator_channel_ = init_info.creator_channel;
|
|
force_entry_newbie_room_ = init_info.force_entry_newbie_room;
|
|
|
|
map_tpl_name_ = init_info.map_tpl_name;
|
|
grid_service = init_info.grid_service;
|
|
map_service = init_info.map_service;
|
|
map_instance = init_info.map_instance;
|
|
map_meta_ = init_info.map_meta;
|
|
mini_room_spawn_points_ = init_info.mini_room_spawn_points;
|
|
normal_room_spawn_points_ = init_info.normal_room_spawn_points;
|
|
room_monster_spawn_points_ = init_info.room_monster_spawn_points;
|
|
level0room_born_point_meta_ = init_info.level0room_born_point_meta;
|
|
level1room_born_point_meta_ = init_info.level1room_born_point_meta;
|
|
loots_ = init_info.loots;
|
|
buildings_ = init_info.buildings;
|
|
level0room_spec_things_ = init_info.level0room_spec_things;
|
|
}
|
|
|
|
void Room::Init()
|
|
{
|
|
xtimer.Init(RoomXGetTickCount, this, 100, 100);
|
|
xtimer_attacher_.xtimer = &xtimer;
|
|
|
|
frame_event.room = this;
|
|
|
|
CreateSpawnPoints();
|
|
CreateMonsterSpawnPoints();
|
|
CreateLoots();
|
|
CreateDropObjs();
|
|
InitObstacleDatas();
|
|
ShuaAndroid();
|
|
incubator_ = new Incubator();
|
|
incubator_->room = this;
|
|
incubator_->Init();
|
|
if (room_type_ == RT_NewBrid && creator_game_times_ <= 0) {
|
|
CreateLevel0RoomSpecThings();
|
|
}
|
|
#ifdef DEBUG
|
|
InitDebugInfo();
|
|
#endif
|
|
}
|
|
|
|
void Room::UnInit()
|
|
{
|
|
incubator_->UnInit();
|
|
#ifdef DEBUG
|
|
UnInitDebugInfo();
|
|
#endif
|
|
incubator_->UnInit();
|
|
A8_SAFE_DELETE(incubator_);
|
|
timer_attacher.ClearTimerList();
|
|
xtimer_attacher_.ClearTimerList();
|
|
grid_service->ClearRoomData(this);
|
|
for (auto& pair : accountid_hash_) {
|
|
PlayerMgr::Instance()->RemovePlayerBySocket(pair.second->socket_handle);
|
|
}
|
|
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();
|
|
for (auto& pair : team_hash_) {
|
|
delete pair.second;
|
|
}
|
|
team_hash_.clear();
|
|
PerfMonitor::Instance()->alive_count -= alive_count_;
|
|
}
|
|
|
|
void Room::Update(int delta_time)
|
|
{
|
|
xtimer.Update();
|
|
if (IsGameOver() && GetFrameNo() - game_over_frameno_ > SERVER_FRAME_RATE * 20) {
|
|
return;
|
|
}
|
|
|
|
elapsed_time_ += delta_time;
|
|
while (elapsed_time_ >= 50) {
|
|
#ifdef DEBUG1
|
|
long long begin_tick = a8::XGetTickCount();
|
|
long long end_tick = a8::XGetTickCount();
|
|
#endif
|
|
if (GetFrameNo() % 2 == 0) {
|
|
UpdateGas();
|
|
}
|
|
#ifdef DEBUG1
|
|
end_tick = a8::XGetTickCount();
|
|
if (a8::XGetTickCount() - begin_tick > 1000) {
|
|
abort();
|
|
}
|
|
begin_tick = a8::XGetTickCount();
|
|
#endif
|
|
for (auto& pair : moveable_hash_) {
|
|
pair.second->Update(50);
|
|
}
|
|
#ifdef DEBUG1
|
|
end_tick = a8::XGetTickCount();
|
|
if (a8::XGetTickCount() - begin_tick > 1000) {
|
|
abort();
|
|
}
|
|
begin_tick = a8::XGetTickCount();
|
|
#endif
|
|
if (GetFrameNo() % 2 == 0) {
|
|
SyncFrameData();
|
|
}
|
|
#ifdef DEBUG1
|
|
end_tick = a8::XGetTickCount();
|
|
if (a8::XGetTickCount() - begin_tick > 1000) {
|
|
abort();
|
|
}
|
|
#endif
|
|
++frameno_;
|
|
elapsed_time_ -= 50;
|
|
}
|
|
}
|
|
|
|
int Room::GetPlayerNum()
|
|
{
|
|
return accountid_hash_.size();
|
|
}
|
|
|
|
int Room::GetHumanNum()
|
|
{
|
|
return human_hash_.size();
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (uniid < FIXED_OBJECT_MAXID) {
|
|
return map_instance->GetEntityByUniId(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)
|
|
{
|
|
if (gas_data_.gas_mode != GasInactive) {
|
|
abort();
|
|
}
|
|
while (human_hash_.size() >= GetRoomMaxPlayerNum()) {
|
|
RandRemoveAndroid();
|
|
}
|
|
hum->born_point = AllocBornPoint(hum);
|
|
if (!hum->born_point) {
|
|
hum->SetPos(GetDefaultBornPoint());
|
|
} else {
|
|
hum->SetPos(hum->born_point->RandPoint());
|
|
}
|
|
a8::Vec2 attack_dir = hum->GetPos();
|
|
attack_dir.Normalize();
|
|
attack_dir.Rotate(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);
|
|
AddToAliveHumanHash(hum);
|
|
MatchTeam(hum);
|
|
hum->PushJoinRoomMsg();
|
|
++alive_count_;
|
|
alive_count_chged_frameno_ = GetFrameNo();
|
|
++PerfMonitor::Instance()->alive_count;
|
|
|
|
grid_service->AddCreature(hum);
|
|
hum->FindLocation();
|
|
hum->RefreshView();
|
|
AddPlayerPostProc(hum);
|
|
NotifyUiUpdate();
|
|
GameLog::Instance()->GameStart(hum);
|
|
}
|
|
|
|
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 (gas_data_.gas_mode != GasInactive) {
|
|
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) {
|
|
if (IsMiniRoom()) {
|
|
#if 0
|
|
robot_num /= 2;
|
|
robot_num = std::max(1, robot_num);
|
|
#endif
|
|
refresh_time /= 2;
|
|
refresh_time = std::max(2, refresh_time);
|
|
}
|
|
CreateAndroid(robot_num);
|
|
xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * refresh_time,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->ShuaAndroid();
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
}
|
|
|
|
void Room::ShowAndroid(Human* target, int num)
|
|
{
|
|
if (!target->born_point) {
|
|
return;
|
|
}
|
|
int i = 0;
|
|
for (auto& pair : human_hash_) {
|
|
Human* hum = pair.second;
|
|
if (hum->IsAndroid() &&
|
|
a8::HasBitFlag(hum->status, CS_Disable)) {
|
|
if (hum->born_point) {
|
|
DecBornPointHumanNum(hum->born_point, hum);
|
|
}
|
|
hum->born_point = target->born_point;
|
|
IncBornPointHumanNum(hum->born_point, hum);
|
|
hum->SetPos(hum->born_point->RandPoint());
|
|
EnableHuman(hum);
|
|
++i;
|
|
if (i >= num) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateAndroid(int robot_num)
|
|
{
|
|
for (int i = 0; i < robot_num; ++i) {
|
|
if (human_hash_.size() >= GetRoomMaxPlayerNum()) {
|
|
return;
|
|
}
|
|
MetaData::Robot* robot_meta = MetaMgr::Instance()->RandRobot(refreshed_robot_set_);
|
|
if (!robot_meta) {
|
|
abort();
|
|
}
|
|
|
|
Android* hum = EntityFactory::Instance()->MakeAndroid(AllocUniid());
|
|
hum->name = robot_meta->i->name();
|
|
hum->meta = MetaMgr::Instance()->GetPlayer(robot_meta->i->hero_id());
|
|
hum->robot_meta = robot_meta;
|
|
hum->born_point = AllocBornPoint(hum);
|
|
if (!hum->born_point) {
|
|
hum->SetPos(GetDefaultBornPoint());
|
|
} else {
|
|
hum->SetPos(hum->born_point->RandPoint());
|
|
}
|
|
a8::Vec2 attack_dir = hum->GetPos();
|
|
attack_dir.Normalize();
|
|
attack_dir.Rotate(a8::RandAngle());
|
|
hum->SetAttackDir(attack_dir);
|
|
hum->SetMoveDir(attack_dir);
|
|
hum->room = this;
|
|
hum->Initialize();
|
|
AddToEntityHash(hum);
|
|
AddToHumanHash(hum);
|
|
MatchTeam(hum);
|
|
++alive_count_;
|
|
alive_count_chged_frameno_ = GetFrameNo();
|
|
++PerfMonitor::Instance()->alive_count;
|
|
refreshed_robot_set_.insert(robot_meta->i->id());
|
|
if (GetRoomMode() == kZombieMode) {
|
|
hum->ChangeToRace(kHumanRace, 1);
|
|
}
|
|
|
|
if (!CanAddToScene(hum)) {
|
|
a8::SetBitFlag(hum->status, CS_Disable);
|
|
} else {
|
|
AddToAliveHumanHash(hum);
|
|
AddToMoveableHash(hum);
|
|
grid_service->AddCreature(hum);
|
|
hum->FindLocation();
|
|
hum->RefreshView();
|
|
}
|
|
}
|
|
NotifyUiUpdate();
|
|
}
|
|
|
|
Human* Room::FindEnemy(Human* hum)
|
|
{
|
|
std::vector<Human*> enemys;
|
|
enemys.reserve(50);
|
|
EntitySubType_e sub_type = EST_Player;
|
|
if ((rand() % 10) < 2) {
|
|
sub_type = EST_Android;
|
|
}
|
|
if (room_type_ == RT_MidBrid) {
|
|
sub_type = EST_Android;
|
|
Human* target = nullptr;
|
|
hum->room->TraverseHumanList
|
|
(
|
|
a8::XParams(),
|
|
[hum, &target] (Human* huma, a8::XParams& param)
|
|
{
|
|
if (!huma->dead &&
|
|
huma->IsAndroid() &&
|
|
hum->team_id != huma->team_id &&
|
|
!a8::HasBitFlag(huma->status, CS_Disable)) {
|
|
if (!target) {
|
|
target = huma;
|
|
} else {
|
|
if (hum->GetPos().ManhattanDistance(huma->GetPos()) <
|
|
hum->GetPos().ManhattanDistance(target->GetPos())) {
|
|
target = huma;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
if (target) {
|
|
if (hum->GetPos().ManhattanDistance(target->GetPos()) > 190) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
hum->TraverseAllLayerHumanList
|
|
(
|
|
[&enemys, hum, sub_type] (Human* target, bool& stop)
|
|
{
|
|
if (target->IsEntitySubType(sub_type) &&
|
|
!target->dead) {
|
|
if (hum->GetPos().Distance(target->GetPos()) < 300.0f) {
|
|
if (target->team_id == 0 ||
|
|
target->team_id != hum->team_id
|
|
) {
|
|
enemys.push_back(target);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
std::sort(enemys.begin(), enemys.end(),
|
|
[hum] (Human* a, Human *b) -> bool
|
|
{
|
|
return (hum->GetPos()-a->GetPos()).Norm() < (hum->GetPos()-b->GetPos()).Norm();
|
|
});
|
|
return !enemys.empty() ? enemys[0] : nullptr;
|
|
}
|
|
|
|
void Room::FillSMJoinedNotify(Player* self_hum, cs::SMJoinedNotify& msg)
|
|
{
|
|
msg.set_team_mode(msg.team_mode());
|
|
msg.set_player_id(self_hum->GetUniId());
|
|
msg.set_started(false);
|
|
msg.set_room_uuid(a8::XValue(room_uuid_).GetString());
|
|
}
|
|
|
|
void Room::ScatterDrop(a8::Vec2 center, int drop_id)
|
|
{
|
|
MetaData::Drop* drop_meta = MetaMgr::Instance()->GetDrop(drop_id);
|
|
if (drop_meta) {
|
|
std::vector<std::tuple<int, int, int>> drop_items;
|
|
drop_meta->RandItems(drop_items);
|
|
for (auto& item : drop_items) {
|
|
a8::Vec2 dir = a8::Vec2::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
DropItemEx(center,
|
|
center + dir * (5 + rand() % 50),
|
|
std::get<0>(item), std::get<1>(item),
|
|
std::get<1>(item),
|
|
true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::DropItem(a8::Vec2 pos, int item_id, int item_count, int item_lv)
|
|
{
|
|
DropItemEx(pos, pos, item_id, item_count, item_lv, false);
|
|
}
|
|
|
|
void Room::DropItemEx(a8::Vec2 born_pos, a8::Vec2 pos, int item_id, int item_count, int item_lv, bool show_anim)
|
|
{
|
|
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquip(item_id);
|
|
if (equip_meta && equip_meta->i->group_num() > 0 && item_count > 0) {
|
|
int total_count = item_count;
|
|
while (total_count > 0) {
|
|
int drop_num = std::min(total_count, equip_meta->i->group_num());
|
|
if (drop_num < 1) {
|
|
drop_num = 1;
|
|
}
|
|
{
|
|
a8::Vec2 dir = a8::Vec2::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
pos = pos + dir * (25 + rand() % 50);
|
|
}
|
|
CreateLootEx(item_id, born_pos, pos, drop_num, item_lv, show_anim);
|
|
total_count -= drop_num;
|
|
}
|
|
}
|
|
}
|
|
|
|
RoomObstacle* Room::CreateObstacle(int id, float x, float y)
|
|
{
|
|
RoomObstacle* entity = InternalCreateObstacle(id, x, y,
|
|
[] (Obstacle*)
|
|
{
|
|
});
|
|
assert(entity);
|
|
if (entity) {
|
|
entity->BroadcastFullState(this);
|
|
}
|
|
return entity;
|
|
}
|
|
|
|
int Room::CreateLoot(int equip_id, a8::Vec2 pos, int count, int equip_lv)
|
|
{
|
|
return CreateLootEx(equip_id, pos, pos, count, equip_lv, false);
|
|
}
|
|
|
|
int Room::CreateLootEx(int equip_id, a8::Vec2 born_pos, a8::Vec2 pos, int count, int equip_lv, bool show_anim)
|
|
{
|
|
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquip(equip_id);
|
|
if (equip_meta) {
|
|
Loot* entity = EntityFactory::Instance()->MakeLoot(AllocUniid());
|
|
entity->room = this;
|
|
entity->meta = equip_meta;
|
|
entity->SetPos(pos);
|
|
entity->born_pos = born_pos;
|
|
entity->show_anim = show_anim;
|
|
entity->create_frame_no = GetFrameNo();
|
|
#if 1
|
|
{
|
|
if (entity->GetX() >= map_meta_->i->map_width()) {
|
|
entity->SetX(map_meta_->i->map_width() - 1);
|
|
}
|
|
if (entity->GetX() < 1.0f) {
|
|
entity->SetX(1.0f);
|
|
}
|
|
if (entity->GetY() >= map_meta_->i->map_height()) {
|
|
entity->SetY(map_meta_->i->map_height() - 1);
|
|
}
|
|
if (entity->GetY() < 1.0f) {
|
|
entity->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);
|
|
if (equip_meta->i->_inventory_slot() == IS_OIL_BUCKET) {
|
|
MetaData::MapThing* dummy_meta = MetaMgr::Instance()->GetMapThing(equip_meta->int_param1);
|
|
if (dummy_meta->i->thing_type() != kObstacleOilBucket) {
|
|
abort();
|
|
}
|
|
RoomObstacle* dummy_obj = CreateObstacle(equip_meta->int_param1, pos.x, pos.y);
|
|
entity->dummy_thing_uniid = dummy_obj->GetUniId();
|
|
dummy_obj->real_object_uniid = entity->GetUniId();
|
|
}
|
|
return entity->GetUniId();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int Room::CreateBullet(Creature* sender,
|
|
Creature* passenger,
|
|
MetaData::Equip* weapon_meta,
|
|
MetaData::EquipUpgrade* weapon_upgrade_meta,
|
|
MetaData::Equip* bullet_meta,
|
|
a8::Vec2 pos,
|
|
a8::Vec2 dir,
|
|
float fly_distance,
|
|
bool is_tank_skin)
|
|
{
|
|
int bullet_uniid = 0;
|
|
if (grid_service->CanAdd(pos.x, pos.y)) {
|
|
Bullet* bullet = EntityFactory::Instance()->MakeBullet(AllocUniid());
|
|
bullet->sender.Attach(sender);
|
|
if (passenger) {
|
|
bullet->passenger.Attach(passenger);
|
|
}
|
|
bullet->room = this;
|
|
bullet->gun_meta = weapon_meta;
|
|
bullet->gun_upgrade_meta = weapon_upgrade_meta;
|
|
bullet->meta = bullet_meta;
|
|
bullet->SetPos(pos);
|
|
bullet->dir = dir;
|
|
bullet->born_pos = pos;
|
|
bullet->born_dir = dir;
|
|
bullet->fly_distance = fly_distance;
|
|
bullet->is_tank_skin = is_tank_skin;
|
|
bullet->Initialize();
|
|
AddObjectLater(bullet);
|
|
bullet_uniid = bullet->GetUniId();
|
|
}
|
|
return bullet_uniid;
|
|
}
|
|
|
|
Car* Room::CreateCar(Human* driver,
|
|
int car_uniid,
|
|
MetaData::Equip* item_meta,
|
|
const a8::Vec2& pos,
|
|
int team_id)
|
|
{
|
|
Car* car = EntityFactory::Instance()->MakeCar(AllocUniid());
|
|
car->car_uniid = car_uniid;
|
|
car->meta = item_meta;
|
|
car->room = this;
|
|
car->team_id = team_id;
|
|
car->SetPos(pos);
|
|
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,
|
|
MetaData::Player* meta,
|
|
const a8::Vec2& pos,
|
|
const a8::Vec2& dir,
|
|
int team_id)
|
|
{
|
|
Hero* hero = EntityFactory::Instance()->MakeHero(AllocUniid());
|
|
hero->meta = meta;
|
|
if (master) {
|
|
hero->master.Attach(master);
|
|
}
|
|
hero->room = this;
|
|
hero->SetPos(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::XTimerAttacher& xtimer_attacher)
|
|
{
|
|
auto remove_func =
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Entity* entity = (Entity*)param.sender.GetUserData();
|
|
Room* room = (Room*)param.param1.GetUserData();
|
|
switch (entity->GetEntityType()) {
|
|
case ET_Bullet:
|
|
{
|
|
room->RemoveFromMoveableHash((Bullet*)entity);
|
|
}
|
|
break;
|
|
case ET_Loot:
|
|
{
|
|
entity->BroadcastDeleteState(room);
|
|
room->grid_service->DelRoomEntity(room, entity);
|
|
}
|
|
break;
|
|
case ET_Player:
|
|
{
|
|
room->RemoveFromMoveableHash((Human*)entity);
|
|
room->RemoveFromHuamnHash((Human*)entity);
|
|
}
|
|
break;
|
|
case ET_Car:
|
|
{
|
|
#if 0
|
|
RemoveFromAroundPlayers(entity->room);
|
|
BroadcastDeleteState(entity->room);
|
|
room->grid_service->RemoveCreature((Car*)entity);
|
|
#endif
|
|
room->RemoveFromMoveableHash((Car*)entity);
|
|
}
|
|
break;
|
|
case ET_Hero:
|
|
{
|
|
#if 0
|
|
BroadcastDeleteState(entity->room);
|
|
RemoveFromAroundPlayers(entity->room);
|
|
room->grid_service->RemoveCreature((Hero*)entity);
|
|
#endif
|
|
room->RemoveFromMoveableHash((Hero*)entity);
|
|
}
|
|
break;
|
|
case ET_Obstacle:
|
|
{
|
|
entity->BroadcastDeleteState(room);
|
|
room->grid_service->DelRoomEntity(room, entity);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
abort();
|
|
}
|
|
break;
|
|
}
|
|
room->RemoveFromEntityHash(entity);
|
|
#ifdef DEBUG
|
|
#if 0
|
|
a8::UdpLog::Instance()->Debug
|
|
(
|
|
"remove object pointer:%d uniid:%d",
|
|
{
|
|
(long long)entity,
|
|
entity->GetUniId()
|
|
}
|
|
);
|
|
#endif
|
|
#endif
|
|
delete entity;
|
|
};
|
|
xtimer.AddDeadLineTimerAndAttach(NEXT_FRAME_TIMER,
|
|
a8::XParams()
|
|
.SetSender(entity)
|
|
.SetParam1(this),
|
|
remove_func,
|
|
&xtimer_attacher.timer_list_);
|
|
}
|
|
|
|
void Room::OnHumanDie(Human* hum)
|
|
{
|
|
if (GetRoomMode() == kZombieMode) {
|
|
if (debug_trace) {
|
|
a8::UdpLog::Instance()->Debug
|
|
(
|
|
"OnHumanDie uniid:%d name:%s race:%d level:%d exp:%d killer_id:%d ",
|
|
{
|
|
hum->GetUniId(),
|
|
hum->name,
|
|
hum->GetRace(),
|
|
hum->GetLevel(),
|
|
hum->GetExp(),
|
|
hum->stats.killer_id
|
|
}
|
|
);
|
|
}
|
|
if (hum->GetRace() == kHumanRace) {
|
|
RemoveRescue(hum);
|
|
hum->DeadDrop();
|
|
std::vector<Human*> alive_humans;
|
|
alive_humans.reserve(GetRoomMaxPlayerNum());
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second != hum) {
|
|
pair.second->WinExp(hum, hum->meta->i->dead_exp());
|
|
}
|
|
if (!pair.second->dead && pair.second->GetRace() == kHumanRace) {
|
|
alive_humans.push_back(pair.second);
|
|
}
|
|
}
|
|
if (alive_humans.size() == 1) {
|
|
Human* terminator = alive_humans[0];
|
|
if (!terminator->HasBuffEffect(kBET_Terminator)) {
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(TERMINATOR_BUFF_ID);
|
|
if (buff_meta) {
|
|
terminator->AddBuff(terminator, buff_meta, 1);
|
|
}
|
|
}
|
|
}
|
|
{
|
|
Human* killer = GetPlayerByUniId(hum->stats.killer_id);
|
|
if (killer && killer != hum) {
|
|
killer->WinExp(hum, hum->meta->i->killer_exp());
|
|
}
|
|
}
|
|
} else if (hum->GetRace() == kZombieRace) {
|
|
} else {
|
|
abort();
|
|
}
|
|
NotifyUiUpdate();
|
|
} else {
|
|
--alive_count_;
|
|
alive_count_chged_frameno_ = GetFrameNo();
|
|
--PerfMonitor::Instance()->alive_count;
|
|
RemoveFromAliveHumanHash(hum);
|
|
NotifyUiUpdate();
|
|
CheckShowHand();
|
|
}
|
|
}
|
|
|
|
void Room::OnHumanRevive(Human* hum)
|
|
{
|
|
NotifyUiUpdate();
|
|
}
|
|
|
|
bool Room::OverBorder(const a8::Vec2& pos, float radius)
|
|
{
|
|
CircleCollider collider;
|
|
collider.pos = pos;
|
|
collider.rad = radius;
|
|
return OverBorder(pos, &collider);
|
|
}
|
|
|
|
bool Room::OverBorder(const a8::Vec2& pos, ColliderComponent* collider)
|
|
{
|
|
switch (collider->type) {
|
|
case CT_Aabb:
|
|
{
|
|
AabbCollider* aabb_box = (AabbCollider*)collider;
|
|
//检查x轴
|
|
{
|
|
float left_x = (pos + aabb_box->_min).x;
|
|
if (left_x < 0.001f) {
|
|
return true;
|
|
}
|
|
float right_x = (pos + aabb_box->_max).x;
|
|
if (right_x > map_meta_->i->map_width()) {
|
|
return true;
|
|
}
|
|
}
|
|
//检查y轴
|
|
{
|
|
float down_y = (pos + aabb_box->_min).y;
|
|
if (down_y < 0.001f) {
|
|
return true;
|
|
}
|
|
float up_y = (pos + aabb_box->_max).y;
|
|
if (up_y > map_meta_->i->map_height()) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case CT_Circle:
|
|
{
|
|
CircleCollider* circle_collider = (CircleCollider*)collider;
|
|
//检查x轴
|
|
{
|
|
float left_x = pos.x - circle_collider->rad;
|
|
if (left_x < 0.001f) {
|
|
return true;
|
|
}
|
|
float right_x = pos.x + circle_collider->rad;
|
|
if (right_x > map_meta_->i->map_width()) {
|
|
return true;
|
|
}
|
|
}
|
|
//检查y轴
|
|
{
|
|
float down_y = pos.y - circle_collider->rad;
|
|
if (down_y < 0.001f) {
|
|
return true;
|
|
}
|
|
float up_y = pos.y + circle_collider->rad;
|
|
if (up_y > map_meta_->i->map_height()) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Room::AdjustPosInnerMap(a8::Vec2& pos, float radius)
|
|
{
|
|
//检查x轴
|
|
{
|
|
int left_x = pos.x - radius;
|
|
if (left_x < 0.001f) {
|
|
pos.x = radius + 10;
|
|
}
|
|
int right_x = pos.x + radius;
|
|
if (right_x > map_meta_->i->map_width()) {
|
|
pos.x = map_meta_->i->map_width() - radius - 10;
|
|
}
|
|
}
|
|
//检查y轴
|
|
{
|
|
int up_y = pos.y + radius;
|
|
if (up_y > map_meta_->i->map_height()) {
|
|
pos.y = map_meta_->i->map_height() - radius - 10;
|
|
}
|
|
int down_y = pos.y - radius;
|
|
if (down_y < 0.001f) {
|
|
pos.y = radius + 10;
|
|
}
|
|
}
|
|
if (OverBorder(pos, radius)) {
|
|
pos = a8::Vec2(1800, 1800);
|
|
#ifdef DEBUG
|
|
abort();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
Human* Room::GetWatchWarTarget(Human* hum)
|
|
{
|
|
if (hum->GetTeam()) {
|
|
Human* member = hum->GetTeam()->GetOneAliveMember(hum);
|
|
if (member) {
|
|
return member;
|
|
}
|
|
}
|
|
std::vector<Human*> humans;
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.first != hum->GetUniId() && !pair.second->dead) {
|
|
humans.push_back(pair.second);
|
|
}
|
|
}
|
|
if (!humans.empty()) {
|
|
Human* target = humans[rand() % humans.size()];
|
|
return target;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool Room::BattleStarted()
|
|
{
|
|
return battle_start_frameno_ != 0;
|
|
}
|
|
|
|
int Room::GetAliveTeamNum()
|
|
{
|
|
int num = 0;
|
|
for (auto& pair : team_hash_) {
|
|
if (pair.second->HasAliveMember()) {
|
|
++num;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
bool Room::CanJoin(const std::string& accountid,
|
|
RoomType_e self_room_type,
|
|
RoomMode_e self_room_mode,
|
|
int self_proto_version,
|
|
int self_channel,
|
|
int init_map_id)
|
|
{
|
|
if (self_room_mode < kChiJiMode) {
|
|
self_room_mode = kChiJiMode;
|
|
}
|
|
if (self_room_mode > kRoomModeEnd) {
|
|
self_room_mode = kZombieMode;
|
|
}
|
|
if (room_mode_ != self_room_mode) {
|
|
return false;
|
|
}
|
|
if (gas_data_.gas_mode != GasInactive) {
|
|
return false;
|
|
}
|
|
if (init_map_id != 0) {
|
|
MapInstance* map_instance = MapMgr::Instance()->GetMapInstance(init_map_id);
|
|
if (map_instance && map_instance->GetMapMeta()->i->map_mode() == room_mode_ &&
|
|
map_instance->map_id != map_meta_->i->map_id()) {
|
|
return false;
|
|
}
|
|
}
|
|
if (GetPlayerByAccountId(accountid)) {
|
|
return false;
|
|
}
|
|
if (room_type_ == RT_NewBrid) {
|
|
if (room_type_ != self_room_type || GetPlayerNum() > 0) {
|
|
return false;
|
|
}
|
|
}
|
|
if (room_type_ == RT_MidBrid) {
|
|
if (room_type_ != self_room_type || GetPlayerNum() >= 4) {
|
|
return false;
|
|
}
|
|
}
|
|
return GetPlayerNum() < (int)GetRoomMaxPlayerNum();
|
|
}
|
|
|
|
void Room::OnPlayerOffline(Player* hum)
|
|
{
|
|
if (GetOnlinePlayerNum() <= 0) {
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE * 15,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (room->GetOnlinePlayerNum() <= 0 && !room->added_to_over_room) {
|
|
GameLog::Instance()->ForceOver(room);
|
|
RoomMgr::Instance()->AddOverRoom(room->room_uuid_);
|
|
}
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
}
|
|
|
|
void Room::FindLocationWithAabb(ColliderComponent* target_collider,
|
|
const a8::Vec2& aabb_pos,
|
|
AabbCollider* aabb_box,
|
|
float& new_x, float& new_y)
|
|
{
|
|
a8::Vec2 old_pos = aabb_pos;
|
|
a8::Vec2 new_pos = aabb_pos;
|
|
{
|
|
bool ret = aabb_box->CalcSafePointEx(aabb_pos, target_collider, new_pos);
|
|
if (!ret) {
|
|
abort();
|
|
}
|
|
}
|
|
a8::Vec2 new_pos_dir = new_pos - old_pos;
|
|
new_pos_dir.Normalize();
|
|
float distance = (new_pos - old_pos).Norm();
|
|
for (int i = distance; i < 100000; i += 5) {
|
|
a8::Vec2 pos = old_pos + new_pos_dir * i;
|
|
new_x = pos.x;
|
|
new_y = pos.y;
|
|
|
|
bool is_collision = false;
|
|
std::set<ColliderComponent*> colliders;
|
|
map_service->GetColliders(this, pos.x, pos.y, colliders);
|
|
for (ColliderComponent* collider : colliders) {
|
|
if (collider->IntersectEx(pos, aabb_box)) {
|
|
is_collision = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!is_collision) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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());
|
|
}
|
|
}
|
|
if (GetRoomMode() == kZombieMode) {
|
|
#if 1
|
|
{
|
|
zombie_alive_count_ = 0;
|
|
human_alive_count_ = 0;
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->GetRace() == kHumanRace) {
|
|
++human_alive_count_;
|
|
} else if (pair.second->GetRace() == kZombieRace) {
|
|
++zombie_alive_count_;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
msg.set_zombie_num(zombie_alive_count_);
|
|
msg.set_human_num(human_alive_count_);
|
|
if (BattleStarted() && human_alive_count_ <= 2 && !sent_terminator_airdrop) {
|
|
sent_terminator_airdrop = true;
|
|
MetaData::AirDrop* airdrop_meta = MetaMgr::Instance()->GetAirDrop
|
|
(map_meta_->i->terminator_airdrop());
|
|
if (airdrop_meta) {
|
|
AirDrop(airdrop_meta->i->appear_time(),
|
|
airdrop_meta->i->drop_id(),
|
|
airdrop_meta->i->id());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Team* Room::GetAliveTeam()
|
|
{
|
|
for (auto& pair : team_hash_) {
|
|
if (pair.second->HasAliveMember()) {
|
|
return pair.second;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Team* Room::NewTeam()
|
|
{
|
|
Team* team = new Team();
|
|
team->room = this;
|
|
team->SetTeamId(++current_teamid_);
|
|
team_hash_[team->GetTeamId()] = team;
|
|
return team;
|
|
}
|
|
|
|
void Room::TraversePlayerList(a8::XParams param,
|
|
std::function<void (Player*, a8::XParams&)> func)
|
|
{
|
|
if (!func) {
|
|
return;
|
|
}
|
|
for (auto& pair : accountid_hash_) {
|
|
if (pair.second) {
|
|
func(pair.second, param);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseHumanList(a8::XParams param,
|
|
std::function<bool (Human*, a8::XParams&)> func)
|
|
{
|
|
if (!func) {
|
|
return;
|
|
}
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second) {
|
|
if (!func(pair.second, param)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseEntityList(a8::XParams param,
|
|
std::function<bool (Entity*, a8::XParams&)> func)
|
|
{
|
|
if (!func) {
|
|
return;
|
|
}
|
|
for (auto& pair : uniid_hash_) {
|
|
if (pair.second) {
|
|
if (!func(pair.second, param)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TraverseAlivePlayers(a8::XParams param,
|
|
std::function<bool (Human*, a8::XParams&)> func)
|
|
{
|
|
for (auto& pair : alive_player_hash_) {
|
|
if (!func(pair.second, param)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::BroadcastDebugMsg(const std::string& debug_msg)
|
|
{
|
|
#ifdef DEBUG
|
|
TraverseHumanList
|
|
(
|
|
a8::XParams()
|
|
.SetParam1(debug_msg),
|
|
[] (Human* hum, a8::XParams& param) -> bool
|
|
{
|
|
hum->SendDebugMsg(param.param1);
|
|
return true;
|
|
});
|
|
#endif
|
|
}
|
|
|
|
void Room::UpdateGas()
|
|
{
|
|
switch (gas_data_.gas_mode) {
|
|
case GasInactive:
|
|
UpdateGasInactive();
|
|
break;
|
|
case GasJump:
|
|
UpdateGasJump();
|
|
break;
|
|
case GasWaiting:
|
|
UpdateGasWaiting();
|
|
break;
|
|
case GasMoving:
|
|
UpdateGasMoving();
|
|
break;
|
|
}
|
|
if (gas_data_.gas_mode != GasInactive && gas_data_.gas_mode != GasJump) {
|
|
#if 1
|
|
if (GetRoomMode() == kZombieMode) {
|
|
int zombie_num = 0;
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->GetRace() == kZombieRace) {
|
|
++zombie_num;
|
|
}
|
|
}
|
|
if (zombie_num >= GetRoomMaxPlayerNum() && !game_over_) {
|
|
game_over_ = true;
|
|
game_over_frameno_ = GetFrameNo();
|
|
OnGameOver();
|
|
}
|
|
}
|
|
#endif
|
|
if (gas_data_.gas_mode != GasInactive && GetRoomMode() == kChiJiMode) {
|
|
if (!IsGameOver() && alive_count_ <= MAX_TEAM_NUM && GetAliveTeamNum() <= 1) {
|
|
game_over_ = true;
|
|
game_over_frameno_ = GetFrameNo();
|
|
OnGameOver();
|
|
}
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->real_dead ||
|
|
a8::HasBitFlag(pair.second->status, CS_Disable)) {
|
|
continue;
|
|
}
|
|
bool b1 = a8::CircleContainCircle(gas_data_.pos_old,
|
|
gas_data_.gas_progress,
|
|
pair.second->GetPos(),
|
|
pair.second->GetRadius()
|
|
);
|
|
bool b2 = a8::CircleContainCircle(gas_data_.pos_new,
|
|
gas_data_.rad_new,
|
|
pair.second->GetPos(),
|
|
pair.second->GetRadius()
|
|
);
|
|
if (!b1 && !b2) {
|
|
pair.second->poisoning = true;
|
|
if (!pair.second->GetBuffByEffectId(kBET_Poisoning)) {
|
|
pair.second->TryAddBuff(pair.second, kPoisioningBuffId);
|
|
}
|
|
} else {
|
|
pair.second->poisoning = false;
|
|
pair.second->poisoning_time = false;
|
|
if (pair.second->GetBuffByEffectId(kBET_Poisoning)) {
|
|
pair.second->RemoveBuffByEffectId(kBET_Poisoning);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasInactive()
|
|
{
|
|
if (GetFrameNo() - gas_data_.gas_start_frameno >= GetGasInactiveTime() * SERVER_FRAME_RATE) {
|
|
long long begin_tick = a8::XGetTickCount();
|
|
gas_data_.gas_mode = GasJump;
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
if (human_hash_.size() < GetRoomMaxPlayerNum()) {
|
|
CreateAndroid(GetRoomMaxPlayerNum() - human_hash_.size());
|
|
NotifyUiUpdate();
|
|
}
|
|
battle_start_frameno_ = GetFrameNo();
|
|
CombineTeam();
|
|
ClearPostBattleAutoFreeList();
|
|
OnBattleStart();
|
|
ShuaPlane();
|
|
NotifyWxVoip();
|
|
InitAndroidAI();
|
|
RoomMgr::Instance()->ActiveRoom(GetRoomUuid());
|
|
int auto_jump_interval = MetaMgr::Instance()->GetSysParamAsInt("auto_jump_interval");
|
|
auto_jump_timer_ = xtimer.AddRepeatTimerAndAttach
|
|
(SERVER_FRAME_RATE * auto_jump_interval,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
int auto_jump_min_num = MetaMgr::Instance()->GetSysParamAsInt("auto_jump_min_num");
|
|
int auto_jump_max_num = MetaMgr::Instance()->GetSysParamAsInt("auto_jump_max_num");
|
|
int jump_num = a8::RandEx(auto_jump_min_num, auto_jump_max_num);
|
|
if (room->last_player_jump_pos.Distance(room->plane.curr_pos) < 64 * 8) {
|
|
jump_num = 1 + rand() % 2;
|
|
}
|
|
for (int i = 0; i < jump_num; ++i) {
|
|
room->TraverseHumanList
|
|
(
|
|
a8::XParams()
|
|
.SetSender(room),
|
|
[] (Human* hum, a8::XParams& param) -> bool
|
|
{
|
|
if (hum->HasBuffEffect(kBET_Fly) &&
|
|
hum->GetEntitySubType() != EST_Player) {
|
|
hum->DoJump();
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
},
|
|
&xtimer_attacher_.timer_list_,
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->auto_jump_timer_ = nullptr;
|
|
});
|
|
#if 1
|
|
a8::XPrintf("max_run_delay:%d %d\n", {PerfMonitor::Instance()->max_run_delay_time,
|
|
a8::XGetTickCount() - begin_tick});
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasWaiting()
|
|
{
|
|
if (GetFrameNo() - gas_data_.gas_start_frameno >=
|
|
gas_data_.old_area_meta->i->wait_time() * SERVER_FRAME_RATE) {
|
|
gas_data_.gas_mode = 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->i->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 (!(gas_data_.pos_new == gas_data_.pos_old)) {
|
|
a8::Vec2 p1 = gas_data_.pos_new - gas_data_.pos_old_bk;
|
|
gas_data_.pre_pos_old = gas_data_.pos_old;
|
|
if (p1.Norm() - distance <= 0.01f) {
|
|
gas_data_.pos_old = gas_data_.pos_new;
|
|
} else {
|
|
a8::Vec2 dir = p1;
|
|
dir.Normalize();
|
|
gas_data_.pos_old = gas_data_.pos_old_bk + dir * distance;
|
|
}
|
|
if (gas_data_.rad_old - distance <= gas_data_.rad_new) {
|
|
assert(gas_data_.pos_new == gas_data_.pos_old);
|
|
}
|
|
}
|
|
if (std::abs(gas_data_.gas_progress - gas_data_.rad_new) <= 0.001f) {
|
|
int pre_area_id = gas_data_.new_area_meta->i->id();
|
|
if (!MetaMgr::Instance()->GetSafeArea(pre_area_id + 1)) {
|
|
gas_data_.is_last_gas = true;
|
|
return;
|
|
}
|
|
ForwardGasRing(1);
|
|
if (!MetaMgr::Instance()->GetSafeArea(gas_data_.new_area_meta->i->id() + 2)) {
|
|
#if 1
|
|
//最后一圈
|
|
if (room_type_ == RT_MidBrid) {
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(2,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->ShuaLastGas();
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::UpdateGasJump()
|
|
{
|
|
a8::Vec2 len_vec = plane.dir *
|
|
((GetFrameNo() - GetGasData().gas_start_frameno)*airline_->i->plane_speed() / SERVER_FRAME_RATE);
|
|
plane.curr_pos = plane.start_point + len_vec;
|
|
if ((plane.end_point - plane.start_point).Norm() <= len_vec.Norm()) {
|
|
TraverseHumanList(
|
|
a8::XParams(),
|
|
[] (Human* hum, a8::XParams& param) -> bool
|
|
{
|
|
if (hum->HasBuffEffect(kBET_Fly)) {
|
|
hum->DoJump();
|
|
}
|
|
if (hum->GetEntitySubType() == EST_Player) {
|
|
GameLog::Instance()->GameStart((Player*)hum);
|
|
}
|
|
return true;
|
|
});
|
|
gas_data_.gas_mode = GasWaiting;
|
|
gas_data_.old_area_meta = MetaMgr::Instance()->GetSafeArea(map_meta_->i->safearea());
|
|
gas_data_.new_area_meta = MetaMgr::Instance()->GetSafeArea(map_meta_->i->safearea() + 1);
|
|
gas_data_.pos_list = MetaMgr::Instance()->RandSafeAreaPos(map_meta_->i->safearea());
|
|
gas_data_.gas_progress = gas_data_.old_area_meta->i->rad();
|
|
gas_data_.gas_start_frameno = GetFrameNo();
|
|
gas_data_.pos_old = map_meta_->first_safearea_center;
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
{
|
|
if (gas_data_.pos_list && !gas_data_.pos_list->poses.empty()) {
|
|
gas_data_.pos_old = gas_data_.pos_list->poses[0];
|
|
gas_data_.pos_old_bk = gas_data_.pos_old;
|
|
}
|
|
bool gen_ok = GenSmallCircle();
|
|
if (!gen_ok) {
|
|
abort();
|
|
}
|
|
}
|
|
gas_data_.rad_old = gas_data_.old_area_meta->i->rad();
|
|
gas_data_.rad_new = gas_data_.new_area_meta->i->rad();
|
|
if (map_meta_->i->init_gas_ring() > 0) {
|
|
ForwardGasRing(map_meta_->i->init_gas_ring());
|
|
}
|
|
xtimer.DeleteTimer(auto_jump_timer_);
|
|
NotifyGameStart();
|
|
NotifyUiUpdate();
|
|
NotifyWxVoip();
|
|
if (room_type_ != RT_NewBrid) {
|
|
InitAirDrop();
|
|
InitAirRaid();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Room::GenSmallCircle()
|
|
{
|
|
if (gas_data_.new_area_meta->i->rad() >= gas_data_.old_area_meta->i->rad()) {
|
|
abort();
|
|
}
|
|
if (gas_data_.pos_list && gas_data_.gas_count + 1 < gas_data_.pos_list->poses.size()) {
|
|
gas_data_.pos_new = gas_data_.pos_list->poses[gas_data_.gas_count + 1];
|
|
} else {
|
|
a8::Vec2 dir = a8::Vec2::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
float rad = rand() % (int)(gas_data_.old_area_meta->i->rad() -
|
|
gas_data_.new_area_meta->i->rad());
|
|
if (rad <= 0.001f){
|
|
rad = 0.001f;
|
|
}
|
|
gas_data_.pos_new = gas_data_.pos_old + dir * rad;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Room::MatchTeam(Human* hum)
|
|
{
|
|
if (!hum->team_uuid.empty() && GetRoomMode() != kZombieMode) {
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second != hum) {
|
|
if (!hum->team_uuid.empty() && pair.second->team_uuid == hum->team_uuid) {
|
|
if (!pair.second->GetTeam()) {
|
|
NewTeam()->AddMember(pair.second);
|
|
}
|
|
if (!pair.second->GetTeam()->IsFull()) {
|
|
pair.second->GetTeam()->AddMember(hum);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!hum->GetTeam()) {
|
|
NewTeam()->AddMember(hum);
|
|
}
|
|
}
|
|
|
|
void Room::CombineTeam()
|
|
{
|
|
if (GetRoomMode() == kZombieMode) {
|
|
return;
|
|
}
|
|
std::map<int, size_t> need_combine_teams;
|
|
std::map<int, size_t> need_combine_teams_copy;
|
|
|
|
if (room_type_ == RT_MidBrid) {
|
|
for (auto& pair : accountid_hash_) {
|
|
Human* hum = pair.second;
|
|
hum->auto_fill = true;
|
|
hum->team_uuid = a8::XValue(room_uuid_).GetString();
|
|
}
|
|
for (size_t i = 0; i < MAX_TEAM_NUM - accountid_hash_.size(); ++i) {
|
|
for (auto& pair : human_hash_) {
|
|
Human* hum = pair.second;
|
|
if (hum->IsAndroid() &&
|
|
!hum->auto_fill) {
|
|
hum->auto_fill = true;
|
|
hum->team_uuid = a8::XValue(room_uuid_).GetString();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int first_team_id = 0;
|
|
int total_count = 0;
|
|
for (auto& pair : team_hash_) {
|
|
Team* team = pair.second;
|
|
team->TraverseMembers
|
|
(
|
|
[this, 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 = team->GetTeamId();
|
|
}
|
|
need_combine_teams[team->GetTeamId()] = team->GetMemberNum();
|
|
total_count += team->GetMemberNum();
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
if (total_count <= 1) {
|
|
return;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
if (room_type_ == RT_MidBrid) {
|
|
first_team_num = 4;
|
|
}
|
|
|
|
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 <= MAX_TEAM_NUM) {
|
|
int new_team_num = pair1.second + pair2.second;
|
|
{
|
|
Team* team1 = team_hash_[team_id1];
|
|
Team* team2 = team_hash_[team_id2];
|
|
if (team1->GetMemberNum() + team2->GetMemberNum() > MAX_TEAM_NUM) {
|
|
a8::UdpLog::Instance()->Warning("team_member > 4 :%d",
|
|
{
|
|
team1->GetMemberNum() + team2->GetMemberNum()
|
|
});
|
|
}
|
|
if (pair1.first == first_team_id || pair1.second >= pair2.second) {
|
|
team1->CombineTeam(team2);
|
|
delete team2;
|
|
team_hash_.erase(pair2.first);
|
|
} else {
|
|
team2->CombineTeam(team1);
|
|
delete team1;
|
|
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 >= MAX_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 >= MAX_TEAM_NUM) {
|
|
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::InitAirDrop()
|
|
{
|
|
if (GetRoomMode() == kZombieMode) {
|
|
for (int airdrop_id : map_meta_->airdrops) {
|
|
MetaData::AirDrop* airdrop_meta = MetaMgr::Instance()->GetAirDrop(airdrop_id);
|
|
if (airdrop_meta) {
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * airdrop_meta->i->time(),
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(airdrop_meta->i->appear_time())
|
|
.SetParam2(airdrop_meta->i->drop_id())
|
|
.SetParam3(airdrop_meta->i->id()),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (!room->IsGameOver()) {
|
|
room->AirDrop(param.param1, param.param2, param.param3);
|
|
}
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
}
|
|
} else {
|
|
std::list<MetaData::AirDrop>& air_drops = MetaMgr::Instance()->GetAirDrops();
|
|
for (auto& air_drop : air_drops) {
|
|
if (air_drop.i->id() >= 1 && air_drop.i->id() <= 6) {
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * air_drop.i->time(),
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(air_drop.i->appear_time())
|
|
.SetParam2(air_drop.i->drop_id())
|
|
.SetParam3(air_drop.i->id()),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (!room->IsGameOver()) {
|
|
room->AirDrop(param.param1, param.param2, param.param3);
|
|
}
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::AirDrop(int appear_time, int box_id, int airdrop_id)
|
|
{
|
|
MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(box_id);
|
|
if (room_type_ == RT_NewBrid &&
|
|
airdrop_times_ < MetaMgr::Instance()->level0room_spec_airdrops.size()) {
|
|
int spec_box_id = MetaMgr::Instance()->level0room_spec_airdrops[airdrop_times_];
|
|
if (MetaMgr::Instance()->GetMapThing(spec_box_id)) {
|
|
thing_meta = MetaMgr::Instance()->GetMapThing(spec_box_id);
|
|
box_id = spec_box_id;
|
|
}
|
|
}
|
|
if (GetRoomMode() == kZombieMode) {
|
|
if (airdrop_id != map_meta_->i->terminator_airdrop()) {
|
|
NotifyCountdown(TEXT("battle_server_box_countdown", "距离物资箱抵达还有%d秒"), appear_time / 1000);
|
|
}
|
|
}
|
|
if (thing_meta && thing_meta->i->type() == 2) {
|
|
a8::Vec2 dir = a8::Vec2::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
a8::Vec2 box_pos = gas_data_.pos_new + dir * (500 + rand() % 300);
|
|
if (box_pos.x < 1.0f) {
|
|
box_pos.x = 1.0f;
|
|
}
|
|
if (box_pos.x >= map_meta_->i->map_width()) {
|
|
box_pos.x = map_meta_->i->map_width() - 1;
|
|
}
|
|
if (box_pos.y < 1.0f) {
|
|
box_pos.y = 1.0f;
|
|
}
|
|
if (box_pos.y >= map_meta_->i->map_height()) {
|
|
box_pos.y = map_meta_->i->map_height() - 1;
|
|
}
|
|
AdjustAirDropPos(thing_meta, box_pos);
|
|
AabbCollider air_drop_aabb_box;
|
|
{
|
|
air_drop_aabb_box._min.x = 0 - thing_meta->i->width()/2.0f;
|
|
air_drop_aabb_box._min.y = 0 - thing_meta->i->height()/2.0f;
|
|
air_drop_aabb_box._max.x = 0 + thing_meta->i->width()/2.0f;
|
|
air_drop_aabb_box._max.y = 0 + thing_meta->i->height()/2.0f;
|
|
}
|
|
ColliderComponent* pickup_collider = nullptr;
|
|
{
|
|
bool through_wall = false;
|
|
bool is_collision = map_service->CollisionDetectionAndGetCollider
|
|
(
|
|
this,
|
|
through_wall,
|
|
box_pos,
|
|
&air_drop_aabb_box,
|
|
&pickup_collider
|
|
);
|
|
if (is_collision) {
|
|
if (!pickup_collider) {
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
if (pickup_collider) {
|
|
float new_x = box_pos.x;
|
|
float new_y = box_pos.y;
|
|
FindLocationWithAabb(pickup_collider, box_pos, &air_drop_aabb_box, new_x, new_y);
|
|
box_pos.x = new_x;
|
|
box_pos.y = new_y;
|
|
}
|
|
if (box_pos.x + thing_meta->i->width()/2 + 2 > map_meta_->i->map_width() ||
|
|
box_pos.x - thing_meta->i->width()/2 - 2 < 1 ||
|
|
box_pos.y + thing_meta->i->height()/2 + 2 > map_meta_->i->map_height() ||
|
|
box_pos.y - thing_meta->i->height()/2 - 2 < 1
|
|
) {
|
|
return;
|
|
}
|
|
frame_event.AddAirDrop(appear_time, box_id, box_pos);
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * appear_time / 1000.f,
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(a8::MakeInt64(airdrop_id, box_id))
|
|
.SetParam2(box_pos.x)
|
|
.SetParam3(box_pos.y),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (!room->IsGameOver()) {
|
|
int airdrop_id = a8::Low32(param.param1.GetInt64());
|
|
int box_id = a8::High32(param.param1.GetInt64());
|
|
RoomObstacle* obstacle = room->CreateObstacle
|
|
(
|
|
box_id,
|
|
param.param2.GetDouble(),
|
|
param.param3.GetDouble()
|
|
);
|
|
obstacle->PushCollisionObjects();
|
|
obstacle->is_treasure_box = true;
|
|
if (room->GetRoomMode() == kZombieMode) {
|
|
obstacle->is_terminator_airdrop_box =
|
|
airdrop_id == room->map_meta_->i->terminator_airdrop();
|
|
if (obstacle->is_terminator_airdrop_box) {
|
|
room->NotifySysPiao
|
|
(
|
|
TEXT("battle_server_box_serviced", "终结者补给箱已送达"),
|
|
a8::MkRgb(0, 255, 0),
|
|
3
|
|
);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
++airdrop_times_;
|
|
#if 1
|
|
ShuaMon(box_pos,
|
|
thing_meta->airdrop_mon_list,
|
|
std::max(thing_meta->i->width(), thing_meta->i->height()));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Room::AdjustAirDropPos(MetaData::MapThing* thing_meta, a8::Vec2& box_pos)
|
|
{
|
|
if (room_type_ == RT_NewBrid) {
|
|
if (airdrop_times_ < MetaMgr::Instance()->newbie_airdrop.size()) {
|
|
for (auto& pair : accountid_hash_) {
|
|
if (pair.second) {
|
|
Human* hum = pair.second;
|
|
a8::Vec2 dir = a8::Vec2::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
box_pos = hum->GetPos() + dir * (80 + rand() % 50);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
AdjustPosInnerMap(box_pos, 100);
|
|
}
|
|
|
|
void Room::ShuaPlane()
|
|
{
|
|
airline_ = MetaMgr::Instance()->RandAirLine(map_meta_->i->map_id());
|
|
if (!airline_) {
|
|
abort();
|
|
}
|
|
plane.start_point = a8::Vec2(airline_->start_point_x, airline_->start_point_y);
|
|
plane.end_point = a8::Vec2(airline_->end_point_x, airline_->end_point_y);
|
|
plane.dir = plane.end_point - plane.start_point;
|
|
plane.dir.Normalize();
|
|
plane.curr_pos = plane.start_point;
|
|
last_player_jump_pos = plane.curr_pos;
|
|
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->MustBeAddBuff(pair.second, FLY_BUFFID);
|
|
pair.second->ResetAllSkillCd();
|
|
pair.second->SetPos(plane.curr_pos);
|
|
pair.second->SetAttackDir(plane.dir);
|
|
pair.second->SetMoveDir(plane.dir);
|
|
grid_service->MoveCreature(pair.second);
|
|
pair.second->AddToNewObjects(pair.second);
|
|
pair.second->ActiveAllSkill();
|
|
}
|
|
}
|
|
|
|
RoomObstacle* Room::InternalCreateObstacle(int id, float x, float y,
|
|
std::function<void (Obstacle*)> on_precreate)
|
|
{
|
|
MetaData::MapThing* thing = MetaMgr::Instance()->GetMapThing(id);
|
|
if (thing) {
|
|
RoomObstacle* entity = EntityFactory::Instance()->MakeRoomObstacle(AllocUniid());
|
|
entity->meta = thing;
|
|
entity->room = this;
|
|
entity->SetPos(a8::Vec2(x, y));
|
|
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 = [] (const a8::XParams& param)
|
|
{
|
|
RoomEntity* entity = (RoomEntity*)param.sender.GetUserData();
|
|
if (entity->IsEntityType(ET_Bullet)) {
|
|
MoveableEntity* moveableentity = (MoveableEntity*)entity;
|
|
entity->room->AddToMoveableHash(moveableentity);
|
|
}
|
|
entity->room->AddToEntityHash(entity);
|
|
entity->room->RemoveFromLaterAddHash(entity);
|
|
};
|
|
AddToLaterAddHash(entity);
|
|
xtimer.AddDeadLineTimerAndAttach(0,
|
|
a8::XParams()
|
|
.SetSender(entity),
|
|
add_func,
|
|
&entity->xtimer_attacher.timer_list_);
|
|
}
|
|
|
|
void Room::OnGameOver()
|
|
{
|
|
for (auto& pair : human_hash_) {
|
|
if (IsGameOver() && game_over_frameno_ == GetFrameNo()) {
|
|
pair.second->SendGameOver();
|
|
}
|
|
}
|
|
if (GetRoomMode() == kZombieMode) {
|
|
GameLog::Instance()->ZbModeEnd(this);
|
|
}
|
|
RoomMgr::Instance()->AddOverRoom(room_uuid_);
|
|
}
|
|
|
|
void Room::RandRemoveAndroid()
|
|
{
|
|
Human* hum = nullptr;
|
|
if (room_type_ == RT_MidBrid) {
|
|
for (auto& pair : alive_human_hash_) {
|
|
if (pair.second->IsAndroid()) {
|
|
hum = pair.second;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!hum) {
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->IsAndroid()) {
|
|
hum = pair.second;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (hum) {
|
|
if (hum->team_id != 0) {
|
|
team_hash_.erase(hum->team_id);
|
|
}
|
|
if (hum->born_point) {
|
|
DecBornPointHumanNum(hum->born_point, hum);
|
|
}
|
|
grid_service->DeatchHuman(hum);
|
|
RemoveFromMoveableHash(hum);
|
|
RemoveFromEntityHash(hum);
|
|
RemoveFromHuamnHash(hum);
|
|
RemoveFromAliveHumanHash(hum);
|
|
AddToRemovedRobotHash(hum);
|
|
--alive_count_;
|
|
alive_count_chged_frameno_ = GetFrameNo();
|
|
--PerfMonitor::Instance()->alive_count;
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->RemovePartObjects(hum);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::NotifyUiUpdate()
|
|
{
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(0,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->TraversePlayerList(a8::XParams(),
|
|
[] (Player * hum, a8::XParams & param)
|
|
{
|
|
hum->SendUIUpdate();
|
|
});
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
|
|
void Room::UpdateCarObject(int old_uniid, int new_uniid, a8::Vec2 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, a8::Vec2 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, a8::Vec2 pos)
|
|
{
|
|
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(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;
|
|
}
|
|
|
|
void Room::NotifyWxVoip()
|
|
{
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(0,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->TraversePlayerList(a8::XParams(),
|
|
[] (Player * hum, a8::XParams & param)
|
|
{
|
|
hum->SendWxVoip();
|
|
});
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
|
|
void Room::BattleReport()
|
|
{
|
|
for (auto& pair : accountid_hash_) {
|
|
pair.second->SendGameOver();
|
|
}
|
|
game_over_ = true;
|
|
game_over_frameno_ = frameno_;
|
|
RoomMgr::Instance()->AddOverRoom(room_uuid_);
|
|
}
|
|
|
|
BornPoint* Room::AllocBornPoint(Human* hum)
|
|
{
|
|
BornPoint* born_point = nullptr;
|
|
if (hum->born_point) {
|
|
std::vector<BornPoint*> point_list;
|
|
std::vector<BornPoint*> free_point_list;
|
|
BornPoint* pre_point = nullptr;
|
|
BornPoint* reserve_point = nullptr;
|
|
for (auto& pair : born_point_hash_) {
|
|
if (&pair.second != hum->born_point) {
|
|
if (pair.second.player_num + pair.second.android_num <
|
|
pair.second.thing_tpl->param1_int) {
|
|
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<BornPoint*> free_point_list;
|
|
for (auto& pair : born_point_hash_) {
|
|
if (pair.second.player_num + pair.second.android_num <
|
|
pair.second.thing_tpl->param1_int) {
|
|
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 DEBUG
|
|
if (!born_point) {
|
|
abort();
|
|
}
|
|
#endif
|
|
return born_point;
|
|
}
|
|
|
|
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::CreateSpawnPoints()
|
|
{
|
|
const std::vector<MetaData::MapTplThing*>* spawn_points = nullptr;
|
|
if (IsMiniRoom()) {
|
|
spawn_points = mini_room_spawn_points_;
|
|
} else {
|
|
spawn_points = normal_room_spawn_points_;
|
|
}
|
|
if (!spawn_points || spawn_points->empty()) {
|
|
abort();
|
|
}
|
|
for (auto& thing_tpl : *spawn_points) {
|
|
int uniid = AllocUniid();
|
|
BornPoint born_point;
|
|
born_point.thing_tpl = thing_tpl;
|
|
born_point_hash_[uniid] = born_point;
|
|
if (thing_tpl == level0room_born_point_meta_) {
|
|
level0room_born_point_uniid_ = uniid;
|
|
}
|
|
if (thing_tpl == level1room_born_point_meta_) {
|
|
level1room_born_point_uniid_ = uniid;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateMonsterSpawnPoints()
|
|
{
|
|
if (room_monster_spawn_points_) {
|
|
for (auto& thing_tpl : *room_monster_spawn_points_) {
|
|
for (int hero_id : thing_tpl->heros) {
|
|
MetaData::Player* hero_meta = MetaMgr::Instance()->GetPlayer(hero_id);
|
|
if (hero_meta) {
|
|
a8::Vec2 left_bottom;
|
|
left_bottom.x = thing_tpl->i->x() - thing_tpl->i->width() / 2;
|
|
left_bottom.y = thing_tpl->i->y() - thing_tpl->i->height() / 2;
|
|
|
|
a8::Vec2 hero_pos;
|
|
hero_pos.x = left_bottom.x + (rand() % (int)thing_tpl->i->width());
|
|
hero_pos.y = left_bottom.y + (rand() % (int)thing_tpl->i->height());
|
|
|
|
int team_id = 666;
|
|
Creature* master = nullptr;
|
|
|
|
a8::Vec2 dir = hero_pos;
|
|
dir.Normalize();
|
|
|
|
Hero* hero = CreateHero(master,
|
|
hero_meta,
|
|
hero_pos,
|
|
dir,
|
|
team_id);
|
|
if (!hero) {
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateLoots()
|
|
{
|
|
std::vector<std::tuple<MetaData::Equip*, MetaData::MapTplThing*>> car_equips;
|
|
for (auto& thing_tpl : *loots_) {
|
|
int num = 0;
|
|
int thing_id = thing_tpl->RandThing(num);
|
|
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquip(thing_id);
|
|
if (equip_meta) {
|
|
if (equip_meta->i->equip_type() == EQUIP_TYPE_CAR) {
|
|
car_equips.push_back(std::make_tuple(equip_meta, thing_tpl));
|
|
} else {
|
|
int loot_uniid = CreateLoot(
|
|
equip_meta->i->id(),
|
|
a8::Vec2
|
|
(
|
|
thing_tpl->i->x(),
|
|
thing_tpl->i->y()
|
|
),
|
|
num,
|
|
1
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::map<int, int> car_nums;
|
|
std::random_shuffle(car_equips.begin(), car_equips.end());
|
|
for (size_t i = 0; i < car_equips.size(); ++i) {
|
|
MetaData::Equip* equip_meta = std::get<0>(car_equips[i]);
|
|
MetaData::MapTplThing* thing_tpl = std::get<1>(car_equips[i]);
|
|
|
|
if (car_nums.find(equip_meta->i->id()) == car_nums.end()) {
|
|
car_nums[equip_meta->i->id()] = 0;
|
|
}
|
|
car_nums[equip_meta->i->id()] += 1;
|
|
if (car_nums[equip_meta->i->id()] <= ((MetaData::Map*)map_meta_)->GetCarLimit(equip_meta->i->id())) {
|
|
int car_uniid = AllocUniid();
|
|
Car* c = CreateCar(nullptr,
|
|
car_uniid,
|
|
equip_meta,
|
|
a8::Vec2
|
|
(
|
|
thing_tpl->i->x(),
|
|
thing_tpl->i->y()
|
|
),
|
|
0);
|
|
if (c) {
|
|
CarObject car;
|
|
car.car_id = equip_meta->i->id();
|
|
car.pos = c->GetPos();
|
|
car_hash_[c->GetUniId()] = car;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateDropObjs()
|
|
{
|
|
for (auto& building : *buildings_) {
|
|
for (auto& obj : building->meta->i->dropobj()) {
|
|
CreateLoot(obj.id(),
|
|
a8::Vec2
|
|
(
|
|
building->GetX() + obj.x() - building->meta->i->tilewidth() / 2.0,
|
|
building->GetY() + obj.y() - building->meta->i->tileheight() / 2.0
|
|
),
|
|
1,
|
|
1
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::IncBornPointHumanNum(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(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::SecondRandPoint()
|
|
{
|
|
#ifdef DEBUG
|
|
CheckPartObjects();
|
|
#endif
|
|
for (auto& pair : accountid_hash_) {
|
|
Human* hum = pair.second;
|
|
hum->born_point = AllocBornPoint(hum);
|
|
}
|
|
CombineTeamBornPoint();
|
|
if (room_type_ == RT_MidBrid) {
|
|
BornPoint* newbie_point = GetBornPoint(level1room_born_point_uniid_);
|
|
for (auto& pair : accountid_hash_) {
|
|
pair.second->on_grid_chg = std::bind(&Room::OnHumanGridChg,
|
|
this,
|
|
std::placeholders::_1);
|
|
if (pair.second->GetTeam()) {
|
|
pair.second->GetTeam()->TraverseMembers
|
|
(
|
|
[this, newbie_point] (Human* member) -> bool
|
|
{
|
|
if (newbie_point) {
|
|
ForceSetBornPoint(member, newbie_point);
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
CheckPartObjects();
|
|
#endif
|
|
if (room_type_ == RT_NewBrid || room_type_ == RT_MidBrid) {
|
|
std::vector<Human*> tmp_humans;
|
|
tmp_humans.reserve(GetRoomMaxPlayerNum());
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->IsAndroid() &&
|
|
a8::HasBitFlag(pair.second->status, CS_Disable) &&
|
|
pair.second->team_uuid.empty()
|
|
) {
|
|
tmp_humans.push_back(pair.second);
|
|
}
|
|
}
|
|
std::random_shuffle(tmp_humans.begin(), tmp_humans.end());
|
|
for (size_t i = 0; i < accountid_hash_.size(); ++i) {
|
|
last_human_hash_[tmp_humans[i]->GetUniId()] = tmp_humans[i];
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
#if 0
|
|
if (GetRoomMode() == kZombieMode) {
|
|
BornPoint* born_point = nullptr;
|
|
int i = 0;
|
|
for (auto& pair : human_hash_) {
|
|
if (!born_point) {
|
|
born_point = pair.second->born_point;
|
|
} else {
|
|
++i;
|
|
pair.second->born_point = born_point;
|
|
a8::Vec2 pos = pair.second->born_point->RandPoint();
|
|
pos.x += i * 60;
|
|
pair.second->SetPos(pos);
|
|
pair.second->FindLocation();
|
|
pair.second->RefreshView();
|
|
grid_service->MoveHuman(pair.second);
|
|
#if 0
|
|
if (++i > 5) {
|
|
i = 0;
|
|
born_point = nullptr;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void Room::NotifyGameStart()
|
|
{
|
|
cs::SMGameStart msg;
|
|
for (auto& pair : accountid_hash_) {
|
|
pair.second->SendNotifyMsg(msg);
|
|
}
|
|
for (auto& pair : human_hash_) {
|
|
a8::SetBitFlag(pair.second->status, CS_DisableAttack);
|
|
}
|
|
|
|
waiting_start_ = true;
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * 2,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->waiting_start_ = false;
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(MetaMgr::Instance()->GetSysParamAsInt("prepare_time", 3000) / FRAME_RATE_MS,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
for (auto& pair : room->human_hash_) {
|
|
a8::UnSetBitFlag(pair.second->status, CS_DisableAttack);
|
|
for (int buff_id : room->map_meta_->buff_list) {
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(buff_id);
|
|
if (buff_meta) {
|
|
#if 0
|
|
pair.second->AddBuff(pair.second,
|
|
buff_meta,
|
|
1,
|
|
nullptr);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
#if 0
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * 1,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->ProcDisableHuman();
|
|
room->SecondRandPoint();
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
#endif
|
|
if (room_type_ == RT_NewBrid || room_type_ == RT_MidBrid) {
|
|
NewBieRoomStart();
|
|
}
|
|
if (GetRoomMode() == kZombieMode) {
|
|
ZombieModeStart();
|
|
}
|
|
}
|
|
|
|
void Room::InitObstacleDatas()
|
|
{
|
|
obstacle_datas_.resize(FIXED_OBJECT_MAXID);
|
|
memset(&obstacle_datas_[0], 0, sizeof(ObstacleData) * FIXED_OBJECT_MAXID);
|
|
}
|
|
|
|
ObstacleData* Room::GetPermanentObstacleData(int obstacle_uniid)
|
|
{
|
|
if (obstacle_uniid >= 0 && obstacle_uniid < (int)obstacle_datas_.size()) {
|
|
return &obstacle_datas_[obstacle_uniid];
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
long long Room::GetGasInactiveTime()
|
|
{
|
|
#ifdef DEBUG
|
|
return App::Instance()->debug_params.find(1) != App::Instance()->debug_params.end() ?
|
|
App::Instance()->debug_params[1] : 10;
|
|
#endif
|
|
if (room_mode_ == kZombieMode) {
|
|
#if DEBUG
|
|
if (f8::IsTestEnv()) {
|
|
return MetaMgr::Instance()->zbmode_gas_inactive_time;
|
|
} else {
|
|
return 5 + 5;
|
|
}
|
|
#else
|
|
return MetaMgr::Instance()->zbmode_gas_inactive_time;
|
|
#endif
|
|
} else {
|
|
if (room_type_ == RT_NewBrid) {
|
|
if (creator_game_times_ <= 0) {
|
|
return MetaMgr::Instance()->newbie_gas_inactive_time;
|
|
} else {
|
|
return MetaMgr::Instance()->common_gas_inactive_time;
|
|
}
|
|
} else if (room_type_ == RT_MidBrid) {
|
|
return MetaMgr::Instance()->midbrid_gas_inactive_time;
|
|
} else {
|
|
return MetaMgr::Instance()->gas_inactive_time;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::EnableHuman(Human* target)
|
|
{
|
|
if (!RuningInTimer()) {
|
|
abort();
|
|
}
|
|
#ifdef DEBUG
|
|
CheckPartObjects();
|
|
a8::UdpLog::Instance()->Debug("enablehuman %d %d",
|
|
{
|
|
(long long)target,
|
|
target->GetUniId()
|
|
});
|
|
#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 {
|
|
abort();
|
|
}
|
|
#endif
|
|
#ifdef DEBUG
|
|
CheckPartObjects();
|
|
#endif
|
|
}
|
|
|
|
void Room::DisableHuman(Human* target)
|
|
{
|
|
#if 0
|
|
if (!RuningInTimer()) {
|
|
abort();
|
|
}
|
|
#endif
|
|
#ifdef DEBUG
|
|
CheckPartObjects();
|
|
a8::UdpLog::Instance()->Debug("disablehuman %d %d",
|
|
{
|
|
(long long)target,
|
|
target->GetUniId()
|
|
});
|
|
#endif
|
|
if (!a8::HasBitFlag(target->status, CS_Disable)) {
|
|
target->OnDisable();
|
|
RemoveFromMoveableHash(target);
|
|
RemoveFromAliveHumanHash(target);
|
|
}
|
|
#ifdef DEBUG
|
|
CheckPartObjects();
|
|
#endif
|
|
}
|
|
|
|
void Room::ShuaGuideAndroid(Human* target)
|
|
{
|
|
#ifdef DEBUG
|
|
a8::UdpLog::Instance()->Debug("room_idx:%d ShuaNewBieAndroid %s %s",
|
|
{
|
|
GetRoomIdx(),
|
|
target->account_id,
|
|
target->name
|
|
});
|
|
#endif
|
|
{
|
|
Human* hum = GetOneCanEnableAndroid();
|
|
if (hum) {
|
|
a8::Vec2 pos = target->GetPos();
|
|
pos.x -= MetaMgr::Instance()->newbie_first_robot_distance;
|
|
if (OverBorder(pos, hum->GetRadius())) {
|
|
pos = target->GetPos();
|
|
pos.x += MetaMgr::Instance()->newbie_first_robot_distance;
|
|
if (OverBorder(pos, hum->GetRadius())) {
|
|
pos = target->GetPos();
|
|
pos.y -= MetaMgr::Instance()->newbie_first_robot_distance;
|
|
if (OverBorder(pos, hum->GetRadius())) {
|
|
pos = target->GetPos();
|
|
pos.y += MetaMgr::Instance()->newbie_first_robot_distance;
|
|
if (OverBorder(pos, hum->GetRadius())) {
|
|
pos = a8::Vec2(1800, 1800);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
hum->SetPos(pos);
|
|
EnableHuman(hum);
|
|
}
|
|
}
|
|
{
|
|
int shua_time = a8::RandEx(
|
|
MetaMgr::Instance()->level0room_shua_robot_min_time,
|
|
MetaMgr::Instance()->level0room_shua_robot_max_time
|
|
);
|
|
xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * (shua_time),
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->ShuaAndroidTimerFunc();
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
{
|
|
int die_time = a8::RandEx(
|
|
MetaMgr::Instance()->level0room_die_robot_min_time,
|
|
MetaMgr::Instance()->level0room_die_robot_max_time
|
|
);
|
|
xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * (die_time),
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->DieAndroidTimerFunc();
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
}
|
|
|
|
void Room::ShuaAndroidTimerFunc()
|
|
{
|
|
if (room_type_ == RT_NewBrid || room_type_ == RT_MidBrid) {
|
|
int shua_time = a8::RandEx(
|
|
MetaMgr::Instance()->level0room_shua_robot_min_time,
|
|
MetaMgr::Instance()->level0room_shua_robot_max_time
|
|
);
|
|
int shua_num = a8::RandEx(
|
|
MetaMgr::Instance()->level0room_shua_robot_min_num,
|
|
MetaMgr::Instance()->level0room_shua_robot_max_num
|
|
);
|
|
if (room_type_ == RT_MidBrid) {
|
|
shua_time = a8::RandEx(
|
|
MetaMgr::Instance()->level1room_shua_robot_min_time,
|
|
MetaMgr::Instance()->level1room_shua_robot_max_time
|
|
);
|
|
shua_num = a8::RandEx(
|
|
MetaMgr::Instance()->level1room_shua_robot_min_num,
|
|
MetaMgr::Instance()->level1room_shua_robot_max_num
|
|
);
|
|
}
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * shua_time,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->ShuaAndroidTimerFunc();
|
|
},
|
|
&xtimer_attacher_.timer_list_,
|
|
[] (const a8::XParams& param)
|
|
{
|
|
}
|
|
);
|
|
if (shua_time > 0 && shua_num > 0) {
|
|
ProcShuaAndroid(shua_time, shua_num);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::DieAndroidTimerFunc()
|
|
{
|
|
if (room_type_ == RT_NewBrid || room_type_ == RT_MidBrid) {
|
|
int die_time = a8::RandEx(
|
|
MetaMgr::Instance()->level0room_die_robot_min_time,
|
|
MetaMgr::Instance()->level0room_die_robot_max_time
|
|
);
|
|
int die_num = a8::RandEx(
|
|
MetaMgr::Instance()->level0room_die_robot_min_num,
|
|
MetaMgr::Instance()->level0room_die_robot_max_num
|
|
);
|
|
if (room_type_ == RT_MidBrid) {
|
|
die_time = a8::RandEx(
|
|
MetaMgr::Instance()->level1room_die_robot_min_time,
|
|
MetaMgr::Instance()->level1room_die_robot_max_time
|
|
);
|
|
die_num = a8::RandEx(
|
|
MetaMgr::Instance()->level1room_die_robot_min_num,
|
|
MetaMgr::Instance()->level1room_die_robot_max_num
|
|
);
|
|
}
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * die_time,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->DieAndroidTimerFunc();
|
|
},
|
|
&xtimer_attacher_.timer_list_,
|
|
[] (const a8::XParams& param)
|
|
{
|
|
}
|
|
);
|
|
if (die_time > 0 && die_num > 0) {
|
|
ProcDieAndroid(die_time, die_num);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::ProcShuaAndroid(int shua_time, int shua_num)
|
|
{
|
|
Human* target = GetOneAlivePlayer();
|
|
if (!target) {
|
|
return;
|
|
}
|
|
int real_shua_num = GetCanShuaNum(shua_num);
|
|
if (real_shua_num <= 0) {
|
|
return;
|
|
}
|
|
#ifdef DEBUG
|
|
a8::UdpLog::Instance()->Debug("ProcShuaAndroid room_idx:%d shua_time:%d shua_num%d real_shua_num:%d",
|
|
{
|
|
GetRoomIdx(),
|
|
shua_time,
|
|
shua_num,
|
|
real_shua_num
|
|
});
|
|
#endif
|
|
|
|
std::vector<Human*> humans;
|
|
GetCanEnableAndroids(humans, real_shua_num);
|
|
for (auto& hum : humans) {
|
|
a8::Vec2 pos = target->GetPos();
|
|
a8::Vec2 dir = target->GetMoveDir();
|
|
dir = a8::Vec2::UP;
|
|
if (rand() % 100 < 1) {
|
|
dir.Rotate(a8::RandAngle() / 2.0f);
|
|
} else {
|
|
dir.Rotate(a8::RandAngle());
|
|
}
|
|
pos = pos + dir * SHUA_RANGE;
|
|
if (OverBorder(pos, hum->GetRadius())) {
|
|
pos.x = target->GetPos().x;
|
|
if (OverBorder(pos, hum->GetRadius())) {
|
|
break;
|
|
}
|
|
}
|
|
hum->SetPos(pos);
|
|
EnableHuman(hum);
|
|
#if 0
|
|
a8::SetBitFlag(hum->status, HS_NewBieGuideAndroid);
|
|
#endif
|
|
InstallCheckAutoDieTimer(hum);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Room::ProcDieAndroid(int die_time, int die_num)
|
|
{
|
|
#ifdef DEBUG
|
|
a8::UdpLog::Instance()->Debug("ProcDieAndroid room_idx:%d die_time:%d die_num:%d",
|
|
{
|
|
GetRoomIdx(),
|
|
die_time,
|
|
die_num
|
|
});
|
|
#endif
|
|
std::vector<Human*> alive_humans;
|
|
alive_humans.reserve(human_hash_.size());
|
|
{
|
|
Human* first_alive_player = nullptr;
|
|
for (auto& pair : accountid_hash_) {
|
|
if (!pair.second->real_dead) {
|
|
first_alive_player = pair.second;
|
|
break;
|
|
}
|
|
}
|
|
if (first_alive_player) {
|
|
std::sort(alive_humans.begin(), alive_humans.end(),
|
|
[first_alive_player] (Human* a, Human* b )
|
|
{
|
|
return first_alive_player->GetPos().ManhattanDistance(a->GetPos()) >
|
|
first_alive_player->GetPos().ManhattanDistance(b->GetPos());
|
|
});
|
|
}
|
|
}
|
|
{
|
|
if (alive_humans.size() == 1) {
|
|
Human* hum = alive_humans[0];
|
|
hum->BeKill(VP_SafeArea,
|
|
TEXT("battle_server_killer_gas", "毒圈"),
|
|
VW_SafeArea);
|
|
a8::UnSetBitFlag(hum->status, CS_Disable);
|
|
return;
|
|
}
|
|
}
|
|
int dead_num = 0;
|
|
int try_count = 0;
|
|
std::vector<Human*> alive_humans_copy = alive_humans;
|
|
do {
|
|
for (size_t i = 0; i < alive_humans.size(); ++i) {
|
|
Human* hum = alive_humans[i];
|
|
Human* killer = nullptr;
|
|
for (size_t ii = i + 1; ii < alive_humans_copy.size(); ++ii) {
|
|
killer = alive_humans_copy[ii];
|
|
alive_humans.erase(alive_humans.begin() + ii);
|
|
alive_humans.erase(alive_humans.begin() + i);
|
|
alive_humans_copy.erase(alive_humans_copy.begin() + ii);
|
|
alive_humans_copy.erase(alive_humans_copy.begin() + i);
|
|
break;
|
|
}
|
|
if (killer && ((rand() % 100 < 70) || !gas_data_.old_area_meta)) {
|
|
hum->BeKill(killer->GetUniId(),
|
|
killer->name,
|
|
killer->GetCurrWeapon()->weapon_id);
|
|
a8::UnSetBitFlag(hum->status, CS_Disable);
|
|
} else {
|
|
hum->BeKill(VP_SafeArea,
|
|
TEXT("battle_server_killer_gas", "毒圈"),
|
|
VW_SafeArea);
|
|
if (!alive_humans.empty()) {
|
|
alive_humans.erase(alive_humans.begin() + i);
|
|
alive_humans_copy.erase(alive_humans_copy.begin() + i);
|
|
}
|
|
a8::UnSetBitFlag(hum->status, CS_Disable);
|
|
}
|
|
++dead_num;
|
|
break;
|
|
}
|
|
} while(++try_count < 10 && dead_num < die_num && !alive_humans.empty());
|
|
}
|
|
|
|
void Room::CheckAutoDie(Human* target,
|
|
int autodie_time,
|
|
int autodie_distance,
|
|
int check_times)
|
|
{
|
|
bool nodie = false;
|
|
target->TraverseAllLayerHumanList
|
|
(
|
|
[&nodie, target, autodie_time, autodie_distance] (Human* hum, bool& stop)
|
|
{
|
|
if (!hum->real_dead &&
|
|
hum->GetUniId() != target->GetUniId() &&
|
|
hum->IsPlayer()) {
|
|
if (std::fabs(hum->GetPos().x - target->GetPos().x) <= autodie_distance &&
|
|
std::fabs(hum->GetPos().y - target->GetPos().y) <= autodie_distance) {
|
|
stop = true;
|
|
nodie = true;
|
|
}
|
|
}
|
|
});
|
|
if (nodie) {
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE * (2 + rand() % 3),
|
|
a8::XParams()
|
|
.SetSender(target)
|
|
.SetParam1(autodie_time)
|
|
.SetParam2(autodie_distance)
|
|
.SetParam3(check_times + 1),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Human* hum = (Human*)param.sender.GetUserData();
|
|
hum->room->CheckAutoDie(
|
|
hum,
|
|
param.param1,
|
|
param.param2,
|
|
param.param3
|
|
);
|
|
},
|
|
&target->xtimer_attacher.timer_list_);
|
|
} else {
|
|
std::vector<Human*> alive_humans;
|
|
GetAliveHumans(alive_humans, 5, target);
|
|
if (!alive_humans.empty()) {
|
|
Human* killer = alive_humans[rand() % alive_humans.size()];
|
|
a8::UnSetBitFlag(target->status, CS_Disable);
|
|
target->BeKill(killer->GetUniId(),
|
|
killer->name,
|
|
killer->GetCurrWeapon()->weapon_id);
|
|
} else {
|
|
a8::UnSetBitFlag(target->status, CS_Disable);
|
|
target->BeKill(VP_SafeArea,
|
|
TEXT("battle_server_killer_gas", "毒圈"),
|
|
VW_SafeArea);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Room::HasPlayerInRound(const a8::Vec2& pos, float rad)
|
|
{
|
|
for (auto& pair : accountid_hash_) {
|
|
if (std::fabs(pair.second->GetPos().x - pos.x) < rad &&
|
|
std::fabs(pair.second->GetPos().y - pos.y) < rad) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Room::ProcDisableHuman()
|
|
{
|
|
#if 1
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->IsAndroid() &&
|
|
pair.second->team_uuid.empty() &&
|
|
!a8::HasBitFlag(pair.second->status, CS_Disable)) {
|
|
DisableHuman(pair.second);
|
|
}
|
|
}
|
|
#else
|
|
if (room_type_ == RT_NewBrid || room_type_ == RT_MidBrid) {
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->IsAndroid() &&
|
|
pair.second->team_uuid.empty() &&
|
|
!a8::HasBitFlag(pair.second->status, CS_Disable)) {
|
|
DisableHuman(pair.second);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Room::OnHumanGridChg(Human* target)
|
|
{
|
|
xtimer.AddDeadLineTimerAndAttach(2,
|
|
a8::XParams()
|
|
.SetSender(target),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Human* hum = (Human*)param.sender.GetUserData();
|
|
hum->room->ShuaGridRound(hum);
|
|
},
|
|
&target->xtimer_attacher.timer_list_);
|
|
}
|
|
|
|
void Room::ShuaGridRound(Human* target)
|
|
{
|
|
int count = 0;
|
|
for (auto& pair : human_hash_) {
|
|
Human* hum = pair.second;
|
|
if (hum->IsAndroid() &&
|
|
a8::HasBitFlag(hum->status, CS_Disable) &&
|
|
!hum->real_dead &&
|
|
hum->team_uuid.empty() &&
|
|
grid_service->InView(target->GetGridId(), hum->GetPos().x, hum->GetPos().y)
|
|
) {
|
|
EnableHuman(hum);
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE * 10,
|
|
a8::XParams()
|
|
.SetSender(hum)
|
|
.SetParam1(10)
|
|
.SetParam2(VIEW_RANGE * 1.5)
|
|
.SetParam3(0),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Human* hum = (Human*)param.sender.GetUserData();
|
|
hum->room->CheckAutoDie(
|
|
hum,
|
|
param.param1,
|
|
param.param2,
|
|
param.param3
|
|
);
|
|
},
|
|
&hum->xtimer_attacher.timer_list_);
|
|
++count;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
a8::UdpLog::Instance()->Debug("OnHumanGrid %d %d", {target->GetGridId(), count});
|
|
#endif
|
|
#ifdef DEBUG
|
|
CheckPartObjects();
|
|
#endif
|
|
}
|
|
|
|
void Room::CheckPartObjects(Human* testa, Human* testb)
|
|
{
|
|
for (auto& pair1 : human_hash_) {
|
|
Human* a = pair1.second;
|
|
for (auto& pair2 : human_hash_) {
|
|
Human* b = pair2.second;
|
|
if (testa && testb) {
|
|
if ((a == testa && b == testb) ||
|
|
(a == testb && b == testa)) {
|
|
}
|
|
}
|
|
if (a->InPartObjects(b)) {
|
|
if (!b->InPartObjects(a)) {
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto& pair1 : human_hash_) {
|
|
Human* huma = pair1.second;
|
|
huma->TraverseAllLayerHumanList
|
|
(
|
|
[&huma, testa, testb] (Human* humb, bool& stop)
|
|
{
|
|
if (testa && testb) {
|
|
if ((huma == testa && humb == testb) ||
|
|
(huma == testb && humb == testa)) {
|
|
}
|
|
}
|
|
if (a8::HasBitFlag(huma->status, CS_Disable) ||
|
|
a8::HasBitFlag(humb->status, CS_Disable) ||
|
|
huma->GetPartObjectsCount() <= 0
|
|
) {
|
|
return;
|
|
}
|
|
if (!huma->InPartObjects(humb)) {
|
|
abort();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
void Room::GetAliveHumans(std::vector<Human*>& alive_humans, size_t num, Human* exclude_hum)
|
|
{
|
|
alive_humans.reserve(num);
|
|
{
|
|
if (GetFrameNo() % 8 < 5) {
|
|
for (auto itr = human_hash_.begin(); itr != human_hash_.end(); ++itr) {
|
|
if (itr->second == exclude_hum) {
|
|
continue;
|
|
}
|
|
CheckAliveHuman(itr->second, alive_humans);
|
|
if (alive_humans.size() > num) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for (auto itr = human_hash_.rbegin(); itr != human_hash_.rend(); ++itr) {
|
|
if (itr->second == exclude_hum) {
|
|
continue;
|
|
}
|
|
CheckAliveHuman(itr->second, alive_humans);
|
|
if (alive_humans.size() > num) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CheckAliveHuman(Human* hum, std::vector<Human*>& alive_humans)
|
|
{
|
|
if (hum->IsAndroid() &&
|
|
!hum->real_dead &&
|
|
hum->team_uuid.empty() &&
|
|
a8::HasBitFlag(hum->status, CS_Disable) &&
|
|
!HasPlayerInRound(hum->GetPos(), VIEW_RANGE)) {
|
|
alive_humans.push_back(hum);
|
|
}
|
|
}
|
|
|
|
bool Room::RuningInTimer()
|
|
{
|
|
return xtimer.GetRunningTimer() != nullptr;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void Room::InitDebugInfo()
|
|
{
|
|
#if 0
|
|
xtimer.AddRepeatTimer
|
|
(
|
|
SERVER_FRAME_RATE * 3,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
a8::UdpLog::Instance()->Debug("room_idx:%d real_alive_count:%d",
|
|
{
|
|
room->GetRoomIdx(),
|
|
room->RealAliveCount()
|
|
});
|
|
});
|
|
#endif
|
|
}
|
|
|
|
void Room::UnInitDebugInfo()
|
|
{
|
|
#if 0
|
|
a8::UdpLog::Instance()->Debug("destroy room_idx:%d",
|
|
{
|
|
GetRoomIdx()
|
|
});
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
a8::Vec2 Room::GetDefaultBornPoint()
|
|
{
|
|
a8::Vec2 pos = a8::Vec2(DEFAULT_BORN_POINT_X + rand() % 1400,
|
|
DEFAULT_BORN_POINT_Y + rand() % 1500);
|
|
return pos;
|
|
}
|
|
|
|
void Room::AddPlayerPostProc(Player* hum)
|
|
{
|
|
if (room_type_ == RT_NewBrid) {
|
|
if (creator_game_times_ <= 0) {
|
|
CreateAndroid(10 + rand() % 5);
|
|
} else {
|
|
CreateAndroid(2);
|
|
}
|
|
xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * (1 + rand() % 3),
|
|
a8::XParams()
|
|
.SetSender(hum),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Human* hum = (Human*)param.sender.GetUserData();
|
|
hum->room->ShowAndroid(hum, 1 + rand() % 2);
|
|
},
|
|
&hum->xtimer_attacher.timer_list_);
|
|
}
|
|
if (room_type_ == RT_NewBrid || room_type_ == RT_MidBrid) {
|
|
for (int buff_id : MetaMgr::Instance()->newbie_buff_list) {
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(buff_id);
|
|
if (buff_meta) {
|
|
hum->AddBuff(hum, buff_meta, 1);
|
|
}
|
|
}
|
|
if (room_type_ == RT_MidBrid) {
|
|
Player* first_player = GetOneAlivePlayer();
|
|
if (first_player && first_player->born_point) {
|
|
if (hum->born_point) {
|
|
DecBornPointHumanNum(hum->born_point, hum);
|
|
}
|
|
hum->born_point = first_player->born_point;
|
|
IncBornPointHumanNum(hum->born_point, hum);
|
|
}
|
|
}
|
|
}
|
|
if (GetRoomMode() == kZombieMode) {
|
|
#if 0
|
|
hum->ChangeToRace(kZombieRace, 2);
|
|
#else
|
|
hum->ChangeToRace(kHumanRace, 1);
|
|
#endif
|
|
}
|
|
#ifdef DEBUG
|
|
xtimer.AddRepeatTimerAndAttach
|
|
(SERVER_FRAME_RATE * 5,
|
|
a8::XParams()
|
|
.SetSender(hum),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Human* hum = (Human*)param.sender.GetUserData();
|
|
std::string debugmsg = a8::Format("weapon_id:%d weapon_lv:%d atk:%f fire_rate:%f "
|
|
"volume:%d maxhp:%f hp:%f curr_hp:%f curr_max_hp:%f "
|
|
"base_reload_time:%f grow_reload_time:%f finaly_reload_time:%f",
|
|
{
|
|
hum->GetCurrWeapon()->weapon_id,
|
|
hum->GetCurrWeapon()->weapon_lv,
|
|
hum->GetCurrWeapon()->GetAttrValue(kHAT_Atk),
|
|
hum->GetCurrWeapon()->GetAttrValue(kHAT_FireRate),
|
|
hum->GetCurrWeapon()->GetAttrValue(kHAT_Volume),
|
|
hum->GetCurrWeapon()->GetAttrValue(kHAT_MaxHp),
|
|
hum->GetCurrWeapon()->GetAttrValue(kHAT_Hp),
|
|
hum->GetHP(),
|
|
hum->GetMaxHP(),
|
|
hum->GetCurrWeapon()->meta->i->reload_time(),
|
|
hum->GetCurrWeapon()->GetUpgradeMeta() ?
|
|
hum->GetCurrWeapon()->GetUpgradeMeta()->GetAttrValue
|
|
(hum->GetCurrWeapon()->weapon_lv, kHAT_ReloadTime) : 0,
|
|
hum->GetCurrWeapon()->GetAttrValue(kHAT_ReloadTime)
|
|
});
|
|
hum->SendDebugMsg(debugmsg);
|
|
},
|
|
&hum->xtimer_attacher.timer_list_);
|
|
#endif
|
|
}
|
|
|
|
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)
|
|
{
|
|
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::CombineTeamBornPoint()
|
|
{
|
|
for (auto& pair : team_hash_) {
|
|
pair.second->CombineBornPoint();
|
|
}
|
|
}
|
|
|
|
void Room::ForceSetBornPoint(Human* hum, BornPoint* born_point)
|
|
{
|
|
if (born_point && hum->born_point != born_point) {
|
|
if (hum->born_point) {
|
|
DecBornPointHumanNum(hum->born_point, hum);
|
|
}
|
|
hum->born_point = born_point;
|
|
if (hum->born_point) {
|
|
IncBornPointHumanNum(hum->born_point, hum);
|
|
hum->SetPos(hum->born_point->RandPoint());
|
|
}
|
|
hum->FindLocation();
|
|
hum->RefreshView();
|
|
grid_service->MoveCreature(hum);
|
|
}
|
|
}
|
|
|
|
BornPoint* Room::ForceTakeBornPoint(Human* hum, BornPoint* reserve_born_point)
|
|
{
|
|
if (!reserve_born_point) {
|
|
abort();
|
|
}
|
|
if (hum->born_point == reserve_born_point) {
|
|
abort();
|
|
}
|
|
if (!hum->born_point) {
|
|
abort();
|
|
}
|
|
BornPoint* pre_point = hum->born_point;
|
|
if (pre_point) {
|
|
DecBornPointHumanNum(pre_point, hum);
|
|
}
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->born_point == reserve_born_point) {
|
|
ForceSetBornPoint(pair.second, pre_point);
|
|
}
|
|
}
|
|
return reserve_born_point;
|
|
}
|
|
|
|
void Room::NewBieRoomStart()
|
|
{
|
|
#if 0
|
|
if (room_type_ == RT_NewBrid) {
|
|
for (auto& pair : accountid_hash_) {
|
|
first_newbie_ = pair.second;
|
|
break;
|
|
}
|
|
int protect_time = MetaMgr::Instance()->level0room_robot_protect_time;
|
|
if (creator_game_times_ > 0) {
|
|
protect_time = 6;
|
|
}
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * protect_time,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (room->GetFirstNewBie()) {
|
|
room->GetFirstNewBie()->ProcNewBieLogic();
|
|
}
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
if (room_type_ == RT_MidBrid) {
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * MetaMgr::Instance()->level1room_shua_robot_min_time,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->DieAndroidTimerFunc();
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Room::ZombieModeStart()
|
|
{
|
|
if (GetRoomMode() != kZombieMode) {
|
|
abort();
|
|
}
|
|
if (human_hash_.size() != GetRoomMaxPlayerNum()) {
|
|
abort();
|
|
}
|
|
#ifdef DEBUG
|
|
debug_trace = true;
|
|
#endif
|
|
std::vector<Human*> human_list;
|
|
for (auto& pair : human_hash_) {
|
|
human_list.push_back(pair.second);
|
|
if (RoomMgr::Instance()->IsGM(pair.second->account_id)) {
|
|
debug_trace = true;
|
|
}
|
|
}
|
|
std::random_shuffle(human_list.begin(), human_list.end());
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
Human* hum = human_list[i];
|
|
hum->ChangeToRace(kZombieRace, 1);
|
|
}
|
|
battle_report_timer_ = xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * MetaMgr::Instance()->zbmode_game_duration,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
#if 1
|
|
if (!room->game_over_) {
|
|
room->game_timeout_ = true;
|
|
room->game_over_ = true;
|
|
room->game_over_frameno_ = room->GetFrameNo();
|
|
room->OnGameOver();
|
|
}
|
|
#else
|
|
room->BattleReport();
|
|
#endif
|
|
},
|
|
&xtimer_attacher_.timer_list_,
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->battle_report_timer_ = nullptr;
|
|
}
|
|
);
|
|
}
|
|
|
|
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)
|
|
{
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->IsAndroid() &&
|
|
!pair.second->real_dead &&
|
|
a8::HasBitFlag(pair.second->status, CS_Disable)
|
|
) {
|
|
if (humans.size() >= num) {
|
|
break;
|
|
}
|
|
humans.push_back(pair.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::InstallCheckAutoDieTimer(Human* hum)
|
|
{
|
|
int autodie_time = 10;
|
|
int autodie_distance = 500;
|
|
if (room_type_ == RT_NewBrid) {
|
|
autodie_time = MetaMgr::Instance()->level0room_robot_autodie_time;
|
|
autodie_distance = MetaMgr::Instance()->level0room_robot_autodie_distance;
|
|
} else if (room_type_ == RT_MidBrid) {
|
|
autodie_time = MetaMgr::Instance()->level1room_robot_autodie_time;
|
|
autodie_distance = MetaMgr::Instance()->level1room_robot_autodie_distance;
|
|
}
|
|
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE * autodie_time,
|
|
a8::XParams()
|
|
.SetSender(hum)
|
|
.SetParam1(autodie_time)
|
|
.SetParam2(autodie_distance)
|
|
.SetParam3(0),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Human* hum = (Human*)param.sender.GetUserData();
|
|
hum->room->CheckAutoDie(
|
|
hum,
|
|
param.param1,
|
|
param.param2,
|
|
param.param3
|
|
);
|
|
},
|
|
&hum->xtimer_attacher.timer_list_);
|
|
}
|
|
|
|
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;
|
|
if (room_type_ == RT_NewBrid) {
|
|
real_shua_num = std::max(0,
|
|
MetaMgr::Instance()->level0room_robot_water - RealAliveCount() +
|
|
(int)accountid_hash_.size());
|
|
} else if (room_type_ == RT_MidBrid) {
|
|
real_shua_num = std::max(0,
|
|
MetaMgr::Instance()->level1room_robot_water - RealAliveCount() +
|
|
(int)accountid_hash_.size());
|
|
}
|
|
return real_shua_num;
|
|
}
|
|
|
|
void Room::CreateLevel0RoomSpecThings()
|
|
{
|
|
if (level0room_spec_things_) {
|
|
for (auto& thing_tpl : *level0room_spec_things_) {
|
|
int num = 0;
|
|
int thing_id = thing_tpl->RandThing(num);
|
|
MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(thing_id);
|
|
if (thing_meta) {
|
|
InternalCreateObstacle(thing_id, thing_tpl->i->x(), thing_tpl->i->y(),
|
|
[] (Obstacle* entity)
|
|
{
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Room::CanAddToScene(Human* hum)
|
|
{
|
|
if (room_type_ == RT_NewBrid) {
|
|
return false;
|
|
} else if (room_type_ == RT_MidBrid) {
|
|
Player* player = GetOneAlivePlayer();
|
|
if (player) {
|
|
if (std::fabs(hum->GetPos().x - player->GetPos().x) <= 1024 &&
|
|
std::fabs(hum->GetPos().y - player->GetPos().y) <= 1024) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Room::SyncFrameData()
|
|
{
|
|
#ifdef DEBUG
|
|
long long begin_tick = a8::XGetTickCount();
|
|
long long end_tick = a8::XGetTickCount();
|
|
#endif
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->SendUpdateMsg();
|
|
#ifdef DEBUG
|
|
end_tick = a8::XGetTickCount();
|
|
if (a8::XGetTickCount() - begin_tick > 100) {
|
|
abort();
|
|
}
|
|
begin_tick = a8::XGetTickCount();
|
|
#endif
|
|
}
|
|
#ifdef DEBUG
|
|
end_tick = a8::XGetTickCount();
|
|
if (a8::XGetTickCount() - begin_tick > 1000) {
|
|
abort();
|
|
}
|
|
begin_tick = a8::XGetTickCount();
|
|
#endif
|
|
frame_event.Clear();
|
|
}
|
|
|
|
void Room::CheckShowHand()
|
|
{
|
|
if (show_handed_) {
|
|
return;
|
|
}
|
|
if (room_type_ == RT_NewBrid || room_type_ == RT_MidBrid) {
|
|
int real_player_num = accountid_hash_.size();
|
|
if (room_type_ == RT_MidBrid) {
|
|
for (auto& pair : accountid_hash_) {
|
|
Human* player = pair.second;
|
|
real_player_num = 0;
|
|
real_player_num = player->GetTeam()->GetAliveNum();
|
|
break;
|
|
}
|
|
}
|
|
if (alive_count_ <= (int)(real_player_num + last_human_hash_.size())) {
|
|
#ifdef DEBUG
|
|
a8::UdpLog::Instance()->Debug
|
|
(
|
|
"showHand %d %d %d %d",
|
|
{
|
|
alive_count_,
|
|
accountid_hash_.size(),
|
|
last_human_hash_.size(),
|
|
real_player_num
|
|
}
|
|
);
|
|
#endif
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->ShowHand();
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
show_handed_ = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::ShowHand()
|
|
{
|
|
std::vector<Player*> players;
|
|
std::vector<Human*> androids;
|
|
for (auto& pair : accountid_hash_) {
|
|
players.push_back(pair.second);
|
|
}
|
|
for (auto& pair : last_human_hash_) {
|
|
androids.push_back(pair.second);
|
|
}
|
|
for (size_t i = 0; i < players.size(); ++i) {
|
|
if (i >= androids.size()) {
|
|
break;
|
|
}
|
|
Player* target = players[i];
|
|
Human* hum = androids[i];
|
|
{
|
|
a8::Vec2 pos = target->GetPos();
|
|
a8::Vec2 dir = target->GetMoveDir();
|
|
if (rand() % 100 < 80) {
|
|
dir.Rotate(a8::RandAngle() / 2.0f);
|
|
} else {
|
|
dir.Rotate(a8::RandAngle());
|
|
}
|
|
pos = pos + dir * VIEW_RANGE;
|
|
if (OverBorder(pos, hum->GetRadius())) {
|
|
pos.x = target->GetPos().x;
|
|
if (OverBorder(pos, hum->GetRadius())) {
|
|
pos = target->GetPos(); //!!!
|
|
}
|
|
}
|
|
hum->last_human_target = target;
|
|
hum->SetPos(pos);
|
|
EnableHuman(hum);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::ShuaLastGas()
|
|
{
|
|
for (auto& pair : human_hash_) {
|
|
Human* hum = pair.second;
|
|
if (hum->IsAndroid() &&
|
|
a8::HasBitFlag(hum->status, CS_Disable) &&
|
|
!hum->real_dead &&
|
|
hum->team_uuid.empty()
|
|
) {
|
|
EnableHuman(hum);
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE * 10,
|
|
a8::XParams()
|
|
.SetSender(hum)
|
|
.SetParam1(10)
|
|
.SetParam2(VIEW_RANGE * 1.5)
|
|
.SetParam3(0),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Human* hum = (Human*)param.sender.GetUserData();
|
|
hum->room->CheckAutoDie(
|
|
hum,
|
|
param.param1,
|
|
param.param2,
|
|
param.param3
|
|
);
|
|
},
|
|
&hum->xtimer_attacher.timer_list_);
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
CheckPartObjects();
|
|
#endif
|
|
}
|
|
|
|
bool Room::IsMiniRoom()
|
|
{
|
|
#if 1
|
|
return false;
|
|
#else
|
|
return
|
|
GetRoomType() == RT_NewBrid ||
|
|
GetRoomType() == RT_MidBrid ||
|
|
GetRoomType() == RT_OldBrid1;
|
|
#endif
|
|
}
|
|
|
|
void Room::FillObjectPositions(Human* hum, cs::SMUpdate& msg)
|
|
{
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second != hum) {
|
|
auto p = msg.add_object_positions();
|
|
p->set_obj_uniid(pair.second->GetUniId());
|
|
TypeConvert::ToPb(pair.second->GetPos(), p->mutable_pos());
|
|
TypeConvert::ToPb(pair.second->GetAttackDir(), p->mutable_dir());
|
|
p->set_race((int)pair.second->GetRace());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::RemoveRescue(Human* hum)
|
|
{
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second != hum && pair.second->GetActionType() == AT_Relive &&
|
|
pair.second->GetActionTargetId() == hum->GetUniId()) {
|
|
pair.second->CancelAction();
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
void Room::OnZombieAppear(Human* hum)
|
|
{
|
|
if (hum->GetRace() == kZombieRace && hum->meta->i->level() == 3 && !sent_zombie_boss_notify) {
|
|
sent_zombie_boss_notify = true;
|
|
TraversePlayerList
|
|
(
|
|
a8::XParams()
|
|
.SetParam1(hum->meta->i->name()),
|
|
[] (Player* hum, a8::XParams& param)
|
|
{
|
|
hum->SendSysPiaoMsg(a8::Format(TEXT("battle_server_appear", "%s出现了").c_str(),
|
|
{param.param1.GetString()}),
|
|
a8::MkRgb(255, 0, 0),
|
|
3);
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
int Room::GetAliveCountByRace(RaceType_e race)
|
|
{
|
|
int count = 0;
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->GetRace() == race &&
|
|
!pair.second->dead) {
|
|
++count;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int Room::GetOnlinePlayerNum()
|
|
{
|
|
int num = 0;
|
|
for (auto& pair : accountid_hash_) {
|
|
if (pair.second->socket_handle != 0) {
|
|
++num;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
size_t Room::GetRoomMaxPlayerNum()
|
|
{
|
|
#if 1
|
|
return map_meta_->i->player();
|
|
#else
|
|
if (room_mode_ == kZombieMode) {
|
|
return MetaMgr::Instance()->zbmode_player_num;
|
|
} else {
|
|
if (IsMiniRoom()) {
|
|
return MINI_ROOM_MAX_PLAYER_NUM;
|
|
} else {
|
|
return NORMAL_ROOM_MAX_PLAYER_NUM;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Room::InitAndroidAI()
|
|
{
|
|
std::vector<Android*> androids;
|
|
for (auto& pair : human_hash_) {
|
|
Human* hum = pair.second;
|
|
if (hum->IsAndroid()) {
|
|
androids.push_back((Android*)hum);
|
|
}
|
|
}
|
|
std::vector<std::tuple<int, int>>* ai_weights = nullptr;
|
|
int ai_weights_space = 0;
|
|
switch (GetRoomType()) {
|
|
case RT_OldBrid1:
|
|
{
|
|
ai_weights = &MetaMgr::Instance()->a_room_ai_weights;
|
|
ai_weights_space = MetaMgr::Instance()->a_room_ai_weights_space;
|
|
}
|
|
break;
|
|
case RT_OldBrid2:
|
|
{
|
|
ai_weights = &MetaMgr::Instance()->b_room_ai_weights;
|
|
ai_weights_space = MetaMgr::Instance()->b_room_ai_weights_space;
|
|
}
|
|
break;
|
|
case RT_OldBrid3:
|
|
{
|
|
ai_weights = &MetaMgr::Instance()->c_room_ai_weights;
|
|
ai_weights_space = MetaMgr::Instance()->c_room_ai_weights_space;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
ai_weights = &MetaMgr::Instance()->a_room_ai_weights;
|
|
ai_weights_space = MetaMgr::Instance()->a_room_ai_weights_space;
|
|
}
|
|
break;
|
|
}
|
|
std::array<int, MAX_AI_LEVEL> ai_num = {};
|
|
for (Android* hum : androids) {
|
|
#ifdef DEBUG
|
|
#if 0
|
|
hum->SetAiLevel(7);
|
|
continue;
|
|
#endif
|
|
#endif
|
|
int rnd = rand() % ai_weights_space;
|
|
++rnd;
|
|
for (auto& tuple : *ai_weights) {
|
|
int ai_level = std::get<0>(tuple);
|
|
int space = std::get<1>(tuple);
|
|
if (rnd <= space) {
|
|
hum->SetAiLevel(ai_level);
|
|
++ai_num[ai_level];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
for (auto& pair : accountid_hash_) {
|
|
pair.second->SendDebugMsg
|
|
(
|
|
a8::Format("room_type:%d ai_num level1:%d level2:%d level3:%d level4:%d level5:%d level6:%d level7:%d level8:%d",
|
|
{
|
|
GetRoomType(),
|
|
ai_num[0],
|
|
ai_num[1],
|
|
ai_num[2],
|
|
ai_num[3],
|
|
ai_num[4],
|
|
ai_num[5],
|
|
ai_num[6],
|
|
ai_num[7]
|
|
}
|
|
)
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Room::ForwardGasRing(int n)
|
|
{
|
|
while (n > 0) {
|
|
int pre_area_id = gas_data_.new_area_meta->i->id();
|
|
if (!MetaMgr::Instance()->GetSafeArea(pre_area_id + 1)) {
|
|
gas_data_.is_last_gas = true;
|
|
return;
|
|
}
|
|
a8::Vec2 pre_pos = gas_data_.pos_new;
|
|
gas_data_.old_area_meta = MetaMgr::Instance()->GetSafeArea(pre_area_id);
|
|
gas_data_.new_area_meta = MetaMgr::Instance()->GetSafeArea(pre_area_id + 1);
|
|
gas_data_.gas_progress = gas_data_.old_area_meta->i->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) {
|
|
abort();
|
|
}
|
|
}
|
|
gas_data_.rad_old = gas_data_.old_area_meta->i->rad();
|
|
gas_data_.rad_new = gas_data_.new_area_meta->i->rad();
|
|
gas_data_.gas_count++;
|
|
--n;
|
|
}
|
|
}
|
|
|
|
void Room::ShuaMon(const a8::Vec2& center, std::vector<int>& airdrop_mon_list, float radius)
|
|
{
|
|
int last_hero_idx = 0;
|
|
for (int hero_id : airdrop_mon_list) {
|
|
MetaData::Player* hero_meta = MetaMgr::Instance()->GetPlayer(hero_id);
|
|
if (hero_meta) {
|
|
int team_id = 666;
|
|
Creature* master = nullptr;
|
|
for (int i = 0; i < 10; ++i) {
|
|
a8::Vec2 born_dir = center;
|
|
a8::Vec2 born_offset(hero_meta->i->radius() + 1 + radius + (50 * i),
|
|
hero_meta->i->radius() + 1 + radius + (50 * i));
|
|
born_offset.Rotate(born_dir.CalcAngle(a8::Vec2::UP));
|
|
born_offset.Rotate((last_hero_idx + i) * 0.5);
|
|
|
|
a8::Vec2 hero_pos = center + born_offset;
|
|
a8::Vec2 dir = born_offset;
|
|
dir.Normalize();
|
|
|
|
CircleCollider collider;
|
|
collider.pos = hero_pos;
|
|
collider.rad = hero_meta->i->radius();
|
|
if (!map_service->CollisionDetection
|
|
(
|
|
this,
|
|
false,
|
|
hero_pos,
|
|
&collider
|
|
)) {
|
|
Hero* hero = CreateHero(master,
|
|
hero_meta,
|
|
hero_pos,
|
|
dir,
|
|
team_id);
|
|
if (!hero) {
|
|
abort();
|
|
}
|
|
last_hero_idx = i;
|
|
#ifdef DEBUG
|
|
BroadcastDebugMsg(a8::Format("ShuaMon pos:%d,%d hero_id:%d",
|
|
{
|
|
hero_pos.x,
|
|
hero_pos.y,
|
|
hero->meta->i->id()
|
|
}));
|
|
#endif
|
|
break;
|
|
}
|
|
}//end for i
|
|
}//end if
|
|
}//end for hero_id
|
|
}
|
|
|
|
void Room::GetPartObjectWatchList(Entity* entity, std::vector<Human*>& watch_list)
|
|
{
|
|
TraverseHumanList
|
|
(
|
|
a8::XParams(),
|
|
[&watch_list, entity] (Human* hum, a8::XParams& param) -> 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::InitAirRaid()
|
|
{
|
|
std::list<MetaData::AirRaid>& air_raids = MetaMgr::Instance()->GetAirRaids();
|
|
for (auto& air_raid : air_raids) {
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * air_raid.i->time(),
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(air_raid.i->id()),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (!room->IsGameOver()) {
|
|
room->AirRaid(param.param1);
|
|
}
|
|
},
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
}
|
|
|
|
void Room::AirRaid(int airraid_id)
|
|
{
|
|
MetaData::AirRaid* raid_meta = MetaMgr::Instance()->GetAirRaid(airraid_id);
|
|
if (!raid_meta) {
|
|
return;
|
|
}
|
|
MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(raid_meta->i->bomb_id());
|
|
if (!thing_meta) {
|
|
return;
|
|
}
|
|
a8::Vec2 dir = a8::Vec2::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
float rnd_rad = gas_data_.new_area_meta->i->rad() > 0 ? rand() % gas_data_.new_area_meta->i->rad() : 0;
|
|
a8::Vec2 center = gas_data_.pos_new + dir * (100 + rnd_rad);
|
|
{
|
|
std::vector<Player*> humans;
|
|
GetAlivePlayers(humans, GetRoomMaxPlayerNum());
|
|
if (humans.size() > 3) {
|
|
std::random_shuffle(humans.begin(), humans.end());
|
|
for (Human* hum : humans) {
|
|
if (!hum->poisoning) {
|
|
center = hum->GetPos() + dir * (200 + rand() % 500);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#if 0
|
|
if (humans.size() > 0) {
|
|
center = humans[0]->GetPos();
|
|
}
|
|
#endif
|
|
}
|
|
frame_event.AddAirRaid(raid_meta->i->appear_time(), center, raid_meta->i->rad());
|
|
|
|
auto raid_cb =
|
|
[] (const a8::XParams& param)
|
|
{
|
|
auto bomb_cb =
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (room->IsGameOver()) {
|
|
return;
|
|
}
|
|
MetaData::AirRaid* raid_meta = (MetaData::AirRaid*)param.param1.GetUserData();
|
|
a8::Vec2 center = a8::Vec2
|
|
(
|
|
param.param2.GetDouble(),
|
|
param.param3.GetDouble()
|
|
);
|
|
a8::Vec2 dir = a8::Vec2::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
a8::Vec2 pos = center + dir * (50 + rand() % 100);
|
|
if (room->grid_service->CanAdd(pos.x, pos.y)) {
|
|
RoomObstacle* obstacle = room->CreateObstacle
|
|
(
|
|
raid_meta->i->bomb_id(),
|
|
pos.x,
|
|
pos.y
|
|
);
|
|
obstacle->Active();
|
|
}
|
|
};
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (room->IsGameOver()) {
|
|
return;
|
|
}
|
|
MetaData::AirRaid* raid_meta = (MetaData::AirRaid*)param.param1.GetUserData();
|
|
for (auto& tuple : raid_meta->raid_waves) {
|
|
int num = std::get<0>(tuple);
|
|
int delay = std::get<1>(tuple);
|
|
for (int i = 0; i < num; ++i) {
|
|
room->xtimer.AddDeadLineTimerAndAttach
|
|
(delay / FRAME_RATE_MS,
|
|
a8::XParams()
|
|
.SetSender(room)
|
|
.SetParam1(raid_meta)
|
|
.SetParam2(param.param2.GetDouble())
|
|
.SetParam3(param.param3.GetDouble()),
|
|
bomb_cb,
|
|
&room->xtimer_attacher_.timer_list_);
|
|
}
|
|
}
|
|
};
|
|
|
|
xtimer.AddDeadLineTimerAndAttach
|
|
(SERVER_FRAME_RATE * raid_meta->i->appear_time() / 1000.f,
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(raid_meta)
|
|
.SetParam2(center.x)
|
|
.SetParam3(center.y),
|
|
raid_cb,
|
|
&xtimer_attacher_.timer_list_);
|
|
}
|
|
|
|
void Room::AddToPostBattleAutoFreeList(xtimer_list* timer)
|
|
{
|
|
if (BattleStarted()) {
|
|
abort();
|
|
}
|
|
if (!timer) {
|
|
abort();
|
|
}
|
|
if (post_battle_auto_free_list_.find(timer) != post_battle_auto_free_list_.end()) {
|
|
abort();
|
|
}
|
|
auto cb =
|
|
[this] (xtimer_list* timer)
|
|
{
|
|
post_battle_auto_free_list_.erase(timer);
|
|
};
|
|
xtimer.AddTimerDestoryHandle(timer, cb);
|
|
post_battle_auto_free_list_.insert(timer);
|
|
}
|
|
|
|
void Room::ClearPostBattleAutoFreeList()
|
|
{
|
|
while (!post_battle_auto_free_list_.empty()) {
|
|
for (xtimer_list* timer : post_battle_auto_free_list_) {
|
|
xtimer.DeleteTimer(timer);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::OnBattleStart()
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|