aozhiwei c25560e035 1
2019-04-28 19:57:06 +08:00

1195 lines
43 KiB
C++

#include "precompile.h"
#include "human.h"
#include "cs_proto.pb.h"
#include "metamgr.h"
#include "room.h"
#include "bullet.h"
#include "collider.h"
#include "loot.h"
#include "collision.h"
#include "building.h"
#include "hero.h"
Human::Human():Entity()
{
default_weapon.weapon_idx = 0;
default_weapon.weapon_id = 12101;
default_weapon.weapon_lv = 1;
default_weapon.ammo = 1;
default_weapon.meta = MetaMgr::Instance()->GetEquip(default_weapon.weapon_id);
weapons.reserve(MAX_WEAPON_NUM);
for (size_t i = 0; i < MAX_WEAPON_NUM; ++i) {
auto& weapon = a8::FastAppend(weapons);
weapon.weapon_idx = i;
weapon.weapon_id = 0;
weapon.weapon_lv = 0;
weapon.ammo = 0;
}
weapons[0] = default_weapon;
curr_weapon = &weapons[0];
inventory_[IS_1XSCOPE] = 1;
}
Human::~Human()
{
}
void Human::Initialize()
{
Entity::Initialize();
RecalcSelfCollider();
volume_ = meta->volume;
}
float Human::GetSpeed()
{
return meta->i->move_speed() + buff.speed;
}
void Human::FillMFObjectPart(cs::MFObjectPart* part_data)
{
part_data->set_object_type(ET_Player);
cs::MFPlayerPart* p = part_data->mutable_union_obj_1();
p->set_obj_uniid(entity_uniid);
pos.ToPB(p->mutable_pos());
attack_dir.ToPB(p->mutable_dir());
}
void Human::FillMFObjectFull(cs::MFObjectFull* full_data)
{
full_data->set_object_type(ET_Player);
cs::MFPlayerFull* p = full_data->mutable_union_obj_1();
p->set_obj_uniid(entity_uniid);
pos.ToPB(p->mutable_pos());
attack_dir.ToPB(p->mutable_dir());
p->set_health(health);
p->set_max_health(GetMaxHP());
p->set_dead(dead);
p->set_downed(downed);
p->set_disconnected(disconnected);
p->set_anim_type(anim_type);
p->set_anim_seq(anim_seq);
p->set_skin(skin);
p->set_backpack(backpack);
p->set_helmet(helmet);
p->set_chest(chest);
curr_weapon->ToPB(p->mutable_weapon());
p->set_energy_shield(energy_shield);
#if 1
{
p->set_max_energy_shield(max_energy_shield);
}
#endif
p->set_vip(vip);
p->set_sdmg(sdmg);
FillBodyState(p->mutable_states());
}
ColliderComponent* Human::GetBoxBound()
{
CircleCollider* collider = new CircleCollider();
collider->owner = this;
collider->pos = Vector2D();
collider->rad = GetRadius();
return collider;
}
void Human::FillMFPlayerStats(cs::MFPlayerStats* stats_pb)
{
stats_pb->set_player_id(entity_uniid);
stats_pb->set_player_avatar_url(avatar_url);
if (!dead) {
stats_pb->set_time_alive(room->frame_no * 1000.0f / SERVER_FRAME_RATE);
} else {
stats_pb->set_time_alive(dead_frameno * 1000.0f / SERVER_FRAME_RATE);
}
stats_pb->set_kills(stats.kills);
stats_pb->set_damage_amount(stats.damage_amount);
stats_pb->set_heal_amount(stats.heal_amount);
stats_pb->set_history_time_alive(stats.history_time_alive);
stats_pb->set_history_kills(stats.history_kills);
stats_pb->set_history_damage_amount(stats.history_damage_amount);
stats_pb->set_history_heal_amount(stats.history_heal_amount);
stats_pb->set_gold(stats.gold);
stats_pb->set_score(stats.score);
stats_pb->set_dead(dead);
stats_pb->set_killer_id(stats.killer_id);
stats_pb->set_killer_name(stats.killer_name);
stats_pb->set_account_id(account_id);
}
void Human::FillMFTeamData(cs::MFTeamData* team_data)
{
team_data->set_player_id(entity_uniid);
team_data->set_name(name);
pos.ToPB(team_data->mutable_pos());
attack_dir.ToPB(team_data->mutable_dir());
team_data->set_health(health);
team_data->set_max_health(GetMaxHP());
team_data->set_disconnected(false);
team_data->set_dead(dead);
team_data->set_downed(downed);
}
void Human::Shot(Vector2D& target_dir)
{
if (!curr_weapon->meta) {
return;
}
if (curr_weapon->weapon_idx != 0 &&
curr_weapon->ammo <= 0) {
AutoLoadingBullet();
return;
}
#if 1
float fly_distance = 5;
#endif
room->frame_event.AddShot(this);
for (auto& tuple : curr_weapon->meta->bullet_born_offset) {
Vector2D bullet_born_offset = Vector2D(std::get<0>(tuple), std::get<1>(tuple));
bullet_born_offset.Rotate(attack_dir.CalcAngle(Vector2D::UP));
Vector2D bullet_born_pos = pos + bullet_born_offset;
room->frame_event.AddBullet(this, bullet_born_pos, fly_distance);
room->CreateBullet(this, curr_weapon->meta, bullet_born_pos, attack_dir, fly_distance);
}
--curr_weapon->ammo;
int slot_id = curr_weapon->meta->i->_inventory_slot();
switch (slot_id) {
case 5:
{
//手雷
if (GetInventory(slot_id) > 0) {
DecInventory(slot_id, 1);
++curr_weapon->ammo;
} else {
int weapon_idx = curr_weapon->weapon_idx;
*curr_weapon = Weapon();
curr_weapon->weapon_idx = weapon_idx;
if (weapons[SMOKE_SLOT].weapon_id != 0) {
curr_weapon = &weapons[SMOKE_SLOT];
} else {
curr_weapon = &weapons[0];
}
AutoLoadingBullet();
}
need_sync_active_player = true;
SyncAroundPlayers();
}
break;
case 6:
{
//烟雾弹
if (GetInventory(slot_id) > 0) {
DecInventory(slot_id, 1);
++curr_weapon->ammo;
} else {
int weapon_idx = curr_weapon->weapon_idx;
*curr_weapon = Weapon();
curr_weapon->weapon_idx = weapon_idx;
if (weapons[FRAG_SLOT].weapon_id != 0) {
curr_weapon = &weapons[FRAG_SLOT];
} else {
curr_weapon = &weapons[0];
}
AutoLoadingBullet();
}
need_sync_active_player = true;
SyncAroundPlayers();
}
break;
}
last_shot_frameno_ = room->frame_no;
need_sync_active_player = true;
}
void Human::RecalcSelfCollider()
{
if (!self_collider_) {
self_collider_ = new CircleCollider();
self_collider_->owner = this;
colliders.push_back(self_collider_);
}
self_collider_->pos = Vector2D();
self_collider_->rad = meta->i->radius();
}
bool Human::IsCollision()
{
if (room->OverBorder(pos, meta->i->radius())){
return true;
}
if (a8::HasBitFlag(status, HS_Jump)) {
return false;
}
std::vector<Entity*> objects;
for (auto& grid : grid_list) {
for (Entity* entity : grid->entity_list) {
switch (entity->entity_type) {
case ET_Obstacle:
{
if (
(last_collision_door == nullptr || last_collision_door != entity) &&
TestCollision(entity)
){
objects.push_back(entity);
}
}
break;
case ET_Building:
{
if (TestCollision(entity)) {
objects.push_back(entity);
}
}
break;
default:
{
}
break;
}
}
}
return !objects.empty();
}
void Human::FindPath()
{
Vector2D old_pos = pos;
{
float up_dot = Vector2D::UP.Dot(move_dir);
bool at_left_side = Vector2D::LEFT.Dot(move_dir) > 0.0001f;
if (std::abs(up_dot) <= 0.001f) { //相互垂直
//向上
pos = old_pos + Vector2D::UP;
if (!IsCollision()) {
return;
} else {
//向下
pos = old_pos + Vector2D::DOWN;
if (!IsCollision()) {
return;
}
}
} else if (up_dot > 0.001f) { //基本相同
pos = old_pos + (at_left_side ? Vector2D::LEFT : Vector2D::RIGHT);
if (!IsCollision()) {
return;
} else {
//向上
pos = old_pos + Vector2D::UP;
if (!IsCollision()) {
return;
}
}
} else if (up_dot < 0.001f) { //基本相反
pos = old_pos + (at_left_side ? Vector2D::LEFT : Vector2D::RIGHT);
if (!IsCollision()) {
return;
} else {
//向下
pos = old_pos + Vector2D::DOWN;
if (!IsCollision()) {
return;
}
}
}
}
pos = old_pos;
}
float Human::GetRadius()
{
return meta->i->radius();
}
float Human::GetMaxHP()
{
return meta->i->health();
}
void Human::UpdatePoisoning()
{
if (dead) {
return;
}
bool need_notify = poisoning_time > 1000;
while (poisoning_time > 1000) {
if (room->gas_data.is_last_gas) {
DecHP(room->gas_data.new_area_meta->i->hurt(), -1, "安全区");
} else {
DecHP(room->gas_data.old_area_meta->i->hurt(), -1, "安全区");
}
if (dead) {
poisoning_time = 0;
break;
}
poisoning_time -= 1000;
}
if (need_notify && entity_subtype == EST_Player) {
SyncAroundPlayers();
}
}
void Human::SyncAroundPlayers()
{
room->TouchHumanList(a8::XParams(),
[this] (Human* hum, a8::XParams& param) -> bool
{
hum->new_objects.insert(this);
return true;
});
}
void Human::AutoLoadingBullet(bool manual)
{
if (curr_weapon->weapon_idx != 0 &&
(curr_weapon->ammo <= 0 ||
(manual && curr_weapon->ammo < curr_weapon->meta->i->clip_volume()))
) {
MetaData::Equip* bullet_meta = MetaMgr::Instance()->GetEquip(curr_weapon->meta->i->use_bullet());
if (bullet_meta &&
bullet_meta->i->_inventory_slot() >= 0 &&
bullet_meta->i->_inventory_slot() < inventory_.size()
) {
if (GetInventory(bullet_meta->i->_inventory_slot()) > 0) {
StartAction(AT_Reload,
curr_weapon->meta->i->reload_time(),
curr_weapon->weapon_id,
curr_weapon->weapon_idx);
}
}
return;
}
}
void Human::StartAction(ActionType_e action_type,
int action_duration,
int item_id,
int target_id)
{
if (this->action_type == action_type &&
this->action_item_id == item_id &&
this->action_target_id == target_id) {
return;
}
this->action_type = action_type;
this->action_frameno = room->frame_no;
this->action_duration = action_duration;
this->action_item_id = item_id;
this->action_target_id = target_id;
need_sync_active_player = true;
}
void Human::CancelAction()
{
ResetAction();
}
void Human::ResetAction()
{
action_type = AT_None;
action_duration = 0;
action_frameno = 0;
action_item_id = 0;
action_target_id = 0;
need_sync_active_player = true;
}
void Human::FillSMGameOver(cs::SMGameOver& msg)
{
std::vector<Human*> human_list;
room->TouchHumanList(a8::XParams(),
[&human_list] (Human* hum, a8::XParams& param) -> bool
{
human_list.push_back(hum);
return true;
});
std::sort(human_list.begin(), human_list.end(),
[] (Human* a, Human* b )
{
if (a->dead_frameno == b->dead_frameno) {
return a->entity_uniid < b->entity_uniid;
} else {
return a->dead_frameno == 0 ||
(b->dead_frameno != 0 && a->dead_frameno > b->dead_frameno);
}
});
int rank = human_list.size();
for (size_t i = 0; i < human_list.size(); ++i) {
if (human_list[i] == this) {
rank = i + 1;
break;
}
}
msg.set_team_id(0);
msg.set_team_rank(rank);
msg.set_team_allcnt(1);
msg.set_game_over(room->game_over);
msg.set_victory(!dead);
cs::MFPlayerStats* p = msg.add_player_stats();
FillMFPlayerStats(p);
}
void Human::BeKill(int killer_id, const std::string& killer_name)
{
if (!dead && !room->game_over) {
Entity* hum = room->GetEntityByUniId(killer_id);
if (hum && hum->entity_type == ET_Player) {
((Human*)hum)->stats.kills++;
}
stats.killer_id = killer_id;
stats.killer_name = killer_name;
dead = true;
health = 0.0f;
dead_frameno = room->frame_no;
send_gameover = true;
room->OnHumanDie(this);
SyncAroundPlayers();
if (team_members) {
for (auto& hum : *team_members) {
if (hum != this && hum->action_type == AT_Relive &&
hum->action_target_id == entity_uniid) {
hum->CancelAction();
}
}
}
}
}
void Human::DecHP(float dec_hp, int killer_id, const std::string& killer_name)
{
auto downed_func = [] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
if (!hum->downed) {
hum->room->xtimer.DeleteTimer(hum->downed_timer);
return;
}
if (hum->dead) {
return;
}
if (!hum->HasLiveTeammate()) {
hum->BeKill(param.param1, param.param2);
return;
}
int dec_hp = MetaMgr::Instance()->GetSysParamAsInt("downed_dec_hp");
hum->DecHP(dec_hp, param.param1, param.param2);
};
if (energy_shield > 0.001f) {
energy_shield = std::max(0.0f, energy_shield - dec_hp);
} else {
health = std::max(0.0f, health - dec_hp);
if (health <= 0.0001f && !dead) {
if (downed) {
if (downed_timer) {
room->xtimer.DeleteTimer(downed_timer);
}
downed = false;
downed_timer = nullptr;
BeKill(killer_id, killer_name);
} else {
if (HasLiveTeammate()) {
health = MetaMgr::Instance()->GetSysParamAsInt("downed_recover_hp");
downed = true;
downed_timer = room->xtimer.AddRepeatTimerAndAttach(
SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this)
.SetParam1(killer_id)
.SetParam2(killer_name),
downed_func,
&xtimer_attacher.timer_list_
);
} else {
BeKill(killer_id, killer_name);
}
}
}
}
SyncAroundPlayers();
}
void Human::AddToNewObjects(Entity* entity)
{
new_objects.insert(entity);
}
void Human::AddToPartObjects(Entity* entity)
{
part_objects.insert(entity);
}
void Human::RemoveObjects(Entity* entity)
{
del_objects.insert(entity->entity_uniid);
}
bool Human::HasLiveTeammate()
{
if (team_members) {
for (auto& hum : *team_members) {
if (!hum->dead) {
return true;
}
}
}
return false;
}
void Human::Land()
{
a8::UnSetBitFlag(status, HS_Jump);
FindLocation();
SyncAroundPlayers();
}
void Human::DoJump()
{
if (a8::HasBitFlag(status, HS_Fly)) {
a8::UnSetBitFlag(status, HS_Fly);
a8::SetBitFlag(status, HS_Jump);
jump_frameno = room->frame_no;
SyncAroundPlayers();
room->xtimer.AddDeadLineTimerAndAttach(MetaMgr::Instance()->jump_time * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->Land();
},
&xtimer_attacher.timer_list_);
}
}
void Human::DoSkill()
{
if (skill_meta && skill_meta->i->condition() == SC_Active) {
int passed_time = (room->frame_no - last_use_skill_frameno_) * FRAME_RATE_MS;
int skill_left_time = std::max(0, skill_meta->i->last_time() * 1000 - passed_time);
if (skill_left_time <= 0 || last_use_skill_frameno_ == 0) {
skill_xtimer_attacher_.ClearTimerList();
switch (skill_meta->i->type()) {
case ST_Hide:
{
hide_frameno_ = room->frame_no;
a8::SetBitFlag(status, HS_Hide);
room->xtimer.AddDeadLineTimerAndAttach(skill_meta->i->last_time() * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
},
&skill_xtimer_attacher_.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
a8::UnSetBitFlag(hum->status, HS_Hide);
hum->need_sync_active_player = true;
hum->BroadcastFullState();
}
);
need_sync_active_player = true;
BroadcastFullState();
}
break;
case ST_SummonHero:
{
SummonHero();
}
break;
case ST_Accelerate:
{
accelerate_frameno_ = room->frame_no;
a8::SetBitFlag(status, HS_Accelerate);
room->xtimer.AddDeadLineTimerAndAttach(skill_meta->i->last_time() * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
},
&skill_xtimer_attacher_.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
a8::UnSetBitFlag(hum->status, HS_Accelerate);
hum->need_sync_active_player = true;
hum->BroadcastFullState();
}
);
need_sync_active_player = true;
BroadcastFullState();
}
break;
case ST_DamageAdd:
{
damageadd_frameno_ = room->frame_no;
a8::SetBitFlag(status, HS_DamageAdd);
room->xtimer.AddDeadLineTimerAndAttach(skill_meta->i->last_time() * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
},
&skill_xtimer_attacher_.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
a8::UnSetBitFlag(hum->status, HS_DamageAdd);
hum->need_sync_active_player = true;
hum->BroadcastFullState();
}
);
need_sync_active_player = true;
BroadcastFullState();
}
break;
case ST_DefAdd:
{
defadd_frameno_ = room->frame_no;
a8::SetBitFlag(status, HS_DefAdd);
room->xtimer.AddDeadLineTimerAndAttach(skill_meta->i->last_time() * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
},
&skill_xtimer_attacher_.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
a8::UnSetBitFlag(hum->status, HS_DefAdd);
hum->need_sync_active_player = true;
hum->BroadcastFullState();
}
);
need_sync_active_player = true;
BroadcastFullState();
}
break;
case ST_RecoverHP:
{
recover_hp_frameno_ = room->frame_no;
a8::SetBitFlag(status, HS_RecoverHP);
room->xtimer.AddRepeatTimerAndAttach(SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this)
.SetParam1(skill_meta->i->value1()),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
if (a8::HasBitFlag(hum->status, HS_RecoverHP)) {
hum->RecoverHp(param.param1);
hum->need_sync_active_player = true;
}
},
&skill_xtimer_attacher_.timer_list_
);
room->xtimer.AddDeadLineTimerAndAttach(skill_meta->i->last_time() * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
},
&skill_xtimer_attacher_.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
a8::UnSetBitFlag(hum->status, HS_RecoverHP);
hum->need_sync_active_player = true;
hum->BroadcastFullState();
}
);
need_sync_active_player = true;
BroadcastFullState();
}
break;
case ST_ReflectDamage:
{
reflect_damage_frameno_ = room->frame_no;
a8::SetBitFlag(status, HS_ReflectDamage);
room->xtimer.AddDeadLineTimerAndAttach(skill_meta->i->last_time() * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
},
&skill_xtimer_attacher_.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
a8::UnSetBitFlag(hum->status, HS_ReflectDamage);
hum->need_sync_active_player = true;
hum->BroadcastFullState();
}
);
need_sync_active_player = true;
BroadcastFullState();
}
break;
default:
{
}
break;
}
last_use_skill_frameno_ = room->frame_no;
}
}
}
void Human::FindLocation()
{
{
std::vector<Entity*> objects;
room->BuildingBoxBoundCollisionDetection(this, objects);
if (objects.size() > 1) {
abort();
}
if (!objects.empty()) {
Building* building = (Building*)objects[0];
Vector2D b_min = Vector2D(
building->pos.x - building->meta->i->tilewidth()/2.0,
building->pos.y - building->meta->i->tileheight()/2.0
);
Vector2D b_max = Vector2D(
building->pos.x + building->meta->i->tilewidth()/2.0,
building->pos.y + building->meta->i->tileheight()/2.0
);
Vector2D new_pos;
bool ret = CalcCircleAabbSafePoint(
pos,
GetRadius(),
b_min,
b_max,
new_pos
);
if (!ret) {
abort();
}
if (ret) {
pos = new_pos;
return;
}
}
}
{
std::vector<Entity*> objects;
for (auto& grid : grid_list) {
for (Entity* entity : grid->entity_list) {
switch (entity->entity_type) {
case ET_Obstacle:
{
if (TestCollision(entity)){
objects.push_back(entity);
}
}
break;
default:
{
}
break;
}
}
}
if (objects.empty()) {
return;
}
std::sort(objects.begin(), objects.end(),
[this] (Entity* a, Entity *b) -> bool
{
return (this->pos - a->pos).Norm() < (this->pos - b->pos).Norm();
});
Entity* target = objects[0];
FindLocationWithTarget(target);
}
}
void Human::RefreshView()
{
for (auto& cell : grid_list) {
for (Human* hum : cell->human_list) {
hum->AddToNewObjects(this);
hum->AddToPartObjects(this);
AddToNewObjects(hum);
AddToPartObjects(hum);
}
for (Entity* entity : cell->entity_list) {
switch (entity->entity_type) {
case ET_Building:
case ET_Obstacle:
{
AddToNewObjects(entity);
}
break;
default:
{
}
break;
}
}
}
}
void Human::OnGridListChange(std::set<GridCell*>& old_grid_list,
std::set<GridCell*>& inc_grid_list,
std::set<GridCell*>& dec_grid_list
)
{
for (GridCell* cell : inc_grid_list) {
for (Human* hum : cell->human_list) {
if (!room->grid_service.HumanInGridList(hum, old_grid_list)) {
hum->AddToNewObjects(this);
hum->AddToPartObjects(this);
AddToNewObjects(hum);
AddToPartObjects(hum);
}
}
for (Entity* entity : cell->entity_list) {
if (!room->grid_service.EntityInGridList(entity, old_grid_list)) {
switch (entity->entity_type) {
case ET_Building:
case ET_Obstacle:
{
AddToNewObjects(entity);
}
break;
default:
{
}
break;
}
}
}
}
for (GridCell* cell : dec_grid_list) {
for (Human* entity : cell->human_list) {
#if 0
if (!room->grid_service.HumanInGridList(entity, grid_list)) {
RemoveObjects(entity);
}
#endif
}
for (Entity* entity : cell->entity_list) {
if (!room->grid_service.EntityInGridList(entity, grid_list)) {
switch (entity->entity_type) {
case ET_Building:
case ET_Obstacle:
{
#if 0
RemoveObjects(entity);
#endif
}
break;
default:
{
}
break;
}
}
}
}
}
void Human::FillMFActivePlayerData(cs::MFActivePlayerData* player_data)
{
{
player_data->set_action_type(action_type);
if (action_type != AT_None) {
int duration = std::max(0,
action_duration -
(int)((room->frame_no - action_frameno) * 1.0f / SERVER_FRAME_RATE) * 1000
);
player_data->set_action_item_id(action_item_id);
player_data->set_action_duration(duration);
player_data->set_action_target_id(action_target_id);
}
}
player_data->set_skin(skin);
player_data->set_backpack(backpack);
player_data->set_helmet(helmet);
player_data->set_chest(chest);
player_data->set_health(health);
player_data->set_max_health(GetMaxHP());
player_data->set_cur_weapon_idx(curr_weapon->weapon_idx);
player_data->set_cur_scope(curr_scope_idx);
for (auto& weapon : weapons) {
auto p = player_data->add_weapons();
weapon.ToPB(p);
}
for (auto& num : inventory_) {
player_data->add_inventory(num);
}
player_data->set_energy_shield(energy_shield);
#if 1
{
player_data->set_max_energy_shield(max_energy_shield);
}
#endif
#if 1
if (skill_meta) {
if (last_use_skill_frameno_ == 0) {
player_data->set_skill_left_time(0);
player_data->set_skill_cd_time(skill_meta->i->cd_time() * 1000);
} else {
int passed_time = (room->frame_no - last_use_skill_frameno_) * FRAME_RATE_MS;
int skill_left_time = std::max(0, skill_meta->i->cd_time() * 1000 - passed_time);
player_data->set_skill_left_time(skill_left_time);
player_data->set_skill_cd_time(skill_meta->i->cd_time() * 1000);
}
}
#endif
FillBodyState(player_data->mutable_states());
}
void Human::FillMFGasData(cs::MFGasData* gas_data)
{
gas_data->set_mode(room->gas_data.gas_mode);
if (room->gas_data.gas_mode == GasInactive) {
long long duration = MetaMgr::Instance()->gas_inactive_time * SERVER_FRAME_RATE -
(room->frame_no - room->gas_data.gas_start_frameno);
gas_data->set_duration(std::max(duration * 50, (long long)1000) / 1000);
} else if (room->gas_data.gas_mode == GasJump) {
gas_data->set_duration(0);
} else {
if (room->gas_data.old_area_meta->i->wait_time() <= 0) {
gas_data->set_duration(0);
} else {
long long duration = room->gas_data.old_area_meta->i->wait_time() * 20 -
(room->frame_no - room->gas_data.gas_start_frameno);
gas_data->set_duration(std::max(duration * 50, (long long)1000) / 1000);
}
}
room->gas_data.pos_old.ToPB(gas_data->mutable_pos_old());
room->gas_data.pos_new.ToPB(gas_data->mutable_pos_new());
gas_data->set_rad_old(room->gas_data.rad_old);
gas_data->set_rad_new(room->gas_data.rad_new);
}
bool Human::CanSee(Human* hum)
{
return room->grid_service.InView(grid_id, hum->grid_id);
}
void Human::RecalcAttr()
{
def = meta->i->def();
MetaData::Equip* chest_meta = MetaMgr::Instance()->GetEquip(chest);
if (chest_meta) {
def += chest_meta->i->def();
}
MetaData::Equip* helmet_meta = MetaMgr::Instance()->GetEquip(helmet);
if (helmet_meta) {
def += helmet_meta->i->def();
}
}
void Human::RecalcVolume()
{
MetaData::Equip* backpack_meta = MetaMgr::Instance()->GetEquip(backpack);
if (backpack_meta) {
for (size_t i = 0; i < backpack_meta->volume.size(); ++i) {
volume_[i] = meta->volume[i] + backpack_meta->volume[i];
}
}
}
int Human::GetInventory(int slot_id)
{
if (!IsValidSlotId(slot_id)) {
abort();
}
return inventory_[slot_id];
}
void Human::AddInventory(int slot_id, int num)
{
assert(num > 0);
if (!IsValidSlotId(slot_id)) {
abort();
}
inventory_[slot_id] += num;
}
void Human::DecInventory(int slot_id, int num)
{
assert(num > 0);
if (!IsValidSlotId(slot_id)) {
abort();
}
inventory_[slot_id] -= num;
}
int Human::GetVolume(int slot_id)
{
if (!IsValidSlotId(slot_id)) {
abort();
}
return volume_[slot_id];
}
void Human::RecoverHp(int inc_hp)
{
if (!dead) {
health += inc_hp;
health = std::max(health, GetMaxHP());
}
}
void Human::FillBodyState(::google::protobuf::RepeatedPtrField<::cs::MFBodyState>* states)
{
if (pain_killer_timer) {
int passed_time = (room->frame_no - pain_killer_frameno) * FRAME_RATE_MS;
int left_time = std::max(0, pain_killer_lastingtime * 1000 - passed_time);
int anodyne_max_time = MetaMgr::Instance()->GetSysParamAsInt("anodyne_max_time");
left_time = std::min(left_time, anodyne_max_time * 1000);
cs::MFBodyState* state = states->Add();
state->set_state_type(1);
state->set_left_time(left_time);
state->set_lasting_time(anodyne_max_time * 1000);
}
if (a8::HasBitFlag(status, HS_Fly)) {
cs::MFBodyState* state = states->Add();
state->set_state_type(2);
}
if (a8::HasBitFlag(status, HS_Jump)) {
int passed_time = (room->frame_no - jump_frameno) * FRAME_RATE_MS;
cs::MFBodyState* state = states->Add();
state->set_state_type(3);
state->set_left_time(std::max(0, MetaMgr::Instance()->jump_time * 1000 - passed_time));
state->set_lasting_time(MetaMgr::Instance()->jump_time * 1000);
}
if (a8::HasBitFlag(status, HS_Hide) && skill_meta) {
int passed_time = (room->frame_no - hide_frameno_) * FRAME_RATE_MS;
cs::MFBodyState* state = states->Add();
state->set_state_type(HS_Hide);
state->set_left_time(std::max(0, skill_meta->i->last_time() * 1000 - passed_time));
state->set_lasting_time(skill_meta->i->last_time() * 1000);
}
if (a8::HasBitFlag(status, HS_Accelerate) && skill_meta) {
int passed_time = (room->frame_no - accelerate_frameno_) * FRAME_RATE_MS;
cs::MFBodyState* state = states->Add();
state->set_state_type(HS_Accelerate);
state->set_left_time(std::max(0, skill_meta->i->last_time() * 1000 - passed_time));
state->set_lasting_time(skill_meta->i->last_time() * 1000);
}
if (a8::HasBitFlag(status, HS_DamageAdd) && skill_meta) {
int passed_time = (room->frame_no - damageadd_frameno_) * FRAME_RATE_MS;
cs::MFBodyState* state = states->Add();
state->set_state_type(HS_DamageAdd);
state->set_left_time(std::max(0, skill_meta->i->last_time() * 1000 - passed_time));
state->set_lasting_time(skill_meta->i->last_time() * 1000);
}
if (a8::HasBitFlag(status, HS_DefAdd) && skill_meta) {
int passed_time = (room->frame_no - defadd_frameno_) * FRAME_RATE_MS;
cs::MFBodyState* state = states->Add();
state->set_state_type(HS_DefAdd);
state->set_left_time(std::max(0, skill_meta->i->last_time() * 1000 - passed_time));
state->set_lasting_time(skill_meta->i->last_time() * 1000);
}
if (a8::HasBitFlag(status, HS_RecoverHP) && skill_meta) {
int passed_time = (room->frame_no - recover_hp_frameno_) * FRAME_RATE_MS;
cs::MFBodyState* state = states->Add();
state->set_state_type(HS_RecoverHP);
state->set_left_time(std::max(0, skill_meta->i->last_time() * 1000 - passed_time));
state->set_lasting_time(skill_meta->i->last_time() * 1000);
}
if (a8::HasBitFlag(status, HS_ReflectDamage) && skill_meta) {
int passed_time = (room->frame_no - reflect_damage_frameno_) * FRAME_RATE_MS;
cs::MFBodyState* state = states->Add();
state->set_state_type(HS_ReflectDamage);
state->set_left_time(std::max(0, skill_meta->i->last_time() * 1000 - passed_time));
state->set_lasting_time(skill_meta->i->last_time() * 1000);
}
if (a8::HasBitFlag(status, HS_SummonHero) && skill_meta) {
int passed_time = (room->frame_no - summon_hero_frameno_) * FRAME_RATE_MS;
cs::MFBodyState* state = states->Add();
state->set_state_type(HS_SummonHero);
state->set_left_time(std::max(0, skill_meta->i->last_time() * 1000 - passed_time));
state->set_lasting_time(skill_meta->i->last_time() * 1000);
}
}
void Human::SummonHero()
{
Hero* hero = room->CreateHero(this);
if (hero) {
summon_hero_frameno_ = room->frame_no;
a8::SetBitFlag(status, HS_SummonHero);
room->xtimer.AddDeadLineTimerAndAttach(skill_meta->i->last_time() * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this)
.SetParam1(hero->entity_uniid),
[] (const a8::XParams& param)
{
},
&skill_xtimer_attacher_.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
Entity* hero = hum->room->GetEntityByUniId(param.param1);
if (hero && hero->entity_type == ET_Hero) {
hum->room->RemoveObjectLater(hero);
}
a8::UnSetBitFlag(hum->status, HS_SummonHero);
hum->need_sync_active_player = true;
hum->BroadcastFullState();
}
);
need_sync_active_player = true;
BroadcastFullState();
}
}
void Human::AddObserver(Human* observer)
{
observers_.insert(observer);
}
void Human::RemoveObserver(Human* observer)
{
observers_.erase(observer);
}
void Human::SendUpdateMsg()
{
if (!follow_) {
cs::SMUpdate* msg = room->frame_maker.MakeUpdateMsg(this);
if (msg) {
SendNotifyMsg(*msg);
delete msg;
msg = nullptr;
}
}
if (send_gameover) {
UpdateGameOver();
}
{
if (!new_objects.empty()) {
new_objects.clear();
}
}
}
void Human::UpdateGameOver()
{
cs::SMGameOver msg;
FillSMGameOver(msg);
SendNotifyMsg(msg);
send_gameover = false;
}