951 lines
34 KiB
C++
951 lines
34 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():Human()
|
|
{
|
|
entity_type = ET_Player;
|
|
entity_subtype = EST_Player;
|
|
}
|
|
|
|
Player::~Player()
|
|
{
|
|
|
|
}
|
|
|
|
void Player::Initialize()
|
|
{
|
|
Human::Initialize();
|
|
health = meta->i->health();
|
|
max_energy_shield = energy_shield;
|
|
skin_meta = MetaMgr::Instance()->GetDress(skin);
|
|
if (skin_meta) {
|
|
skill_meta = MetaMgr::Instance()->GetSkill(skin_meta->i->skill_id());
|
|
} else {
|
|
skill_meta = nullptr;
|
|
}
|
|
}
|
|
|
|
void Player::Update(int delta_time)
|
|
{
|
|
if (poisoning) {
|
|
poisoning_time += delta_time;
|
|
}
|
|
if (a8::HasBitFlag(status, HS_Fly)) {
|
|
pos = room->plane.curr_pos;
|
|
room->grid_service.MoveHuman(this);
|
|
}
|
|
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();
|
|
}
|
|
if (use_skill) {
|
|
UpdateUseSkill();
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
bool move_ok = false;
|
|
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;
|
|
}
|
|
move_ok = true;
|
|
}
|
|
if (move_ok) {
|
|
room->grid_service.MoveHuman(this);
|
|
}
|
|
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() < IS_END) {
|
|
if (GetInventory(bullet_meta->i->_inventory_slot()) > 0) {
|
|
int add_num = 0;
|
|
if (GetInventory(bullet_meta->i->_inventory_slot()) <=
|
|
curr_weapon->meta->i->clip_volume() - ammo) {
|
|
add_num = GetInventory(bullet_meta->i->_inventory_slot());
|
|
DecInventory(bullet_meta->i->_inventory_slot(), add_num);
|
|
} else {
|
|
add_num = curr_weapon->meta->i->clip_volume() - ammo;
|
|
DecInventory(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 (GetInventory(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;
|
|
DecInventory(item_meta->i->_inventory_slot(), 1);
|
|
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 (GetInventory(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_
|
|
);
|
|
}
|
|
DecInventory(item_meta->i->_inventory_slot(), 1);
|
|
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->stats.rescue_member;
|
|
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 < IS_END) {
|
|
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 (room->gas_data.gas_mode == GasInactive ||
|
|
room->gas_data.gas_mode == GasJump ||
|
|
a8::HasBitFlag(status, HS_Fly)) {
|
|
spectate = false;
|
|
return;
|
|
}
|
|
BeKill(entity_uniid, name, VW_Spectate);
|
|
spectate = false;
|
|
}
|
|
|
|
void Player::UpdateEmote()
|
|
{
|
|
if (a8::HasBitFlag(status, HS_Fly)) {
|
|
emote = false;
|
|
emote_id = 0;
|
|
return;
|
|
}
|
|
room->frame_event.AddEmote(this, emote_id);
|
|
emote = false;
|
|
emote_id = 0;
|
|
}
|
|
|
|
void Player::UpdateJump()
|
|
{
|
|
if (a8::HasBitFlag(status, HS_Fly)) {
|
|
DoJump();
|
|
for (size_t i = 0; i < 4; ++i){
|
|
room->xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE / 10,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (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->entity_subtype != EST_Player) {
|
|
hum->DoJump();
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
},
|
|
&xtimer_attacher.timer_list_);
|
|
}
|
|
}
|
|
jump = false;
|
|
}
|
|
|
|
void Player::UpdateUseSkill()
|
|
{
|
|
DoSkill();
|
|
use_skill = false;
|
|
}
|
|
|
|
void Player::Shot()
|
|
{
|
|
if (!curr_weapon->meta) {
|
|
return;
|
|
}
|
|
|
|
if (curr_weapon->weapon_idx != 0 &&
|
|
curr_weapon->ammo <= 0) {
|
|
AutoLoadingBullet();
|
|
return;
|
|
}
|
|
|
|
room->frame_event.AddShot(this);
|
|
if (room->gas_data.gas_mode != GasInactive &&
|
|
!a8::HasBitFlag(status, HS_Fly) &&
|
|
!a8::HasBitFlag(status, HS_Jump)
|
|
) {
|
|
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);
|
|
}
|
|
}
|
|
if (curr_weapon->weapon_idx != 0) {
|
|
--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;
|
|
}
|
|
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;
|
|
});
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
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;
|
|
skin_meta = MetaMgr::Instance()->GetDress(skin);
|
|
if (skin_meta) {
|
|
skill_meta = MetaMgr::Instance()->GetSkill(skin_meta->i->skill_id());
|
|
} else {
|
|
skill_meta = nullptr;
|
|
}
|
|
SyncAroundPlayers();
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
if (item_meta->i->_inventory_slot() >= 0 &&
|
|
item_meta->i->_inventory_slot() < IS_END) {
|
|
if (GetInventory(item_meta->i->_inventory_slot()) >=
|
|
GetVolume(item_meta->i->_inventory_slot())
|
|
) {
|
|
/*
|
|
cs::SMPickup notifymsg;
|
|
notifymsg.set_error_code(1);
|
|
SendNotifyMsg(notifymsg);
|
|
*/
|
|
return;
|
|
}
|
|
int add_num = GetVolume(item_meta->i->_inventory_slot()) -
|
|
GetInventory(item_meta->i->_inventory_slot());
|
|
add_num = std::min(entity->count, add_num);
|
|
|
|
AddInventory(item_meta->i->_inventory_slot(), add_num);
|
|
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;
|
|
DecInventory(item_meta->i->_inventory_slot(), add_num);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
if (add_num < entity->count) {
|
|
//刷新数量
|
|
entity->count -= add_num;
|
|
entity->BroadcastFullState();
|
|
return;
|
|
}
|
|
} 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();
|
|
RecalcVolume();
|
|
}
|
|
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();
|
|
RecalcAttr();
|
|
} 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();
|
|
RecalcAttr();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (action_type == AT_None) {
|
|
AutoLoadingBullet();
|
|
}
|
|
need_sync_active_player = true;
|
|
SyncAroundPlayers();
|
|
}
|
|
break;
|
|
}
|
|
entity->pickuped = true;
|
|
room->RemoveObjectLater(entity);
|
|
}
|
|
|
|
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::_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 (!a8::HasBitFlag(status, HS_Fly)) {
|
|
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;
|
|
}
|
|
if (msg.has_use_skill()) {
|
|
use_skill = 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 (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(¬ifymsg),
|
|
send_func);
|
|
}
|