2020-08-14 14:15:37 +08:00

1374 lines
45 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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"
#include "playermgr.h"
#include "perfmonitor.h"
#include "jsondatamgr.h"
const int kREVIVE_BUFF_ID = 1005;
Player::Player():Human()
{
++PerfMonitor::Instance()->entity_num[ET_Player];
}
Player::~Player()
{
--PerfMonitor::Instance()->entity_num[ET_Player];
PlayerMgr::Instance()->DecAccountNum(account_id);
}
void Player::Initialize()
{
Human::Initialize();
max_energy_shield = energy_shield;
skill_meta_ = MetaMgr::Instance()->GetSkill(41001);
RecalcBaseAttr();
}
void Player::Update(int delta_time)
{
if (UpdatedTimes() <= 0) {
if (room->GetFrameNo() % 2 != 0) {
return;
}
}
InternalUpdate(delta_time);
++updated_times_;
}
void Player::InternalUpdate(int delta_time)
{
if (poisoning) {
poisoning_time += delta_time;
}
if (HasSpecMove()) {
_UpdateSpecMove();
} else {
if (moving) {
UpdateMove();
}
}
if (room->GetFrameNo() % 2 == 0) {
if (drop_weapon) {
UpdateDropWeapon();
}
if (interaction_objids.size() > 0) {
ProcInteraction();
}
if (poisoning) {
UpdatePoisoning();
}
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 (get_down) {
UpdateGetDown();
}
if (shot_start || shot_hold) {
UpdateShot();
}
if (use_skill) {
UpdateUseSkill();
}
if (aiming) {
if (HasBuffEffect(kBET_Camouflage)) {
RemoveBuffByEffectId(kBET_Camouflage);
}
}
if (has_use_item_id) {
UpdateUseItemId();
}
}
}
void Player::UpdateMove()
{
if (action_type == AT_Relive) {
CancelAction();
}
if (dead ||
room->IsWaitingStart()) {
moving = false;
moved_frames = 0;
SetLastCollisionDoor(nullptr);
return;
}
if (HasBuffEffect(kBET_Vertigo)) {
return;
}
if (HasBuffEffect(kBET_Camouflage)) {
RemoveBuffByEffectId(kBET_Camouflage);
}
++moved_frames;
if (moved_frames > 4) {
moving = false;
moved_frames = 0;
return;
}
_UpdateMove(std::max(1, (int)GetSpeed()));
if (GetLastCollisionDoor() && !TestCollision(room, GetLastCollisionDoor())) {
SetLastCollisionDoor(nullptr);
}
#if 0
a8::Vec2 old_pos = GetPos();
if (tank_weapon.meta) {
CheckSkinTank();
tank_oil_value -= old_pos.Distance(GetPos()) * (MetaMgr::Instance()->average_oil / 100.0f);
tank_oil_value = std::max(0.0f, tank_oil_value);
}
#endif
#ifdef DEBUG
room->CheckPartObjects();
#endif
}
void Player::UpdateShot()
{
if (dead ||
downed ||
room->IsWaitingStart()) {
shot_start = false;
shot_hold = false;
series_shot_frames = 0;
return;
}
if (HasBuffEffect(kBET_Vertigo)) {
return;
}
if (shot_start) {
shot_start = false;
Shot();
return;
}
Weapon* p_weapon = curr_weapon;
if (car_weapon.meta) {
p_weapon = &car_weapon;
}
if (shot_hold) {
++series_shot_frames;
if (last_shot_frameno_ == 0 ||
(
(room->GetFrameNo() - last_shot_frameno_) * (1000 / SERVER_FRAME_RATE)) >=
p_weapon->GetAttrValue(kHAT_FireRate)
) {
Shot();
}
if (series_shot_frames > 8) {
shot_hold = false;
series_shot_frames = 0;
}
}
if (HasBuffEffect(kBET_Camouflage)) {
RemoveBuffByEffectId(kBET_Camouflage);
}
}
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(__FILE__, __LINE__, __func__);
if (old_weapon != weapon) {
AutoLoadingBullet();
}
}
}
select_weapon = false;
selected_weapon_idx = 0;
if (HasBuffEffect(kBET_Camouflage)) {
RemoveBuffByEffectId(kBET_Camouflage);
}
}
void Player::UpdateReload()
{
AutoLoadingBullet(true);
reload = false;
}
void Player::UpdateCancelAction()
{
CancelAction();
cancel_action = false;
}
void Player::UpdateUseItemIdx()
{
if (downed) {
return;
}
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::UpdateUseItemId()
{
if (downed) {
return;
}
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(use_item_id);
if (item_meta && item_meta->i->equip_type() == EQUIP_TYPE_CAMOUFLAGE) {
int item_num = GetItemNum(use_item_id);
if (item_num > 0) {
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(item_meta->i->buffid());
if (buff_meta && !GetBuffById(item_meta->i->buffid())) {
if (HasBuffEffect(kBET_Camouflage)) {
RemoveBuffByEffectId(kBET_Camouflage);
}
AddBuff(this, buff_meta, 1);
DecItem(use_item_id, 1);
}
}
}
use_item_id = 0;
has_use_item_id = false;
}
void Player::UpdateSpectate()
{
if (room->GetGasData().gas_mode == GasInactive) {
spectate = false;
return;
}
BeKill(GetEntityUniId(), name, VW_Spectate);
spectate = false;
}
void Player::UpdateEmote()
{
room->frame_event.AddEmote(this, emote_id);
emote = false;
emote_id = 0;
}
void Player::UpdateGetDown()
{
DoGetDown();
get_down = false;
}
void Player::UpdateUseSkill()
{
if (HasBuffEffect(kBET_Vertigo)) {
return;
}
DoSkill();
}
void Player::Shot()
{
if (car_weapon.meta) {
CarShot(attack_dir);
return;
}
if (!curr_weapon->meta) {
return;
}
if (curr_weapon->weapon_idx != 0 &&
curr_weapon->ammo <= 0) {
AutoLoadingBullet();
return;
}
if (action_type == AT_Reload) {
CancelAction();
}
if (action_type == AT_Reload ||
action_type == AT_Rescue ||
action_type == AT_UseItem ||
action_type == AT_Relive) {
CancelAction();
}
InternalShot(this,
curr_weapon->meta,
curr_weapon->GetUpgradeMeta(),
curr_weapon->bullet_meta,
curr_weapon->weapon_lv,
0,
fly_distance,
false);
if (curr_weapon->weapon_idx != 0) {
--curr_weapon->ammo;
}
int slot_id = curr_weapon->meta->i->_inventory_slot();
//扔完手雷,如无手雷则优先换武器1>武器2
switch (slot_id) {
case 5:
{
//手雷
if (curr_weapon->ammo <= 0) {
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 {
AutoChgWeapon();
}
AutoLoadingBullet();
}
}
need_sync_active_player = true;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
break;
case 6:
{
//烟雾弹
if (curr_weapon->ammo <= 0) {
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 {
AutoChgWeapon();
}
AutoLoadingBullet();
}
}
need_sync_active_player = true;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
break;
}
if (curr_weapon->weapon_idx != 0 &&
curr_weapon->ammo <= 0) {
AutoLoadingBullet();
}
last_shot_frameno_ = room->GetFrameNo();
room->frame_event.AddWeaponAmmoChg(this);
}
void Player::ProcInteraction()
{
if (room->GetGasData().gas_mode == GasInactive) {
return;
}
for (auto obj_id : interaction_objids) {
Entity* entity = room->GetEntityByUniId(obj_id);
if (entity) {
switch (entity->GetEntityType()) {
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->IsDoor()) {
if (entity->GetDoorState(room) == DoorStateClose) {
entity->SetDoorState(room, DoorStateOpen);
float x = entity->GetBuilding()->GetX() + entity->GetDoorState1()->x() - entity->GetBuilding()->meta->i->tilewidth() / 2.0;
float y = entity->GetBuilding()->GetY() + entity->GetDoorState1()->y() - entity->GetBuilding()->meta->i->tileheight() / 2.0;
entity->SetPos(a8::Vec2(x, y));
} else {
entity->SetDoorState(room, DoorStateClose);
float x = entity->GetBuilding()->GetX() + entity->GetDoorState0()->x() - entity->GetBuilding()->meta->i->tilewidth() / 2.0;
float y = entity->GetBuilding()->GetY() + entity->GetDoorState0()->y() - entity->GetBuilding()->meta->i->tileheight() / 2.0;
entity->SetPos(a8::Vec2(x, y));
}
entity->IncDoorOpenTimes(room);
entity->RecalcSelfCollider();
room->TouchHumanList(a8::XParams(),
[entity] (Human* hum, a8::XParams& param) -> bool
{
hum->AddToNewObjects(entity);
if (entity->TestCollision(hum->room, hum)) {
hum->SetLastCollisionDoor(entity);
} else if (hum->GetLastCollisionDoor() == entity) {
hum->SetLastCollisionDoor(nullptr);
}
return true;
});
}
}
void Player::LootInteraction(Loot* entity)
{
if (room->GetRoomMode() == kZombieMode &&
GetRace() == kZombieRace) {
return;
}
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 EQUIP_TYPE_WEAPON:
{
//装备
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;
#if 1
weapons[0].weapon_lv = std::max(1, entity->item_level);
#else
weapons[0].weapon_lv = std::max(1, GetWeaponConfigLv(weapons[0].weapon_id));
#endif
weapons[0].ammo = 0;
weapons[0].meta = item_meta;
weapons[0].Recalc();
}
need_sync_active_player = true;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
} 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;
#if 1
weapon->weapon_lv = std::max(1, entity->item_level);
#else
weapon->weapon_lv = std::max(1, GetWeaponConfigLv(weapon->weapon_id));
#endif
weapon->ammo = 0;
weapon->meta = item_meta;
weapon->Recalc();
if (room->GetRoomMode() == kZombieMode && HasBuffEffect(kBET_Car)) {
} else {
AutoLoadingBullet();
}
need_sync_active_player = true;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
if (room->GetRoomType() == RT_NewBrid &&
!a8::HasBitFlag(status, HS_AlreadyEquip)) {
a8::SetBitFlag(status, HS_AlreadyEquip);
ProcNewBieLogic();
}
}
break;
case EQUIP_TYPE_OLDSKIN:
{
abort();
}
break;
case EQUIP_TYPE_SKIN:
{
ProcLootSkin(entity, item_meta);
}
break;
case EQUIP_TYPE_CAR:
{
ProcLootCar(entity, item_meta);
}
break;
case EQUIP_TYPE_CAMOUFLAGE:
{
ProcCamoutflage(entity, item_meta);
}
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)];
weapon->weapon_id = entity->item_id;
weapon->weapon_lv = 1;
weapon->ammo += entity->count;
weapon->meta = item_meta;
weapon->Recalc();
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(room);
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(GetPos(), old_item_meta->i->id(), 1, 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(GetPos(), old_item_meta->i->id(), 1, 1);
}
chest = item_meta->i->id();
RecalcBaseAttr();
} 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(GetPos(), old_item_meta->i->id(), 1, 1);
}
helmet = item_meta->i->id();
RecalcBaseAttr();
}
}
break;
}
}
if (action_type == AT_None) {
AutoLoadingBullet();
}
need_sync_active_player = true;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
break;
}
entity->pickuped = true;
room->RemoveObjectLater(entity);
}
void Player::HumanInteraction(Human* hum)
{
if (downed) {
return;
}
if (hum == this) {
return;
}
if (!hum->downed) {
return;
}
if (hum->action_type == AT_Rescue) {
return;
}
hum->StartAction(
AT_Rescue,
MetaMgr::Instance()->GetSysParamAsInt("downed_relive_time") * 1000,
room->GetFrameNo(),
GetEntityUniId()
);
StartAction(
AT_Relive,
MetaMgr::Instance()->GetSysParamAsInt("downed_relive_time") * 1000,
room->GetFrameNo(),
hum->GetEntityUniId()
);
}
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) {
switch (item_meta->i->equip_type()) {
case EQUIP_TYPE_WEAPON:
{
//装备
if (item_meta->i->equip_subtype() == 1) {
//近战
if (default_weapon.weapon_id == weapons[0].weapon_id) {
weapons[0].weapon_idx = 0;
weapons[0].weapon_id = equip_id;
weapons[0].weapon_lv = std::max(1, GetWeaponConfigLv(weapons[0].weapon_id));
weapons[0].ammo = 0;
weapons[0].meta = item_meta;
weapons[0].Recalc();
}
} 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) {
weapon->weapon_id = equip_id;
weapon->weapon_lv = std::max(1, GetWeaponConfigLv(weapon->weapon_id));
weapon->ammo = 0;
weapon->meta = item_meta;
weapon->Recalc();
}
}
}
break;
case EQUIP_TYPE_CAR:
{
int car_uniid = room->CreateAndTakeonCar(item_meta->i->id(), GetPos());
if (car_uniid != -1) {
car_.car_uniid = car_uniid;
car_.car_id = item_meta->i->id();
car_.meta = item_meta;
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(car_.meta->i->buffid());
if (buff_meta) {
AddBuff(this, buff_meta, 1);
}
}
}
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())
) {
break;
}
int add_num = GetVolume(item_meta->i->_inventory_slot()) -
GetInventory(item_meta->i->_inventory_slot());
add_num = std::min(1, 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)];
weapon->weapon_id = equip_id;
weapon->weapon_lv = 1;
weapon->ammo += 1;
weapon->meta = item_meta;
weapon->Recalc();
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;
}
}
} 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()) {
break;
}
room->DropItem(GetPos(), old_item_meta->i->id(), 1, 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()) {
break;
}
room->DropItem(GetPos(), old_item_meta->i->id(), 1, 1);
}
chest = item_meta->i->id();
RecalcBaseAttr();
} 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()) {
break;
}
room->DropItem(GetPos(), old_item_meta->i->id(), 1, 1);
}
helmet = item_meta->i->id();
RecalcBaseAttr();
}
}
break;
}
}
}
break;
}
}
}//end for
if (curr_weapon) {
MetaData::Equip* bullet_meta = MetaMgr::Instance()->GetEquip(curr_weapon->meta->i->use_bullet());
if (bullet_meta) {
int add_num = GetInventory(bullet_meta->i->_inventory_slot());
add_num = curr_weapon->GetClipVolume();
curr_weapon->ammo = add_num;
}
}
for (auto& spec_weapon : spec_weapons) {
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(spec_weapon.weapon_id);
if (item_meta &&
item_meta->i->equip_type() == EQUIP_TYPE_WEAPON) {
if (item_meta->i->equip_subtype() != 1) {
int weapon_idx = GUN_SLOT1;
if (weapons[weapon_idx].weapon_id != 0) {
weapon_idx = GUN_SLOT2;
}
if (weapons[weapon_idx].weapon_id == 0) {
Weapon* weapon = &weapons[weapon_idx];
weapon->weapon_idx = weapon_idx;
weapon->weapon_id = spec_weapon.weapon_id;
weapon->weapon_lv = spec_weapon.weapon_lv;
weapon->ammo = spec_weapon.ammo;
weapon->meta = item_meta;
weapon->Recalc();
curr_weapon = &weapons[GUN_SLOT1];
}
}
}
}
need_sync_active_player = true;
if (prepare_items.size() > 0) {
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
}
void Player::ProcPrepareItems2(const ::google::protobuf::RepeatedPtrField< cs::MFPair >&
prepare_items)
{
for (auto& pair : prepare_items) {
AddItem(pair.key(), pair.value());
}
}
void Player::_CMReconnect(f8::MsgHdr& hdr, const cs::CMReconnect& msg)
{
int old_socket_handle = socket_handle;
if (socket_handle != 0) {
GGListener::Instance()->ForceCloseChildSocket(socket_handle);
PlayerMgr::Instance()->RemovePlayerBySocket(socket_handle);
}
socket_handle = hdr.socket_handle;
TouchAllLayerHumanList
(
[this] (Human* hum, bool& stop)
{
AddToNewObjects(hum);
}
);
need_sync_active_player = true;
cs::SMReconnect respmsg;
respmsg.set_errcode(0);
respmsg.set_errmsg("战斗重连成功");
SendNotifyMsg(respmsg);
PlayerMgr::Instance()->ReBindSocket(this);
a8::UdpLog::Instance()->Debug
("战斗服重连成功 %s %d %d",
{
account_id,
hdr.socket_handle,
old_socket_handle
});
}
void Player::_CMMove(f8::MsgHdr& hdr, const cs::CMMove& msg)
{
moving = false;
if (msg.has_move_dir()) {
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();
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_use_item_id()) {
has_use_item_id = true;
use_item_id = msg.use_item_id();
}
if (msg.has_spectate()) {
spectate = true;
}
if (msg.has_emote()) {
emote = true;
emote_id = msg.emote();
}
if (msg.has_aiming()) {
aiming = msg.aiming();
} else {
aiming = false;
}
if (msg.has_get_down()) {
get_down = msg.get_down();
}
if (msg.has_use_skill()) {
use_skill = msg.use_skill();
skill_target_id = msg.skill_target_id();
} else {
use_skill = false;
}
last_cmmove_frameno = room->GetFrameNo();
}
void Player::UpdateDropWeapon()
{
if (drop_weapon_idx >= 0 &&
drop_weapon_idx < weapons.size() &&
!HasBuffEffect(kBET_Terminator)) {
bool drop_ok = false;
Weapon* weapon = &weapons[drop_weapon_idx];
int weapon_id = weapon->weapon_id;
int weapon_lv = weapon->weapon_lv;
int weapon_ammo = weapon->ammo;
MetaData::Equip* weapon_meta = weapon->meta;
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 ||
drop_weapon_idx == FRAG_SLOT ||
drop_weapon_idx == SMOKE_SLOT
) {
a8::Vec2 dir = a8::Vec2::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(weapon_id, GetPos() + dir * (40 + rand() % 50), 1, weapon_lv);
}
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 &&
!(drop_weapon_idx == FRAG_SLOT || drop_weapon_idx == SMOKE_SLOT)) {
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 = GetPos() + drop_dir * (25 + rand() % 50);
if (bullet_meta->i->_inventory_slot() == IS_FRAG ||
bullet_meta->i->_inventory_slot() == IS_SMOKE) {
//只有手雷和烟雾弹会掉落
room->DropItem(drop_pos, bullet_meta->i->id(), drop_num, 1);
}
}
}
}
need_sync_active_player = true;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
}
}
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)
{
CancelRevive();
SendGameOver();
}
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(GetEntityUniId(), name, VW_Spectate);
}
leave_ = true;
leave_frameno_ = room->GetFrameNo();
}
cs::SMLeave respmsg;
SendNotifyMsg(respmsg);
}
void Player::_CMRevive(f8::MsgHdr& hdr, const cs::CMRevive& msg)
{
if (real_dead) {
SendGameOver();
return;
}
if (dead && !real_dead && revive_timer) {
dead = false;
real_dead = false;
downed = false;
FreeDownedTimer();
ability.hp = GetMaxHP();
SyncAroundPlayers(__FILE__, __LINE__, __func__);
FreeReviveTimer();
#if 1
{
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(kREVIVE_BUFF_ID);
if (buff_meta) {
AddBuff(this, buff_meta, 1);
}
}
#endif
InternalAdOk();
}
}
void Player::_CMCancelRevive(f8::MsgHdr& hdr, const cs::CMCancelRevive& msg)
{
CancelRevive();
}
void Player::_CMAdStart(f8::MsgHdr& hdr, const cs::CMAdStart& msg)
{
if (downed || dead) {
return;
}
if (GetBuffByEffectId(kBET_LordMode)) {
return;
}
if (GetBuffByEffectId(kBET_AdPlaying)) {
return;
}
if (a8::HasBitFlag(status, HS_AlreadyLordMode)) {
return;
}
if (ad_timer_) {
room->xtimer.DeleteTimer(ad_timer_);
ad_timer_ = nullptr;
}
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(ADPLAY_BUFFID);
if (buff_meta) {
AddBuff(this, buff_meta, 1);
room->xtimer.
AddDeadLineTimerAndAttach(
buff_meta->i->duration_time() * SERVER_FRAME_RATE + 2,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
Player* hum = (Player*)param.sender.GetUserData();
hum->InternalAdCancel();
},
&xtimer_attacher.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->ad_timer_ = nullptr;
}
);
}
}
void Player::_CMAdCancel(f8::MsgHdr& hdr, const cs::CMAdCancel& msg)
{
InternalAdCancel();
}
void Player::_CMAdEnd(f8::MsgHdr& hdr, const cs::CMAdEnd& msg)
{
if (GetBuffByEffectId(kBET_LordMode)) {
return;
}
InternalAdOk();
}
void Player::InternalAdCancel()
{
if (GetBuffByEffectId(kBET_AdPlaying)) {
RemoveBuffByEffectId(kBET_AdPlaying);
if (ad_timer_) {
room->xtimer.DeleteTimer(ad_timer_);
ad_timer_ = nullptr;
}
}
if (GetBuffByEffectId(kBET_LordMode)) {
return;
}
}
void Player::InternalAdOk()
{
if (a8::HasBitFlag(status, HS_AlreadyLordMode)) {
return;
}
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(ADPLAY_BUFFID);
if (buff_meta) {
MetaData::Buff* lord_buff_meta = nullptr;
if (rand() % 2 < 1) {
lord_buff_meta = MetaMgr::Instance()->GetBuff(buff_meta->param1);
} else {
lord_buff_meta = MetaMgr::Instance()->GetBuff(buff_meta->param2);
}
if (lord_buff_meta) {
a8::SetBitFlag(status, HS_AlreadyLordMode);
AddBuff(this, lord_buff_meta, 1);
std::vector<std::string> strings;
a8::Split(lord_buff_meta->i->buff_param1(), strings, ':');
for (auto& str : strings) {
int buff_id = a8::XValue(str);
MetaData::Buff* ext_buff_meta = MetaMgr::Instance()->GetBuff(buff_id);
if (ext_buff_meta) {
AddBuff(this, ext_buff_meta, 1);
}
}
}
}
RemoveBuffByEffectId(kBET_AdPlaying);
if (ad_timer_) {
room->xtimer.DeleteTimer(ad_timer_);
ad_timer_ = nullptr;
}
}
void Player::PushJoinRoomMsg()
{
{
cs::SMJoinedNotify notifymsg;
notifymsg.set_error_code(0);
notifymsg.set_room_mode((int)room->GetRoomMode());
notifymsg.set_server_info(JsonDataMgr::Instance()->server_info);
room->FillSMJoinedNotify(this, notifymsg);
GGListener::Instance()->SendToClient(socket_handle, 0, notifymsg);
}
{
cs::SMMapInfo notifymsg;
notifymsg.set_map_id(room->GetMapMeta()->i->map_id());
notifymsg.set_map_width(room->GetMapMeta()->i->map_width());
notifymsg.set_map_height(room->GetMapMeta()->i->map_height());
GGListener::Instance()->SendToClient(socket_handle, 0, notifymsg);
}
}
void Player::ProcPreSettlementInfo(const std::string& pre_settlement_info)
{
std::vector<std::string> tmp_strings;
a8::Split(pre_settlement_info, tmp_strings, ',');
if (tmp_strings.size() >= 4) {
game_times = a8::XValue(tmp_strings[0]);
win_times = a8::XValue(tmp_strings[1]);
kill_times = a8::XValue(tmp_strings[2]);
rank = a8::XValue(tmp_strings[3]);
}
}