2019-07-20 13:55:26 +08:00

570 lines
16 KiB
C++

#include "precompile.h"
#include <float.h>
#include "playermgr.h"
#include "player.h"
#include "cs_proto.pb.h"
#include "room.h"
#include "metamgr.h"
#include "bullet.h"
#include "obstacle.h"
#include "building.h"
#include "loot.h"
#include "app.h"
#include "collider.h"
#include "typeconvert.h"
Player::Player():Human()
{
entity_type = ET_Player;
entity_subtype = EST_Player;
++App::Instance()->perf.entity_num[ET_Player];
}
Player::~Player()
{
--App::Instance()->perf.entity_num[ET_Player];
}
void Player::Initialize()
{
Human::Initialize();
tank_meta_ = MetaMgr::Instance()->GetTank(TankId());
if (tank_meta_) {
skill_meta_ = MetaMgr::Instance()->GetSkill(tank_meta_->i->skill_id());
MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(tank_meta_->i->bullet_id());
if (weapon_meta) {
weapons[GUN_SLOT1].weapon_idx = GUN_SLOT1;
weapons[GUN_SLOT1].weapon_id = weapon_meta->i->id();
weapons[GUN_SLOT1].weapon_lv = 1;
weapons[GUN_SLOT1].ammo = 0;
weapons[GUN_SLOT1].meta = weapon_meta;
weapons[GUN_SLOT1].Recalc();
curr_weapon = &weapons[GUN_SLOT1];
DirectReload();
}
}
driver_meta = MetaMgr::Instance()->GetDriver(driver.driver_id);
RecalcBaseAttr();
}
void Player::Update(int delta_time)
{
if (a8::HasBitFlag(status, HS_Assaulting)) {
_UpdateAssaultMove();
} else {
if (moving) {
UpdateMove();
}
}
if (room->frame_no % 2 == 0) {
if (shot_start || shot_hold) {
UpdateShot();
}
if (drop_weapon) {
UpdateDropWeapon();
}
if (interaction_objids.size() > 0) {
ProcInteraction();
}
if (playing_skill) {
UpdateSkill();
}
if (select_weapon) {
UpdateSelectWeapon();
}
if (use_scope) {
UpdateUseScope();
}
if (reload) {
UpdateReload();
}
if (cancel_action) {
UpdateCancelAction();
}
if (use_item) {
UpdateUseItemIdx();
}
if (action_type != AT_None) {
UpdateAction();
}
if (spectate) {
UpdateSpectate();
}
if (emote) {
UpdateEmote();
}
if (use_skill) {
UpdateUseSkill();
}
}
}
void Player::UpdateMove()
{
if (dead || HasBuffEffect(BET_Vertigo) || HasBuffEffect(BET_Dcgr)) {
moving = false;
moved_frames = 0;
last_collision_door = nullptr;
return;
}
++moved_frames;
if (moved_frames > 4) {
moving = false;
moved_frames = 0;
return;
}
_UpdateMove(std::max(1, (int)GetSpeed()));
if (last_collision_door && !TestCollision(last_collision_door)) {
last_collision_door = nullptr;
}
}
void Player::UpdateShot()
{
if (dead || HasBuffEffect(BET_Vertigo) || HasBuffEffect(BET_Dcgr)) {
shot_start = false;
shot_hold = false;
series_shot_frames = 0;
shot_target_id = 0;
return;
}
if (shot_start) {
shot_start = false;
Shot();
shot_target_id = 0;
return;
}
if (shot_hold) {
++series_shot_frames;
if (last_shot_frameno_ == 0 ||
(
(room->frame_no - last_shot_frameno_) * (1000 / SERVER_FRAME_RATE)) >=
curr_weapon->meta->i->fire_rate()
) {
Shot();
}
if (series_shot_frames > 8) {
shot_hold = false;
series_shot_frames = 0;
shot_target_id = 0;
}
}
}
void Player::UpdateSelectWeapon()
{
if (selected_weapon_idx >= 0 && selected_weapon_idx < weapons.size()) {
Weapon* old_weapon = curr_weapon;
Weapon* weapon = &weapons[selected_weapon_idx];
if (weapon->weapon_id != 0) {
curr_weapon = weapon;
ResetAction();
need_sync_active_player = true;
SyncAroundPlayers();
if (old_weapon != weapon) {
AutoLoadingBullet();
}
}
}
select_weapon = false;
selected_weapon_idx = 0;
}
void Player::UpdateReload()
{
AutoLoadingBullet(true);
reload = false;
}
void Player::UpdateCancelAction()
{
CancelAction();
cancel_action = false;
}
void Player::UpdateUseItemIdx()
{
if (use_item_idx >= 0 && use_item_idx < IS_END) {
switch (use_item_idx) {
case IS_HEALTHKIT:
{
}
break;
case IS_PAIN_KILLER:
{
}
break;
default:
{
}
break;
}
}
use_item_idx = 0;
use_item = false;
}
void Player::UpdateSpectate()
{
if (room->gas_data.gas_mode == GasInactive) {
spectate = false;
return;
}
BeKill(entity_uniid, name, VW_Spectate);
spectate = false;
}
void Player::UpdateEmote()
{
room->frame_event.AddEmote(this, emote_id);
emote = false;
emote_id = 0;
}
void Player::UpdateUseSkill()
{
DoSkill();
}
void Player::ProcInteraction()
{
for (auto obj_id : interaction_objids) {
Entity* entity = room->GetEntityByUniId(obj_id);
if (entity) {
switch (entity->entity_type) {
case ET_Obstacle:
{
ObstacleInteraction((Obstacle*)entity);
}
break;
case ET_Loot:
{
LootInteraction((Loot*)entity);
}
break;
case ET_Player:
{
HumanInteraction((Human*)entity);
}
break;
default:
break;
}
}
}
interaction_objids.Clear();
}
void Player::ObstacleInteraction(Obstacle* entity)
{
if (entity->is_door) {
if (entity->door_state == DoorStateClose) {
entity->door_state = DoorStateOpen;
entity->pos = a8::Vec2(entity->building->pos.x + entity->door_state1->x() - entity->building->meta->i->tilewidth() / 2.0,
entity->building->pos.y + entity->door_state1->y() - entity->building->meta->i->tileheight() / 2.0);
} else {
entity->door_state = DoorStateClose;
entity->pos = a8::Vec2(entity->building->pos.x + entity->door_state0->x() - entity->building->meta->i->tilewidth() / 2.0,
entity->building->pos.y + entity->door_state0->y() - entity->building->meta->i->tileheight() / 2.0);
}
++entity->door_open_times;
entity->RecalcSelfCollider();
room->TouchHumanList(a8::XParams(),
[entity] (Human* hum, a8::XParams& param) -> bool
{
hum->AddToNewObjects(entity);
if (entity->TestCollision(hum)) {
hum->last_collision_door = entity;
} else if (hum->last_collision_door == entity) {
hum->last_collision_door = nullptr;
}
return true;
});
}
}
void Player::LootInteraction(Loot* entity)
{
if (entity->pickuped ||
entity->count <= 0) {
return;
}
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(entity->item_id);
if (!item_meta) {
return;
}
entity->pickuped = true;
room->RemoveObjectLater(entity);
}
void Player::HumanInteraction(Human* hum)
{
if (hum == this) {
return;
}
}
void Player::ProcPrepareItems(const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& prepare_items)
{
std::set<int> handled_items;
for (int equip_id : prepare_items) {
if (handled_items.find(equip_id) != handled_items.end()) {
continue;
}
handled_items.insert(equip_id);
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(equip_id);
if (item_meta) {
}
}//end for
need_sync_active_player = true;
if (prepare_items.size() > 0) {
SyncAroundPlayers();
}
}
void Player::_CMMove(f8::MsgHdr& hdr, const cs::CMMove& msg)
{
moving = false;
if (msg.has_move_dir() && !a8::HasBitFlag(status, HS_Assaulting)) {
if (std::abs(msg.move_dir().x()) > FLT_EPSILON ||
std::abs(msg.move_dir().y()) > FLT_EPSILON
) {
a8::Vec2 old_move_dir;
TypeConvert::FromPb(move_dir, &msg.move_dir());
move_dir.Normalize();
moving = true;
}
}
assert(!isnan(move_dir.x) && !isnan(move_dir.y));
if (msg.has_attack_dir()) {
if (std::isfinite(msg.attack_dir().x()) &&
std::isfinite(msg.attack_dir().y()) &&
(
std::abs(msg.attack_dir().x()) > 0.00001f ||
std::abs(msg.attack_dir().y()) > 0.00001f
)
){
TypeConvert::FromPb(attack_dir, &msg.attack_dir());
attack_dir.Normalize();
}
} else {
if (moving) {
attack_dir = move_dir;
}
}
if (moving) {
moved_frames = 0;
}
shot_start = msg.shot_start();
shot_hold = msg.shot_hold();
shot_target_id = msg.shot_target_id();
fly_distance = std::min(200.0f, msg.fly_distance());
if (!shot_hold) {
series_shot_frames = 0;
}
if (msg.has_interaction()) {
interaction_objids = msg.interaction_objids();
}
last_seq_id = msg.seq();
if (msg.has_select_weapon()) {
select_weapon = true;
selected_weapon_idx = msg.select_weapon();
}
if (msg.has_drop_weapon()) {
drop_weapon = true;
drop_weapon_idx = msg.drop_weapon();
}
if (msg.has_use_scope()) {
use_scope = true;
use_scope_idx = msg.use_scope();
}
if (msg.has_reload()) {
reload = msg.reload();
}
if (msg.has_cancel_action()) {
cancel_action = msg.cancel_action();
}
if (msg.has_use_item_idx()) {
use_item = true;
use_item_idx = msg.use_item_idx();
}
if (msg.has_spectate()) {
spectate = true;
}
if (msg.has_emote()) {
emote = true;
emote_id = msg.emote();
}
if (msg.has_use_skill()) {
use_skill = true;
skill_target_id = msg.skill_target_id();
}
}
void Player::UpdateDropWeapon()
{
if (drop_weapon_idx >= 0 && drop_weapon_idx < weapons.size()) {
bool drop_ok = false;
Weapon* weapon = &weapons[drop_weapon_idx];
int weapon_id = weapon->weapon_id;
int weapon_lv = weapon->weapon_lv;
if (weapon->weapon_id != 0) {
if (weapon->weapon_idx == 0) {
if (weapon->weapon_id != default_weapon.weapon_id) {
drop_ok = true;
*weapon = default_weapon;
}
} else if (weapon->weapon_idx == GUN_SLOT1) {
drop_ok = true;
*weapon = Weapon();
weapon->weapon_idx = drop_weapon_idx;
if (curr_weapon == weapon) {
if (weapons[GUN_SLOT2].weapon_id != 0) {
curr_weapon = &weapons[GUN_SLOT2];
} else {
curr_weapon = &weapons[0];
}
}
} else if (weapon->weapon_idx == GUN_SLOT2) {
drop_ok = true;
*weapon = Weapon();
weapon->weapon_idx = drop_weapon_idx;
if (curr_weapon == weapon) {
if (weapons[GUN_SLOT1].weapon_id != 0) {
curr_weapon = &weapons[GUN_SLOT1];
} else {
curr_weapon = &weapons[0];
}
}
} else if (weapon->weapon_idx == FRAG_SLOT) {
drop_ok = true;
*weapon = Weapon();
weapon->weapon_idx = drop_weapon_idx;
if (curr_weapon == weapon) {
if (weapons[GUN_SLOT1].weapon_id != 0) {
curr_weapon = &weapons[GUN_SLOT1];
} else if (weapons[GUN_SLOT2].weapon_id != 0) {
curr_weapon = &weapons[GUN_SLOT2];
} else {
curr_weapon = &weapons[0];
}
}
} else if (weapon->weapon_idx == SMOKE_SLOT) {
drop_ok = true;
*weapon = Weapon();
weapon->weapon_idx = drop_weapon_idx;
if (curr_weapon == weapon) {
if (weapons[GUN_SLOT1].weapon_id != 0) {
curr_weapon = &weapons[GUN_SLOT1];
} else if (weapons[GUN_SLOT2].weapon_id != 0) {
curr_weapon = &weapons[GUN_SLOT2];
} else {
curr_weapon = &weapons[0];
}
}
}
if (drop_ok) {
if (drop_weapon_idx == 0 ||
drop_weapon_idx == GUN_SLOT1 ||
drop_weapon_idx == GUN_SLOT2
) {
a8::Vec2 dir = a8::Vec2::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(weapon_id, pos + dir * (25 + rand() % 50), 1, weapon_lv);
}
#if 0
if (weapon_ammo > 0) {
MetaData::Equip* bullet_meta = MetaMgr::Instance()->GetEquip(weapon_meta->i->use_bullet());
if (bullet_meta && bullet_meta->i->_inventory_slot() > 0) {
int volume = GetVolume(bullet_meta->i->_inventory_slot());
int inventory = GetInventory(bullet_meta->i->_inventory_slot());
int add_inventory = std::min(weapon_ammo, volume - std::min(volume, inventory));
if (add_inventory > 0) {
AddInventory(bullet_meta->i->_inventory_slot(), add_inventory);
}
int drop_num = weapon_ammo - add_inventory;
if (drop_num > 0) {
a8::Vec2 drop_dir = a8::Vec2::UP;
drop_dir.Rotate(a8::RandAngle());
a8::Vec2 drop_pos = pos + drop_dir * (25 + rand() % 50);
room->DropItem(drop_pos, bullet_meta->i->id(), drop_num, 1);
}
}
}
#endif
need_sync_active_player = true;
SyncAroundPlayers();
}
}
}
ResetAction();
AutoLoadingBullet();
drop_weapon = false;
drop_weapon_idx = 0;
}
void Player::UpdateUseScope()
{
if (IS_1XSCOPE + use_scope_idx >= IS_1XSCOPE && IS_1XSCOPE + use_scope_idx <= IS_15XSCOPE) {
if (GetInventory(IS_1XSCOPE + use_scope_idx) > 0) {
curr_scope_idx = use_scope_idx;
need_sync_active_player = true;
}
}
use_scope = false;
use_scope_idx = 0;
}
void Player::_CMEmote(f8::MsgHdr& hdr, const cs::CMEmote& msg)
{
}
void Player::_CMVoice(f8::MsgHdr& hdr, const cs::CMVoice& msg)
{
cs::SMVoiceNotify notifymsg;
notifymsg.set_account_id(account_id);
notifymsg.set_download_url(msg.download_url());
auto send_func = [] (Player* hum, a8::XParams& param)
{
cs::SMVoiceNotify* msg = (cs::SMVoiceNotify*)param.sender.GetUserData();
hum->SendNotifyMsg(*msg);
};
room->TouchPlayerList(a8::XParams()
.SetSender(&notifymsg),
send_func);
}
void Player::_CMGameOver(f8::MsgHdr& hdr, const cs::CMGameOver& msg)
{
}
void Player::_CMWatchWar(f8::MsgHdr& hdr, const cs::CMWatchWar& msg)
{
cs::SMWatchWar respmsg;
Human* target = room->GetWatchWarTarget(this);
if (target) {
SendNotifyMsg(respmsg);
hdr.hum->FollowTarget(target);
} else {
respmsg.set_error_code(1);
SendNotifyMsg(respmsg);
}
}
void Player::_CMLeave(f8::MsgHdr& hdr, const cs::CMLeave& msg)
{
if (!leave_) {
if (room->BattleStarted()) {
//如果战斗已经开始算自杀
BeKill(entity_uniid, name, VW_Spectate);
}
leave_ = true;
leave_frameno_ = room->frame_no;
}
cs::SMLeave respmsg;
SendNotifyMsg(respmsg);
}