2019-04-10 14:06:20 +08:00

384 lines
10 KiB
C++

#include "precompile.h"
#include "human.h"
#include "cs_proto.pb.h"
#include "movement.h"
#include "metamgr.h"
#include "room.h"
#include "bullet.h"
#include "collider.h"
#include "loot.h"
Human::Human()
{
movement = new MovementComponent();
movement->owner = this;
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.reserve(MAX_INVENTORY_NUM);
for (size_t i = 0; i < MAX_INVENTORY_NUM; ++i) {
inventory.push_back(0);
}
inventory[12] = 1;
}
Human::~Human()
{
delete movement;
movement = nullptr;
}
void Human::Initialize()
{
}
float Human::GetSpeed()
{
return meta->i->move_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_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);
p->set_vip(vip);
p->set_sdmg(sdmg);
}
void Human::FillMFPlayerStats(cs::MFPlayerStats* stats_pb)
{
stats_pb->set_player_id(entity_uniid);
stats_pb->set_player_avatar_url(avatar_url);
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::Shot(Vector2D& target_dir)
{
if (!curr_weapon->meta) {
return;
}
{
cs::MFShot* shot = room->frame_data.shots.Add();
shot->set_player_id(entity_uniid);
curr_weapon->ToPB(shot->mutable_weapon());
shot->set_offhand(true);
shot->set_bullskin(10001);
}
{
cs::MFBullet* bullet = room->frame_data.bullets.Add();
bullet->set_player_id(entity_uniid);
bullet->set_bullet_id(curr_weapon->meta->i->use_bullet());
pos.ToPB(bullet->mutable_pos());
target_dir.ToPB(bullet->mutable_dir());
bullet->set_bulletskin(10001);
bullet->set_gun_id(curr_weapon->meta->i->id());
}
{
Bullet* bullet = new Bullet();
bullet->player = this;
bullet->room = room;
bullet->gun_meta = curr_weapon->meta;
bullet->meta = MetaMgr::Instance()->GetEquip(curr_weapon->meta->i->use_bullet());
bullet->pos = pos;
bullet->dir = target_dir;
bullet->born_pos = pos;
bullet->born_dir = target_dir;
bullet->entity_uniid = bullet->room->AllocUniid();
bullet->Initialize();
room->AddBullet(bullet);
}
}
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()
{
//检查x轴
{
int left_x = pos.x - meta->i->radius();
if (left_x < 0.001f) {
return true;
}
int right_x = pos.x + meta->i->radius();
if (right_x > MAP_WIDTH) {
return true;
}
}
//检查y轴
{
int up_y = pos.y + meta->i->radius();
if (up_y > MAP_HEIGHT) {
return true;
}
int down_y = pos.y - meta->i->radius();
if (down_y < 0.001f) {
return true;
}
}
int detection_flags = 0;
a8::SetBitFlag(detection_flags, ET_Obstacle);
a8::SetBitFlag(detection_flags, ET_Building);
std::vector<Entity*> objects;
room->CollisionDetection(this, detection_flags, objects);
return !objects.empty();
}
ColliderComponent* Human::GetFirstCollision()
{
int detection_flags = 0;
a8::SetBitFlag(detection_flags, ET_Obstacle);
a8::SetBitFlag(detection_flags, ET_Building);
std::vector<Entity*> objects;
room->CollisionDetection(this, detection_flags, objects);
return objects.empty() ? *objects[0]->colliders.begin() : nullptr;
}
void Human::FindPath()
{
ColliderComponent* first_collider = nullptr;
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();
}
void Human::UpdatePoisoning()
{
if (dead) {
return;
}
bool need_notify = poisoning_time > 1000;
while (poisoning_time > 1000) {
if (room->gas_data.is_last_gas) {
health = std::max(0.0f, health - room->gas_data.new_area_meta->i->hurt());
} else {
health = std::max(0.0f, health - room->gas_data.old_area_meta->i->hurt());
}
if (health <= 0.0f) {
dead = true;
downed = true;
poisoning_time = 0;
break;
}
poisoning_time -= 1000;
}
if (need_notify && entity_subtype == EST_Player) {
SyncAroundPlayers();
}
}
void Human::DropItem(int item_id)
{
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquip(item_id);
if (equip_meta) {
Loot* entity = new Loot();
entity->room = room;
entity->meta = equip_meta;
entity->entity_uniid = room->AllocUniid();
{
Vector2D dir = Vector2D::UP;
dir.Rotate(a8::RandAngle());
entity->pos = pos + dir * (25 + rand() % 50);
}
entity->item_id = equip_meta->i->id();
entity->count = 1;
entity->Initialize();
room->uniid_hash_[entity->entity_uniid] = entity;
for (auto& pair : room->human_hash_) {
pair.second->new_objects.insert(entity);
pair.second->part_objects.insert(entity);
}
}
}
void Human::SyncAroundPlayers()
{
for (auto& pair : room->human_hash_) {
pair.second->new_objects.insert(this);
}
}
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() < MAX_INVENTORY_NUM
) {
if (inventory[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)
{
msg.set_team_id(0);
msg.set_team_rank(0);
msg.set_team_allcnt(1);
msg.set_game_over(true);
msg.set_victory(false);
cs::MFPlayerStats* p = msg.add_player_stats();
FillMFPlayerStats(p);
}
void Human::BeKill(int killer_id, const std::string& killer_name)
{
stats.killer_id = killer_id;
stats.killer_name = killer_name;
dead = true;
health = 0.0f;
}