aozhiwei 868c91ac11 1
2021-05-28 13:51:49 +08:00

3677 lines
117 KiB
C++

#include "precompile.h"
#include <float.h>
#include <a8/mutable_xobject.h>
#include <a8/collision.h>
#include "human.h"
#include "cs_proto.pb.h"
#include "metamgr.h"
#include "room.h"
#include "bullet.h"
#include "collider.h"
#include "loot.h"
#include "building.h"
#include "app.h"
#include "roommgr.h"
#include "android.h"
#include "gamelog.h"
#include "typeconvert.h"
#include "obstacle.h"
#include "roomobstacle.h"
#include "player.h"
#include "buff.h"
#include "car.h"
#include "roomobstacle.h"
#include "aicomponent.h"
#include "jsondatamgr.h"
#include "skill.h"
#include "incubator.h"
#include "framework/cpp/utils.h"
#include "framework/cpp/httpclientpool.h"
const int kReviveTimeAdd = 12;
const int kSkinNum = 4;
const int kREVIVE_BUFF_ID = 0;
Human::Human():Creature()
{
default_weapon.weapon_idx = 0;
default_weapon.weapon_id = 30101;
default_weapon.weapon_lv = 1;
default_weapon.ammo = 1;
default_weapon.meta = MetaMgr::Instance()->GetEquip(default_weapon.weapon_id);
default_weapon.Recalc();
for (int i = 0; i < kSkinNum; ++i) {
Skin& skin = a8::FastAppend(skins);
skin.skin_id = 0;
skin.skin_lv = 1;
}
weapons[0] = default_weapon;
SetCurrWeapon(&weapons[0]);
}
Human::~Human()
{
}
void Human::Initialize()
{
Creature::Initialize();
RecalcSelfCollider();
volume_ = meta->volume;
observers_.insert(this);
ability.hp = meta->i->health();
for (auto& weapon : spec_weapons) {
if (weapon.meta) {
ability.hp += weapon.meta ? weapon.GetAttrValue(kHAT_MaxHp) : 0;
}
}
}
float Human::GetSpeed()
{
{
Buff* buff = GetBuffByEffectId(kBET_JumpTo);
if (buff) {
return buff->meta->param2;
}
}
{
Buff* buff = GetBuffByEffectId(kBET_BePull);
if (buff) {
return buff->meta->param2;
}
}
if (downed) {
return meta->i->move_speed3();
} else {
if (shot_hold) {
if (GetCurrWeapon()->weapon_idx == GUN_SLOT1 ||
GetCurrWeapon()->weapon_idx == GUN_SLOT2) {
if (action_type != AT_Reload) {
return meta->i->shot_speed();
}
}
} else if (aiming) {
return std::max(1, meta->i->aiming_speed());
} else if (action_type != AT_None) {
return std::max(1, meta->i->reload_speed());
}
float speed = meta->i->move_speed();
speed = (speed + GetBuffAttrAbs(kHAT_Speed)) * (1 + GetBuffAttrRate(kHAT_Speed));
if (a8::HasBitFlag(cell_flags_, kColliderTag_Water)) {
speed *= MetaMgr::Instance()->water_move_coefficient;
}
return std::max(speed, 1.0f);
}
}
float Human::GetSpeed4()
{
return meta->i->move_speed4();
}
void Human::FillMFObjectPart(Room* room, Human* hum, cs::MFObjectPart* part_data)
{
part_data->set_object_type(ET_Player);
cs::MFPlayerPart* p = part_data->mutable_union_obj_1();
p->set_obj_uniid(GetEntityUniId());
p->set_speed(GetSpeed() * SERVER_FRAME_RATE);
TypeConvert::ToPb(GetPos(), p->mutable_pos());
TypeConvert::ToPb(GetAttackDir(), p->mutable_dir());
}
void Human::FillMFObjectLess(Room* room, Human* hum, cs::MFPlayerFull* full_data)
{
cs::MFPlayerFull* p = full_data;
p->set_obj_uniid(GetEntityUniId());
TypeConvert::ToPb(GetPos(), p->mutable_pos());
TypeConvert::ToPb(GetAttackDir(), p->mutable_dir());
p->set_health(GetHP());
p->set_max_health(GetMaxHP());
p->set_dead(dead);
p->set_downed(downed);
p->set_disconnected(disconnected);
p->set_anim_type(anim_type);
p->set_anim_seq(anim_seq);
for (auto itr : skins) {
auto skin = p->add_skin();
itr.ToPB(skin);
}
p->set_backpack(backpack);
p->set_helmet(helmet);
p->set_chest(chest);
p->set_shoot_offset_x(shoot_offset.x);
p->set_shoot_offset_y(shoot_offset.y);
GetCurrWeapon()->ToPB(p->mutable_weapon());
}
void Human::FillMFObjectFull(Room* room, Human* hum, cs::MFObjectFull* full_data)
{
full_data->set_object_type(ET_Player);
cs::MFPlayerFull* p = full_data->mutable_union_obj_1();
p->set_obj_uniid(GetEntityUniId());
TypeConvert::ToPb(GetPos(), p->mutable_pos());
TypeConvert::ToPb(GetAttackDir(), p->mutable_dir());
p->set_health(GetHP());
p->set_max_health(GetMaxHP());
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_speed(GetSpeed() * SERVER_FRAME_RATE);
for (auto itr : skins) {
auto skin = p->add_skin();
itr.ToPB(skin);
}
p->set_backpack(backpack);
p->set_helmet(helmet);
p->set_chest(chest);
GetCurrWeapon()->ToPB(p->mutable_weapon());
p->set_energy_shield(energy_shield);
p->set_shoot_offset_x(shoot_offset.x);
p->set_shoot_offset_y(shoot_offset.y);
#if 1
{
p->set_max_energy_shield(max_energy_shield);
}
#endif
if (guild_id != 0) {
p->set_guild_id(guild_id);
}
if (vip_lv != 0) {
p->set_vip_lv(vip_lv);
}
if (head != 0) {
p->set_head(head);
}
if (sex != 0) {
p->set_sex(sex);
}
if (!user_data.empty()) {
p->set_user_data(user_data);
}
p->set_vip(vip);
p->set_sdmg(sdmg);
p->set_kill_count(stats.kills);
if (emoji1 != 0) {
p->set_emoji1(emoji1);
}
if (emoji2 != 0) {
p->set_emoji2(emoji2);
}
if (parachute != 0) {
p->set_parachute(parachute);
}
FillBodyState(p->mutable_states());
FillBuffList(hum, p->mutable_buff_list());
FillSkillList(p->mutable_skill_list());
if (dead) {
p->set_killer_name(stats.killer_name);
p->set_killer_id(stats.killer_id);
if (real_dead){
p->set_can_revive(false);
} else {
p->set_can_revive(true);
int countdown = 0;
if (revive_timer) {
countdown = std::ceil(room->xtimer.GetRemainTime(revive_timer) / SERVER_FRAME_RATE);
} else {
a8::UdpLog::Instance()->Warning("Human::FillMFObjectfull revive_timer == nullptr "
"dead_frameno:%d dead_times:%d alive_count:%d "
"room.frameno:%d",
{
dead_frameno,
dead_times,
room->AliveCount(),
room->GetFrameNo()
});
}
countdown = std::max(0, countdown - kReviveTimeAdd);
p->set_revive_countdown(countdown);
}
}
if (room->GetRoomMode() == kZombieMode) {
p->set_charid(meta->i->id());
}
if (GetCar()) {
p->set_car_uniid(GetCar()->car_uniid);
p->set_car_seat(GetSeat());
} else {
p->set_car_uniid(0);
p->set_car_seat(0);
}
}
void Human::FillMFPlayerStats(cs::MFPlayerStats* stats_pb)
{
stats_pb->set_player_id(GetEntityUniId());
stats_pb->set_player_avatar_url(avatar_url);
stats_pb->set_charid(meta->i->id());
stats_pb->set_team_id(team_id);
stats_pb->set_nickname(name);
if (!dead) {
stats_pb->set_time_alive(room->GetFrameNo() * 1000.0f / SERVER_FRAME_RATE);
} else {
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_out);
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_pass_score(stats.pass_score);
stats_pb->set_rank_score(stats.rank_score);
stats_pb->set_has_pass(has_pass);
stats_pb->set_dead(dead);
stats_pb->set_killer_id(stats.killer_id);
stats_pb->set_killer_name(stats.killer_name);
{
Player* killer = room->GetPlayerByUniId(stats.killer_id);
if (killer) {
stats_pb->set_killer_avatar_url(killer->avatar_url);
stats_pb->set_killer_account_id(killer->account_id);
} else {
stats_pb->set_killer_avatar_url("");
stats_pb->set_killer_account_id("");
}
}
stats_pb->set_account_id(account_id);
if (guild_id != 0) {
stats_pb->set_guild_id(guild_id);
}
stats_pb->set_rescue_guild_member(stats.rescue_guild_member);
for (auto& pair : stats.items) {
auto p = stats_pb->add_items();
p->set_key(pair.first);
p->set_value(pair.second);
}
for (auto& pair : stats.extra_drop) {
auto p = stats_pb->add_extra_drop();
p->set_key(pair.first);
p->set_value(pair.second);
}
if (vip_lv != 0) {
stats_pb->set_vip_lv(vip_lv);
}
if (head != 0) {
stats_pb->set_head(head);
}
if (sex != 0) {
stats_pb->set_sex(sex);
}
{
for (auto& skin : skins) {
auto pb_skin = stats_pb->add_skin();
skin.ToPB(pb_skin);
}
}
}
void Human::GetAabbBox(AabbCollider& aabb_box)
{
if (!meta) {
abort();
}
aabb_box.active = true;
aabb_box.owner = this;
if (GetCar() && GetCar()->IsDriver(this)) {
aabb_box._min.x = -GetCar()->meta->i->rad();
aabb_box._min.y = -GetCar()->meta->i->rad();
aabb_box._max.x = GetCar()->meta->i->rad();
aabb_box._max.y = GetCar()->meta->i->rad();
} else {
aabb_box._min.x = -meta->i->radius();
aabb_box._min.y = -meta->i->radius();
aabb_box._max.x = meta->i->radius();
aabb_box._max.y = meta->i->radius();
}
}
bool Human::IsDead(Room * room)
{
return dead;
}
long long Human::GetDeadFrameNo(Room* room)
{
return dead_frameno;
}
void Human::FillItemList(::google::protobuf::RepeatedPtrField<::cs::MFPair>* pb_item_list)
{
for (auto& pair : items_) {
auto p = pb_item_list->Add();
p->set_key(pair.first);
p->set_value(pair.second);
}
}
long long Human::GetRealDeadFrameNo(Room* room)
{
return real_dead_frameno;
}
void Human::FillMFTeamData(cs::MFTeamData* team_data, bool is_game_over)
{
{
last_sync_teamdata_frameno_ = room->GetFrameNo();
team_data->set_player_id(GetEntityUniId());
if (is_game_over || !real_dead || room->GetFrameNo() - GetRealDeadFrameNo(room) < 4) {
TypeConvert::ToPb(GetPos(), team_data->mutable_pos());
TypeConvert::ToPb(GetAttackDir(), team_data->mutable_dir());
team_data->set_health(GetHP());
team_data->set_max_health(GetMaxHP());
team_data->set_dead(dead);
team_data->set_downed(downed);
}
if (is_game_over || room->GetGasData().gas_mode == GasInactive) {
team_data->set_name(name);
}
if (room->GetGasData().gas_mode != GasInactive &&
room->GetFrameNo() - room->GetBattleStartFrameNo() < 4) {
team_data->set_name(name);
team_data->set_disconnected(socket_handle == 0);
}
if (is_game_over) {
team_data->set_account_id(account_id);
team_data->set_avatar_url(avatar_url);
team_data->set_user_value1(user_value1);
team_data->set_user_value2(user_value2);
team_data->set_user_value3(user_value3);
if (guild_id != 0) {
team_data->set_guild_id(guild_id);
}
}
if (vip_lv != 0) {
team_data->set_vip_lv(vip_lv);
}
if (head != 0) {
team_data->set_head(head);
}
if (sex != 0) {
team_data->set_sex(sex);
}
if (room->GetGasData().gas_mode == GasInactive ||
room->GetFrameNo() - room->GetBattleStartFrameNo() < 4) {
team_data->set_user_data(user_data);
}
}
}
void Human::CarShot(const a8::Vec2& target_dir)
{
if (!second_weapon.meta) {
return;
}
if (second_weapon.weapon_idx != 0 &&
second_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,
second_weapon.meta,
second_weapon.GetUpgradeMeta(),
second_weapon.bullet_meta,
second_weapon.weapon_lv,
0,
5,
false);
--second_weapon.ammo;
last_shot_frameno_ = room->GetFrameNo();
}
void Human::RecalcSelfCollider()
{
if (!self_collider_) {
self_collider_ = new CircleCollider();
self_collider_->owner = this;
AddEntityCollider(self_collider_);
}
self_collider_->pos = a8::Vec2();
self_collider_->rad = meta->i->radius();
Buff* buff = GetBuffByEffectId(kBET_Car);
if (buff) {
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquip(buff->meta->param4);
if (equip_meta &&
equip_meta->i->rad() > 1 &&
equip_meta->i->equip_type() == EQUIP_TYPE_CAR
) {
self_collider_->rad = equip_meta->i->rad();
}
}
}
bool Human::IsCollisionInMapService()
{
Global::last_collider = nullptr;
if (room->OverBorder(GetPos(), meta->i->radius())){
return true;
}
if (HasBuffEffect(kBET_ThroughWall) ||
HasBuffEffect(kBET_Fly)) {
return false;
}
std::set<ColliderComponent*> colliders;
room->map_service->GetColliders(room, GetX(), GetY(), colliders);
AabbCollider aabb_box;
GetAabbBox(aabb_box);
for (ColliderComponent* collider : colliders) {
switch (collider->owner->GetEntityType()) {
case ET_Obstacle:
{
Obstacle* obstacle = (Obstacle*)collider->owner;
if (!obstacle->IsDead(room) &&
(
(collider->type == CT_Aabb && aabb_box.Intersect((ColliderComponent*)collider)) ||
(collider->type == CT_Circle && self_collider_->Intersect((ColliderComponent*)collider))
) &&
!obstacle->CanThroughable(this)) {
if (last_collision_door_ != collider->owner) {
if (!obstacle->IsDead(room) &&
obstacle->Attackable() &&
obstacle->meta->i->drop() != 0 &&
room->GetGasData().gas_mode != GasInactive &&
(!obstacle->IsTerminatorAirDropBox(room) || GetRace() == kHumanRace)
) {
obstacle->Die(room);
if (obstacle->IsDead(room)) {
#if 0
if (obstacle->meta->i->damage_dia() > 0.01f &&
obstacle->meta->i->damage() > 0.01f) {
obstacle->Explosion(this);
}
#endif
DropItems(obstacle);
}
obstacle->BroadcastFullState(room);
if (obstacle->IsTerminatorAirDropBox(room) &&
GetRace() == kHumanRace &&
!HasBuffEffect(kBET_Terminator)) {
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(TERMINATOR_BUFF_ID);
if (buff_meta) {
AddBuff(this, buff_meta, 1);
}
}
} else {
Global::last_collider = collider;
return true;
}
}
}
}
break;
case ET_Building:
{
#if 1
if (
(
(collider->type == CT_Aabb && aabb_box.Intersect((ColliderComponent*)collider)) ||
(collider->type == CT_Circle && self_collider_->Intersect((ColliderComponent*)collider))
)
) {
#else
if (!collider->owner->dead && TestCollision((ColliderComponent*)collider)) {
#endif
if (last_collision_door_ != collider->owner) {
Global::last_collider = collider;
return true;
}
}
}
break;
default:
break;
}
}
return false;
}
void Human::FindPathInMapService()
{
a8::Vec2 old_pos = GetPos();
ColliderComponent* last_collider = Global::last_collider;
if (last_collider) {
switch (last_collider->type) {
case CT_Aabb:
{
}
break;
case CT_Circle:
{
a8::Vec2 extend_dir = GetPos() - last_collider->owner->GetPos();
if (std::abs(extend_dir.x) > FLT_EPSILON ||
std::abs(extend_dir.y) > FLT_EPSILON) {
extend_dir.Normalize();
{
#if 0
a8::Vec2 extend_dir_inverse(extend_dir.y, extend_dir.x);
float angle = extend_dir_inverse.CalcAngle(move_dir);
if (angle > 0.001f) {
extend_dir.Rotate(-1/180.0f);
} else {
extend_dir.Rotate(1/180.0f);
}
#endif
extend_dir.Rotate(1/180.0f);
}
float distance = ((CircleCollider*)last_collider)->rad + meta->i->radius();
SetPos(last_collider->owner->GetPos() + extend_dir * (distance + 1));
if (IsCollisionInMapService()) {
SetPos(old_pos);
}
}
return;
}
break;
default:
break;
}
}
{
float up_dot = a8::Vec2::UP.Dot(GetMoveDir());
bool at_left_side = a8::Vec2::LEFT.Dot(GetMoveDir()) > 0.0001f;
if (std::abs(up_dot) <= 0.001f) { //相互垂直
//向上
SetPos(old_pos + a8::Vec2::UP);
if (!IsCollisionInMapService()) {
return;
} else {
//向下
SetPos(old_pos + a8::Vec2::DOWN);
if (!IsCollisionInMapService()) {
return;
}
}
} else if (up_dot > 0.001f) { //基本相同
SetPos(old_pos + (at_left_side ? a8::Vec2::LEFT : a8::Vec2::RIGHT));
if (!IsCollisionInMapService()) {
return;
} else {
//向上
SetPos(old_pos + a8::Vec2::UP);
if (!IsCollisionInMapService()) {
return;
}
}
} else if (up_dot < 0.001f) { //基本相反
SetPos(old_pos + (at_left_side ? a8::Vec2::LEFT : a8::Vec2::RIGHT));
if (!IsCollisionInMapService()) {
return;
} else {
//向下
SetPos(old_pos + a8::Vec2::DOWN);
if (!IsCollisionInMapService()) {
return;
}
}
}
}
SetPos(old_pos);
}
void Human::FillSMGameOver(cs::SMGameOver& msg)
{
if (stats.rank <= 0) {
std::vector<Human*> human_list;
room->TraverseHumanList(a8::XParams(),
[&human_list] (Human* hum, a8::XParams& param) -> bool
{
if (hum->leave_frameno_ == 0 ||
hum->leave_frameno_ > hum->room->GetBattleStartFrameNo()) {
human_list.push_back(hum);
}
return true;
});
std::sort(human_list.begin(), human_list.end(),
[] (Human* a, Human* b )
{
if (a->real_dead && b->real_dead) {
if (a->dead_frameno == b->dead_frameno) {
return a->GetEntityUniId() < b->GetEntityUniId();
} else {
return a->dead_frameno == 0 ||
(b->dead_frameno != 0 && a->dead_frameno > b->dead_frameno);
}
} else {
if (a->real_dead) {
return false;
}
if (b->real_dead) {
return true;
}
return a->GetEntityUniId() < b->GetEntityUniId();
}
});
int rank = human_list.size();
for (size_t i = 0; i < human_list.size(); ++i) {
if (human_list[i] == this) {
rank = i + 1;
break;
}
}
if (room->GetAliveTeamNum() == 1) {
std::set<Human*>* alive_team = room->GetAliveTeam();
if (alive_team == team_members) {
rank = 1;
}
}
stats.rank = rank;
}
msg.set_team_id(team_id);
msg.set_team_rank(stats.rank);
msg.set_team_allcnt(1);
msg.set_game_over(room->IsGameOver());
msg.set_victory(!dead);
msg.set_room_uuid(a8::XValue(room->GetRoomUuid()));
msg.set_total_human_num(room->GetHumanNum());
msg.set_alive_human_num(room->AliveCount());
{
for (auto& itr : *team_members) {
if (itr != this) {
itr->FillMFTeamData(msg.add_team_data(), true);
}
}
}
{
cs::MFPlayerStats* p = msg.add_player_stats();
FillMFPlayerStats(p);
}
{
for (auto& pair : spoils_items) {
auto p = msg.add_spoils_items();
p->add_values(pair.first);
p->add_values(pair.second);
}
}
}
void Human::BeKill(int killer_id, const std::string& killer_name, int weapon_id)
{
#ifdef DEBUG
room->CheckPartObjects();
#endif
if (!dead && !room->IsGameOver() && !real_dead) {
lethal_weapon = weapon_id;
Entity* hum = room->GetEntityByUniId(killer_id);
if (hum && hum->IsEntityType(ET_Player)) {
Creature* killer = (Creature*)hum;
if (killer_id == GetEntityUniId()) {
std::string msg = a8::Format(TEXT("battle_server_dead_specate", "%s 自杀").c_str(),
{
killer_name,
});
SendRollMsg(msg, killer->GetEntityUniId(), killer->team_id);
} else {
((Human*)hum)->stats.kills++;
((Human*)hum)->stats.last_kill_frameno = room->GetFrameNo();
((Human*)hum)->kill_humans.insert(this);
((Human*)hum)->SyncAroundPlayers(__FILE__, __LINE__, __func__);
if (weapon_id == VW_Tank) {
std::string msg = a8::Format(TEXT("battle_server_dead_car", "%s 使用 载具 干掉了 %s").c_str(),
{
killer_name,
name
});
SendRollMsg(msg, killer->GetEntityUniId(), killer->team_id);
} else {
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquip(weapon_id);
if (equip_meta) {
std::string msg = a8::Format(TEXT("battle_server_dead_weapon", "%s 使用 %s 干掉了 %s").c_str(),
{
killer_name,
equip_meta->i->name(),
name
});
SendRollMsg(msg, killer->GetEntityUniId(), killer->team_id);
}
}
}
} else {
switch (weapon_id) {
case VW_SafeArea:
{
std::string msg = a8::Format(TEXT("battle_server_dead_gas", "%s 被毒圈干掉").c_str(),
{
name
});
SendRollMsg(msg, 0, 0);
}
break;
case VW_Spectate:
{
std::string msg = a8::Format(TEXT("battle_server_dead_specate", "%s 自杀").c_str(),
{
name
});
SendRollMsg(msg, 0, 0);
}
break;
case VW_SelfDetonate:
{
std::string msg = a8::Format(TEXT("battle_server_dead_self_detonate", "%s 被炸死").c_str(),
{
name
});
SendRollMsg(msg, 0, 0);
}
break;
case VW_Mine:
{
std::string msg = a8::Format(TEXT("battle_server_dead_mine", "%s 被地雷炸死").c_str(),
{
name
});
SendRollMsg(msg, 0, 0);
}
break;
}
}
++stats.dead_times;
stats.killer_id = killer_id;
stats.killer_name = killer_name;
stats.weapon_id = weapon_id;
if (room->GetRoomMode() == kZombieMode) {
dead = true;
downed = false;
real_dead = true;
dead_frameno = room->GetFrameNo();
DoGetDown();
if (HasBuffEffect(kBET_Camouflage)) {
RemoveBuffByEffectId(kBET_Camouflage);
}
ClearLordMode();
ClearBuffList();
room->frame_event.AddDead(GetWeakPtrRef(),
meta->i->revive_time() * 1000);
SyncAroundPlayers(__FILE__, __LINE__, __func__);
room->xtimer.AddDeadLineTimerAndAttach
(meta->i->revive_time() * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->Revive();
},
&xtimer_attacher.timer_list_
);
room->OnHumanDie(this);
} else {
dead = true;
downed = false;
ability.hp = 0.0f;
dead_frameno = room->GetFrameNo();
++dead_times;
if (HasBuffEffect(kBET_Camouflage)) {
RemoveBuffByEffectId(kBET_Camouflage);
}
ClearLordMode();
room->frame_event.AddDead(GetWeakPtrRef(),
0);
#ifdef DEBUG
room->CheckPartObjects();
#endif
#if 1
real_dead = true;
OnDie();
#else
int max_revive_times = MetaMgr::Instance()->GetSysParamAsInt("max_revive_times", 1);
if (weapon_id != VW_Spectate &&
dead_times <= max_revive_times &&
room->AliveCount() >= 5 &&
IsEntitySubType(EST_Player)) {
Revive();
} else {
real_dead = true;
OnDie();
}
#endif
DoGetDown();
}
}
}
void Human::DecHP(float dec_hp, int killer_id, const std::string& killer_name, int weapon_id)
{
#ifdef DEBUG
#if 0
if (IsPlayer()) {
return;
}
#endif
#endif
{
Buff* buff = GetBuffByEffectId(kBET_Shield);
if (buff) {
dec_hp = std::max((float)1.0, dec_hp - buff->meta->param2);
}
}
auto downed_func =
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
if (!hum->downed) {
hum->FreeDownedTimer();
return;
}
if (hum->dead) {
hum->FreeDownedTimer();
return;
}
if (!hum->HasLiveTeammate()) {
hum->FreeDownedTimer();
hum->BeKill(param.param1, param.param2, param.param3);
return;
}
int dec_hp = MetaMgr::Instance()->GetSysParamAsInt("downed_dec_hp");
hum->DecHP(dec_hp, param.param1, param.param2, param.param3);
};
if (energy_shield > 0.001f) {
energy_shield = std::max(0.0f, energy_shield - dec_hp);
SyncAroundPlayers(__FILE__, __LINE__, __func__);
} else {
float old_health = GetHP();
float new_health = std::max(0.0f, GetHP() - dec_hp);
AdjustDecHp(old_health, new_health);
ability.hp = std::max(0.0f, new_health);
if (GetHP() - old_health > 0.001f) {
stats.damage_amount_in += GetHP() - old_health;
}
if (GetHP() <= 0.0001f && !dead) {
if (downed) {
if (downed_timer) {
room->xtimer.DeleteTimer(downed_timer);
}
downed = false;
downed_timer = nullptr;
BeKill(killer_id, killer_name, weapon_id);
SyncAroundPlayers(__FILE__, __LINE__, __func__);
} else {
if (HasNoDownedTeammate()) {
ability.hp = MetaMgr::Instance()->GetSysParamAsInt("downed_recover_hp");
downed = true;
if (HasBuffEffect(kBET_Camouflage)) {
RemoveBuffByEffectId(kBET_Camouflage);
}
CancelAction();
DoGetDown();
downed_timer = room->xtimer.AddRepeatTimerAndAttach
(
SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this)
.SetParam1(killer_id)
.SetParam2(killer_name)
.SetParam3(weapon_id),
downed_func,
&xtimer_attacher.timer_list_
);
SyncAroundPlayers(__FILE__, __LINE__, __func__);
if (GetNearbyTeammateNum(MetaMgr::Instance()->refresh_ai_downed_nearby_range) <
MetaMgr::Instance()->refresh_ai_downed_nearby_teammate_num) {
#if 0
room->GetIncubator()->AllocAndroid(this, 1 + rand() % 2);
#endif
}
} else {
BeKill(killer_id, killer_name, weapon_id);
}
}
}
room->frame_event.AddHpChg(GetWeakPtrRef());
}
}
void Human::AddToNewObjects(Entity* entity)
{
new_objects.insert(entity);
}
void Human::AddToPartObjects(Entity* entity)
{
PartObject part_obj;
part_obj.entity_uniid = entity->GetEntityUniId();
part_obj.entity_type = entity->GetEntityType();
part_obj.entity_subtype = entity->GetEntitySubType();
part_obj.add_frameno = room->GetFrameNo();
part_objects[entity] = part_obj;
entity->OnAddToTargetPartObject(this);
}
void Human::RemovePartObjects(Entity* entity)
{
part_objects.erase(entity);
entity->OnRemoveFromTargetPartObject(this);
}
void Human::ClearPartObjects()
{
part_objects.clear();
}
int Human::GetPartObjectsCount()
{
return part_objects.size();
}
bool Human::InNewObjects(Entity* target)
{
return new_objects.find(target) != new_objects.end();
}
bool Human::InPartObjects(Entity* target)
{
return part_objects.find(target) != part_objects.end();
}
void Human::RemoveObjects(Entity* entity)
{
del_objects.insert(entity->GetEntityUniId());
}
void Human::AddOutObjects(Entity* entity)
{
out_objects.insert(entity->GetEntityUniId());
}
void Human::RemoveOutObjects(Entity* entity)
{
out_objects.erase(entity->GetEntityUniId());
}
bool Human::HasLiveTeammate()
{
if (room->GetRoomMode() == kZombieMode) {
return true;
}
if (team_members) {
for (auto& hum : *team_members) {
if (hum != this && !hum->dead) {
return true;
}
}
}
return false;
}
bool Human::HasNoDownedTeammate()
{
if (room->GetRoomMode() == kZombieMode) {
if (GetRace() == kHumanRace) {
bool has_now_downed_teammate = false;
Human* myself = this;
room->TraverseHumanList
(
a8::XParams(),
[myself, &has_now_downed_teammate] (Human* hum, const a8::XParams& param)
{
if (myself != hum &&
!hum->dead &&
!hum->downed &&
hum->GetRace() == kHumanRace) {
has_now_downed_teammate = true;
return false;
}
return true;
}
);
return has_now_downed_teammate;
} else {
return false;
}
}
if (team_members) {
for (auto& hum : *team_members) {
if (hum != this && !hum->dead && !hum->downed) {
return true;
}
}
}
return false;
}
int Human::GetNearbyTeammateNum(float range)
{
int num = 0;
if (team_members) {
for (auto& hum : *team_members) {
if (hum != this && !hum->dead && !hum->downed) {
if (hum->GetPos().Distance(GetPos()) <= range) {
++num;
}
}
}
}
return num;
}
bool Human::CanUseSkill(int skill_id)
{
return !downed && Creature::CanUseSkill(skill_id);
}
void Human::DoJump()
{
if (HasBuffEffect(kBET_Fly)) {
a8::UnSetBitFlag(status, HS_DisableAttack);
RemoveBuffByEffectId(kBET_Fly);
MustBeAddBuff(this, kThroughWall_BUFFID);
MustBeAddBuff(this, JUMP_BUFFID);
jump_frameno_ = room->GetFrameNo();
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
}
Skill* Human::SelectSkill()
{
return nullptr;
}
void Human::DoGetOn(int obj_uniid)
{
if (room->GetGasData().gas_mode == GasInactive) {
return;
}
Entity* entity = room->GetEntityByUniId(obj_uniid);
if (!entity) {
return;
}
if (GetPos().Distance(entity->GetPos()) > MetaMgr::Instance()->max_mount_horse_distance) {
return;
}
if (downed) {
return;
}
switch (entity->GetEntityType()) {
case ET_Loot:
{
DoGetOnWithLoot((Loot*)entity);
}
break;
case ET_Car:
{
DoGetOnWithCar((Car*)entity);
}
break;
default:
break;
}
}
void Human::FindLocation()
{
Entity* target = nullptr;
TraverseAllLayerEntityList
(
[this, &target] (Entity* entity, bool& stop)
{
switch (entity->GetEntityType()) {
case ET_Obstacle:
{
if (!target) {
if (TestCollision(room, entity)) {
target = entity;
}
}
}
break;
case ET_Building:
{
if (!target || !target->IsEntityType(ET_Building)) {
AabbCollider aabb_box;
entity->GetAabbBox(aabb_box);
if (TestCollision(room, &aabb_box)) {
target = entity;
}
}
}
break;
default:
{
}
break;
}
});
if (target) {
FindLocationWithTarget(target);
}
}
void Human::RefreshView()
{
TraverseAllLayerHumanList
(
[this] (Human* hum, bool& stop)
{
hum->AddToNewObjects(this);
hum->AddToPartObjects(this);
AddToNewObjects(hum);
AddToPartObjects(hum);
});
TraverseAllLayerEntityList
(
[this] (Entity* entity, bool& stop)
{
switch (entity->GetEntityType()) {
case ET_Building:
case ET_Obstacle:
case ET_Loot:
{
AddToNewObjects(entity);
}
break;
default:
{
}
break;
}
});
}
void Human::OnGridListChange(std::set<GridCell*>& old_grids,
std::set<GridCell*>& inc_grids,
std::set<GridCell*>& dec_grids
)
{
ProcIncGridList(old_grids, inc_grids, dec_grids);
ProcDecGridList(old_grids, inc_grids, dec_grids);
if (IsPlayer() && on_grid_chg) {
on_grid_chg(this);
}
}
void Human::SyncAroundPlayers(const char* file, int line, const char* func)
{
#if 0
if (a8::HasBitFlag(status, HS_Disable)) {
return;
}
#endif
#ifdef DEBUG
#if 0
room->CheckPartObjects();
a8::UdpLog::Instance()->Debug("room_idx:%d syncaround begin %s %d %s",
{
room->GetRoomIdx(),
file,
line,
func
});
#endif
#endif
TraverseAllLayerHumanList
(
[this, file, line, func] (Human* hum, bool& stop)
{
hum->AddToNewObjects(this);
#ifdef DEBUG
#if 0
{
std::string objs_str;
for (auto& obj : hum->part_objects) {
objs_str += a8::Format("%d ", {(long long)obj});
}
a8::UdpLog::Instance()->Debug("hum1 %d %s", {(long long)hum, objs_str});
}
{
std::string objs_str;
for (auto& obj : part_objects) {
objs_str += a8::Format("%d ", {(long long)obj});
}
a8::UdpLog::Instance()->Debug("hum2 %d %s", {(long long)this, objs_str});
}
room->CheckPartObjects(hum, this);
hum->InPartObjects(this);
#endif
#endif
assert(hum->InPartObjects(this));
if (!hum->InPartObjects(this)) {
static long long last_debugout_tick = 0;
if (a8::XGetTickCount() - last_debugout_tick > 1000 * 10) {
last_debugout_tick = a8::XGetTickCount();
a8::UdpLog::Instance()->Warning
("SyncAroundPlayers error room_idx:%d, file:%s line:%d func:%s",
{
room->GetRoomIdx(),
file,
line,
func
});
}
}
});
#ifdef DEBUG
#if 0
room->CheckPartObjects();
a8::UdpLog::Instance()->Debug("syncaround end %s %d %s",
{
file,
line,
func
});
#endif
#endif
}
void Human::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->GetFrameNo() - 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);
}
}
#if 1
for (auto itr : skins) {
auto skin = player_data->add_skin();
itr.ToPB(skin);
}
#else
skin.ToPB(player_data->mutable_skin());
#endif
player_data->set_backpack(backpack);
player_data->set_helmet(helmet);
player_data->set_chest(chest);
player_data->set_health(GetHP());
player_data->set_max_health(GetMaxHP());
player_data->set_cur_weapon_idx(GetCurrWeapon()->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 : GetInventoryData()) {
player_data->add_inventory(num);
}
player_data->set_energy_shield(energy_shield);
#if 1
{
player_data->set_max_energy_shield(max_energy_shield);
}
#endif
FillBodyState(player_data->mutable_states());
FillItemList(player_data->mutable_items());
FillSkillList(player_data->mutable_skill_list());
player_data->set_shoot_offset_x(shoot_offset.x);
player_data->set_shoot_offset_y(shoot_offset.y);
}
void Human::FillMFGasData(cs::MFGasData* gas_data)
{
gas_data->set_mode(room->GetGasData().gas_mode);
if (room->GetGasData().gas_mode == GasInactive) {
long long duration = room->GetGasInactiveTime() * SERVER_FRAME_RATE -
(room->GetFrameNo() - room->GetGasData().gas_start_frameno);
gas_data->set_duration(std::max(duration * 50, (long long)1000) / 1000);
} else if (room->GetGasData().gas_mode == GasJump) {
gas_data->set_duration(0);
} else if (room->GetGasData().gas_mode == GasMoving) {
if (room->GetGasData().new_area_meta->i->shrink_speed() > 0.01f) {
long long duration = (room->GetGasData().old_area_meta->i->rad() - room->GetGasData().new_area_meta->i->rad()) /
room->GetGasData().new_area_meta->i->shrink_speed();
++duration;
gas_data->set_duration(++duration);
} else {
gas_data->set_duration(0);
}
} else {
if (room->GetGasData().old_area_meta->i->wait_time() <= 0) {
gas_data->set_duration(0);
} else {
long long duration = room->GetGasData().old_area_meta->i->wait_time() * 20 -
(room->GetFrameNo() - room->GetGasData().gas_start_frameno);
gas_data->set_duration(std::max(duration * 50, (long long)1000) / 1000);
}
}
TypeConvert::ToPb(room->GetGasData().pos_old, gas_data->mutable_pos_old());
TypeConvert::ToPb(room->GetGasData().pos_new, gas_data->mutable_pos_new());
gas_data->set_rad_old(room->GetGasData().rad_old);
gas_data->set_rad_new(room->GetGasData().rad_new);
}
void Human::RecalcVolume()
{
MetaData::Equip* backpack_meta = MetaMgr::Instance()->GetEquip(backpack);
if (backpack_meta) {
for (size_t i = 0; i < backpack_meta->volume.size(); ++i) {
volume_[i] = meta->volume[i] + backpack_meta->volume[i];
}
}
}
void Human::RecalcBaseAttr()
{
ability.def = meta->i->def();
MetaData::Equip* chest_meta = MetaMgr::Instance()->GetEquip(chest);
if (chest_meta) {
ability.def += chest_meta->i->def();
}
MetaData::Equip* helmet_meta = MetaMgr::Instance()->GetEquip(helmet);
if (helmet_meta) {
ability.def += helmet_meta->i->def();
}
ability.max_hp = std::max(ability.hp, ability.max_hp);
}
int Human::GetVolume(int slot_id)
{
if (!IsValidSlotId(slot_id)) {
abort();
}
return volume_[slot_id];
}
void Human::RecoverHp(int inc_hp)
{
if (!dead) {
ability.hp += inc_hp;
ability.hp = std::max(GetHP(), GetMaxHP());
}
}
void Human::FillBodyState(::google::protobuf::RepeatedPtrField<::cs::MFBodyState>* states)
{
if (pain_killer_timer) {
int passed_time = (room->GetFrameNo() - 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* state = states->Add();
state->set_state_type(1);
state->set_left_time(left_time);
state->set_lasting_time(anodyne_max_time * 1000);
}
}
void Human::AddObserver(Human* observer)
{
observers_.insert(observer);
}
void Human::RemoveObserver(Human* observer)
{
observers_.erase(observer);
}
void Human::SendUpdateMsg()
{
if (!follow_target_ && !a8::HasBitFlag(status, HS_Disable) && IsPlayer()) {
#ifdef DEBUG
long long begin_tick = a8::XGetTickCount();
long long end_tick = a8::XGetTickCount();
#endif
cs::MFActivePlayerData* active_player_data_pb = nullptr;
if (send_msg_times == 0 || need_sync_active_player) {
active_player_data_pb = new cs::MFActivePlayerData();
FillMFActivePlayerData(active_player_data_pb);
need_sync_active_player = false;
}
#ifdef DEBUG
end_tick = a8::XGetTickCount();
if (a8::XGetTickCount() - begin_tick > 1000) {
abort();
}
begin_tick = a8::XGetTickCount();
#endif
cs::SMUpdate* msg = room->frame_maker.MakeUpdateMsg(this);
if (send_msg_times == 0 || last_sync_gas_frameno < room->GetGasData().gas_start_frameno) {
last_sync_gas_frameno = room->GetGasData().gas_start_frameno;
FillMFGasData(msg->mutable_gas_data());
}
#ifdef DEBUG
end_tick = a8::XGetTickCount();
if (a8::XGetTickCount() - begin_tick > 1000) {
abort();
}
begin_tick = a8::XGetTickCount();
#endif
NotifyObservers(msg, active_player_data_pb);
delete msg;
if (active_player_data_pb) {
delete active_player_data_pb;
}
++send_msg_times;
} else {
need_sync_active_player = false;
}
ClearFrameData();
}
void Human::SendGameOver()
{
if (IsEntitySubType(EST_Player)) {
//!!!必须要在SendNotifyMsg之前注意哦
if (!sent_battlereport_) {
SendBattleReport();
sent_battlereport_ = true;
GameLog::Instance()->GameEnd((Player*)this);
}
{
cs::SMGameOver msg;
FillSMGameOver(msg);
SendNotifyMsg(msg);
}
}
}
void Human::FollowTarget(Human* target)
{
if (target == this) {
return;
}
if (follow_target_) {
follow_target_->RemoveObserver(this);
}
target->AddObserver(this);
follow_target_ = target;
follow_synced_active_player = false;
}
void Human::SendDebugMsg(const std::string& debug_msg)
{
cs::SMDebugMsg notify_msg;
notify_msg.set_debug_msg(debug_msg);
SendNotifyMsg(notify_msg);
}
void Human::SendRollMsg(const std::string& msg, int killer_id, bool killer_team_id)
{
room->xtimer.AddDeadLineTimerAndAttach
(
0,
a8::XParams()
.SetSender(this)
.SetParam1(killer_id)
.SetParam2(killer_team_id)
.SetParam3(msg),
[] (const a8::XParams& param)
{
Human* target = (Human*)param.sender.GetUserData();
int killer_id = param.param1;
int killer_team_id = param.param2;
std::string text = param.param3.GetString();
target->room->TraversePlayerList
(a8::XParams(),
[target, killer_id, killer_team_id, text] (Human* hum, a8::XParams& param) -> bool
{
cs::SMRollMsg msg;
auto element = msg.add_elements();
element->set_element_type(1);
element->mutable_union_obj_1()->set_text(text);
if (killer_id == hum->GetEntityUniId()){
element->mutable_union_obj_1()->set_color(MetaMgr::Instance()->self_kill_color);
} else if (killer_team_id == hum->team_id) {
element->mutable_union_obj_1()->set_color(MetaMgr::Instance()->teammate_kill_color);
} else if (target == hum) {
element->mutable_union_obj_1()->set_color(MetaMgr::Instance()->self_bekill_color);
} else if (target->team_id == hum->team_id) {
element->mutable_union_obj_1()->set_color(MetaMgr::Instance()->teammate_bekill_color);
}
hum->SendNotifyMsg(msg);
return true;
});
},
&xtimer_attacher.timer_list_,
[] (const a8::XParams& param)
{
}
);
}
void Human::UpdateAction()
{
int passed_time = (room->GetFrameNo() - action_frameno) * FRAME_RATE_MS;
int left_time = std::max(0, action_duration - passed_time);
if (left_time <= 0) {
switch (action_type) {
case AT_Reload:
{
ProcReloadAction();
}
break;
case AT_UseItem:
{
ProcUseItemAction();
}
break;
case AT_Relive:
{
ProcReliveAction();
}
break;
default:
{
}
break;
}
ResetAction();
}
}
void Human::SendUIUpdate()
{
cs::SMUiUpdate notifymsg;
notifymsg.set_alive_count(room->AliveCount());
notifymsg.set_kill_count(stats.kills);
room->FillSMUiUpdate(notifymsg);
SendNotifyMsg(notifymsg);
}
void Human::SendWxVoip()
{
cs::SMWxVoip notifymsg;
if (!team_uuid.empty()) {
notifymsg.set_group_id(a8::XValue(room->GetRoomUuid()).GetString() + "_" + a8::XValue(team_id).GetString());
}
SendNotifyMsg(notifymsg);
}
void Human::SendSysPiaoMsg(const std::string& msg, int color, int duration)
{
cs::SMSysPiaoMsg notifymsg;
notifymsg.set_msg(msg);
notifymsg.set_color(color);
notifymsg.set_duration(duration);
SendNotifyMsg(notifymsg);
}
void Human::SendShowCountdown(const std::string& msg, int countdown)
{
cs::SMShowCountdown notifymsg;
notifymsg.set_msg(msg);
notifymsg.set_countdown(countdown);
SendNotifyMsg(notifymsg);
}
int Human::GetWeaponConfigLv(int weapon_id)
{
auto itr = weapon_configs.find(weapon_id);
return itr != weapon_configs.end() ? itr->second : 0;
}
int Human::GetSkinConfigLv(int skin_id)
{
auto itr = skin_configs.find(skin_id);
return itr != skin_configs.end() ? itr->second : 0;
}
bool Human::HasSpecMove()
{
return GetBuffByEffectId(kBET_JumpTo) ||
GetBuffByEffectId(kBET_BePull);
}
void Human::_UpdateSpecMove()
{
if (!HasSpecMove()) {
return;
}
bool move_end = false;
float target_distance = target_pos.Distance(GetPos());
if (target_distance <= 0.000001f) {
move_end = true;
} else {
a8::Vec2 old_move_dir = GetMoveDir();
a8::Vec2 move_dir = target_pos - GetPos();
move_dir.Normalize();
SetMoveDir(move_dir);
bool is_collision = false;
std::function<bool ()> old_on_move_collision = on_move_collision;
on_move_collision =
[&is_collision] () {
is_collision = true;
return false;
};
_UpdateMove(std::min((int)target_distance, (int)GetSpeed()));
on_move_collision = old_on_move_collision;
move_dir = old_move_dir;
target_distance = target_pos.Distance(GetPos());
if (is_collision || target_distance <= 1.0001f) {
move_end = true;
}
}
if (move_end) {
Buff* buff = GetBuffByEffectId(kBET_JumpTo);
if (buff) {
if (CurrentSkill() &&
buff->skill_meta == CurrentSkill()->meta &&
!CurrentSkill()->meta->phases.empty()) {
std::set<Creature*> target_list;
metatable::Skill* mutable_skill_meta = (metatable::Skill*)CurrentSkill()->meta->i;
float old_skill_distance = CurrentSkill()->meta->i->skill_distance();
mutable_skill_meta->set_skill_distance(CurrentSkill()->meta->phases[0].param1.GetDouble());
SelectSkillTargets(CurrentSkill(), GetPos(), target_list);
mutable_skill_meta->set_skill_distance(old_skill_distance);
TriggerBuff(CurrentSkill(), target_list, kBTT_SkillHit);
}
RemoveBuffByEffectId(kBET_JumpTo);
}
buff = GetBuffByEffectId(kBET_BePull);
if (buff) {
MetaData::Buff* new_buff = MetaMgr::Instance()->GetBuff(1039);
if (new_buff) {
AddBuff(this, new_buff, 1);
}
RemoveBuffByEffectId(kBET_BePull);
}
}
}
void Human::_UpdateMove(int speed)
{
if (!HasBuffEffect(kBET_Vertigo)) {
do {
int distance = std::min(5, speed);
_InternalUpdateMove(distance);
speed -= distance;
} while (speed > 0);
CheckSpecObject();
}
}
void Human::ChangeToRace(RaceType_e race, int level)
{
if (race != kHumanRace &&
race != kZombieRace) {
abort();
}
if (race_ != race && IsAndroid()) {
Android* android = (Android*)this;
android->ai->Reset();
if (race == kHumanRace) {
android->ai->SetAiMode(kHumanAiMode);
} else if (race == kZombieRace) {
android->ai->SetAiMode(kZombieAiMode);
}
}
race_ = race;
level_ = level;
if (race_ == kHumanRace) {
meta = MetaMgr::Instance()->GetPlayer(HUMAN_RACE_META_START_ID + level_ - 1);
if (!meta) {
abort();
}
exp_ = meta->i->exp();
OnMetaChange();
} else if (race_ == kZombieRace) {
DoGetDown();
meta = MetaMgr::Instance()->GetPlayer(ZOMBIE_RACE_META_START_ID + level_ - 1);
if (!meta) {
abort();
}
exp_ = meta->i->exp();
OnMetaChange();
} else {
abort();
}
}
void Human::ChangeToRaceAndNotify(RaceType_e race, int level)
{
ChangeToRace(race, level);
room->frame_event.AddZombieIdChg(this);
}
void Human::WinExp(Human* sender, int exp)
{
if (race_ != kHumanRace &&
race_ != kZombieRace) {
abort();
}
if (room->debug_trace) {
a8::UdpLog::Instance()->Debug
(
"WinExp before sender_id:%d uniid:%d race:%d level:%d exp:%d add_exp:%d ",
{
sender->GetEntityUniId(),
GetEntityUniId(),
GetRace(),
GetLevel(),
GetExp(),
exp
}
);
}
exp_ += exp;
MetaData::Player* old_meta = meta;
int start_meta_id = race_ == kHumanRace ? HUMAN_RACE_META_START_ID : ZOMBIE_RACE_META_START_ID;
ClearSkill();
do {
MetaData::Player* tmp_meta = MetaMgr::Instance()->GetPlayer(start_meta_id + level_);
if (!tmp_meta) {
break;
}
if (exp_ >= tmp_meta->i->exp()) {
meta = tmp_meta;
AddSkill(meta->i->active_skill());
ResetSkill();
++level_;
} else {
break;
}
} while (true);
if (old_meta != meta) {
room->frame_event.AddZombieIdChg(this);
OnMetaChange();
if (GetRace() == kZombieRace && meta->i->level() == 3) {
room->OnZombieAppear(this);
}
}
if (room->debug_trace) {
a8::UdpLog::Instance()->Debug
(
"WinExp after sender_id:%d uniid:%d race:%d level:%d exp:%d add_exp:%d ",
{
sender->GetEntityUniId(),
GetEntityUniId(),
GetRace(),
GetLevel(),
GetExp(),
exp
}
);
}
}
void Human::_InternalUpdateMove(float speed)
{
float nx = GetMoveDir().x * speed;
float ny = GetMoveDir().y * speed;
a8::Vec2 old_pos = GetPos();
#if 1
SetPos(old_pos + a8::Vec2(nx, ny));
if (!IsCollisionInMapService()) {
room->grid_service->MoveCreature(this);
return;
} else {
if (Global::last_collider && Global::last_collider->type == CT_Circle) {
SetPos(old_pos + a8::Vec2(nx, ny));
if (self_collider_->Intersect(Global::last_collider)) {
CircleCollider* circle_collider = (CircleCollider*)Global::last_collider;
a8::Vec2 tmp_dir = GetPos() - (circle_collider->owner->GetPos() + circle_collider->pos);
float len = circle_collider->rad + self_collider_->rad + 1;
float rate = len - tmp_dir.Norm();
tmp_dir.Normalize();
a8::Vec2 new_dir = tmp_dir * rate;
SetPos(GetPos() + new_dir);
}
if (!IsCollisionInMapService()) {
room->grid_service->MoveCreature(this);
return;
}
}
}
#endif
SetPos(old_pos + a8::Vec2(nx, 0));
if (IsCollisionInMapService()) {
if (on_move_collision && !on_move_collision()) {
SetPos(old_pos);
return;
}
nx = 0;
}
SetPos(old_pos + a8::Vec2(nx, ny));
if (IsCollisionInMapService()) {
if (on_move_collision && !on_move_collision()) {
SetPos(old_pos);
return;
}
ny = 0;
}
SetPos(old_pos + a8::Vec2(nx, ny));
room->grid_service->MoveCreature(this);
}
void Human::ClearFrameData()
{
if (!new_objects.empty()) {
new_objects.clear();
}
if (!del_objects.empty()) {
if (!a8::HasBitFlag(status, HS_Disable)) {
for (auto& itr : del_objects) {
Entity* entity = room->GetEntityByUniId(itr);
if (entity) {
RemovePartObjects(entity);
if (entity->IsEntityType(ET_Player)) {
Human* hum = (Human*)entity;
hum->RemovePartObjects(this);
}
#ifdef DEBUG1
room->CheckPartObjects();
#endif
}
}
}
del_objects.clear();
}
if (!out_objects.empty()) {
if (!a8::HasBitFlag(status, HS_Disable)) {
for (auto& itr : out_objects) {
Entity* entity = room->GetEntityByUniId(itr);
if (entity) {
RemovePartObjects(entity);
if (entity->IsEntityType(ET_Player)) {
Human* hum = (Human*)entity;
hum->RemovePartObjects(this);
}
}
#ifdef DEBUG1
room->CheckPartObjects();
#endif
}
}
out_objects.clear();
}
if (!shots_.empty()) {
shots_.clear();
}
if (!bullets_.empty()) {
bullets_.clear();
}
if (!explosions_.empty()) {
explosions_.clear();
}
if (!smokes_.empty()) {
smokes_.clear();
}
if (!play_skills_.empty()) {
play_skills_.clear();
}
if (!emotes_.empty()) {
emotes_.clear();
}
if (!chged_bullet_nums_.empty()) {
chged_bullet_nums_.clear();
}
if (!chged_hps_.empty()) {
chged_hps_.clear();
}
if (!chged_buffs_.empty()) {
chged_buffs_.clear();
}
if (!chged_skillcds_.empty()) {
chged_skillcds_.clear();
}
if (!chged_skill_curr_times_.empty()) {
chged_skill_curr_times_.clear();
}
if (!chged_items_.empty()) {
chged_items_.clear();
}
if (!chged_weapon_ammo_.empty()) {
chged_weapon_ammo_.clear();
}
if (!chged_level_.empty()) {
chged_level_.clear();
}
if (!chged_exp_.empty()) {
chged_exp_.clear();
}
if (!chged_race_.empty()) {
chged_race_.clear();
}
if (!chged_zombieid_.empty()) {
chged_zombieid_.clear();
}
if (!dead_alive_objs_.empty()) {
dead_alive_objs_.clear();
}
if (!chged_cars_.empty()) {
chged_cars_.clear();
}
}
void Human::GenBattleReportData(a8::MutableXObject* params)
{
params->SetVal("room_mode", room->GetRoomMode());
int rank = 0;
{
std::vector<Human*> human_list;
room->TraverseHumanList(a8::XParams(),
[&human_list] (Human* hum, a8::XParams& param) -> bool
{
human_list.push_back(hum);
return true;
});
std::sort(human_list.begin(), human_list.end(),
[] (Human* a, Human* b )
{
if (a->real_dead && b->real_dead) {
if (a->dead_frameno == b->dead_frameno) {
return a->GetEntityUniId() < b->GetEntityUniId();
} else {
return a->dead_frameno == 0 ||
(b->dead_frameno != 0 && a->dead_frameno > b->dead_frameno);
}
} else {
if (a->real_dead) {
return false;
}
if (b->real_dead) {
return true;
}
return a->GetEntityUniId() < b->GetEntityUniId();
}
});
rank = human_list.size();
for (size_t i = 0; i < human_list.size(); ++i) {
if (human_list[i] == this) {
rank = i + 1;
break;
}
}
if (room->GetAliveTeamNum() == 1) {
std::set<Human*>* alive_team = room->GetAliveTeam();
if (alive_team == team_members) {
rank = 1;
}
}
}
stats.rank = rank;
params->SetVal("account_id", account_id);
params->SetVal("session_id", session_id);
params->SetVal("map_id", room->GetMapMeta()->i->map_id());
params->SetVal("map_name", room->GetMapMeta()->i->map_name());
params->SetVal("map_tpl_name", room->GetMapTplName());
params->SetVal("game_time", time(nullptr));
params->SetVal("hurt", stats.damage_amount_in);
params->SetVal("rank", rank);
params->SetVal("kills", stats.kills);
params->SetVal("harm", stats.damage_amount_out);
params->SetVal("add_HP", stats.heal_amount);
if (!dead) {
params->SetVal("alive_time", room->GetFrameNo() * 1000.0f / SERVER_FRAME_RATE);
} else {
params->SetVal("alive_time", dead_frameno * 1000.0f / SERVER_FRAME_RATE);
}
params->SetVal("team_status", team_members && team_members->size() > 1 ? 1 : 0);
params->SetVal("room_uuid", room->GetRoomUuid());
int snipe_kill = 0;
int rifle_kill = 0;
int pistol_kill = 0;
int submachine_kill = 0;
for (Human* hum : kill_humans) {
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquip(hum->lethal_weapon);
if (equip_meta) {
switch (equip_meta->i->equip_subtype()) {
case 7:
{
//狙击枪
++snipe_kill;
}
break;
case 5:
{
//步枪
++rifle_kill;
}
break;
case 2:
{
//手枪
++pistol_kill;
}
break;
case 3:
{
//冲锋枪
++submachine_kill;
}
break;
}
}
}
params->SetVal("snipe_kill", snipe_kill);
params->SetVal("rifle_kill", rifle_kill);
params->SetVal("pistol_kill", pistol_kill);
params->SetVal("submachine_kill", submachine_kill);
params->SetVal("rescue_member", stats.rescue_member);
params->SetVal("rescue_guild_member", stats.rescue_guild_member);
{
float rank_param = MetaMgr::Instance()->GetRankRewardParam(rank);
float kill_param = MetaMgr::Instance()->GetKillRewardParam(stats.kills);
int coin_num = (rank_param * MetaMgr::Instance()->rank_param) +
(kill_param * MetaMgr::Instance()->kill_param);
stats.gold = coin_num;
params->SetVal("coin_num", coin_num);
}
{
std::string items_str;
MetaData::RankReward* rank_reward_meta = MetaMgr::Instance()->GetRankReward(rank);
#ifdef DEBUG1
{
#else
if (rank_reward_meta && rank_reward_meta->i->drop() > 0) {
#endif
#ifdef DEBUG1
{
#else
if (rand() % 100 < rank_reward_meta->i->drop()) {
#endif
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(grow_weapon.weapon_id);
if (item_meta) {
MetaData::Drop* drop_meta = MetaMgr::Instance()->GetDrop(item_meta->i->drop_id());
if (drop_meta) {
std::vector<std::tuple<int, int, int>> drop_items;
drop_meta->RandItems(drop_items);
for (auto& item : drop_items) {
int item_id = std::get<0>(item);
int item_num = std::get<1>(item);
stats.items.push_back(std::make_pair(
item_id,
item_num
));
items_str += a8::Format("%d:%d|", {item_id, item_num});
#ifdef DEBUG
SendDebugMsg
(a8::Format("drop weapon_id:%d drop_id:%d item_id:%d item_num:%d",
{
grow_weapon.weapon_id,
item_meta->i->drop_id(),
item_id,
item_num
}));
#endif
}
}
}
}
}//end if rank_reward_meta
if (!items_str.empty() && items_str[items_str.size() - 1] == '|') {
items_str.erase(items_str.begin() + items_str.size() - 1);
}
params->SetVal("items", items_str);
}
{
stats.pass_score = MetaMgr::Instance()->GetKillPointParam1(stats.kills);
stats.pass_score += MetaMgr::Instance()->GetRankPointParam1(rank);
stats.rank_score = MetaMgr::Instance()->GetKillPointParam2(stats.kills);
if (room->IsMiniRoom()) {
stats.rank_score += MetaMgr::Instance()->GetRankPointParam3(rank);
} else {
stats.rank_score += MetaMgr::Instance()->GetRankPointParam2(rank);
}
}
params->SetVal("score", 0);
params->SetVal("pass_score", has_pass ? stats.pass_score * 2 : stats.pass_score);
params->SetVal("rank_score", stats.rank_score);
}
void Human::GenZbModeBattleReportData(a8::MutableXObject* params)
{
params->SetVal("room_mode", room->GetRoomMode());
int rank = 0;
{
std::vector<Human*> human_list;
room->TraverseHumanList(a8::XParams(),
[&human_list] (Human* hum, a8::XParams& param) -> bool
{
human_list.push_back(hum);
return true;
});
std::sort(human_list.begin(), human_list.end(),
[] (Human* a, Human* b )
{
if (a->stats.kills > b->stats.kills) {
return true;
}
if (a->stats.kills < b->stats.kills) {
return false;
}
if (a->stats.last_kill_frameno < b->stats.last_kill_frameno) {
return true;
}
return a->GetEntityUniId() < b->GetEntityUniId();
});
rank = human_list.size();
for (size_t i = 0; i < human_list.size(); ++i) {
if (human_list[i] == this) {
rank = i + 1;
break;
}
}
}
stats.rank = rank;
params->SetVal("account_id", account_id);
params->SetVal("session_id", session_id);
params->SetVal("map_id", room->GetMapMeta()->i->map_id());
params->SetVal("game_time", time(nullptr));
params->SetVal("rank", rank);
params->SetVal("kills", stats.kills);
params->SetVal("room_uuid", room->GetRoomUuid());
}
void Human::DeadDrop()
{
auto SkinCanDrop =
[this] (Skin* skin) -> bool
{
#ifdef DEBUG
return false;
#else
if (JsonDataMgr::Instance()->channel == kTouTiaoChannelId) {
return false;
} else {
return skin->skin_id != 0;
}
#endif
};
if (GetRace() == kHumanRace &&
!HasBuffEffect(kBET_Terminator) &&
!(HasBuffEffect(kBET_Become) && GetBuffByEffectId(kBET_Become)->FreezeOperate())) {
for (auto& weapon : weapons) {
if (weapon.weapon_id != 0 &&
weapon.weapon_id != default_weapon.weapon_id
) {
a8::Vec2 drop_pos = GetPos();
room->DropItem(drop_pos, weapon.weapon_id, 1, weapon.weapon_lv);
weapon.Clear();
}
}
{
weapons[0] = default_weapon;
SetCurrWeapon(&weapons[0]);
}
}
{
Skin* old_skin = GetSkinByIdx(kSkinSlot_HAT);
if (old_skin && old_skin->skin_id != 0 && SkinCanDrop(old_skin)) {
a8::Vec2 dir = a8::Vec2::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(old_skin->skin_id, GetPos() + dir * (40 + rand() % 50), 1, 1);
*old_skin = Skin();
}
}
{
Skin* old_skin = GetSkinByIdx(kSkinSlot_CLOTH);
if (old_skin && old_skin->skin_id != 0 && SkinCanDrop(old_skin)) {
a8::Vec2 dir = a8::Vec2::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(old_skin->skin_id, GetPos() + dir * (40 + rand() % 50), 1, 1);
*old_skin = Skin();
}
}
{
//头盔
if (helmet != 0) {
a8::Vec2 dir = a8::Vec2::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(helmet, GetPos() + dir * (40 + rand() % 50), 1, 1);
helmet = 0;
}
//衣服
if (chest != 0) {
a8::Vec2 dir = a8::Vec2::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(chest, GetPos() + dir * (40 + rand() % 50), 1, 1);
chest = 0;
}
//背包
if (backpack != 0) {
a8::Vec2 dir = a8::Vec2::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(backpack, GetPos() + dir * (40 + rand() % 50), 1, 1);
backpack = 0;
}
}
for (size_t slot = 0; slot < GetInventoryData().size(); ++slot) {
if (GetInventoryData()[slot] > 0) {
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquipBySlotId(slot);
if (equip_meta) {
if (equip_meta->i->equip_type() == EQUIP_TYPE_BULLET) {
switch (equip_meta->i->_inventory_slot()) {
case IS_FRAG:
case IS_SMOKE:
case IS_POSION_GAS_BOMB:
case IS_MOLOTOR_COCKTAIL:
case IS_TRAP:
case IS_MINE:
{
a8::Vec2 drop_pos = GetPos();
room->DropItem(drop_pos, equip_meta->i->id(), GetInventoryData()[slot], 1);
DecInventory(slot, GetInventoryData()[slot]);
}
break;
default:
break;
}
} else {
a8::Vec2 drop_pos = GetPos();
room->DropItem(drop_pos, equip_meta->i->id(), GetInventoryData()[slot], 1);
}
}
}
}
need_sync_active_player = true;
}
void Human::SendBattleReport()
{
a8::MutableXObject* params = a8::MutableXObject::NewObject();
if (room->GetRoomMode() == kZombieMode) {
GenZbModeBattleReportData(params);
} else {
GenBattleReportData(params);
}
auto on_ok = [] (a8::XParams& param, a8::XObject& data)
{
};
auto on_error = [] (a8::XParams& param, const std::string& response)
{
a8::UdpLog::Instance()->Error("battleReport http error params: %s response: %s",
{
param.param2,
response
});
};
std::string url;
if (!f8::IsOnlineEnv()) {
if (JsonDataMgr::Instance()->channel != 0) {
url = a8::Format("http://game2005api-test.kingsome.cn/%d/webapp/index.php?c=Role&a=battleReport",
{
JsonDataMgr::Instance()->channel
});
} else {
url = "https://game2005api-test.kingsome.cn/webapp/index.php?c=Role&a=battleReport";
}
} else {
if (JsonDataMgr::Instance()->channel != 0) {
if (kTouTiaoChannelId == JsonDataMgr::Instance()->channel) {
url = a8::Format("http://game2005api-al.kingsome.cn/%d/webapp/index.php?c=Role&a=battleReport",
{
JsonDataMgr::Instance()->channel
});
} else {
url = a8::Format("http://game2005api.kingsome.cn/%d/webapp/index.php?c=Role&a=battleReport",
{
JsonDataMgr::Instance()->channel
});
}
} else {
url = "http://game2005api.kingsome.cn/webapp/index.php?c=Role&a=battleReport";
}
}
JsonDataMgr::Instance()->GetBattleReportUrl(url);
std::string data;
params->ToUrlEncodeStr(data);
f8::HttpClientPool::Instance()->HttpGet(
a8::XParams()
.SetSender(room->GetRoomUuid())
.SetParam1(GetEntityUniId())
.SetParam2(data),
on_ok,
on_error,
url.c_str(),
*params,
MAX_SYS_HTTP_NUM + (GetEntityUniId() % MAX_USER_HTTP_NUM)
);
delete params;
}
void Human::ProcLootSkin(Loot* entity, MetaData::Equip* item_meta)
{
switch (item_meta->i->equip_subtype()) {
case 11:
{
//装饰
Skin* old_skin = GetSkinByIdx(kSkinSlot_HAT);
if (old_skin) {
if (old_skin->skin_id != 0) {
a8::Vec2 dir = a8::Vec2::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(old_skin->skin_id, GetPos() + dir * (40 + rand() % 50), 1, 1);
}
*old_skin = Skin();
old_skin->skin_id = item_meta->i->id();
old_skin->skin_lv = 1;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
}
break;
case 12:
{
//衣服
Skin* old_skin = GetSkinByIdx(kSkinSlot_CLOTH);
if (old_skin) {
if (old_skin->skin_id != 0) {
a8::Vec2 dir = a8::Vec2::UP;
dir.Rotate(a8::RandAngle());
room->CreateLoot(old_skin->skin_id, GetPos() + dir * (40 + rand() % 50), 1, 1);
}
*old_skin = Skin();
old_skin->skin_id = item_meta->i->id();
old_skin->skin_lv = 1;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
}
break;
}
}
void Human::ProcLootCar(Loot* entity, MetaData::Equip* item_meta)
{
DoGetOn(entity->GetEntityUniId());
}
void Human::ProcCamoutflage(Loot* entity, MetaData::Equip* item_meta)
{
AddItem(item_meta->i->id(), 1);
}
void Human::ProcSpoils(Loot* entity, MetaData::Equip* item_meta)
{
if (spoils_items.find(item_meta->i->id()) !=
spoils_items.end()) {
spoils_items[item_meta->i->id()] += entity->count;
} else {
spoils_items[item_meta->i->id()] = entity->count;
}
}
void Human::FindLocationWithTarget(Entity* target)
{
a8::Vec2 old_pos = GetPos();
a8::Vec2 new_pos = GetPos();
AabbCollider a_collider;
GetAabbBox(a_collider);
AabbCollider target_collider;
target->GetAabbBox(target_collider);
{
bool ret = a_collider.CalcSafePoint(&target_collider, new_pos);
if (!ret) {
abort();
}
}
a8::Vec2 new_pos_dir = new_pos - old_pos;
new_pos_dir.Normalize();
float distance = (new_pos - old_pos).Norm();
for (int i = distance; i < 10000000; i += 5) {
SetPos(old_pos + new_pos_dir * i);
room->grid_service->MoveCreature(this);
Entity* building = nullptr;
std::set<GridCell*> tmp_grids;
room->grid_service->GetAllCellsByXy(room, GetX(), GetY(), tmp_grids);
room->grid_service->TraverseAllLayerEntityList
(
room->GetRoomIdx(),
tmp_grids,
[this, &building] (Entity* entity, bool& stop)
{
switch (entity->GetEntityType()) {
case ET_Building:
{
if (TestCollision(room, entity)) {
building = entity;
stop = true;
}
}
break;
default:
break;
}
});
if (!building) {
bool is_collision = false;
std::set<ColliderComponent*> colliders;
room->map_service->GetColliders(room, GetX(), GetY(), colliders);
for (ColliderComponent* collider : colliders) {
if (TestCollision(room, collider)) {
is_collision = true;
break;
}
}
if (!is_collision) {
break;
}
}
}
}
void Human::OnDie()
{
real_dead_frameno = room->GetFrameNo();
room->OnHumanDie(this);
SyncAroundPlayers(__FILE__, __LINE__, __func__);
if (team_members) {
for (auto& hum : *team_members) {
if (hum != this && hum->action_type == AT_Relive &&
hum->action_target_id == GetEntityUniId()) {
hum->CancelAction();
}
}
}
{
std::set<Human*> over_humans;
if (!leave_) {
if (!HasNoDownedTeammate()) {
if (team_members) {
for (auto& member : *team_members) {
if (member->real_dead) {
over_humans.insert(member);
}
}
} else {
over_humans.insert(this);
}
} else {
over_humans.insert(this);
}
}
if (room->GetAliveTeamNum() == 1) {
std::set<Human*>* alive_team = room->GetAliveTeam();
if (alive_team) {
for (Human* member : *alive_team) {
over_humans.insert(member);
}
}
}
for (Human* hum : over_humans) {
hum->SendGameOver();
}
}
DeadDrop();
}
void Human::FreeDownedTimer()
{
if (downed_timer) {
room->xtimer.DeleteTimer(downed_timer);
downed_timer = nullptr;
}
}
void Human::FreeReviveTimer()
{
if (revive_timer) {
room->xtimer.DeleteTimer(revive_timer);
revive_timer = nullptr;
}
}
void Human::SetSkin(int idx, int skin_id)
{
if (idx < kSkinNum) {
Skin& skin = skins[idx];
skin.skin_id = skin_id;
skin.skin_lv = 1;
}
}
Skin* Human::GetSkinByIdx(int idx)
{
int i = 0;
for (auto& skin : skins) {
if (i == idx) {
return &skin;
}
++i;
}
return nullptr;
}
void Human::AddBuffPostProc(Creature* caster, Buff* buff)
{
}
int Human::GetItemNum(int item_id)
{
auto itr = items_.find(item_id);
return itr != items_.end() ? itr->second : 0;
}
void Human::AddItem(int item_id, int item_num)
{
auto itr = items_.find(item_id);
if (itr != items_.end()) {
itr->second += item_num;
} else {
items_[item_id] = item_num;
}
if (room && room->GetFrameNo() > join_frameno) {
room->frame_event.AddItemChg(this, item_id, items_[item_id]);
} else {
if (item_num <= 0) {
battling_items_.insert(item_id);
}
}
}
void Human::DecItem(int item_id, int item_num)
{
auto itr = items_.find(item_id);
if (itr != items_.end()) {
itr->second -= item_num;
room->frame_event.AddItemChg(this, item_id, std::max(0, itr->second));
if (itr->second <= 0) {
if (battling_items_.find(item_id) == battling_items_.end()) {
items_.erase(itr);
}
}
}
}
void Human::DropItems(Obstacle* obstacle)
{
bool is_treasure_box = false;
if (obstacle->IsEntitySubType(EST_RoomObstacle)) {
is_treasure_box = ((RoomObstacle*)obstacle)->is_treasure_box;
}
int drop_id = obstacle->meta->i->drop();
if (drop_id == 0) {
return;
}
if (room->GetRoomType() == RT_NewBrid && IsPlayer()) {
if (is_treasure_box) {
if (box_drop_times_ < MetaMgr::Instance()->newbie_airdrop.size()) {
drop_id = MetaMgr::Instance()->newbie_airdrop[box_drop_times_];
}
} else {
if (normal_drop_times_ < MetaMgr::Instance()->newbie_drop.size()) {
if (normal_drop_times_ == 0) {
}
drop_id = MetaMgr::Instance()->newbie_drop[normal_drop_times_];
}
}
}
if (drop_id == 0) {
drop_id = obstacle->meta->i->drop();
}
room->ScatterDrop(obstacle->GetPos(), drop_id);
if (is_treasure_box) {
++box_drop_times_;
} else {
++normal_drop_times_;
}
{
if (behavior.curr_start_destory_box_frameno <= 0 ||
behavior.curr_destory_box_times >= MetaMgr::Instance()->refresh_ai_destory_box_times ||
(room->GetFrameNo() - behavior.curr_start_destory_box_frameno >
MetaMgr::Instance()->refresh_ai_destory_box_time * SERVER_FRAME_RATE)){
behavior.curr_start_destory_box_frameno = room->GetFrameNo();
behavior.curr_destory_box_times = 0;
}
behavior.curr_destory_box_times++;
behavior.total_destory_box_times++;
if (behavior.curr_destory_box_times >= MetaMgr::Instance()->refresh_ai_destory_box_times) {
#if 0
room->GetIncubator()->AllocAndroid(this, 1 + rand() % 2);
#endif
}
}
#ifdef DEBUG
#if 0
a8::UdpLog::Instance()->Debug("DropItems normal:%d box:%d drop_id:%d is_treasure_box:%d",
{
normal_drop_times_,
box_drop_times_,
drop_id,
is_treasure_box ? 1 : 0
});
#endif
#endif
}
void Human::Revive()
{
if (room->GetRoomMode() == kZombieMode) {
if (GetRace() == kHumanRace) {
ChangeToRaceAndNotify(kZombieRace, 1);
}
dead = false;
downed = false;
real_dead = false;
ability.hp = GetMaxHP();
ClearBuffList();
{
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(kREVIVE_BUFF_ID);
if (buff_meta) {
AddBuff(this, buff_meta, 1);
}
}
room->frame_event.AddRevive(GetWeakPtrRef());
room->OnHumanRevive(this);
ResetSkill();
SyncAroundPlayers(__FILE__, __LINE__, __func__);
} else {
auto callback =
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->dead = true;
hum->real_dead = true;
hum->downed = false;
hum->OnDie();
};
int wait_revive_time = MetaMgr::Instance()->GetSysParamAsInt("revive_time", 25) + kReviveTimeAdd;
revive_timer = room->xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * wait_revive_time,
a8::XParams()
.SetSender(this),
callback,
&xtimer_attacher.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->revive_timer = nullptr;
});
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
}
void Human::CancelRevive()
{
if (dead && revive_timer && !real_dead) {
dead = true;
real_dead = true;
downed = false;
FreeDownedTimer();
OnDie();
FreeReviveTimer();
}
}
void Human::ProcNewBieLogic()
{
if (a8::HasBitFlag(status, HS_AlreadyProcNewBieLogic)) {
return;
}
a8::SetBitFlag(status, HS_AlreadyProcNewBieLogic);
//刷一个机器人
room->xtimer.AddDeadLineTimerAndAttach
(SERVER_FRAME_RATE * MetaMgr::Instance()->newbie_first_robot_appeartime,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->room->ShuaGuideAndroid(hum);
},
&xtimer_attacher.timer_list_
);
//6秒后出现空投
room->xtimer.AddDeadLineTimerAndAttach
(SERVER_FRAME_RATE * MetaMgr::Instance()->newbie_airdrop_appeartime,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->room->InitAirDrop();
},
&xtimer_attacher.timer_list_
);
}
void Human::ClearLordMode()
{
Buff* buff = GetBuffByEffectId(kBET_LordMode);
if (buff) {
std::vector<std::string> strings;
a8::Split(buff->meta->i->buff_param1(), strings, ':');
for (auto& str : strings) {
int buff_id = a8::XValue(str);
RemoveBuffById(buff_id);
}
RemoveBuffByEffectId(kBET_LordMode);
}
}
void Human::AdjustDecHp(float old_health, float& new_health)
{
Buff* buff = GetBuffByEffectId(kBET_NewProtect);
if (buff) {
if (new_health < GetMaxHP() * buff->meta->param1) {
new_health = std::max(GetMaxHP() * buff->meta->param1, (float)0);
}
}
}
void Human::OnEnable()
{
a8::UnSetBitFlag(status, HS_Disable);
enable_frameno = room->GetFrameNo();
room->grid_service->MoveCreature(this);
FindLocation();
RefreshView();
}
void Human::OnDisable()
{
a8::SetBitFlag(status, HS_Disable);
RemoveFromScene();
ClearFrameData();
ClearPartObjects();
}
void Human::GetViewObjects(std::set<Entity*>& view_objects)
{
TraverseAllLayerHumanList
(
[&view_objects] (Human* hum, bool& stop)
{
view_objects.insert(hum);
});
TraverseAllLayerEntityList
(
[&view_objects] (Entity* entity, bool& stop)
{
switch (entity->GetEntityType()) {
case ET_Building:
case ET_Obstacle:
case ET_Loot:
{
view_objects.insert(entity);
}
break;
default:
{
}
break;
}
});
}
void Human::NotifyObservers(cs::SMUpdate* msg, cs::MFActivePlayerData* active_player_data_pb)
{
bool refreshed_view = false;
for (Human* observer : observers_) {
msg->clear_team_data();
if (observer->team_members) {
for (auto& itr : *observer->team_members) {
if (itr != observer) {
itr->FillMFTeamData(msg->add_team_data(), false);
}
}
}
if (observer != this && !observer->follow_synced_active_player) {
msg->set_active_player_id(GetEntityUniId());
FillMFActivePlayerData(msg->mutable_active_player_data());
if (!refreshed_view) {
std::set<Entity*> view_objects;
GetViewObjects(view_objects);
for (Entity* entity : view_objects) {
if (new_objects.find(entity) == new_objects.end()) {
entity->FillMFObjectFull(room, this, msg->add_full_objects());
}
}
refreshed_view = true;
}
observer->follow_synced_active_player = true;
} else {
if (active_player_data_pb) {
msg->set_active_player_id(GetEntityUniId());
*msg->mutable_active_player_data() = *active_player_data_pb;
} else {
msg->clear_active_player_id();
msg->clear_active_player_data();
}
}
observer->SendNotifyMsg(*msg);
}
}
void Human::ProcIncGridList(std::set<GridCell*>& old_grids,
std::set<GridCell*>& inc_grids,
std::set<GridCell*>& dec_grids)
{
room->grid_service->TraverseCreatures
(
room->GetRoomIdx(),
inc_grids,
[this, &old_grids] (Creature* c, bool& stop)
{
if (!room->grid_service->CreatureInGridList(c, old_grids)) {
c->AddToNewObjects(this);
c->AddToPartObjects(this);
c->RemoveOutObjects(this);
AddToNewObjects(c);
AddToPartObjects(c);
RemoveOutObjects(c);
}
});
room->grid_service->TraverseAllLayerEntityList
(
room->GetRoomIdx(),
inc_grids,
[this] (Entity* entity, bool& stop)
{
switch (entity->GetEntityType()) {
case ET_Building:
case ET_Obstacle:
case ET_Loot:
{
AddToNewObjects(entity);
RemoveOutObjects(entity);
}
break;
default:
{
}
break;
}
});
}
void Human::ProcDecGridList(std::set<GridCell*>& old_grids,
std::set<GridCell*>& inc_grids,
std::set<GridCell*>& dec_grids)
{
room->grid_service->TraverseCreatures
(
room->GetRoomIdx(),
dec_grids,
[this] (Creature* c, bool& stop)
{
if (!room->grid_service->CreatureInGridList(c, GetGridList())) {
AddOutObjects(c);
c->AddOutObjects(this);
#ifdef DEBUG
#if 0
a8::UdpLog::Instance()->Debug("addoutobjects %d %d",
{
(long long)c,
c->GetEntityUniId()
});
#endif
#endif
}
});
room->grid_service->TraverseAllLayerEntityList
(
room->GetRoomIdx(),
dec_grids,
[this] (Entity* entity, bool& stop)
{
if (!room->grid_service->EntityInGridList(room, entity, GetGridList())) {
switch (entity->GetEntityType()) {
case ET_Building:
case ET_Obstacle:
case ET_Loot:
{
AddOutObjects(entity);
}
break;
default:
{
}
break;
}
}
});
}
void Human::RemoveFromScene()
{
room->grid_service->DeatchHuman(this);
room->TraverseHumanList
(
a8::XParams()
.SetSender(this),
[] (Human* hum, a8::XParams& param)
{
Human* target = (Human*)param.sender.GetUserData();
hum->RemovePartObjects(target);
return true;
});
last_collision_door_ = nullptr;
}
ObjectSyncFlags* Human::GetObjectSyncFlags(int obj_uniid)
{
if ((size_t)obj_uniid < fixed_object_sync_flags_.size()) {
return &fixed_object_sync_flags_[obj_uniid];
} else {
return nullptr;
}
}
void Human::OnMetaChange()
{
if (GetRace() == kZombieRace) {
MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(meta->i->normal_skill());
if (weapon_meta) {
default_weapon.weapon_idx = 0;
default_weapon.weapon_id = weapon_meta->i->id();
default_weapon.weapon_lv = 1;
default_weapon.ammo = 1;
default_weapon.meta = weapon_meta;
default_weapon.Recalc();
weapons[0] = default_weapon;
SetCurrWeapon(&weapons[0]);
}
}
ability.hp = meta->i->health();
for (auto& weapon : spec_weapons) {
if (weapon.meta) {
ability.hp += weapon.meta ? weapon.GetAttrValue(kHAT_MaxHp) : 0;
}
}
room->frame_event.AddHpChg(GetWeakPtrRef());
RecalcBaseAttr();
ClearSkill();
AddSkill(meta->i->active_skill());
ResetSkill();
ClearPassiveSkill();
AddPassiveSkill(meta->i->passive_skill());
}
void Human::OnChgToTerminator()
{
Buff* buff = GetBuffByEffectId(kBET_Terminator);
if (buff) {
std::vector<std::string> strings;
a8::Split(buff->meta->i->buff_param4(), strings, ':');
if (strings.size() >= 3) {
for (size_t i = 0; i < strings.size(); ++i) {
int weapon_id = a8::XValue(strings[i]);
MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(weapon_id);
if (weapon_meta) {
Weapon* weapon = nullptr;
switch (i) {
case 0:
{
weapon = &weapons[0];
}
break;
case 1:
{
weapon = &weapons[GUN_SLOT1];
}
break;
case 2:
{
weapon = &weapons[GUN_SLOT2];
}
break;
default:
{
}
break;
}
weapon->weapon_idx = i;
weapon->weapon_id = weapon_meta->i->id();
weapon->weapon_lv = 1;
weapon->meta = weapon_meta;
weapon->Recalc();
weapon->ammo = weapon->GetClipVolume();
if (i == 0) {
default_weapon = *weapon;
}
}
}
}//end if
need_sync_active_player = true;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
}
void Human::ProcReloadAction()
{
Weapon* p_weapon = GetCurrWeapon();
if (second_weapon.meta) {
p_weapon = &second_weapon;
}
if (p_weapon->weapon_idx == action_target_id &&
p_weapon->weapon_id == action_item_id &&
p_weapon->weapon_idx != 0) {
MetaData::Equip* bullet_meta = MetaMgr::Instance()->GetEquip(p_weapon->meta->i->use_bullet());
if (bullet_meta) {
int ammo = p_weapon->ammo;
if (ammo < p_weapon->GetClipVolume()) {
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()) <=
p_weapon->GetClipVolume() - ammo) {
add_num = GetInventory(bullet_meta->i->_inventory_slot());
if (p_weapon->meta->i->reloadtype() == 1) {
add_num = 1;
}
DecInventory(bullet_meta->i->_inventory_slot(), add_num);
} else {
add_num = p_weapon->GetClipVolume() - ammo;
if (p_weapon->meta->i->reloadtype() == 1) {
add_num = 1;
}
DecInventory(bullet_meta->i->_inventory_slot(), add_num);
}
p_weapon->ammo += add_num;
need_sync_active_player = true;
if (p_weapon->meta->i->reloadtype() == 1) {
room->xtimer.AddDeadLineTimerAndAttach
(1,
a8::XParams()
.SetSender(this)
.SetParam1(p_weapon->weapon_idx)
.SetParam2(p_weapon->weapon_id),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->NextReload(param.param2, param.param1);
},
&xtimer_attacher.timer_list_
);
}
}
}
}
}
}
}
void Human::ProcUseItemAction()
{
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquipBySlotId(action_item_id);
if (!item_meta) {
return;
}
if (GetInventory(item_meta->i->_inventory_slot()) <= 0) {
return;
}
switch (action_item_id) {
case IS_HEALTHKIT:
{
AddHp(item_meta->i->heal());
DecInventory(item_meta->i->_inventory_slot(), 1);
}
break;
case IS_PAIN_KILLER:
{
if (pain_killer_timer) {
int passed_time = (room->GetFrameNo() - 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;
} else {
pain_killer_frameno = room->GetFrameNo();
pain_killer_lastingtime = item_meta->i->time();
if (pain_killer_lastingtime > 0) {
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();
hum->AddHp(param.param1.GetDouble());
if (hum->room->GetFrameNo() - hum->pain_killer_frameno >
hum->pain_killer_lastingtime * SERVER_FRAME_RATE) {
hum->room->xtimer.DeleteTimer(hum->pain_killer_timer);
}
},
&xtimer_attacher.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->pain_killer_timer = nullptr;
});
}
AddHp(item_meta->i->heal());
}
DecInventory(item_meta->i->_inventory_slot(), 1);
need_sync_active_player = true;
}
break;
default:
{
}
break;
}
}
void Human::ProcReliveAction()
{
Entity* entity = room->GetEntityByUniId(action_target_id);
if (!entity->IsEntityType(ET_Player)) {
return;
}
Human* hum = (Human*)entity;
if (hum->action_type == AT_Rescue) {
hum->CancelAction();
return;
}
if (!hum->dead && hum->downed) {
hum->ability.hp = 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;
if (hum->guild_id != 0 && hum->guild_id == guild_id) {
++hum->stats.rescue_guild_member;
}
}
hum->SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
void Human::OnBuffRemove(Buff& buff)
{
switch (buff.meta->i->buff_effect()) {
case kBET_Jump:
{
//跳伞结束
room->xtimer.AddDeadLineTimerAndAttach
(1,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->OnLand();
},
&xtimer_attacher.timer_list_
);
}
break;
case kBET_Become:
{
buff.ProcRemoveBecome(this);
}
break;
case kBET_Driver:
{
buff.ProcRemoveDriver(this);
}
break;
case kBET_Passenger:
{
buff.ProcRemovePassenger(this);
}
break;
default:
break;
}
if (!buff.meta->i->only_server()) {
room->frame_event.RemoveBuff(GetWeakPtrRef(), buff.meta->i->buff_id());
}
}
void Human::OnLand()
{
//着陆
RemoveBuffByEffectId(kBET_Jump);
RemoveBuffByEffectId(kBET_ThroughWall);
if (IsAndroid() && team_uuid.empty()) {
MustBeAddBuff(this, kBeRecycleBuffId);
}
if (IsPlayer()) {
refresh_view_timer_ = room->xtimer.AddRepeatTimerAndAttach
(
SERVER_FRAME_RATE * MetaMgr::Instance()->refresh_view_time,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->UpdateViewObjects();
},
&xtimer_attacher.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->refresh_view_timer_ = nullptr;
});
}
if (IsCollisionInMapService()) {
a8::Vec2 old_pos = GetPos();
std::vector<a8::Vec2> dirs;
{
dirs.push_back(a8::Vec2::UP);
dirs.push_back(a8::Vec2::DOWN);
dirs.push_back(a8::Vec2::LEFT);
dirs.push_back(a8::Vec2::RIGHT);
}
for (int i = 0; i < 10000000; i += 10) {
for (const a8::Vec2& dir : dirs) {
SetPos(old_pos + dir * i);
if (!IsCollisionInMapService()) {
room->grid_service->MoveCreature(this);
return;
}
}
}
SetPos(old_pos);
}
}
void Human::NextReload(int prev_weapon_id, int prev_weapon_idx)
{
if (action_type != AT_None) {
return;
}
Weapon* p_weapon = GetCurrWeapon();
if (second_weapon.meta) {
p_weapon = &second_weapon;
}
if (p_weapon &&
p_weapon->weapon_id == prev_weapon_id &&
p_weapon->weapon_idx == prev_weapon_idx) {
AutoLoadingBullet(true);
}
}
void Human::DoGetDown()
{
if (GetCar()) {
GetCar()->GetDown(this);
}
}
void Human::DoGetOnWithLoot(Loot* entity)
{
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(entity->item_id);
if (!item_meta) {
return;
}
if (GetCar()) {
GetCar()->GetDown(this);
}
Car* car = room->CreateCar(
this,
entity->GetEntityUniId(),
item_meta,
entity->GetPos(),
team_id
);
car->GetOn(this);
room->TakeOnCarObject(entity->GetEntityUniId());
room->NotifyUiUpdate();
#ifdef DEBUG
a8::XPrintf("DoGetOnWithLoot uniid:%d car_uniid:%d\n", {car->GetEntityUniId(), car->car_uniid});
#endif
}
void Human::DoGetOnWithCar(Car* car)
{
car->GetOn(this);
}
void Human::OnEnterSpecMapArea(int tag, SpecMapObject& map_obj)
{
#ifdef DEBUG
SendDebugMsg("进入特殊区域");
#endif
ClearSpecMapAreaTimer(map_obj);
map_obj.enter_timer = room->xtimer.AddDeadLineTimerAndAttach
(MetaMgr::Instance()->GetSpecMapAreaEnterTime(tag) * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this)
.SetParam1(&map_obj)
.SetParam2(tag),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
int buff_id = MetaMgr::Instance()->GetSpecMapAreaBuffId(param.param2);
hum->MustBeAddBuff(hum, buff_id);
},
&xtimer_attacher.timer_list_,
[] (const a8::XParams& param)
{
SpecMapObject* map_obj = (SpecMapObject*)param.param1.GetUserData();
map_obj->enter_timer = nullptr;
});
}
void Human::OnLeaveSpecMapArea(int tag, SpecMapObject& map_obj)
{
#ifdef DEBUG
SendDebugMsg("离开特殊区域");
#endif
ClearSpecMapAreaTimer(map_obj);
map_obj.leave_timer = room->xtimer.AddDeadLineTimerAndAttach
(MetaMgr::Instance()->GetSpecMapAreaLeaveTime(tag) * SERVER_FRAME_RATE,
a8::XParams()
.SetSender(this)
.SetParam1(&map_obj)
.SetParam2(tag),
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->RemoveBuffById((MetaMgr::Instance()->GetSpecMapAreaBuffId(param.param2)));
},
&xtimer_attacher.timer_list_,
[] (const a8::XParams& param)
{
SpecMapObject* map_obj = (SpecMapObject*)param.param1.GetUserData();
map_obj->leave_timer = nullptr;
});
}
void Human::ClearSpecMapAreaTimer(SpecMapObject& map_obj)
{
if (map_obj.leave_timer) {
room->xtimer.DeleteTimer(map_obj.leave_timer);
map_obj.leave_timer = nullptr;
}
if (map_obj.enter_timer) {
room->xtimer.DeleteTimer(map_obj.enter_timer);
map_obj.enter_timer = nullptr;
}
}
void Human::DoSkillPreProc(int skill_id, int target_id, const a8::Vec2& target_pos)
{
if (action_type == AT_Reload ||
action_type == AT_UseItem
) {
CancelAction();
}
}
void Human::DoSkillPostProc(bool used, int skill_id, int target_id, const a8::Vec2& target_pos)
{
if (used) {
++stats.skill_times;
Skill* skill = GetSkill(skill_id);
if (skill) {
skill->DecTimes();
room->frame_event.AddSkillCdChg(AllocWeakPtr(), skill_id, skill->GetLeftTime());
room->frame_event.AddSkillCurrTimesChg(AllocWeakPtr(), skill_id, skill->GetCurrTimes());
}
OnAttack();
}
}
float Human::GetRadius()
{
return meta->i->radius();
}
float Human::GetHitRadius()
{
return meta->i->hit_radius();
}
void Human::GetHitAabbBox(AabbCollider& aabb_box)
{
if (!meta) {
abort();
}
aabb_box.active = true;
aabb_box.owner = this;
if (GetCar() && GetCar()->IsDriver(this)) {
aabb_box._min.x = -GetCar()->meta->i->rad();
aabb_box._min.y = -GetCar()->meta->i->rad();
aabb_box._max.x = GetCar()->meta->i->rad();
aabb_box._max.y = GetCar()->meta->i->rad();
} else {
aabb_box._min.x = -GetHitRadius();
aabb_box._min.y = -GetHitRadius();
aabb_box._max.x = GetHitRadius();
aabb_box._max.y = GetHitRadius();
}
}
void Human::UpdateViewObjects()
{
if (view_objects_.size() >= 2) {
std::vector<Human*> deleted_humans;
for (Human* hum : view_objects_) {
if (hum->dead ||
hum->GetPos().ManhattanDistance(GetPos()) > MetaMgr::Instance()->view_objects_out_distance) {
deleted_humans.push_back(hum);
}
}
for (Human* hum : deleted_humans) {
view_objects_.erase(hum);
}
}
if (view_objects_.size() < 2) {
TraverseAllLayerHumanList
(
[this] (Human* hum, bool& stop)
{
if (hum->IsAndroid() && !hum->dead && view_objects_.find(hum) == view_objects_.end()) {
if (hum->GetPos().ManhattanDistance(GetPos()) <
MetaMgr::Instance()->view_objects_in_distance) {
view_objects_.insert(hum);
}
if (view_objects_.size() >= 2) {
stop = true;
return;
}
}
});
}
if (view_objects_.size() < 2) {
room->GetIncubator()->AllocAndroid(this, 1 + rand() % 2);
if (refresh_view_timer_) {
room->xtimer.ModifyTimer(refresh_view_timer_,
SERVER_FRAME_RATE * (MetaMgr::Instance()->refresh_view_time + (rand() % 3))
);
}
}
}
void Human::GMAddItem(int item_id, int item_num)
{
MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(item_id);
if (!item_meta) {
return;
}
if (item_meta->i->equip_type() == EQUIP_TYPE_WEAPON) {
if (item_meta->i->equip_subtype() == 1) {
if (default_weapon.weapon_id != weapons[0].weapon_id) {
} else {
weapons[0].weapon_idx = 0;
weapons[0].weapon_id = item_id;
weapons[0].weapon_lv = std::max(1, 1);
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 (GetCurrWeapon() != &weapons[GUN_SLOT2] && !FreezeOperate()) {
SetCurrWeapon(&weapons[GUN_SLOT1]);
}
} else if (weapons[GUN_SLOT2].weapon_id == 0) {
weapon = &weapons[GUN_SLOT2];
weapon->weapon_idx = GUN_SLOT2;
if (GetCurrWeapon() != &weapons[GUN_SLOT1] && !FreezeOperate()) {
SetCurrWeapon(&weapons[GUN_SLOT2]);
}
}
if (weapon) {
weapon->weapon_id = item_id;
weapon->weapon_lv = std::max(1, 1);
weapon->ammo = 0;
weapon->meta = item_meta;
weapon->Recalc();
}
}
} else {
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(item_num, add_num);
AddInventory(item_meta->i->_inventory_slot(), add_num);
switch (item_meta->i->_inventory_slot()) {
case IS_FRAG:
case IS_SMOKE:
{
Weapon* weapon = &weapons[SPEC1_SLOT_BEGIN +
(item_meta->i->_inventory_slot() - SPEC1_IS_BEGIN)
];
weapon->weapon_id = item_id;
weapon->weapon_lv = 1;
weapon->ammo += item_num;
weapon->meta = item_meta;
weapon->Recalc();
DecInventory(item_meta->i->_inventory_slot(), add_num);
}
break;
case IS_1XSCOPE:
case IS_2XSCOPE:
case IS_4XSCOPE:
case IS_8XSCOPE:
case IS_15XSCOPE:
{
if (item_meta->i->_inventory_slot() - IS_1XSCOPE > curr_scope_idx) {
curr_scope_idx = item_meta->i->_inventory_slot() - IS_1XSCOPE;
}
}
break;
case IS_POSION_GAS_BOMB:
case IS_MOLOTOR_COCKTAIL:
case IS_TRAP:
case IS_MINE:
{
Weapon* weapon = &weapons[SPEC2_SLOT_BEGIN +
(item_meta->i->_inventory_slot() - SPEC2_IS_BEGIN)
];
weapon->weapon_id = item_id;
weapon->weapon_lv = 1;
weapon->ammo += item_num;
weapon->meta = item_meta;
weapon->Recalc();
DecInventory(item_meta->i->_inventory_slot(), add_num);
}
break;
default:
{
#if 0
abort();
#endif
}
break;
}
}
}
need_sync_active_player = true;
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
void Human::OnBulletHit(Bullet* bullet)
{
if (IsInvincible()) {
return;
}
if (bullet->sender.Get()->room->GetRoomMode() == kZombieMode &&
bullet->sender.Get()->GetRace() == GetRace()) {
return;
}
if (!dead && (bullet->IsBomb() || bullet->sender.Get()->team_id != team_id)) {
float dmg = bullet->GetAtk() * (1 + bullet->sender.Get()->GetAttrRate(kHAT_Atk)) +
bullet->sender.Get()->GetAttrAbs(kHAT_Atk);
float def = ability.def * (1 + GetAttrRate(kHAT_Def)) +
GetAttrAbs(kHAT_Def);
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
finaly_dmg = std::max(finaly_dmg, 0.0f);
#if 0
sender->stats.damage_amount_out += finaly_dmg;
#endif
#ifdef DEBUG
if (App::Instance()->HasFlag(1) && IsPlayer()) {
return;
}
#endif
if (bullet->meta->buff_meta) {
MustBeAddBuff(this, bullet->meta->i->buffid());
}
DecHP(finaly_dmg,
bullet->sender.Get()->GetEntityUniId(),
bullet->sender.Get()->GetName(),
bullet->gun_meta->i->id());
#ifdef DEBUG
bullet->sender.Get()->SendDebugMsg
(a8::Format("bullet weapon_id:%d atk:%f",
{
bullet->gun_meta->i->id(),
bullet->GetAtk()
})
);
#endif
}
}