#include "precompile.h" #include #include #include #include #include #include #include "human.h" #include "room.h" #include "bullet.h" #include "loot.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 "jsondatamgr.h" #include "skill.h" #include "incubator.h" #include "team.h" #include "explosion.h" #include "killmgr.h" #include "tracemgr.h" #include "httpproxy.h" #include "skillhelper.h" #include "shot.h" #include "battledatacontext.h" #include "mapinstance.h" #include "movement.h" #include "pbutils.h" #include "trigger.h" #include "ability.h" #include "mt/Param.h" #include "mt/Hero.h" #include "mt/Equip.h" #include "mt/Buff.h" #include "mt/Skill.h" #include "mt/SkillNumber.h" #include "mt/GunTalentGrow.h" #include "mt/SafeArea.h" #include "mt/MapThing.h" #include "mt/Text.h" #include "mt/Map.h" #include "mt/PveGemini.h" #include "mt/PveGeminiMode.h" #include "mt/RankReward.h" #include "mt/RankPoint.h" #include "mt/KillReward.h" #include "mt/KillPoint.h" #include "mt/Drop.h" #include "pbutils.h" static double TopXFunc (Human* sender, std::function cmpFunc, bool need_group, std::function validFunc) { std::vector> rank_list; double topx = 0.0f; #if 0 sender->room->TraverseHumanList (a8::XParams(), [cmpFunc, &rank_list, need_group] (Human* hum, a8::XParams& param) -> bool { bool found = false; if (need_group) { for (auto& list : rank_list) { if (cmpFunc(list[0], hum) == 0) { list.push_back(hum); found = true; } } } if (!found) { rank_list.push_back(std::vector({hum})); } return true; }); std::sort (rank_list.begin(), rank_list.end(), [cmpFunc] (const std::vector& a, const std::vector& b ) { a8::XPrintf("id1:%d dead:%d id2:%d dead:%d cmpRet:%d\n", { a[0]->GetUniId(), a[0]->dead ? 1 :0, b[0]->GetUniId(), b[0]->dead ? 1 :0, cmpFunc(a[0], b[0]) }); return cmpFunc(a[0], b[0]) > 0; }); int rank = rank_list.size(); for (int i = 0; i < rank_list.size(); ++i){ bool found = false; for (Human* hum : rank_list[i]) { if (hum == sender){ rank = i + 1; found = true; break; } } if (found) { break; } } #if 1 double topx = (double)rank / 40.0f; if (!validFunc(sender)) { topx = 40.0f / 40.0f; } #else double topx = (double)rank / rank_list.size(); #endif #endif return topx; }; void PlayerStats::Statement(Human* sender) { sender->stats.ranked_topx = (double)sender->stats.rank / sender->room->GetHumanNum(); sender->stats.kills_topx = TopXFunc ( sender, [] (Human* a, Human* b) -> int { if (a->stats.kills == b->stats.kills) { return 0; } else if (a->stats.kills > b->stats.kills) { return 1; } else { return -1; } }, true, [] (Human* hum) { return hum->stats.kills > 0; } ); sender->stats.hero_topx = TopXFunc ( sender, [] (Human* a, Human* b) -> int { long long a_value = 0; long long b_value = 0; if (a->GetBattleContext()) { int hero_lv = 0; int quality = 0; a->GetBattleContext()->GetHeroLvQuality(hero_lv, quality); a_value = hero_lv + quality; } if (b->GetBattleContext()) { int hero_lv = 0; int quality = 0; b->GetBattleContext()->GetHeroLvQuality(hero_lv, quality); b_value = hero_lv + quality; } if (a_value == b_value) { return 0; } else if (a_value > b_value) { return 1; } else { return -1; } }, true, [] (Human* hum) { if (hum->GetBattleContext()) { int hero_lv = 0; int quality = 0; hum->GetBattleContext()->GetHeroLvQuality(hero_lv, quality); return hero_lv + quality > 0; } return false; } ); sender->stats.weapon_topx = TopXFunc ( sender, [] (Human* a, Human* b) -> int { long long a_value = 0; long long b_value = 0; if (a->GetBattleContext()) { int weapon_lv = 0; int quality = 0; a->GetBattleContext()->GetWeaponLvQuality(weapon_lv, quality); a_value = weapon_lv + quality; } if (b->GetBattleContext()) { int weapon_lv = 0; int quality = 0; b->GetBattleContext()->GetWeaponLvQuality(weapon_lv, quality); b_value = weapon_lv + quality; } if (a_value == b_value) { return 0; } else if (a_value > b_value) { return 1; } else { return -1; } }, true, [] (Human* hum) { if (hum->GetBattleContext()) { int weapon_lv = 0; int quality = 0; hum->GetBattleContext()->GetWeaponLvQuality(weapon_lv, quality); return weapon_lv + quality > 0; } return false; } ); sender->stats.survival_topx = TopXFunc ( sender, [] (Human* a, Human* b) -> int { if (a->dead && b->dead) { if (a->dead_frameno == b->dead_frameno) { return 0; } else if (a->dead_frameno > b->dead_frameno) { return 1; } else { return -1; } } else { if (!a->dead && !b->dead) { return 0; } else { if (!a->dead) { return 1; } else { return -1; } } } }, true, [] (Human* hum) { return true; } ); if (sender->GetBattleContext()) { sender->GetBattleContext()->CalcBattleStat(this); } statemented = 1; } WeaponStats& PlayerStats::MustBeWeapon(int weapon_id) { auto itr = weapon_stats.find(weapon_id); if (itr == weapon_stats.end()){ WeaponStats weapon; weapon_stats[weapon_id] = weapon; itr = weapon_stats.find(weapon_id); } return itr->second; } void PlayerStats::IncWeaponKills(int weapon_id, int val) { MustBeWeapon(weapon_id).kills += val; } void PlayerStats::IncWeaponDamageOut(int weapon_id, int val) { MustBeWeapon(weapon_id).damage_out += val; } void PlayerStats::IncWeaponObtainCount(int weapon_id, int val) { MustBeWeapon(weapon_id).obtain_count += val; } void PlayerStats::IncWeaponUseTimes(int weapon_id, int val) { MustBeWeapon(weapon_id).use_times += val; } HeroStats& PlayerStats::MustBeHero(int hero_id) { auto itr = hero_stats.find(hero_id); if (itr == hero_stats.end()){ HeroStats hero; hero_stats[hero_id] = hero; itr = hero_stats.find(hero_id); } return itr->second; } void PlayerStats::SetHeroSkillLv(int hero_id, int skill_lv) { MustBeHero(hero_id).skill_lv = std::max(MustBeHero(hero_id).skill_lv, skill_lv); } void PlayerStats::SetHeroWeaponLv(int hero_id, int weapon_lv) { MustBeHero(hero_id).weapon_lv = std::max(MustBeHero(hero_id).weapon_lv, weapon_lv); } void PlayerStats::ParseReward(Human* hum, a8::XObject& xobj) { if (!xobj.IsObject()) { AdjustRewardData(); return; } auto reward_xobj = xobj.At("reward"); if (!reward_xobj || !reward_xobj->IsObject()) { AdjustRewardData(); return; } over_reward.total_ceg = reward_xobj->At("total_ceg")->AsXValue().GetString(); { auto hero_xobj = reward_xobj->At("hero"); if (hero_xobj && hero_xobj->IsObject()) { over_reward.hero.curr_gold = hero_xobj->At("curr_ceg") ? hero_xobj->At("curr_ceg")->AsXValue().GetString() : "0"; over_reward.hero.obtain_gold = hero_xobj->At("obtain_ceg")->AsXValue().GetString(); over_reward.hero.gold_limit = hero_xobj->At("ceg_uplimit")->AsXValue().GetString(); if (hum->GetBattleContext()->hero_dto && hum->GetBattleContext()->hero_dto->IsObject()) { over_reward.hero.id = hum->GetBattleContext()->hero_dto->At("hero_id")->AsXValue(); } } } { auto weapon_xobj = reward_xobj->At("weapon1"); if (weapon_xobj && weapon_xobj->IsObject()) { over_reward.weapon1.curr_gold = weapon_xobj->At("curr_ceg") ? weapon_xobj->At("curr_ceg")->AsXValue().GetString() : ""; over_reward.weapon1.obtain_gold = weapon_xobj->At("obtain_ceg")->AsXValue().GetString(); over_reward.weapon1.gold_limit = weapon_xobj->At("ceg_uplimit")->AsXValue().GetString(); if (hum->GetBattleContext()->weapon_dto1 && hum->GetBattleContext()->weapon_dto1->IsObject()) { over_reward.weapon1.id = hum->GetBattleContext()->weapon_dto1->At("gun_id")->AsXValue(); } } } { auto weapon_xobj = reward_xobj->At("weapon2"); if (weapon_xobj && weapon_xobj->IsObject()) { over_reward.weapon2.curr_gold = weapon_xobj->At("curr_ceg") ? weapon_xobj->At("curr_ceg")->AsXValue().GetString() : "0"; over_reward.weapon2.obtain_gold = weapon_xobj->At("obtain_ceg")->AsXValue().GetString(); over_reward.weapon2.gold_limit = weapon_xobj->At("ceg_uplimit")->AsXValue().GetString(); if (hum->GetBattleContext()->weapon_dto2 && hum->GetBattleContext()->weapon_dto2->IsObject()) { over_reward.weapon2.id = hum->GetBattleContext()->weapon_dto2->At("gun_id")->AsXValue(); } } } { auto items_xobj = reward_xobj->At("items"); if (items_xobj && items_xobj->IsArray()) { for (int i = 0; i < items_xobj->Size(); ++i) { auto item_xobj = items_xobj->At(i); if (item_xobj && item_xobj->IsObject()) { over_reward.items.push_back (std::make_tuple ( item_xobj->At("item_id")->AsXValue(), item_xobj->At("item_num")->AsXValue() ) ); } } } } { auto score_info_xobj = xobj.At("score_info"); if (score_info_xobj && score_info_xobj->IsObject()) { old_rank = score_info_xobj->At("old_rank")->AsXValue(); new_rank = score_info_xobj->At("new_rank")->AsXValue(); old_score = score_info_xobj->At("old_score")->AsXValue(); new_score = score_info_xobj->At("new_score")->AsXValue(); } } AdjustRewardData(); } void PlayerStats::AdjustRewardData() { auto EmptyStrToZero = [] (std::string& str) { if (str.empty()) { str = "0"; } }; EmptyStrToZero(over_reward.total_ceg); { EmptyStrToZero(over_reward.hero.curr_gold); EmptyStrToZero(over_reward.hero.obtain_gold); EmptyStrToZero(over_reward.hero.gold_limit); } { EmptyStrToZero(over_reward.weapon1.curr_gold); EmptyStrToZero(over_reward.weapon1.obtain_gold); EmptyStrToZero(over_reward.weapon1.gold_limit); } { EmptyStrToZero(over_reward.weapon2.curr_gold); EmptyStrToZero(over_reward.weapon2.obtain_gold); EmptyStrToZero(over_reward.weapon2.gold_limit); } } Human::Human():Creature() { default_weapon.weapon_idx = 0; default_weapon.weapon_id = 30101; default_weapon.ammo = 1; default_weapon.meta = mt::Equip::GetById(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; if (mt::Param::s().fighting_mode) { AddInventory(IS_9MM, FIGHTING_MODE_BULLET_NUM); AddInventory(IS_556MM, FIGHTING_MODE_BULLET_NUM); AddInventory(IS_762MM, FIGHTING_MODE_BULLET_NUM); AddInventory(IS_12GAUGE, FIGHTING_MODE_BULLET_NUM); AddInventory(IS_RPG, FIGHTING_MODE_BULLET_NUM); AddInventory(IS_ICE, FIGHTING_MODE_BULLET_NUM); } } Human::~Human() { int i = 0; } void Human::Initialize() { Creature::Initialize(); volume_ = meta->_volume; observers_.insert(this); SetCurrWeapon(&weapons[0]); SetOxygen(mt::Param::s().dive_oxygen_total); } float Human::GetSpeed() { { Buff* buff = GetBuffByEffectId(kBET_JumpTo); if (buff) { return buff->meta->_buff_param2; } } { Buff* buff = GetBuffByEffectId(kBET_HoldShield); if (buff) { return buff->meta->_buff_param1; } } { Buff* buff = GetBuffByEffectId(kBET_Jump); if (buff) { return meta->jump_speed(); } } { Buff* buff = GetBuffByEffectId(kBET_BePull); if (buff) { return buff->meta->_buff_param2; } } { Buff* buff = GetBuffByEffectId(kBET_Sprint); if (buff) { return buff->meta->_buff_param2; } } float speed = 1.0; if (downed) { speed = meta->move_speed3(); } else { if (shot_hold) { if (GetCurrWeapon()->weapon_idx == GUN_SLOT1 || GetCurrWeapon()->weapon_idx == GUN_SLOT2) { if (action_type != AT_Reload) { speed = meta->shot_speed() * (1 + GetAbility()->GetAttrRate(kHAT_ShotSpeed)); if (HasBuffEffect(kBET_InWater)) { speed *= mt::Param::s().water_move_coefficient; } return speed; } } } else if (aiming) { speed = std::max(1, meta->aiming_speed()); if (HasBuffEffect(kBET_InWater)) { speed *= mt::Param::s().water_move_coefficient; } return speed; } else if (action_type == AT_Reload) { speed = std::max(1, meta->reload_speed()); if (HasBuffEffect(kBET_InWater)) { speed *= mt::Param::s().water_move_coefficient; } return speed; } else if (action_type == AT_UseItem) { speed = std::max(1, meta->useitem_speed()); if (HasBuffEffect(kBET_InWater)) { speed *= mt::Param::s().water_move_coefficient; } return speed; } speed = meta->move_speed(); } float old_speed = speed; #if 1 speed = (speed * SERVER_FRAME_RATE * (1 + GetAbility()->GetSpeedAddition() - GetAbility()->GetSpeedRuduce())) / SERVER_FRAME_RATE; #else speed = (speed + GetAbility()->GetAttrAbs(kHAT_Speed)) * (1 + GetAbility()->GetAttrRate(kHAT_Speed)); #endif if (HasBuffEffect(kBET_InWater)) { speed *= mt::Param::s().water_move_coefficient; } return std::max(speed, 1.0f); } float Human::GetSpeed4() { return meta->move_speed4(); } bool Human::IsDead(Room * room) { return dead; } long long Human::GetDeadFrameNo(Room* room) { return dead_frameno; } long long Human::GetRealDeadFrameNo(Room* room) { return real_dead_frameno; } void Human::CarShot(const glm::vec3& 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.bullet_meta, nullptr, 5, 0, 0); --second_weapon.ammo; last_shot_frameno_ = room->GetFrameNo(); } void Human::BeKill(int killer_id, const std::string& killer_name, int weapon_id, int real_killer_id, const std::string& real_killer_name) { if (!dead && !room->IsGameOver() && !real_dead && !a8::HasBitFlag(status, CS_PreDieSuspended)) { GetTrigger()->PreDie(killer_id, weapon_id); #ifdef DEBUG { if (!f8::IsTestEnv()) { a8::XPrintf("BeKill killer_id:%d killer_name:%s over_delay_time:%d\n", { killer_id, killer_name, over_delay_time }); } } #endif if (over_delay_time > 0) { std::shared_ptr info = std::make_shared(); info->killer_id = killer_id; info->killer_name = killer_name; info->weapon_id = weapon_id; info->real_killer_id = real_killer_id; info->real_killer_name = real_killer_name; a8::SetBitFlag(status, CS_PreDieSuspended); room->xtimer.SetTimeoutEx (over_delay_time / FRAME_RATE_MS, [this, info] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { over_delay_time = 0; a8::UnSetBitFlag(status, CS_PreDieSuspended); InternalBeKill ( info->killer_id, info->killer_name, info->weapon_id, info->real_killer_id, info->real_killer_name ); } }, &xtimer_attacher); } else { InternalBeKill(killer_id, killer_name, weapon_id, real_killer_id, real_killer_name); } } } void Human::DecHP(float dec_hp, int killer_id, const std::string& killer_name, int weapon_id, int real_killer_id, const std::string& real_killer_name) { if (!room->BattleStarted()) { return; } #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->_buff_param2); } } if (HasBuffEffect(kBET_Invincible)) { return; } { Human* hum = room->GetHumanByUniId(real_killer_id); if (hum) { attacker_hash_[real_killer_id] = room->GetFrameNo(); } } struct DownedInfo { int killer_id = 0; std::string killer_name; int weapon_id = 0; int real_killer_id = 0; std::string real_killer_name; }; last_receive_dmg_frameno = room->GetFrameNo(); 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.expired()) { room->xtimer.Delete(downed_timer); } downed = false; BeKill(killer_id, killer_name, weapon_id, real_killer_id, real_killer_name); SyncAroundPlayers(__FILE__, __LINE__, __func__); } else { if (HasNoDownedTeammate() && !room->IsPveRoom()) { SetHP(mt::Param::GetIntParam("downed_recover_hp")); downed = true; if (HasBuffEffect(kBET_Camouflage)) { RemoveBuffByEffectId(kBET_Camouflage); } CancelAction(); DoGetDown(); std::shared_ptr info = std::make_shared(); info->killer_id = killer_id; info->killer_name = killer_name; info->weapon_id = weapon_id; info->real_killer_id = real_killer_id; info->real_killer_name = real_killer_name; downed_timer = room->xtimer.SetIntervalWpEx ( SERVER_FRAME_RATE, [this, info] (int event, const a8::Args* args) mutable { if (a8::TIMER_EXEC_EVENT == event) { if (!downed) { FreeDownedTimer(); return; } if (dead) { FreeDownedTimer(); return; } if (!HasLiveTeammate()) { FreeDownedTimer(); BeKill(info->killer_id, info->killer_name, info->weapon_id, info->real_killer_id, info->real_killer_name); return; } int dec_hp = mt::Param::GetIntParam("downed_dec_hp"); DecHP(dec_hp, info->killer_id, info->killer_name, info->weapon_id, info->real_killer_id, info->real_killer_name); } }, &xtimer_attacher); SyncAroundPlayers(__FILE__, __LINE__, __func__); TryAddBuff(this, kDownBuffId); } else { BeKill(killer_id, killer_name, weapon_id, real_killer_id, real_killer_name); } } } room->frame_event.AddHpChg(GetWeakPtrRef()); } GetTrigger()->HpChg(); } void Human::AddToNewObjects(Entity* entity) { framedata_.new_objects[entity->GetUniId()] = entity->GetEntityWeakPtrRef(); } void Human::AddToImageObjects(Creature* c) { framedata_.image_objects[c->GetUniId()] = c->GetWeakPtrRef(); } void Human::AddToPartObjects(Entity* entity) { #ifdef DEBUG1 { if (!follow_target_) { for (Human* ob : observers_) { if (ob->IsPlayer()) { TraceMgr::Instance()->Trace (a8::Format("add part_object %d->%d frameno:%d %d", { GetUniId(), ob->GetUniId(), room->GetFrameNo(), entity->GetUniId() })); } } } } #endif 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(); framedata_.part_objects[entity->GetUniId()] = part_obj; entity->OnAddToTargetPartObject(this); } void Human::RemovePartObjects(Entity* entity) { #ifdef DEBUG1 if (!follow_target_) { for (Human* observer : observers_) { if (observer->IsPlayer()) { observer->SendDebugMsg(a8::Format("view_debug %d->%d frameno:%d remove_part_obj:%d", { GetUniId(), observer->GetUniId(), room->GetFrameNo(), entity->GetUniId() })); } } } #endif framedata_.part_objects.erase(entity->GetUniId()); entity->OnRemoveFromTargetPartObject(this); } void Human::ClearPartObjects() { framedata_.part_objects.clear(); } int Human::GetPartObjectsCount() { return framedata_.part_objects.size(); } bool Human::InNewObjects(Entity* target) { return framedata_.new_objects.find(target->GetUniId()) != framedata_.new_objects.end(); } bool Human::InPartObjects(Entity* target) { return framedata_.part_objects.find(target->GetUniId()) != framedata_.part_objects.end(); } void Human::RemoveObjects(Entity* entity) { framedata_.del_objects.insert(entity->GetUniId()); framedata_.new_objects.erase(entity->GetUniId()); } void Human::AddOutObjects(Entity* entity) { framedata_.out_objects.insert(entity->GetUniId()); } void Human::RemoveOutObjects(Entity* entity) { framedata_.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().Distance2D2(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__); } } void Human::DoGetOn(int obj_uniid) { if (room->GetGasData().GetGasMode() == GasInactive) { return; } Entity* entity = room->GetEntityByUniId(obj_uniid); if (!entity) { return; } if (GetPos().Distance2D2(entity->GetPos()) > mt::Param::s().max_mount_horse_distance) { return; } if (downed) { return; } if (HasBuffEffect(kBET_Become)) { 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(); f8::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}); } f8::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}); } f8::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(); f8::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(); f8::UdpLog::Instance()->Debug("syncaround end %s %d %s", { file, line, func }); #endif #endif } void Human::RecalcVolume() { const mt::Equip* backpack_meta = mt::Equip::GetById(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() { #if 0 xxxxxxxx const mt::Equip* chest_meta = mt::Equip::GetById(chest); float def = meta->def(); if (chest_meta) { def += chest_meta->def(); } const mt::Equip* helmet_meta = mt::Equip::GetById(helmet); if (helmet_meta) { def += helmet_meta->def(); } SetDef(def); #endif } int Human::GetVolume(int slot_id) { if (!IsValidSlotId(slot_id)) { A8_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::AddObserver(Human* observer) { observers_.insert(observer); } void Human::RemoveObserver(Human* observer) { observers_.erase(observer); } bool Human::HasObserver() { return observers_.size() > 1; } void Human::FollowTarget(Human* target) { if (target == this) { return; } int pre_uniid = 0; if (follow_target_) { pre_uniid = follow_target_->GetUniId(); follow_target_->RemoveObserver(this); } target->AddObserver(this); follow_target_ = target; follow_synced_active_player = false; #ifdef DEBUG SendDebugMsg(a8::Format("观战 watch %d->%d->%d frameno:%d", { room->GetFrameNo(), pre_uniid, follow_target_->GetUniId(), GetUniId() })); #endif } 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: { RemoveBuffByEffectId(kBET_InRescue); } break; default: { } break; } ResetAction(); } } void Human::UpdateMove() { Creature::UpdateMove(); } void Human::GenBattleReportData(a8::MutableXObject* params) { params->SetVal("room_mode", room->GetRoomMode()); int rank = 0; { std::vector human_list; room->TraverseHumanList( [&human_list] (Human* hum) -> 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; if (room->IsPveRoom()) { if (stats.pve_kill_boss) { stats.victory = true; stats.settlement_color = 1; } } else { stats.victory = stats.rank == 1; if (GetTeam()->GetAliveNum() <= 0) { GetTeam()->team_rank = room->GetAliveTeamNum(); stats.pvp_settlement_type = GetTeam()->GetMemberNum() > 1 ? 1 : 0; stats.settlement_color = 1; } else { if (room->GetAliveTeamNum() == 1) { if (room->GetAliveTeam() == GetTeam()) { GetTeam()->team_rank = 1; stats.pvp_settlement_type = GetTeam()->GetMemberNum() > 1 ? 1 : 0; stats.settlement_color = 1; } } } if (rank < 10) { stats.settlement_color = 1; } if (stats.victory) { GetTeam()->team_rank = 0; } } } if (!stats.statemented) { stats.Statement(this); } params->SetVal("account_id", account_id); params->SetVal("session_id", session_id); params->SetVal("team_id", team_id); params->SetVal("pve_instance_id", room->IsPveRoom() ? room->pve_instance->gemini_id() : 0); params->SetVal("pve_instance_mode", room->IsPveRoom() ? room->pve_mode_meta->id() : 0); params->SetVal("battle_uuid", battle_uuid); params->SetVal("match_mode", room->IsPveRoom() ? 2 : 0); params->SetVal("is_valid_battle", is_valid_battle); params->SetVal("payload", payload); params->SetVal("map_id", room->GetMapMeta()->map_id()); params->SetVal("map_name", room->GetMapMeta()->map_name()); params->SetVal("team_mode", GetTeam() && GetTeam()->GetMemberNum() > 1 ? 1 : 0); params->SetVal("map_tpl_name", room->GetMapTplName()); params->SetVal("room_uuid", room->GetRoomUuid()); params->SetVal("room_mode", room->GetRoomMode()); params->SetVal("hero_id", meta->id()); params->SetVal("hero_uniid", hero_uniid); params->SetVal("game_time", time(nullptr)); //? int alive_time = room->GetFrameNo() * FRAME_RATE_MS; if (!dead) { params->SetVal("alive_time", alive_time); } else { alive_time = (dead_frameno - room->GetBattleStartFrameNo()) * FRAME_RATE_MS; if (room->GetBattleStartFrameNo() <= 0) { alive_time = 0; } params->SetVal("alive_time", alive_time); } params->SetVal("weapon_uuid1", spec_weapons.size() > 0 ? spec_weapons[0].weapon_uniid : 0); params->SetVal("weapon_uuid2", spec_weapons.size() > 1 ? spec_weapons[1].weapon_uniid : 0); params->SetVal("ranked", rank); params->SetVal("kills", stats.kills); params->SetVal("damage_out", stats.damage_amount_out); params->SetVal("rescue_teammate_times", stats.rescue_member); params->SetVal("diving_times", stats.diving_times); params->SetVal("damage_in", stats.damage_amount_in); params->SetVal("recover_hp", stats.heal_amount); params->SetVal("open_airdrop_times", stats.open_airdrop_times); params->SetVal("use_medicine_times", stats.use_medicine_times); params->SetVal("destory_car_times", stats.destory_car_times); params->SetVal("use_camouflage_times", stats.use_camouflage_times); params->SetVal("use_skill_times", stats.use_skill_times); params->SetVal("ride_car_move_distance", stats.ride_car_move_distance); params->SetVal("ride_car_kills", stats.ride_car_kills); params->SetVal("max_hero_skill_lv", stats.max_hero_skill_lv); { params->SetVal("pve_rank_score", stats.pve_rank_score); params->SetVal("pve_kill_boss", stats.pve_kill_boss); } { std::string weapons_type; std::string weapons_slot; for (auto& pair : stats.weapon_stats) { auto& weapon = pair.second; if (weapon.kills || weapon.damage_out || weapon.obtain_count) { weapons_type += a8::Format("%d:%d:%d:%d|", { weapon.weapon_id, weapon.kills, weapon.damage_out, weapon.obtain_count }); } if (weapon.use_times) { weapons_slot += a8::Format("%d:%d|", { weapon.weapon_id, weapon.use_times }); } } params->SetVal("weapons_type", weapons_type); params->SetVal("weapons_slot", weapons_slot); } { std::string heros; for (auto& pair : stats.hero_stats) { auto& hero = pair.second; if (hero.skill_lv || hero.weapon_lv) { heros += a8::Format("%d:%d:%d|", { hero.hero_id, hero.skill_lv, hero.weapon_lv, }); } } params->SetVal("heros", heros); } { float rank_param = mt::RankReward::GetRankRewardParam(rank); float kill_param = mt::KillReward::GetKillRewardParam(stats.kills); int coin_num = (rank_param * mt::Param::s().rank_param) + (kill_param * mt::Param::s().kill_param); stats.gold = coin_num; params->SetVal("coin_num", coin_num); } { std::string items_str; for (auto& pair : battlein_items) { items_str += a8::Format("%d:%d|", {pair.first, pair.second }); } params->SetVal("items", items_str); } { stats.pass_score = mt::KillPoint::GetKillPointParam1(stats.kills); stats.pass_score += mt::RankPoint::GetRankPointParam1(rank); stats.rank_score = mt::KillPoint::GetKillPointParam2(stats.kills); stats.rank_score += mt::RankPoint::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); { params->SetVal("ranked_topx", stats.ranked_topx); params->SetVal("kills_topx", stats.kills_topx); params->SetVal("hero_topx", stats.hero_topx); params->SetVal("weapon_topx", stats.weapon_topx); params->SetVal("survival_topx", stats.survival_topx); params->SetVal("hero_stats_uniid", stats.pb_hero_stats.hero_uniid); params->SetVal("hero_stats_name", stats.pb_hero_stats.hero_name); params->SetVal("hero_stats_hero_id", stats.pb_hero_stats.hero_id); params->SetVal("hero_stats_reward_ceg", stats.pb_hero_stats.reward_ceg); params->SetVal("hero_stats_today_get_ceg", stats.pb_hero_stats.today_get_ceg); params->SetVal("hero_stats_ceg_uplimit", stats.pb_hero_stats.ceg_uplimit); for (int i = 0; i < stats.pb_weapons_stats.size(); ++i) { auto& p = stats.pb_weapons_stats.at(i); std::string i_str = a8::XValue(i).GetString(); params->SetVal("weapon_stats_uniid" + i_str, p.weapon_uniid); params->SetVal("weapon_stats_name" + i_str, p.weapon_name); params->SetVal("weapon_stats_weapon_id" + i_str, p.weapon_id); params->SetVal("weapon_stats_reward_ceg" + i_str, p.reward_ceg); params->SetVal("weapon_stats_today_get_ceg" + i_str, p.today_get_ceg); params->SetVal("weapon_stats_ceg_uplimit" + i_str, p.ceg_uplimit); } } { std::shared_ptr post_data = a8::MutableXObject::CreateObject(); std::shared_ptr team_list = a8::MutableXObject::CreateArray(); room->TraverseTeams ( [team_list] (Team* team) { std::shared_ptr team_data = a8::MutableXObject::CreateObject(); std::shared_ptr members_list = a8::MutableXObject::CreateArray(); team->TraverseMembers ( [members_list] (Human* hum) { std::shared_ptr member = a8::MutableXObject::CreateObject(); member->SetVal("account_id", hum->account_id); members_list->Push(*member.get()); return true; }); team_data->SetVal("team_id", team->GetTeamId()); team_data->SetVal("members", *members_list.get()); team_list->Push(*team_data.get()); return true; }); post_data->SetVal("team_list", *team_list.get()); params->SetVal("__POST", post_data->ToJsonStr()); } } void Human::DeadDrop() { #ifdef DEBUG a8::XPrintf("DeadDrop\n", {}); //room->DropItem(GetPos(), 30908, 1, 1); //return; #endif auto SkinCanDrop = [this] (Skin* skin) -> bool { #ifdef DEBUG return false; #else return skin->skin_id != 0; #endif }; if (a8::HasBitFlag(status, CS_DeadNoDrop)) { return; } if (!(HasBuffEffect(kBET_Become) && GetBuffByEffectId(kBET_Become)->FreezeOperate())) { for (auto& weapon : weapons) { if (weapon.weapon_id != 0 && weapon.weapon_id != default_weapon.weapon_id ) { Position drop_pos = GetPos(); room->DropItem(drop_pos, weapon.weapon_id, 1, 1); if (weapon.ammo > 0 && weapon.bullet_meta && weapon.ammo < 200) { if (IsPlayer() && weapon.bullet_meta && IsValidSlotId(weapon.bullet_meta->_inventory_slot())) { AddInventory(weapon.bullet_meta->_inventory_slot(), weapon.ammo); } } if (IsAndroid() && weapon.bullet_meta) { int drop_num = weapon.bullet_meta->group_num(); room->DropItem(GetPos(), weapon.bullet_meta->id(), drop_num, 1); } 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)) { glm::vec3 dir = GlmHelper::UP; GlmHelper::RotateY(dir, a8::RandAngle()); Position drop_pos = GetPos(); drop_pos.AddGlmVec3(dir * (40.0f + rand() % 50)); room->CreateLoot(old_skin->skin_id, drop_pos, 1, 1); *old_skin = Skin(); } } { Skin* old_skin = GetSkinByIdx(kSkinSlot_CLOTH); if (old_skin && old_skin->skin_id != 0 && SkinCanDrop(old_skin)) { glm::vec3 dir = GlmHelper::UP; GlmHelper::RotateY(dir, a8::RandAngle()); Position drop_pos = GetPos(); drop_pos.AddGlmVec3(dir * (40.0f + rand() % 50)); room->CreateLoot(old_skin->skin_id, drop_pos, 1, 1); *old_skin = Skin(); } } { //头盔 if (helmet != 0) { glm::vec3 dir = GlmHelper::UP; GlmHelper::RotateY(dir, a8::RandAngle()); Position drop_pos = GetPos(); drop_pos.AddGlmVec3(dir * (40.0f + rand() % 50)); room->CreateLoot(helmet, drop_pos, 1, 1); helmet = 0; } //衣服 if (chest != 0) { glm::vec3 dir = GlmHelper::UP; GlmHelper::RotateY(dir, a8::RandAngle()); Position drop_pos = GetPos(); drop_pos.AddGlmVec3(dir * (40.0f + rand() % 50)); room->CreateLoot(chest, drop_pos, 1, 1); chest = 0; } //背包 if (backpack != 0) { glm::vec3 dir = GlmHelper::UP; GlmHelper::RotateY(dir, a8::RandAngle()); Position drop_pos = GetPos(); drop_pos.AddGlmVec3(dir * (40.0f + rand() % 50)); room->CreateLoot(backpack, drop_pos, 1, 1); backpack = 0; } } for (size_t slot = 0; slot < GetInventoryData().size(); ++slot) { if (GetInventory(slot) > 0 && !mt::Param::s().fighting_mode) { const mt::Equip* equip_meta = mt::Equip::GetByIdBySlotId(slot); if (equip_meta) { int drop_num = equip_meta->group_num(); if (equip_meta->equip_type() == EQUIP_TYPE_BULLET) { switch (equip_meta->_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) { Position drop_pos = GetPos(); if (IsPlayer()) { room->DropItem(drop_pos, equip_meta->id(), GetInventory(slot), 1); } else { room->DropItem(drop_pos, equip_meta->id(), drop_num, 1); } DecInventory(slot, GetInventory(slot)); } } break; default: { if (drop_num > 0) { Position drop_pos = GetPos(); if (IsPlayer()) { room->DropItem(drop_pos, equip_meta->id(), GetInventory(slot), 1); } else { #if 1 if (GetCurrWeapon()) { } #else room->DropItem(drop_pos, equip_meta->id(), drop_num, 1); #endif } DecInventory(slot, GetInventory(slot)); } } break; } } else { Position drop_pos = GetPos(); room->DropItem(drop_pos, equip_meta->id(), GetInventory(slot), 1); } } } } MarkSyncActivePlayer(__FILE__, __LINE__, __func__); } void Human::SendBattleReport() { std::shared_ptr params = a8::MutableXObject::CreateObject(); GenBattleReportData(params.get()); std::string url; JsonDataMgr::Instance()->GetApiUrl(url); if (url.find('?') != std::string::npos) { url += "c=Battle&a=battleReport"; } else { url += "?c=Battle&a=battleReport"; } std::string data; params->ToUrlEncodeStr(data); if (stats.is_run_away) { sending_battlereport_ = false; already_report_battle_ = true; SendGameOver(); } else { long long room_uuid = room->GetRoomUuid(); std::string sender_id = account_id; HttpProxy::Instance()->HttpGet ( [room_uuid, sender_id, data] (bool ok, a8::XObject* rsp_obj, f8::HttpContext* ctx) { if (!ok) { f8::UdpLog::Instance()->Error("battleReport http error params: %s response: %s", { data, "" }); } Room* room = RoomMgr::Instance()->GetRoomByUuid(room_uuid); if (!room) { return; } Player* hum = room->GetPlayerByAccountId(sender_id); if (!hum) { return; } if (ok) { hum->sending_battlereport_ = false; hum->already_report_battle_ = true; hum->stats.ParseReward(hum, *rsp_obj); hum->SendGameOver(); hum->SendBattleSettlement(); } else { hum->sending_battlereport_ = false; } }, url.c_str(), *params.get() ); } } void Human::ProcLootSkin(AddItemDTO& dto) { switch (dto.item_meta->equip_subtype()) { case 11: { //装饰 Skin* old_skin = GetSkinByIdx(kSkinSlot_HAT); if (old_skin) { if (old_skin->skin_id != 0) { glm::vec3 dir = GlmHelper::UP; GlmHelper::RotateY(dir, a8::RandAngle()); Position drop_pos = GetPos(); drop_pos.AddGlmVec3(dir * (40.0f + rand() % 50)); room->CreateLoot(old_skin->skin_id, drop_pos, 1, 1); } *old_skin = Skin(); old_skin->skin_id = dto.item_meta->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) { glm::vec3 dir = GlmHelper::UP; GlmHelper::RotateY(dir, a8::RandAngle()); Position drop_pos = GetPos(); drop_pos.AddGlmVec3(dir * (40.0f + rand() % 50)); room->CreateLoot(old_skin->skin_id, drop_pos, 1, 1); } *old_skin = Skin(); old_skin->skin_id = dto.item_meta->id(); old_skin->skin_lv = 1; SyncAroundPlayers(__FILE__, __LINE__, __func__); } } break; } dto.handled = true; } void Human::ProcLootCar(AddItemDTO& dto) { DoGetOn(dto.uniid); dto.handled = true; } void Human::ProcNormalItem(AddItemDTO& dto) { AddItem(dto.item_meta->id(), 1); dto.handled = true; MarkSyncActivePlayer(__FILE__, __LINE__, __func__); } void Human::ProcSpoils(AddItemDTO& dto) { dto.handled = true; } void Human::OnDie() { { if (HasBuffEffect(kBET_Camouflage)) { RemoveBuffByEffectId(kBET_Camouflage); } 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; }); } if (real_dead) { 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(); } } if (observers_.size() > 1) { std::vector exclude_self_observers; for (auto& observer : observers_) { if (observer != this) { exclude_self_observers.push_back(observer); } } for (auto& observer : exclude_self_observers) { observers_.erase(observer); observer->OnWatcherDie(this); } } DeadDrop(); } void Human::FreeDownedTimer() { RemoveBuffById(kDownBuffId); if (!downed_timer.expired()) { room->xtimer.Delete(downed_timer); } } void Human::FreeReviveTimer() { if (!revive_timer.expired()) { room->xtimer.Delete(revive_timer); } } 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::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); //为啥????? } items_.erase(itr); } } } void Human::DropItems(Obstacle* obstacle) { bool is_treasure_box = false; int drop_id = obstacle->meta->RandDrop(); if (drop_id == 0) { return; } if (drop_id == 0) { drop_id = obstacle->meta->RandDrop(); } room->ScatterDrop(obstacle->GetPos(), drop_id); if (is_treasure_box) { ++box_drop_times_; } else { ++normal_drop_times_; } } void Human::Revive() { { int wait_revive_time = mt::Param::GetIntParam("revive_time", 25) + kReviveTimeAdd; revive_timer = room->xtimer.SetTimeoutWpEx (SERVER_FRAME_RATE * wait_revive_time, [this] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { dead = true; real_dead = true; downed = false; OnDie(); } }, &xtimer_attacher); SyncAroundPlayers(__FILE__, __LINE__, __func__); } } void Human::CancelRevive() { if (dead && !revive_timer.expired() && !real_dead) { dead = true; real_dead = true; downed = false; FreeDownedTimer(); OnDie(); FreeReviveTimer(); } } void Human::AdjustDecHp(float old_health, float& new_health) { Buff* buff = GetBuffByEffectId(kBET_NewProtect); if (buff) { if (new_health < GetMaxHP() * buff->meta->_buff_param1) { new_health = std::max(GetMaxHP() * buff->meta->_buff_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(); framedata_.ClearFrameData(this); ClearPartObjects(); } void Human::GetViewObjects(std::set& view_objects) { TraverseCreatures ( [&view_objects] (Creature* c, bool& stop) { view_objects.insert(c); }); 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::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 f8::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 ( [this] (Human* hum) { hum->RemovePartObjects(this); return true; }); } 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) { const mt::Equip* bullet_meta = mt::Equip::GetById(p_weapon->meta->use_bullet()); if (bullet_meta) { int ammo = p_weapon->ammo; if (ammo < p_weapon->GetClipVolume(this)) { if (bullet_meta->_inventory_slot() >= 0 && bullet_meta->_inventory_slot() < IS_END) { if (GetInventory(bullet_meta->_inventory_slot()) > 0) { int add_num = 0; if (GetInventory(bullet_meta->_inventory_slot()) <= p_weapon->GetClipVolume(this) - ammo) { add_num = GetInventory(bullet_meta->_inventory_slot()); if (p_weapon->meta->reloadtype() == 1) { add_num = 1; } DecInventory(bullet_meta->_inventory_slot(), add_num); } else { add_num = p_weapon->GetClipVolume(this) - ammo; if (p_weapon->meta->reloadtype() == 1) { add_num = 1; } DecInventory(bullet_meta->_inventory_slot(), add_num); } p_weapon->ammo += add_num; MarkSyncActivePlayer(__FILE__, __LINE__, __func__); if (p_weapon->meta->reloadtype() == 1) { int weapon_idx = p_weapon->weapon_idx; int weapon_id = p_weapon->weapon_id; room->xtimer.SetTimeoutEx (1, [this, weapon_idx, weapon_id] (int event, const a8::Args* args) { NextReload(weapon_id, weapon_idx); }, &xtimer_attacher); } } } } } } } void Human::ProcUseItemAction() { const mt::Equip* item_meta = mt::Equip::GetByIdBySlotId(action_item_id); if (!item_meta) { return; } if (GetInventory(item_meta->_inventory_slot()) <= 0) { return; } switch (action_item_id) { case IS_HEALTHKIT: { +stats.use_medicine_times; AddHp(item_meta->heal() * (1 + GetAbility()->GetAttrRate(kHAT_DrugEfficacy))); DecInventory(item_meta->_inventory_slot(), 1); GetTrigger()->UseItemAction(action_item_id); } break; case IS_PAIN_KILLER: { +stats.use_medicine_times; if (!pain_killer_timer.expired()) { 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 = mt::Param::GetIntParam("anodyne_max_time"); left_time = std::min(left_time, anodyne_max_time * 1000); pain_killer_lastingtime += std::min(item_meta->time() * 1000, anodyne_max_time * 1000 - left_time) / 1000; } else { pain_killer_frameno = room->GetFrameNo(); pain_killer_lastingtime = item_meta->time(); if (pain_killer_lastingtime > 0) { auto heal = item_meta->heal(); pain_killer_timer = room->xtimer.SetIntervalWpEx ( SERVER_FRAME_RATE, [this, heal] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { AddHp(heal); if (room->GetFrameNo() - pain_killer_frameno > pain_killer_lastingtime * SERVER_FRAME_RATE) { room->xtimer.Delete(pain_killer_timer); } } }, &xtimer_attacher); } AddHp(item_meta->heal()); } DecInventory(item_meta->_inventory_slot(), 1); MarkSyncActivePlayer(__FILE__, __LINE__, __func__); GetTrigger()->UseItemAction(action_item_id); } break; case IS_SHEN_BAO: { +stats.use_medicine_times; if (!shen_bao_timer.expired()) { a8::Args args({item_meta->time()}); room->xtimer.FireEvent(shen_bao_timer, kShenBaoAddTimeTimerEvent, &args); } else { int exec_time = 0; int total_time = item_meta->time(); int heal = item_meta->heal(); shen_bao_timer = room->xtimer.SetIntervalWpEx ( SERVER_FRAME_RATE, [this, exec_time, total_time, heal] (int event, const a8::Args* args) mutable { if (a8::TIMER_EXEC_EVENT == event) { exec_time += 1; if (exec_time >= total_time || dead) { room->xtimer.DeleteCurrentTimer(); } else { AddHp(heal); } } else if (kShenBaoAddTimeTimerEvent == event) { total_time += args->Get(0); } }, &xtimer_attacher); AddHp(heal); } DecInventory(item_meta->_inventory_slot(), 1); MarkSyncActivePlayer(__FILE__, __LINE__, __func__); GetTrigger()->UseItemAction(action_item_id); } break; default: { } break; } } void Human::ProcReliveAction() { RemoveBuffByEffectId(kBET_Rescuer); 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(); } if (!dead && downed) { SetHP(mt::Param::GetFloatParam("downed_relive_recover_hp") * GetMaxHP()); downed = false; if (!downed_timer.expired()) { room->xtimer.Delete(downed_timer); } ++hum->stats.rescue_member; if (hum->guild_id != 0 && hum->guild_id == guild_id) { ++hum->stats.rescue_guild_member; } if (GetBuffById(kDownBuffId)) { RemoveBuffById(kDownBuffId); } } SyncAroundPlayers(__FILE__, __LINE__, __func__); } void Human::OnBuffRemove(Buff& buff) { Creature::OnBuffRemove(buff); } 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) { const mt::Equip* item_meta = mt::Equip::GetById(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_ids) { if (action_type == AT_Reload || action_type == AT_UseItem ) { CancelAction(); } } void Human::DoSkillPostProc(bool used, int skill_id, int target_id) { 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->radius(); } float Human::GetHitRadius() { return meta->hit_radius(); } void Human::UpdateViewObjects() { if (view_objects_.size() >= 2) { std::vector deleted_humans; for (Human* hum : view_objects_) { if (hum->dead || hum->GetPos().ManhattanDistance2D(GetPos()) > mt::Param::s().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().ManhattanDistance2D(GetPos()) < mt::Param::s().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_.expired()) { room->xtimer.ModifyTime (refresh_view_timer_, SERVER_FRAME_RATE * (mt::Param::s().refresh_view_time + (rand() % 3)) ); } } } void Human::GMAddItem(int item_id, int item_num) { const mt::Equip* item_meta = mt::Equip::GetById(item_id); if (!item_meta) { return; } AddItemDTO dto; dto.uniid = 0; dto.item_id = item_id; dto.count = item_num; dto.item_level = 1; dto.handled = false; dto.item_meta = item_meta; ProcAddItemDto(dto); MarkSyncActivePlayer(__FILE__, __LINE__, __func__); SyncAroundPlayers(__FILE__, __LINE__, __func__); } void Human::OnBulletHit(IBullet* bullet) { if (IsInvincible()) { return; } if (HasBuffEffect(kBET_Jump) || HasBuffEffect(kBET_Fly)) { return; } { Buff* buff = GetBuffByEffectId(kBET_Camouflage); if (buff && buff->meta->_int_buff_param2 == 1) { return; } } #ifdef DEBUG #if 0 if (IsPlayer()) { return; } #endif #endif if (bullet->GetSender().Get()) { bullet->GetSender().Get()->GetTrigger()->BulletHit(bullet, this); } RemoveBuffByEffectId(kBET_PeaceMode); RemoveBuffByEffectId(kBET_Hide); GetTrigger()->Attacked(bullet->GetSender().Get()); if (!dead && (bullet->IsBomb() || bullet->GetSender().Get()->team_id != team_id)) { float finaly_dmg = 0; if (bullet->GetSkillMeta() && SkillHelper::ProcBulletDmg(bullet, this, finaly_dmg)) { } else { finaly_dmg = bullet->GetSender().Get()->GetBattleContext()->CalcDmg(this, bullet); } if (bullet->GetSender().Get()->IsHuman()) { bullet->GetSender().Get()->AsHuman()->stats.damage_amount_out += finaly_dmg; } if (bullet->GetBulletMeta()->_buff_meta) { MustBeAddBuff(bullet->GetSender().Get(), bullet->GetBulletMeta()->buffid()); } if (bullet->GetSender().Get()->GetBattleContext()->IsCrit()) { room->frame_event.AddPropChg ( GetWeakPtrRef(), kPropCritDmg, 0, bullet->GetSender().Get()->GetBattleContext()->GetCritDmg() ); } if (bullet->GetSender().Get() && bullet->GetSender().Get()->IsCar() && bullet->GetPassenger().Get()) { if (!bullet->IsPreBattleBullet()) { DecHP(finaly_dmg, bullet->GetPassenger().Get()->GetUniId(), bullet->GetPassenger().Get()->GetName(), bullet->GetGunMeta()->id(), bullet->GetPassenger().Get()->GetUniId(), bullet->GetPassenger().Get()->GetName() ); } } else { if (!bullet->IsPreBattleBullet()) { if (bullet->GetSender().Get() && bullet->GetSender().Get()->IsHuman()) { bullet->GetSender().Get()->AsHuman()->stats.IncWeaponDamageOut (bullet->GetGunMeta()->id(), finaly_dmg); } DecHP(finaly_dmg, bullet->GetSender().Get()->GetUniId(), bullet->GetSender().Get()->GetName(), bullet->GetGunMeta()->id(), bullet->GetSender().Get()->GetUniId(), bullet->GetSender().Get()->GetName() ); } } } } void Human::OnExplosionHit(Explosion* e) { if (IsInvincible()) { return; } if (dead) { return; } if (e->IsPreBattleExplosion()) { return; } if (HasBuffEffect(kBET_Jump) || HasBuffEffect(kBET_Fly)) { return; } if (HasBuffEffect(kBET_Dive) && !mt::Param::s().dive_explosion_dmg_switch) { return; } int real_killer_id = 0; std::string real_killer_name; if (e->GetSender().Get()) { real_killer_id = e->GetSender().Get()->GetUniId(); real_killer_name = e->GetSender().Get()->GetName(); } RemoveBuffByEffectId(kBET_PeaceMode); float finaly_dmg = GetBattleContext()->CalcDmg(e); #if 1 { #else if (e->GetSender().Get()) { #endif DecHP(finaly_dmg, VP_Explosion, "", e->GetExplosionEffect(), real_killer_id, real_killer_name); } } void Human::SendRollMsgEx(KillInfo& info, const char* fmt, std::initializer_list args ) { } void Human::ProcUseItem(int item_id) { if (downed) { return; } const mt::Equip* item_meta = mt::Equip::GetById(item_id); if (item_meta && GetItemNum(item_id) > 0) { if (item_meta->use_scene() == 1 && !HasBuffEffect(kBET_InWater)) { SendSysPiaoMsg(TEXT("only_inwater_use", "only in water use"), a8::MkRgb(255, 0, 0), 3 ); return; } if (GetCar() && item_meta->equip_type() == EQUIP_TYPE_CAMOUFLAGE) { return; } std::shared_ptr old_context_ability = context_ability; glm::vec3 old_context_dir = context_dir; Position old_context_pos = context_pos; context_dir = GetAttackDir(); context_pos = GetPos(); if (item_meta->buffid() != 0) { TryAddBuff(this, item_meta->buffid()); } DecItem(item_id, 1); context_dir = old_context_dir; context_pos = old_context_pos; context_ability = old_context_ability; } } Weapon* Human::TakeonWeapon(const mt::Equip* equip_meta) { if (equip_meta->equip_type() != EQUIP_TYPE_WEAPON) { return nullptr; } if (equip_meta->equip_subtype() == 1) { return nullptr; } Weapon* weapon = nullptr; for (int idx = GUN_SLOT1; idx <= GUN_SLOT2; ++idx) { if (weapons[idx].weapon_id == 0) { weapon = &weapons[idx]; weapon->weapon_idx = idx; break; } } return weapon; } void Human::StartRefreshViewTimer() { if (!refresh_view_timer_.expired()) { return; } refresh_view_timer_ = room->xtimer.SetIntervalWpEx ( SERVER_FRAME_RATE * mt::Param::s().refresh_view_time, [this] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { UpdateViewObjects(); } }, &xtimer_attacher); } void Human::ProcLootBag(AddItemDTO& dto) { const mt::Equip* old_item_meta = mt::Equip::GetById(backpack); if (old_item_meta) { if (old_item_meta->equip_lv() >= dto.item_meta->equip_lv()) { return; } room->DropItem(GetPos(), old_item_meta->id(), 1, 1); } backpack = dto.item_meta->id(); RecalcVolume(); dto.handled = true; MarkSyncActivePlayer(__FILE__, __LINE__, __func__); SyncAroundPlayers(__FILE__, __LINE__, __func__); } void Human::ProcLootProtection(AddItemDTO& dto) { if (dto.item_meta->equip_subtype() == 1) { //盔甲 const mt::Equip* old_item_meta = mt::Equip::GetById(chest); if (old_item_meta) { if (old_item_meta->equip_lv() >= dto.item_meta->equip_lv()) { return; } room->DropItem(GetPos(), old_item_meta->id(), 1, 1); } chest = dto.item_meta->id(); RecalcBaseAttr(); } else if (dto.item_meta->equip_subtype() == 2) { //头盔 const mt::Equip* old_item_meta = mt::Equip::GetById(helmet); if (old_item_meta) { if (old_item_meta->equip_lv() >= dto.item_meta->equip_lv()) { return; } room->DropItem(GetPos(), old_item_meta->id(), 1, 1); } helmet = dto.item_meta->id(); RecalcBaseAttr(); } dto.handled = true; MarkSyncActivePlayer(__FILE__, __LINE__, __func__); SyncAroundPlayers(__FILE__, __LINE__, __func__); } void Human::ProcLootSpecItem(AddItemDTO& dto) { if (dto.item_meta->_inventory_slot() >= 0 && dto.item_meta->_inventory_slot() < IS_END) { if (GetInventory(dto.item_meta->_inventory_slot()) >= GetVolume(dto.item_meta->_inventory_slot()) ) { return; } int add_num = GetVolume(dto.item_meta->_inventory_slot()) - GetInventory(dto.item_meta->_inventory_slot()); add_num = std::min(dto.count, add_num); AddInventory(dto.item_meta->_inventory_slot(), add_num); switch (dto.item_meta->_inventory_slot()) { case IS_FRAG: case IS_SMOKE: { Weapon* weapon = &weapons[SPEC1_SLOT_BEGIN + (dto.item_meta->_inventory_slot() - SPEC1_IS_BEGIN) ]; weapon->weapon_id = dto.item_id; weapon->ammo += dto.count; weapon->meta = dto.item_meta; weapon->Recalc(); #if 0 DecInventory(dto.item_meta->_inventory_slot(), add_num); #endif } break; case IS_1XSCOPE: case IS_2XSCOPE: case IS_4XSCOPE: case IS_8XSCOPE: case IS_15XSCOPE: { if (dto.item_meta->_inventory_slot() - IS_1XSCOPE > curr_scope_idx) { curr_scope_idx = dto.item_meta->_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 + (dto.item_meta->_inventory_slot() - SPEC2_IS_BEGIN) ]; weapon->weapon_id = dto.item_id; weapon->ammo += dto.count; weapon->meta = dto.item_meta; weapon->Recalc(); #if 0 DecInventory(dto.item_meta->_inventory_slot(), add_num); #endif } break; case IS_C4: case IS_SHIELD_WALL: case IS_SINGAL_GUN: case IS_OIL_BUCKET: { Weapon* weapon = &weapons[SPEC3_SLOT_BEGIN + (dto.item_meta->_inventory_slot() - SPEC3_IS_BEGIN) ]; weapon->weapon_id = dto.item_id; weapon->ammo += dto.count; weapon->meta = dto.item_meta; weapon->Recalc(); #if 0 DecInventory(dto.item_meta->_inventory_slot(), add_num); #endif } break; default: { int i = 0; #if 0 A8_ABORT(); #endif } break; } if (add_num < dto.count) { //刷新数量 Entity* entity = room->GetEntityByUniId(dto.uniid); if (entity && entity->IsEntityType(ET_Loot)) { ((Loot*)entity)->count -= add_num; ((Loot*)entity)->BroadcastFullState(room); } MarkSyncActivePlayer(__FILE__, __LINE__, __func__); if (action_type == AT_None) { AutoLoadingBullet(); } return; } } if (action_type == AT_None) { AutoLoadingBullet(); } MarkSyncActivePlayer(__FILE__, __LINE__, __func__); SyncAroundPlayers(__FILE__, __LINE__, __func__); dto.handled = true; } void Human::ProcGiftPackage(AddItemDTO& dto) { if (dto.item_meta->equip_type() == EQUIP_TYPE_GIFT_PACKAGE) { const mt::Drop* drop_meta = mt::Drop::GetById(dto.item_meta->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); auto itr = battlein_items.find(item_id); if (itr != battlein_items.end()) { itr->second += item_num; } else { battlein_items[item_id] = item_num; } } } } dto.handled = true; } void Human::ProcLootWeapon(AddItemDTO& dto) { //装备 if (dto.item_meta->equip_subtype() == 1) { //近战 if (default_weapon.weapon_id != weapons[0].weapon_id) { return; } else { weapons[0].weapon_idx = 0; weapons[0].weapon_id = dto.item_id; weapons[0].ammo = 0; weapons[0].meta = dto.item_meta; weapons[0].Recalc(); } MarkSyncActivePlayer(__FILE__, __LINE__, __func__); SyncAroundPlayers(__FILE__, __LINE__, __func__); } else { if (FreezeOperate()) { return; } bool switch_gun = false; Weapon* weapon = TakeonWeapon(dto.item_meta); if (weapon && GetCurrWeapon() != weapon) { if (GetCurrWeapon()->weapon_idx == 0) { switch_gun = true; } } if (!weapon) { return; } weapon->weapon_id = dto.item_id; weapon->ammo = 0; weapon->meta = dto.item_meta; weapon->Recalc(); if (HasBuffEffect(kBET_Car)) { } else { AutoLoadingBullet(); } if (switch_gun) { SetCurrWeapon(weapon); } MarkSyncActivePlayer(__FILE__, __LINE__, __func__); SyncAroundPlayers(__FILE__, __LINE__, __func__); } dto.handled = true; } void Human::LootInteraction(Loot* entity) { #ifdef DEBUG a8::XPrintf("LootInteraction start %d:%d\n", {entity->GetUniId(), entity->item_id}); #endif if (entity->pickuped || entity->count <= 0) { #ifdef DEBUG a8::XPrintf("LootInteraction error1 %d:%d\n", {entity->GetUniId(), entity->item_id}); #endif return; } AddItemDTO dto; dto.uniid = entity->GetUniId(); dto.item_id = entity->item_id; dto.count = entity->count; dto.item_level = entity->item_level; dto.handled = false; dto.item_meta = mt::Equip::GetById(entity->item_id); ProcAddItemDto(dto); if (dto.handled) { entity->pickuped = true; room->RemoveObjectLater(entity); } } void Human::ProcAddItemDto(AddItemDTO& dto) { if (!dto.item_meta) { #ifdef DEBUG a8::XPrintf("LootInteraction error20 %d:%d\n", {dto.uniid, dto.item_id}); #endif return; } switch (dto.item_meta->equip_type()) { case EQUIP_TYPE_WEAPON: { ProcLootWeapon(dto); } break; case EQUIP_TYPE_PROTECTION: { ProcLootProtection(dto); } break; case EQUIP_TYPE_BAG: { ProcLootBag(dto); } break; case EQUIP_TYPE_OLDSKIN: { A8_ABORT(); } break; case EQUIP_TYPE_SKIN: { ProcLootSkin(dto); } break; case EQUIP_TYPE_CAR: { ProcLootCar(dto); } break; case EQUIP_TYPE_SPOILS: { ProcSpoils(dto); } break; case EQUIP_TYPE_CAMOUFLAGE: case EQUIP_TYPE_SINGAL_EMITTER: { ProcNormalItem(dto); } break; case EQUIP_TYPE_GIFT_PACKAGE: { ProcGiftPackage(dto); } break; default: { ProcLootSpecItem(dto); } break; } } void Human::DropWeapon(int weapon_idx, int num) { num = std::max(1, num); switch (weapon_idx) { case 101: case 102: case 103: { int slot_id = -1; if (weapon_idx == 101) { slot_id = IS_HEALTHKIT; } else if (weapon_idx == 102) { slot_id = IS_PAIN_KILLER; } else if (weapon_idx == 103) { slot_id = IS_SHEN_BAO; } if (slot_id >= 0 && GetInventory(slot_id) > 0) { const mt::Equip* item_meta = mt::Equip::GetByIdBySlotId(slot_id); if (item_meta) { num = std::max(1, GetInventory(slot_id)); DecInventory(slot_id, num); MarkSyncActivePlayer(__FILE__, __LINE__, __func__); glm::vec3 drop_dir = GlmHelper::UP; GlmHelper::RotateY(drop_dir, a8::RandAngle()); Position drop_pos = GetPos(); drop_pos.AddGlmVec3(drop_dir * (25.0f + rand() % 50)); room->DropItem(drop_pos, item_meta->id(), num, 1); } } return; } default: { } break; } if (weapon_idx < 0 || weapon_idx >= weapons.size()) { return; } bool drop_ok = false; Weapon* weapon = &weapons[weapon_idx]; int weapon_id = weapon->weapon_id; int weapon_ammo = weapon->ammo; const mt::Equip* weapon_meta = weapon->meta; if (weapon->weapon_id != 0) { switch (weapon->weapon_idx) { case GUN_SLOT0: { if (weapon->weapon_id != default_weapon.weapon_id) { drop_ok = true; *weapon = default_weapon; } } break; case GUN_SLOT1: { drop_ok = true; *weapon = Weapon(); weapon->weapon_idx = weapon_idx; if (GetCurrWeapon() == weapon) { if (weapons[GUN_SLOT2].weapon_id != 0) { SetCurrWeapon(&weapons[GUN_SLOT2]); } else { SetCurrWeapon(&weapons[0]); } } } break; case GUN_SLOT2: { drop_ok = true; *weapon = Weapon(); weapon->weapon_idx = weapon_idx; if (GetCurrWeapon() == weapon) { if (weapons[GUN_SLOT1].weapon_id != 0) { SetCurrWeapon(&weapons[GUN_SLOT1]); } else { SetCurrWeapon(&weapons[0]); } } } break; case FRAG_SLOT: { weapon_ammo = std::min(weapon->ammo, num); if (weapon_ammo > 0) { drop_ok = true; weapon->ammo = std::max(0, weapon->ammo - weapon_ammo); int slot_id = weapon->meta->_inventory_slot(); DecInventory(slot_id, weapon_ammo); if (weapon->ammo <= 0) { *weapon = Weapon(); weapon->weapon_idx = weapon_idx; if (GetCurrWeapon() == weapon) { if (weapons[GUN_SLOT1].weapon_id != 0) { SetCurrWeapon(&weapons[GUN_SLOT1]); } else if (weapons[GUN_SLOT2].weapon_id != 0) { SetCurrWeapon(&weapons[GUN_SLOT2]); } else { SetCurrWeapon(&weapons[0]); } } } } } break; case SMOKE_SLOT: { weapon_ammo = std::min(weapon->ammo, num); if (weapon_ammo > 0) { drop_ok = true; weapon->ammo = std::max(0, weapon->ammo - weapon_ammo); int slot_id = weapon->meta->_inventory_slot(); DecInventory(slot_id, weapon_ammo); if (weapon->ammo <= 0) { *weapon = Weapon(); weapon->weapon_idx = weapon_idx; if (GetCurrWeapon() == weapon) { if (weapons[GUN_SLOT1].weapon_id != 0) { SetCurrWeapon(&weapons[GUN_SLOT1]); } else if (weapons[GUN_SLOT2].weapon_id != 0) { SetCurrWeapon(&weapons[GUN_SLOT2]); } else { SetCurrWeapon(&weapons[0]); } } } } } break; default: { weapon_ammo = std::min(weapon->ammo, num); if (weapon_ammo > 0) { drop_ok = true; weapon->ammo = std::max(0, weapon->ammo - weapon_ammo); int slot_id = weapon->meta->_inventory_slot(); DecInventory(slot_id, weapon_ammo); if (weapon->ammo <= 0) { *weapon = Weapon(); weapon->weapon_idx = weapon_idx; if (GetCurrWeapon() == weapon) { Weapon* next_weapon = ChooseNextSpecWeapon(weapon_idx); if (!next_weapon) { next_weapon = AutoChgWeapon(); } if (next_weapon) { SetCurrWeapon(next_weapon); } } } } } break; } if (drop_ok) { bool create_loot = true; if (weapon_ammo > 0) { const mt::Equip* bullet_meta = mt::Equip::GetById(weapon_meta->use_bullet()); if (bullet_meta && bullet_meta->_inventory_slot() > 0) { #if 1 int drop_num = weapon_ammo; #else int volume = GetVolume(bullet_meta->_inventory_slot()); int inventory = GetInventory(bullet_meta->_inventory_slot()); int add_inventory = std::min(weapon_ammo, volume - std::min(volume, inventory)); if (add_inventory > 0 && !(weapon_idx == FRAG_SLOT || weapon_idx == SMOKE_SLOT)) { AddInventory(bullet_meta->_inventory_slot(), add_inventory); } int drop_num = weapon_ammo - add_inventory; #endif if (drop_num > 0) { glm::vec3 drop_dir = GlmHelper::UP; GlmHelper::RotateY(drop_dir, a8::RandAngle()); Position drop_pos = GetPos(); drop_pos.FromGlmVec3(GetPos().ToGlmVec3() + drop_dir * (25.0f + rand() % 50)); #if 1 { room->DropItem(drop_pos, bullet_meta->id(), drop_num, 1); create_loot = false; } #else if (bullet_meta->_inventory_slot() == IS_FRAG || bullet_meta->_inventory_slot() == IS_SMOKE) { //只有手雷和烟雾弹会掉落 room->DropItem(drop_pos, bullet_meta->id(), drop_num, 1); create_loot = false; } #endif } } } if (create_loot || weapon_idx == GUN_SLOT0 || weapon_idx == GUN_SLOT1 || weapon_idx == GUN_SLOT2) { glm::vec3 dir = GlmHelper::UP; GlmHelper::RotateY(dir, a8::RandAngle()); Position pos = GetPos(); pos.FromGlmVec3(GetPos().ToGlmVec3() + dir * (40.0f + rand() % 50)); room->CreateLoot(weapon_id, pos, 1, 1); } MarkSyncActivePlayer(__FILE__, __LINE__, __func__); SyncAroundPlayers(__FILE__, __LINE__, __func__); } } } void Human::DoFollow(int target_id) { if (target_id == 0){ if (follow_target.Get()) { follow_target.Detach(); room->frame_event.AddPropChg(GetWeakPtrRef(), kPropFollowTarget, 0, 0, true); if (!follow_target_timer_.expired()) { room->xtimer.Delete(follow_target_timer_); } } } else { if (GetTeam()) { Human* member = GetTeam()->GetMemberByUniId(target_id); if (member && member->CanFollow(this)) { #ifdef DEBUG a8::XPrintf("DoFollow %d->%d\n", {GetUniId(), member->GetUniId()}); #endif if (follow_target.Get()) { follow_target.Detach(); if (!follow_target_timer_.expired()) { room->xtimer.Delete(follow_target_timer_); } } follow_target_last_chg_move_dir_times_ = -1; follow_target.Attach(member); room->frame_event.AddPropChg(GetWeakPtrRef(), kPropFollowTarget, 0, target_id, true); follow_target_timer_ = room->xtimer.SetIntervalWpEx ( 400 / FRAME_RATE_MS, [this] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { if (!follow_target.Get()) { if (IsPlayer()) { AsPlayer()->moving = false; AsPlayer()->moved_frames = 0; } room->xtimer.DeleteCurrentTimer(); return; } if (room->GetGasData().GetGasMode() != GasInactive && !(follow_target.Get()->HasBuffEffect(kBET_Fly) || follow_target.Get()->HasBuffEffect(kBET_Jump)) ){ if (IsPlayer()) { AsPlayer()->moving = false; AsPlayer()->moved_frames = 0; } follow_target.Detach(); room->xtimer.DeleteCurrentTimer(); return; } if (follow_target.Get()->HasBuffEffect(kBET_Jump)) { if (HasBuffEffect(kBET_Jump)) { FollowToTarget(); } else { DoJump(); } } } }, &xtimer_attacher); } } } IncFollowTimes(); } void Human::DoDive() { if (!HasBuffEffect(kBET_InWater)) { return; } if (HasBuffEffect(kBET_Dive)) { return; } if (HasBuffEffect(kBET_Driver) || HasBuffEffect(kBET_Passenger)) { return; } if (HasBuffEffect(kBET_Become)) { return; } if (HasBuffEffect(kBET_Camouflage) ) { RemoveBuffByEffectId(kBET_Camouflage); } MustBeAddBuff(this, kDiveBuffId); } void Human::OnWatcherDie(Human* watcher) { if (follow_target_ == watcher) { if (socket_handle != 0 && IsPlayer()) { ((Player*)this)->AsyncRequestWatchWar(true); } } else { #ifdef DEBUG A8_ABORT(); #endif } } void Human::TraverseObservers(std::function func) { bool stop; for (auto& observer : observers_) { func(observer, stop); if (stop) { break; } } } void Human::AddOxygen(int val) { oxygen_ += val; oxygen_ = std::min(mt::Param::s().dive_oxygen_total, oxygen_); } void Human::DecOxygen(int val) { oxygen_ -= val; oxygen_ = std::max(0, oxygen_); } void Human::WinPveScore(int score) { stats.pve_rank_score += score; } void Human::InternalBeKill(int killer_id, const std::string& killer_name, int weapon_id, int real_killer_id, const std::string& real_killer_name) { #ifdef DEBUG if (IsPlayer()) { a8::XPrintf("BeKill %d\n", {GetUniId()}); } #endif if (!dead && !room->IsGameOver() && !real_dead) { KillInfo info; { info.killer_id = killer_id; info.killer_name = killer_name; info.weapon_id = weapon_id; info.real_killer_id = real_killer_id; info.real_killer_name = real_killer_name; } { ++stats.dead_times; stats.killer_id = real_killer_id; stats.killer_name = real_killer_name; stats.weapon_id = weapon_id; } { Entity* killer = room->GetEntityByUniId(real_killer_id); if (killer && killer->IsCreature(room)) { ((Creature*)killer)->GetTrigger()->Kill(this, weapon_id); } } if (room->IsPveRoom()) { dead = true; real_dead = false; downed = false; SetHP(0.0f); if (real_killer_id != GetUniId() && GetTeam() && GetTeam()->HasReviveCoin(this)) { real_dead = true; dead_frameno = room->GetFrameNo(); GetTrigger()->Die(killer_id, weapon_id); if (real_dead) { real_dead = false; OnDie(); KillMgr::Instance()->OnHumanDead(this, &info); room->frame_event.AddDead(GetWeakPtrRef(), 1000 * mt::Param::s().revive_time); dead_timer = room->xtimer.SetTimeoutWpEx (mt::Param::s().revive_time * SERVER_FRAME_RATE, [this] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { real_dead = true; SendGameOver(); } }, &xtimer_attacher); } else { OnDie(); KillMgr::Instance()->OnHumanDead(this, &info); room->frame_event.AddDead(GetWeakPtrRef(), 0); } } else { real_dead = true; dead_frameno = room->GetFrameNo(); GetTrigger()->Die(killer_id, weapon_id); OnDie(); KillMgr::Instance()->OnHumanDead(this, &info); room->frame_event.AddDead(GetWeakPtrRef(), 0); } } else { dead = true; real_dead = true; downed = false; SetHP(0.0f); dead_frameno = room->GetFrameNo(); GetTrigger()->Die(killer_id, weapon_id); OnDie(); KillMgr::Instance()->OnHumanDead(this, &info); room->frame_event.AddDead(GetWeakPtrRef(), 0); } } } int Human::GetTeamMode() { return GetTeam()->GetMemberNum() <= 1 ? 0 : 1; } void Human::CalcAssists(Human* target) { if (GetTeam() && GetTeam()->GetMemberNum() > 1) { GetTeam()->TraverseMembers ( [target, this] (Human* hum) { if (hum->GetUniId() == this->GetUniId()) { return true; } int assist_time = mt::Param::GetIntParam("assist_time", 5); auto itr = target->attacker_hash_.find(hum->GetUniId()); if (itr != target->attacker_hash_.end()) { if (hum->room->GetFrameNo() - itr->second < SERVER_FRAME_RATE * assist_time) { ++hum->stats.assist; } } return true; }); } }