aozhiwei 7b6ba13dd3 1
2019-04-18 10:44:15 +08:00

1125 lines
40 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"
Player::Player()
{
entity_type = ET_Player;
entity_subtype = EST_Player;
update_msg = new cs::SMUpdate();
}
Player::~Player()
{
delete update_msg;
update_msg = nullptr;
}
void Player::Initialize()
{
Human::Initialize();
health = meta->i->health();
RecalcSelfCollider();
}
void Player::Update(int delta_time)
{
if (poisoning) {
poisoning_time += delta_time;
}
if (a8::HasBitFlag(status, HS_Fly)) {
pos = room->plane.curr_pos;
}
if (moving) {
UpdateMove();
}
if (room->frame_no % 2 == 0) {
if (shot_start || shot_hold) {
UpdateShot();
}
if (interaction_objids.size() > 0) {
ProcInteraction();
}
if (poisoning) {
UpdatePoisoning();
}
if (select_weapon) {
UpdateSelectWeapon();
}
if (drop_weapon) {
UpdateDropWeapon();
}
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 (jump) {
UpdateJump();
}
}
}
void Player::UpdateMove()
{
if (action_type == AT_Relive) {
CancelAction();
}
if (a8::HasBitFlag(status, HS_Fly)) {
moving = false;
moved_frames = 0;
last_collision_door = nullptr;
return;
}
++moved_frames;
if (moved_frames > 4) {
moving = false;
moved_frames = 0;
return;
}
int speed = std::max(1, (int)GetSpeed());
for (int i = 0; i < speed; ++i) {
Vector2D old_pos = pos;
pos = pos + move_dir;
if (IsCollision()) {
pos = old_pos;
if (i == 0) {
FindPath();
}
break;
}
}
if (last_collision_door && !TestCollision(last_collision_door)) {
last_collision_door = nullptr;
}
}
void Player::UpdateShot()
{
if (a8::HasBitFlag(status, HS_Fly) ||
a8::HasBitFlag(status, HS_Jump) ) {
shot_start = false;
shot_hold = false;
series_shot_frames = 0;
return;
}
if (shot_start) {
shot_start = false;
Shot();
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 > 4) {
shot_hold = false;
series_shot_frames = 0;
}
}
}
void Player::UpdateSelectWeapon()
{
if (a8::HasBitFlag(status, HS_Fly)) {
select_weapon = false;
selected_weapon_idx = 0;
return;
}
if (selected_weapon_idx >= 0 && selected_weapon_idx < weapons.size()) {
Weapon* weapon = &weapons[selected_weapon_idx];
if (weapon->weapon_id != 0) {
curr_weapon = weapon;
ResetAction();
need_sync_active_player = true;
SyncAroundPlayers();
AutoLoadingBullet();
}
}
select_weapon = false;
selected_weapon_idx = 0;
}
void Player::UpdateAction()
{
int duration = std::max(0,
action_duration -
(int)((room->frame_no - action_frameno) * 1.0f / SERVER_FRAME_RATE) * 1000
);
if (duration <= 0) {
switch (action_type) {
case AT_Reload:
{
if (curr_weapon->weapon_idx == action_target_id &&
curr_weapon->weapon_id == action_item_id &&
curr_weapon->weapon_idx != 0) {
MetaData::Equip* bullet_meta = MetaMgr::Instance()->GetEquip(curr_weapon->meta->i->use_bullet());
if (bullet_meta) {
int ammo = curr_weapon->ammo;
if (ammo < curr_weapon->meta->i->clip_volume()) {
if (bullet_meta->i->_inventory_slot() >= 0 &&
bullet_meta->i->_inventory_slot() < MAX_INVENTORY_NUM) {
if (inventory[bullet_meta->i->_inventory_slot()] > 0) {
int add_num = 0;
if (inventory[bullet_meta->i->_inventory_slot()] <=
curr_weapon->meta->i->clip_volume() - ammo) {
add_num = inventory[bullet_meta->i->_inventory_slot()];
inventory[bullet_meta->i->_inventory_slot()] -= add_num;
} else {
add_num = curr_weapon->meta->i->clip_volume() - ammo;
inventory[bullet_meta->i->_inventory_slot()] -= add_num;
}
curr_weapon->ammo += add_num;
need_sync_active_player = true;;
}
}
}
}
}
}
break;
case AT_UseItem:
{
switch (action_item_id) {
case IS_HEALTHKIT:
{
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquipBySlotId(action_item_id);
if (item_meta){
if (inventory[item_meta->i->_inventory_slot()] > 0) {
float old_health = health;
health += item_meta->i->heal();
health = std::min(health, GetMaxHP());
stats.heal_amount += health - old_health;
--inventory[item_meta->i->_inventory_slot()];
need_sync_active_player = true;
SyncAroundPlayers();
}
}
}
break;
case IS_PAIN_KILLER:
{
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquipBySlotId(action_item_id);
if (item_meta){
if (inventory[item_meta->i->_inventory_slot()] > 0) {
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);
pain_killer_lastingtime += std::min(item_meta->i->time() * 1000, anodyne_max_time * 1000 - left_time) / 1000;
need_sync_active_player = true;
} else {
pain_killer_frameno = room->frame_no;
pain_killer_lastingtime = item_meta->i->time();
pain_killer_timer = room->xtimer.AddRepeatTimerAndAttach(
SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this)
.SetParam1(item_meta->i->heal()),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
float old_health = hum->health;
hum->health += param.param1.GetDouble();
hum->health = std::min(hum->health, hum->GetMaxHP());
hum->stats.heal_amount += hum->health - old_health;
hum->SyncAroundPlayers();
if (hum->room->frame_no - hum->pain_killer_frameno > hum->pain_killer_lastingtime * SERVER_FRAME_RATE) {
hum->room->xtimer.DeleteTimer(hum->pain_killer_timer);
hum->pain_killer_timer = nullptr;
}
},
&xtimer_attacher.timer_list_
);
}
--inventory[item_meta->i->_inventory_slot()];
need_sync_active_player = true;
}
}
}
break;
default:
{
}
break;
}
}
break;
case AT_Relive:
{
Entity* entity = room->GetEntityByUniId(action_target_id);
if (entity->entity_type != ET_Player) {
return;
}
Human* hum = (Human*)entity;
if (!hum->dead && hum->downed) {
hum->health = MetaMgr::Instance()->GetSysParamAsInt("downed_relive_recover_hp");
hum->downed = false;
if (hum->downed_timer) {
room->xtimer.DeleteTimer(hum->downed_timer);
hum->downed_timer = nullptr;
}
hum->SyncAroundPlayers();
}
}
break;
}
ResetAction();
}
}
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 < MAX_INVENTORY_NUM) {
switch (use_item_idx) {
case IS_HEALTHKIT:
{
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquipBySlotId(use_item_idx);
if (item_meta) {
StartAction(
AT_UseItem,
item_meta->i->use_time(),
use_item_idx,
0
);
}
}
break;
case IS_PAIN_KILLER:
{
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquipBySlotId(use_item_idx);
if (item_meta) {
StartAction(
AT_UseItem,
item_meta->i->use_time(),
use_item_idx,
0
);
}
}
break;
default:
{
}
break;
}
}
use_item_idx = 0;
use_item = false;
}
void Player::UpdateSpectate()
{
if (a8::HasBitFlag(status, HS_Fly)) {
spectate = false;
return;
}
BeKill(entity_uniid, name);
spectate = false;
}
void Player::UpdateGameOver()
{
cs::SMGameOver msg;
FillSMGameOver(msg);
SendNotifyMsg(msg);
send_gameover = false;
}
void Player::UpdateEmote()
{
if (a8::HasBitFlag(status, HS_Fly)) {
emote = false;
emote_id = 0;
return;
}
::google::protobuf::RepeatedPtrField<::cs::MFEmote>* emotes = nullptr;
{
auto itr = room->frame_data.emotes_hash.find(room->frame_no);
if (itr == room->frame_data.emotes_hash.end()) {
room->frame_data.emotes_hash[room->frame_no] = ::google::protobuf::RepeatedPtrField<::cs::MFEmote>();
itr = room->frame_data.emotes_hash.find(room->frame_no);
}
emotes = &itr->second;
}
{
cs::MFEmote* p = emotes->Add();
p->set_emote_id(emote_id);
p->set_player_id(entity_uniid);
}
emote = false;
emote_id = 0;
}
void Player::UpdateJump()
{
if (a8::HasBitFlag(status, HS_Fly)) {
DoJump();
room->xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * 3,
a8::XParams(),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->room->TouchHumanList(
a8::XParams()
.SetSender(hum),
[] (Human* hum, a8::XParams& param) -> bool
{
if (a8::HasBitFlag(hum->status, HS_Fly)) {
hum->DoJump();
return false;
}
return true;
});
},
&xtimer_attacher.timer_list_);
}
jump = false;
}
void Player::Shot()
{
if (!curr_weapon->meta) {
return;
}
if (curr_weapon->weapon_idx != 0 &&
curr_weapon->ammo <= 0) {
AutoLoadingBullet();
return;
}
{
::google::protobuf::RepeatedPtrField<::cs::MFShot>* shots = nullptr;
{
{
auto itr = room->frame_data.shots_hash.find(room->frame_no);
if (itr == room->frame_data.shots_hash.end()) {
room->frame_data.shots_hash[room->frame_no] = ::google::protobuf::RepeatedPtrField<::cs::MFShot>();
itr = room->frame_data.shots_hash.find(room->frame_no);
}
shots = &itr->second;
}
}
cs::MFShot* shot = shots->Add();
shot->set_player_id(entity_uniid);
curr_weapon->ToPB(shot->mutable_weapon());
shot->set_offhand(true);
shot->set_bullskin(10001);
}
if (room->gas_data.gas_mode != GasInactive && room->gas_data.gas_mode != GasJump) {
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;
::google::protobuf::RepeatedPtrField<::cs::MFBullet>* bullets = nullptr;
{
{
auto itr = room->frame_data.bullets_hash.find(room->frame_no);
if (itr == room->frame_data.bullets_hash.end()) {
room->frame_data.bullets_hash[room->frame_no] = ::google::protobuf::RepeatedPtrField<::cs::MFBullet>();
itr = room->frame_data.bullets_hash.find(room->frame_no);
}
bullets = &itr->second;
}
}
{
cs::MFBullet* bullet = bullets->Add();
bullet->set_player_id(entity_uniid);
bullet->set_bullet_id(curr_weapon->meta->i->use_bullet());
bullet_born_pos.ToPB(bullet->mutable_pos());
attack_dir.ToPB(bullet->mutable_dir());
bullet->set_bulletskin(10001);
bullet->set_gun_id(curr_weapon->meta->i->id());
bullet->set_fly_distance(fly_distance);
}
room->CreateBullet(this, curr_weapon->meta, bullet_born_pos, attack_dir, fly_distance);
}
}
if (curr_weapon->weapon_idx != 0) {
--curr_weapon->ammo;
}
int slot_id = curr_weapon->meta->i->_inventory_slot();
switch (slot_id) {
case 5:
{
//手雷
if (inventory[slot_id] > 0) {
--inventory[slot_id];
++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 (inventory[slot_id] > 0) {
--inventory[slot_id];
++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;
}
if (curr_weapon->weapon_idx != 0 &&
curr_weapon->ammo <= 0) {
AutoLoadingBullet();
}
last_shot_frameno_ = room->frame_no;
need_sync_active_player = true;
}
void Player::ProcInteraction()
{
if (a8::HasBitFlag(status, HS_Fly)) {
interaction_objids.Clear();
return;
}
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 = Vector2D(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 = Vector2D(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->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;
});
} else {
}
}
void Player::LootInteraction(Loot* entity)
{
if (entity->pickuped) {
return;
}
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(entity->item_id);
if (!item_meta) {
return;
}
switch (item_meta->i->equip_type()) {
case 1:
{
//装备
if (item_meta->i->equip_subtype() == 1) {
//近战
if (default_weapon.weapon_id != weapons[0].weapon_id) {
cs::SMPickup notifymsg;
notifymsg.set_error_code(2);
SendNotifyMsg(notifymsg);
return;
} else {
weapons[0].weapon_idx = 0;
weapons[0].weapon_id = entity->item_id;
weapons[0].weapon_lv = 1;
weapons[0].ammo = 0;
}
need_sync_active_player = true;
SyncAroundPlayers();
} else {
Weapon* weapon = nullptr;
if (weapons[GUN_SLOT1].weapon_id == 0) {
weapon = &weapons[GUN_SLOT1];
weapon->weapon_idx = GUN_SLOT1;
if (curr_weapon != &weapons[GUN_SLOT2]) {
curr_weapon = &weapons[GUN_SLOT1];
}
} else if (weapons[GUN_SLOT2].weapon_id == 0) {
weapon = &weapons[GUN_SLOT2];
weapon->weapon_idx = GUN_SLOT2;
if (curr_weapon != &weapons[GUN_SLOT1]) {
curr_weapon = &weapons[GUN_SLOT2];
}
}
if (!weapon) {
cs::SMPickup notifymsg;
notifymsg.set_error_code(2);
SendNotifyMsg(notifymsg);
return;
}
weapon->weapon_id = entity->item_id;
weapon->weapon_lv = 1;
weapon->ammo = 0;
weapon->meta = item_meta;
AutoLoadingBullet();
need_sync_active_player = true;
SyncAroundPlayers();
}
}
break;
case 8:
{
if (skin != 0) {
room->DropItem(pos, skin, 1);
}
skin = entity->item_id;
SyncAroundPlayers();
}
break;
default:
{
if (item_meta->i->_inventory_slot() >= 0 &&
item_meta->i->_inventory_slot() < MAX_INVENTORY_NUM) {
inventory[item_meta->i->_inventory_slot()] += entity->count;
if (item_meta->i->_inventory_slot() == 5 ||
item_meta->i->_inventory_slot() == 6) {
Weapon* weapon = &weapons[3 + (item_meta->i->_inventory_slot() - 5)];
if (weapon->weapon_id == 0) {
weapon->weapon_id = entity->item_id;
weapon->weapon_lv = 1;
weapon->ammo += entity->count;
weapon->meta = item_meta;
inventory[item_meta->i->_inventory_slot()] -= entity->count;
}
}
if (item_meta->i->_inventory_slot() > 12) {
if (item_meta->i->_inventory_slot() - 12 > curr_scope_idx) {
curr_scope_idx = item_meta->i->_inventory_slot() - 12;
}
}
} else {
switch (item_meta->i->equip_type()) {
case 7:
{
//背包
MetaData::Equip* old_item_meta = MetaMgr::Instance()->GetEquip(backpack);
if (old_item_meta) {
if (old_item_meta->i->equip_lv() >= item_meta->i->equip_lv()) {
return;
}
room->DropItem(pos, old_item_meta->i->id(), 1);
}
backpack = item_meta->i->id();
}
break;
case 4:
{
//防具
if (item_meta->i->equip_subtype() == 1) {
//盔甲
MetaData::Equip* old_item_meta = MetaMgr::Instance()->GetEquip(chest);
if (old_item_meta) {
if (old_item_meta->i->equip_lv() >= item_meta->i->equip_lv()) {
return;
}
room->DropItem(pos, old_item_meta->i->id(), 1);
}
chest = item_meta->i->id();
} else if (item_meta->i->equip_subtype() == 2) {
//头盔
MetaData::Equip* old_item_meta = MetaMgr::Instance()->GetEquip(helmet);
if (old_item_meta) {
if (old_item_meta->i->equip_lv() >= item_meta->i->equip_lv()) {
return;
}
room->DropItem(pos, old_item_meta->i->id(), 1);
}
helmet = item_meta->i->id();
}
}
break;
}
}
if (action_type == AT_None) {
AutoLoadingBullet();
}
need_sync_active_player = true;
SyncAroundPlayers();
}
break;
}
entity->pickuped = true;
room->AddDeletedObject(entity->entity_uniid, false);
}
void Player::HumanInteraction(Human* hum)
{
if (hum == this) {
return;
}
if (!hum->downed) {
return;
}
StartAction(
AT_Relive,
MetaMgr::Instance()->GetSysParamAsInt("downed_relive_time") * 1000,
room->frame_no,
hum->entity_uniid
);
}
void Player::SendUpdateMsg()
{
MakeUpdateMsg();
SendNotifyMsg(*update_msg);
if (send_gameover) {
UpdateGameOver();
}
{
if (!new_objects.empty()) {
new_objects.clear();
}
}
++send_update_msg_times;
}
void Player::_CMMove(f8::MsgHdr& hdr, const cs::CMMove& msg)
{
bool has_move_dir = msg.has_move_dir();
moving = false;
if (msg.has_move_dir()) {
if (std::abs(msg.move_dir().x()) > FLT_EPSILON ||
std::abs(msg.move_dir().y()) > FLT_EPSILON
) {
move_dir.FromPB(&msg.move_dir());
move_dir.Normalize();
moving = true;
}
}
assert(!isnan(move_dir.x) && !isnan(move_dir.y));
#if 0
moving = msg.has_move_dir();
#endif
if (msg.has_attack_dir()) {
attack_dir.FromPB(&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();
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_jump()) {
jump = true;
}
}
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_ammo = weapon->ammo;
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) {
{
Vector2D dir = Vector2D::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(weapon_id, pos + dir * (25 + rand() % 50), std::max(1, weapon_ammo));
}
need_sync_active_player = true;
SyncAroundPlayers();
}
}
}
ResetAction();
AutoLoadingBullet();
drop_weapon = false;
drop_weapon_idx = 0;
}
void Player::UpdateUseScope()
{
if (12 + use_scope_idx >= 12 && 12 + use_scope_idx < 16) {
if (inventory[12 + 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_mode(msg.mode());
notifymsg.set_account_id(account_id);
notifymsg.set_msg(msg.msg());
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::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);
}
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* p = player_data->add_states();
p->set_state_type(1);
p->set_left_time(left_time);
p->set_lasting_time(anodyne_max_time * 1000);
}
player_data->set_energy_shield(energy_shield);
#if 1
{
int max_energy_shield = MetaMgr::Instance()->GetSysParamAsInt("max_energy_shield");
player_data->set_max_energy_shield(max_energy_shield);
}
#endif
}
void Player::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);
}
void Player::MakeUpdateMsg()
{
update_msg->Clear();
{
update_msg->set_ack(last_seq_id);
{
for (auto& pair : room->frame_data.deleted_objects_hash) {
if (pair.first <= room->frame_no) {
for (auto& itr : pair.second) {
update_msg->add_del_objids(itr);
}
}
}
for (auto& pair : room->frame_data.shots_hash) {
if (pair.first <= room->frame_no) {
for (auto& itr : pair.second) {
*update_msg->add_shots() = itr;
}
}
}
for (auto& pair : room->frame_data.bullets_hash) {
if (pair.first <= room->frame_no) {
for (auto& itr : pair.second) {
*update_msg->add_bullets() = itr;
}
}
}
for (auto& pair : room->frame_data.explosions_hash) {
if (pair.first <= room->frame_no) {
for (auto& itr : pair.second) {
*update_msg->add_explosions() = itr;
}
}
}
for (auto& pair : room->frame_data.smokes_hash) {
if (pair.first <= room->frame_no) {
for (auto& itr : pair.second) {
*update_msg->add_smokes() = itr;
}
}
}
for (auto& pair : room->frame_data.emotes_hash) {
if (pair.first <= room->frame_no) {
for (auto& itr : pair.second) {
*update_msg->add_emotes() = itr;
}
}
}
for (auto& pair : room->frame_data.airdrops_hash) {
if (pair.first <= room->frame_no) {
for (auto& itr : pair.second) {
*update_msg->mutable_airdrop() = itr;
break;
}
}
}
}
if (team_members) {
for (auto& itr : *team_members) {
if (itr != this) {
itr->FillMFTeamData(update_msg->add_team_data());
}
}
}
if (send_update_msg_times == 0) {
room->FetchBuilding(this);
}
for (auto& itr : new_objects) {
itr->FillMFObjectFull(update_msg->add_full_objects());
}
for (auto& itr : part_objects) {
itr->FillMFObjectPart(update_msg->add_part_objects());
}
if (send_update_msg_times == 0 || need_sync_active_player) {
update_msg->set_active_player_id(entity_uniid);
FillMFActivePlayerData(update_msg->mutable_active_player_data());
need_sync_active_player = false;
}
if (send_update_msg_times == 0 || last_sync_gas_frameno < room->gas_data.gas_start_frameno) {
last_sync_gas_frameno = room->gas_data.gas_start_frameno;
FillMFGasData(update_msg->mutable_gas_data());
}
if (room->gas_data.gas_mode == GasMoving) {
update_msg->set_gas_progress(room->gas_data.gas_progress);
room->gas_data.pos_old.ToPB(update_msg->mutable_gas_pos_old());
}
update_msg->set_alive_count(room->AliveCount());
}
}