#include "precompile.h" #include #include #include #include #include "framework/cpp/utils.h" #include "framework/cpp/httpclientpool.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 "team.h" #include "explosion.h" #include "killmgr.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; } Human::~Human() { } void Human::Initialize() { Creature::Initialize(); RecalcSelfCollider(); volume_ = meta->volume; observers_.insert(this); SetHP(meta->i->health()); for (auto& weapon : spec_weapons) { if (weapon.meta) { float hp = GetHP(); hp += weapon.meta ? weapon.GetAttrValue(kHAT_MaxHp) : 0; SetHP(hp); } } SetMaxHP(GetHP()); SetCurrWeapon(&weapons[0]); } float Human::GetSpeed() { { Buff* buff = GetBuffByEffectId(kBET_JumpTo); if (buff) { return buff->meta->param2; } } { Buff* buff = GetBuffByEffectId(kBET_Jump); if (buff) { return meta->i->jump_speed(); } } { Buff* buff = GetBuffByEffectId(kBET_BePull); if (buff) { return buff->meta->param2; } } { Buff* buff = GetBuffByEffectId(kBET_Sprint); if (buff) { return buff->meta->param2; } } float speed = 1.0; if (downed) { speed = 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() * (1 + GetAbility()->GetAttrRate(kHAT_ShotSpeed)); } } } 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()); } speed = meta->i->move_speed(); } float old_speed = speed; speed = (speed + GetAbility()->GetAttrAbs(kHAT_Speed)) * (1 + GetAbility()->GetAttrRate(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(GetUniId()); 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(GetUniId()); 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); 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()); GetAbility()->FillMFAttrAdditionList(room, this, p->mutable_attr_addition()); 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::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(GetUniId()); 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_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, stats.dead_times, room->AliveCount(), room->GetFrameNo() }); } countdown = std::max(0, countdown - kReviveTimeAdd); p->set_revive_countdown(countdown); } } 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(GetUniId()); 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(); aabb_box.MoveCenter(GetCar()->hero_meta_->i->move_offset_x(), GetCar()->hero_meta_->i->move_offset_y()); } 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(); aabb_box.MoveCenter(meta->i->move_offset_x(), meta->i->move_offset_y()); } } 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(GetUniId()); 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(meta->i->move_offset_x(), meta->i->move_offset_y()); 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(); } } } 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 (CheckCollision()) { 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 (!CheckCollision()) { return; } else { //向下 SetPos(old_pos + a8::Vec2::DOWN); if (!CheckCollision()) { return; } } } else if (up_dot > 0.001f) { //基本相同 SetPos(old_pos + (at_left_side ? a8::Vec2::LEFT : a8::Vec2::RIGHT)); if (!CheckCollision()) { return; } else { //向上 SetPos(old_pos + a8::Vec2::UP); if (!CheckCollision()) { return; } } } else if (up_dot < 0.001f) { //基本相反 SetPos(old_pos + (at_left_side ? a8::Vec2::LEFT : a8::Vec2::RIGHT)); if (!CheckCollision()) { return; } else { //向下 SetPos(old_pos + a8::Vec2::DOWN); if (!CheckCollision()) { return; } } } } SetPos(old_pos); } void Human::FillSMGameOver(cs::SMGameOver& msg) { if (stats.rank <= 0) { std::vector 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->GetUniId() < b->GetUniId(); } 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->GetUniId() < b->GetUniId(); } }); 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) { if (room->GetAliveTeam() == GetTeam()) { rank = 1; } } stats.rank = rank; } msg.set_watchable(MetaMgr::Instance()->watchable); 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()); if (GetTeam()) { GetTeam()->TraverseMembers ( [this, &msg] (Human* member) -> bool { if (this != member) { member->FillMFTeamData(msg.add_team_data(), true); cs::MFPlayerStats* p = msg.add_player_stats(); member->FillMFPlayerStats(p); } return 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) { if (!dead && !room->IsGameOver() && !real_dead) { KillInfo info; { info.killer_id = killer_id; info.killer_name = killer_name; info.weapon_id = weapon_id; } { ++stats.dead_times; stats.killer_id = killer_id; stats.killer_name = killer_name; stats.weapon_id = weapon_id; } { GetTrigger()->Die(); dead = true; real_dead = true; downed = false; SetHP(0.0f); dead_frameno = room->GetFrameNo(); OnDie(); KillMgr::Instance()->OnHumanDead(this, &info); room->frame_event.AddDead(GetWeakPtrRef(), 0); } } } 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); }; float old_hp = GetHP(); 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); SetHP(std::max(0.0f, new_health)); if (old_health - GetHP() > 0.001f) { stats.damage_amount_in += old_health - GetHP(); GetTrigger()->ReceiveDmg(); } 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()) { SetHP(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__); TryAddBuff(this, kDownBuffId); 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()); } GetTrigger()->HpChg(); } void Human::AddToNewObjects(Entity* entity) { new_objects[entity->GetUniId()] = entity->GetEntityWeakPtrRef(); } void Human::AddToPartObjects(Entity* entity) { PartObject part_obj; part_obj.entity_uniid = entity->GetUniId(); part_obj.entity_type = entity->GetEntityType(); part_obj.entity_subtype = entity->GetEntitySubType(); part_obj.add_frameno = room->GetFrameNo(); part_obj.object = entity->GetEntityWeakPtrRef(); part_objects[entity->GetUniId()] = part_obj; entity->OnAddToTargetPartObject(this); } void Human::RemovePartObjects(Entity* entity) { #ifdef DEBUG SendDebugMsg(a8::Format("view_debug frameno:%d remove_part_obj:%d", { room->GetFrameNo(), entity->GetUniId() })); #endif part_objects.erase(entity->GetUniId()); 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->GetUniId()) != new_objects.end(); } bool Human::InPartObjects(Entity* target) { return part_objects.find(target->GetUniId()) != part_objects.end(); } void Human::RemoveObjects(Entity* entity) { del_objects.insert(entity->GetUniId()); new_objects.erase(entity->GetUniId()); } void Human::AddOutObjects(Entity* entity) { out_objects.insert(entity->GetUniId()); } void Human::RemoveOutObjects(Entity* entity) { out_objects.erase(entity->GetUniId()); } bool Human::HasLiveTeammate() { bool has = false; if (GetTeam()) { GetTeam()->TraverseMembers ( [this, &has] (Human* member) { if (member != this && !member->dead) { has = true; return false; } return true; }); } return has; } bool Human::HasNoDownedTeammate() { bool has = false; if (GetTeam()) { GetTeam()->TraverseMembers ( [this, &has] (Human* member) { if (member != this && !member->dead && !member->downed) { has = true; return false; } return true; }); } return has; } int Human::GetNearbyTeammateNum(float range) { int num = 0; if (GetTeam()) { GetTeam()->TraverseMembers ( [this, &num, range] (Human* member) { if (member != this && !member->dead && !member->downed) { if (member->GetPos().Distance(GetPos()) <= range) { ++num; } } return true; }); } return num; } void Human::DoJump() { if (HasBuffEffect(kBET_Fly)) { a8::UnSetBitFlag(status, CS_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::RefreshView() { #if 1 room->grid_service->TraverseCreatures ( room->GetRoomIdx(), GetGridList(), [this] (Creature* c, bool& stop) { c->AddToNewObjects(this); c->AddToPartObjects(this); AddToNewObjects(c); AddToPartObjects(c); }); #else TraverseAllLayerHumanList ( [this] (Human* hum, bool& stop) { hum->AddToNewObjects(this); hum->AddToPartObjects(this); AddToNewObjects(hum); AddToPartObjects(hum); }); #endif TraverseAllLayerEntityList ( [this] (Entity* entity, bool& stop) { switch (entity->GetEntityType()) { case ET_Building: case ET_Obstacle: case ET_Loot: case ET_MapBlock: { AddToNewObjects(entity); } break; default: { } break; } }); } void Human::OnGridListChange(std::set& old_grids, std::set& inc_grids, std::set& 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, CS_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); player_data->set_action_frameno(action_frameno); } } #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& inv : GetInventoryData()) { player_data->add_inventory(inv.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); GetAbility()->FillMFAttrAdditionList(room, this, player_data->mutable_attr_addition()); } 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); for (size_t i = 0; i < IS_END; ++i) { volume_[i] = meta->volume[i]; volume_[i] += buff_inventory_[i].num; if (backpack_meta) { volume_[i] += backpack_meta->volume[i]; } } } void Human::RecalcBaseAttr() { MetaData::Equip* chest_meta = MetaMgr::Instance()->GetEquip(chest); float def = meta->i->def(); if (chest_meta) { def += chest_meta->i->def(); } MetaData::Equip* helmet_meta = MetaMgr::Instance()->GetEquip(helmet); if (helmet_meta) { def += helmet_meta->i->def(); } SetDef(def); SetMaxHP(std::max(GetHP(), GetMaxHP())); } int Human::GetVolume(int slot_id) { if (!IsValidSlotId(slot_id)) { abort(); } return volume_[slot_id]; } void Human::RecoverHp(int inc_hp) { if (!dead) { float hp = GetHP(); hp += inc_hp; SetHP(hp); SetHP(std::min(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); } bool Human::HasObserver() { return !observers_.empty(); } void Human::SendUpdateMsg() { if (!follow_target_ && !a8::HasBitFlag(status, CS_Disable)) { #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(a8::TimestampToDateTime(time(nullptr)) + " " + debug_msg); SendNotifyMsg(notify_msg); } 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; case AT_Rescue: { RemoveBuffById(kRescueBuffId); } 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 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 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)) { a8::UnSetBitFlag(status, CS_Collisioning); do { int distance = std::min(5, speed); _InternalUpdateMove(distance); speed -= distance; } while (speed > 0 && !a8::HasBitFlag(status, CS_Collisioning)); CheckSpecObject(); } } 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 (!CheckCollision()) { 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 (!CheckCollision()) { room->grid_service->MoveCreature(this); return; } } } #endif if (a8::HasBitFlag(status, CS_Collisioning)) { SetPos(old_pos); return; } SetPos(old_pos + a8::Vec2(nx, 0)); if (CheckCollision()) { if (a8::HasBitFlag(status, CS_Collisioning)) { SetPos(old_pos); return; } if (on_move_collision && !on_move_collision()) { SetPos(old_pos); return; } nx = 0; } SetPos(old_pos + a8::Vec2(nx, ny)); if (CheckCollision()) { if (a8::HasBitFlag(status, CS_Collisioning)) { SetPos(old_pos); return; } 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, CS_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, CS_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 (!dead_alive_objs_.empty()) { dead_alive_objs_.clear(); } if (!chged_cars_.empty()) { chged_cars_.clear(); } if (!chged_props_.empty()) { chged_props_.clear(); } if (!del_bullets_.empty()) { del_bullets_.clear(); } } void Human::GenBattleReportData(a8::MutableXObject* params) { params->SetVal("room_mode", room->GetRoomMode()); int rank = 0; { std::vector 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->GetUniId() < b->GetUniId(); } 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->GetUniId() < b->GetUniId(); } }); 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) { if (room->GetAliveTeam() == GetTeam()) { 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", GetTeam() && GetTeam()->GetMemberNum() > 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(stats.weapon_id); 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> 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::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); if (weapon.ammo > 0 && weapon.bullet_meta && weapon.ammo < 200) { if (IsPlayer() && weapon.bullet_meta && IsValidSlotId(weapon.bullet_meta->i->_inventory_slot())) { AddInventory(weapon.bullet_meta->i->_inventory_slot(), weapon.ammo); } } 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 (GetInventory(slot) > 0) { MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquipBySlotId(slot); if (equip_meta) { int drop_num = equip_meta->i->group_num(); 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: case IS_C4: case IS_SHIELD_WALL: case IS_SINGAL_GUN: case IS_OIL_BUCKET: { if (drop_num > 0) { a8::Vec2 drop_pos = GetPos(); if (IsPlayer()) { room->DropItem(drop_pos, equip_meta->i->id(), GetInventory(slot), 1); } else { room->DropItem(drop_pos, equip_meta->i->id(), drop_num, 1); } DecInventory(slot, GetInventory(slot)); } } break; default: { if (drop_num > 0) { a8::Vec2 drop_pos = GetPos(); if (IsPlayer()) { room->DropItem(drop_pos, equip_meta->i->id(), GetInventory(slot), 1); } else { room->DropItem(drop_pos, equip_meta->i->id(), drop_num, 1); } DecInventory(slot, GetInventory(slot)); } } break; } } else { #if 0 a8::Vec2 drop_pos = GetPos(); room->DropItem(drop_pos, equip_meta->i->id(), GetInventory(slot), 1); #endif } } } } need_sync_active_player = true; } void Human::SendBattleReport() { a8::MutableXObject* params = a8::MutableXObject::NewObject(); 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(GetUniId()) .SetParam2(data), on_ok, on_error, url.c_str(), *params, MAX_SYS_HTTP_NUM + (GetUniId() % 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->GetUniId()); } 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::OnDie() { { if (HasBuffEffect(kBET_Camouflage)) { RemoveBuffByEffectId(kBET_Camouflage); } ClearLordMode(); DoGetDown(); } real_dead_frameno = room->GetFrameNo(); room->OnHumanDie(this); SyncAroundPlayers(__FILE__, __LINE__, __func__); if (GetTeam()) { GetTeam()->TraverseMembers ( [this] (Human* member) -> bool { if (this != member && member->action_type == AT_Relive && member->action_target_id == GetUniId()) { member->CancelAction(); } return true; }); } { std::set over_humans; if (!leave_) { if (!HasNoDownedTeammate()) { if (GetTeam()) { GetTeam()->GetOveredHumans(over_humans); } else { over_humans.insert(this); } } else { over_humans.insert(this); } } if (room->GetAliveTeamNum() == 1) { Team* alive_team = room->GetAliveTeam(); if (alive_team) { alive_team->GetOveredHumans(over_humans); } } for (Human* hum : over_humans) { hum->SendGameOver(); } } DeadDrop(); } void Human::FreeDownedTimer() { RemoveBuffById(kDownBuffId); 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(GetWeakPtrRef(), 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(GetWeakPtrRef(), 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() { { 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::ClearLordMode() { Buff* buff = GetBuffByEffectId(kBET_LordMode); if (buff) { std::vector 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, CS_Disable); enable_frameno = room->GetFrameNo(); room->grid_service->MoveCreature(this); FindLocation(); RefreshView(); } void Human::OnDisable() { a8::SetBitFlag(status, CS_Disable); RemoveFromScene(); ClearFrameData(); ClearPartObjects(); } void Human::GetViewObjects(std::set& 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: case ET_MapBlock: { 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->GetTeam()) { observer->GetTeam()->TraverseMembers ( [observer, msg] (Human* member) -> bool { if (member != observer) { member->FillMFTeamData(msg->add_team_data(), false); } return true; }); } if (observer != this && !observer->follow_synced_active_player) { msg->set_active_player_id(GetUniId()); FillMFActivePlayerData(msg->mutable_active_player_data()); if (!refreshed_view) { std::set synced_objects; { for (auto& full_obj : msg->full_objects()) { synced_objects.insert(full_obj.obj_uniid()); } } std::set view_objects; GetViewObjects(view_objects); for (Entity* entity : view_objects) { if (synced_objects.find(entity->GetUniId()) == synced_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(GetUniId()); *msg->mutable_active_player_data() = *active_player_data_pb; } else { msg->clear_active_player_id(); msg->clear_active_player_data(); } } if (observer != this) { for (int i = 0; i < msg->full_objects_size(); ++i) { cs::MFObjectFull* full_obj = msg->mutable_full_objects(i); if (a8::HasBitFlag(full_obj->object_flags(), kOfReadCache)) { Entity* e = room->GetEntityByUniId(full_obj->obj_uniid()); if (e) { if (!e->IsClientCached(observer)) { #ifdef DEBUG ObjectSyncFlags old_sync_flags = *(observer->GetObjectSyncFlags(e->GetUniId())); #endif e->FillMFObjectFull(room, observer, full_obj); #ifdef DEBUG ObjectSyncFlags* new_sync_flags = observer->GetObjectSyncFlags(e->GetUniId()); observer->SendDebugMsg(a8::Format( "resync full frameno:%d uniid:%d net_flags:%d f2:%d " "old_flags:%d,%d new_flags:%d,%d", { room->GetFrameNo(), full_obj->obj_uniid(), full_obj->object_flags(), msg->full_objects(i).object_flags(), old_sync_flags.flags, old_sync_flags.last_sync_frameno, new_sync_flags->flags, new_sync_flags->last_sync_frameno, })); #endif } } else { #ifdef DEBUG abort(); #endif } } } } observer->SendNotifyMsg(*msg); } } void Human::ProcIncGridList(std::set& old_grids, std::set& inc_grids, std::set& 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: case ET_MapBlock: { AddToNewObjects(entity); RemoveOutObjects(entity); } break; default: { } break; } }); } void Human::ProcDecGridList(std::set& old_grids, std::set& inc_grids, std::set& 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->GetUniId() }); #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: case ET_MapBlock: { 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::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() * (1 + GetAbility()->GetAttrRate(kHAT_DrugEfficacy))); DecInventory(item_meta->i->_inventory_slot(), 1); GetTrigger()->UseItemAction(action_item_id); } 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; GetTrigger()->UseItemAction(action_item_id); } break; case IS_SHEN_BAO: { if (!dead) { if (downed) { SetHP(MetaMgr::Instance()->GetSysParamAsInt("downed_relive_recover_hp")); downed = false; if (downed_timer) { room->xtimer.DeleteTimer(downed_timer); downed_timer = nullptr; } } AddHp(item_meta->i->heal()); } DecInventory(item_meta->i->_inventory_slot(), 1); need_sync_active_player = true; GetTrigger()->UseItemAction(action_item_id); } break; default: { } break; } } void Human::ProcReliveAction() { Entity* entity = room->GetEntityByUniId(action_target_id); if (!entity->IsEntityType(ET_Player)) { return; } Human* hum = (Human*)entity; #if 1 if (hum->action_type == AT_Rescue) { hum->CancelAction(); } #else if (hum->action_type == AT_Rescue) { hum->CancelAction(); return; } #endif if (!hum->dead && hum->downed) { SetHP(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; } if (hum->GetBuffById(kDownBuffId)) { hum->RemoveBuffById(kDownBuffId); } } hum->SyncAroundPlayers(__FILE__, __LINE__, __func__); } void Human::OnBuffRemove(Buff& buff) { Creature::OnBuffRemove(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(); } break; case kBET_Driver: { buff.ProcRemoveDriver(); } break; case kBET_Passenger: { buff.ProcRemovePassenger(); } break; case kBET_AddInventory: { for (int slot : buff.meta->param2_int_list) { if (IsValidSlotId(slot)) { buff_inventory_[slot].num -= buff.meta->int_param1; buff_inventory_[slot].num = std::max(0, buff_inventory_[slot].num); } } RecalcVolume(); need_sync_active_player = true; } break; case kBET_CamouflageAddition: { if (buff.meta->int_param2 != 0) { --camouflage_move_addition_; } if (buff.meta->int_param3 != 0) { --camouflage_aiming_addition_; } camouflage_move_addition_ = std::max(camouflage_move_addition_, 0); camouflage_aiming_addition_ = std::max(camouflage_aiming_addition_, 0); } break; default: { } break; } } void Human::OnLand() { //着陆 RemoveBuffByEffectId(kBET_Jump); RemoveBuffByEffectId(kBET_ThroughWall); if (IsAndroid() && team_uuid.empty()) { MustBeAddBuff(this, kBeRecycleBuffId); } if (IsPlayer()) { StartRefreshViewTimer(); } if (CheckCollision()) { a8::Vec2 old_pos = GetPos(); std::vector 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 (!CheckCollision()) { room->grid_service->MoveCreature(this); return; } } } SetPos(old_pos); } if (IsAndroid()) { int buff_uniid = MustBeAddBuff(this, kPeaceModeBuffId ); if (buff_uniid) { Buff* buff = GetBuffByUniId(buff_uniid); if (buff) { int peace_time = 2000; if (ai->ai_meta->i->peace_time() > 0) { peace_time += ai->ai_meta->i->peace_time(); } room->xtimer.ModifyTimer(buff->remover_timer, peace_time / FRAME_RATE_MS); } } } } 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->GetUniId(), item_meta, entity->GetPos(), team_id ); car->GetOn(this); #ifdef DEBUG a8::XPrintf("DoGetOnWithLoot uniid:%d car_uniid:%d\n", {car->GetUniId(), car->car_uniid}); #endif } void Human::DoGetOnWithCar(Car* car) { car->GetOn(this); } 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(); aabb_box.MoveCenter(GetCar()->hero_meta_->i->hit_offset_x(), GetCar()->hero_meta_->i->hit_offset_y()); } else { aabb_box._min.x = -GetHitRadius(); aabb_box._min.y = -GetHitRadius(); aabb_box._max.x = GetHitRadius(); aabb_box._max.y = GetHitRadius(); aabb_box.MoveCenter(meta->i->hit_offset_x(), meta->i->hit_offset_y()); } } void Human::UpdateViewObjects() { if (view_objects_.size() >= 2) { std::vector 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 = weapon = TakeonWeapon(item_meta); if (weapon) { if (GetCurrWeapon() != weapon) { SetCurrWeapon(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; case IS_C4: case IS_SHIELD_WALL: case IS_SINGAL_GUN: case IS_OIL_BUCKET: { Weapon* weapon = &weapons[SPEC3_SLOT_BEGIN + (item_meta->i->_inventory_slot() - SPEC3_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; } } else { AddItem(item_id, item_num); } } need_sync_active_player = true; SyncAroundPlayers(__FILE__, __LINE__, __func__); } void Human::OnBulletHit(Bullet* bullet) { if (IsInvincible()) { return; } if (HasBuffEffect(kBET_Jump) || HasBuffEffect(kBET_Fly)) { return; } #ifdef DEBUG #if 0 if (IsPlayer()) { return; } #endif #endif RemoveBuffByEffectId(kBET_PeaceMode); if (!dead && (bullet->IsBomb() || bullet->sender.Get()->team_id != team_id)) { float old_hp = GetHP(); float old_max_hp = GetMaxHP(); float dmg = bullet->GetAtk(); float def = GetDef() * (1 + GetAbility()->GetAttrRate(kHAT_Def)) + GetAbility()->GetAttrAbs(kHAT_Def); float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K); finaly_dmg = std::max(finaly_dmg, 0.0f); if (bullet->sender.Get()->IsHuman()) { bullet->sender.Get()->AsHuman()->stats.damage_amount_out += finaly_dmg; } if (bullet->meta->buff_meta) { MustBeAddBuff(bullet->sender.Get(), bullet->meta->i->buffid()); } if (bullet->sender.Get() && bullet->sender.Get()->IsCar() && bullet->passenger.Get()) { if (!bullet->IsPreBattleBullet()) { DecHP(finaly_dmg, bullet->passenger.Get()->GetUniId(), bullet->passenger.Get()->GetName(), bullet->gun_meta->i->id()); } } else { if (!bullet->IsPreBattleBullet()) { DecHP(finaly_dmg, bullet->sender.Get()->GetUniId(), bullet->sender.Get()->GetName(), bullet->gun_meta->i->id()); } } #ifdef DEBUG bullet->sender.Get()->SendDebugMsg (a8::Format("bullet uniid:%d weapon_id:%d atk:%f def:%f finaly_dmg:%f old_hp:%f old_maxhp:%f cur_hp:%f", { bullet->GetUniId(), bullet->gun_meta->i->id(), bullet->GetAtk(), def, finaly_dmg, old_hp, old_max_hp, GetHP() }) ); #endif } } void Human::OnExplosionHit(Explosion* e) { if (IsInvincible()) { return; } if (dead) { return; } if (e->IsPreBattleExplosion()) { return; } if (HasBuffEffect(kBET_Jump) || HasBuffEffect(kBET_Fly)) { return; } RemoveBuffByEffectId(kBET_PeaceMode); float dmg = e->GetDmg(); float def = GetDef() * (1 + GetAbility()->GetAttrRate(kHAT_Def)) + GetAbility()->GetAttrAbs(kHAT_Def); float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K); finaly_dmg = std::max(finaly_dmg, 0.0f); #ifdef DEBUG { room->BroadcastDebugMsg(a8::Format("explosion dmg:%d def:%d finaly_dmg:%d", {dmg, def, finaly_dmg})); } #endif #if 1 DecHP(finaly_dmg, 1, "", 1); #else DecHP(finaly_dmg, sender.Get()->GetUniId(), sender.Get()->GetName(), gun_meta->i->id()); #endif } void Human::SendRollMsgEx(KillInfo& info, const char* fmt, std::initializer_list args ) { } void Human::ProcUseItem(int item_id) { if (downed) { return; } MetaData::Equip* item_meta = MetaMgr::Instance()->GetEquip(item_id); if (item_meta && GetItemNum(item_id) > 0) { if (item_meta->i->use_scene() == 1 && !HasBuffEffect(kBET_InWater)) { SendSysPiaoMsg(TEXT("only_inwater_use", "只能在水中使用"), a8::MkRgb(255, 0, 0), 3 ); return; } if (GetCar() && item_meta->i->equip_type() == EQUIP_TYPE_CAMOUFLAGE) { return; } if (item_meta->i->buffid() != 0) { TryAddBuff(this, item_meta->i->buffid()); } DecItem(item_id, 1); } } Weapon* Human::TakeonWeapon(MetaData::Equip* equip_meta) { Weapon* weapon = nullptr; if (equip_meta->i->equip_type() == EQUIP_TYPE_WEAPON) { if (equip_meta->i->equip_subtype() == 1) { } else { for (int i = GUN_SLOT1; i <= GUN_SLOT2; ++i) { if (weapons[i].weapon_id == 0) { weapon = &weapons[i]; weapon->weapon_idx = i; } else if (weapons[i].meta->i->equip_subtype() == equip_meta->i->equip_subtype() && weapons[i].meta->group_id == equip_meta->group_id){ if (equip_meta->i->quality() > weapons[i].meta->i->quality()) { weapon = &weapons[i]; weapon->weapon_idx = i; } else { weapon = nullptr; } } } } } return weapon; } void Human::StartRefreshViewTimer() { if (refresh_view_timer_) { return; } 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; }); }