aozhiwei d3e74e59dd 1
2024-04-01 20:43:03 +08:00

530 lines
15 KiB
C++

#include "precompile.h"
#include <f8/udplog.h>
#include "hero.h"
#include "human.h"
#include "room.h"
#include "loot.h"
#include "perfmonitor.h"
#include "typeconvert.h"
#include "obstacle.h"
#include "bullet.h"
#include "explosion.h"
#include "roomobstacle.h"
#include "app.h"
#include "pbutils.h"
#include "trigger.h"
#include "netdata.h"
#include "stats.h"
#include "hero_agent.h"
#include "movement.h"
#include "ability.h"
#include "skill.h"
#include "f8/btmgr.h"
#include "mt/Hero.h"
#include "mt/Equip.h"
#include "mt/MapThing.h"
#include "mt/BattleBasicAttribute.h"
#include "mt/Map.h"
#include "mt/MobaRoom.h"
Hero::Hero():Creature()
{
++PerfMonitor::Instance()->entity_num[ET_Hero];
INIT_LIST_HEAD(&entry);
agent_ = behaviac::Agent::Create<HeroAgent>();
if (!agent_) {
abort();
}
}
Hero::~Hero()
{
SetDestorying();
DetachFromMaster();
if (agent_) {
f8::BtMgr::Instance()->BtDestory(agent_);
agent_ = nullptr;
}
--PerfMonitor::Instance()->entity_num[ET_Hero];
}
void Hero::Initialize()
{
Creature::Initialize();
const mt::Equip* weapon_meta = mt::Equip::GetById(meta->default_weapon());
if (weapon_meta) {
Weapon& weapon = weapons[GUN_SLOT1];
weapon.weapon_idx = GUN_SLOT1;
weapon.weapon_id = weapon_meta->id();
weapon.ammo = 10000;
weapon.meta = weapon_meta;
weapon.Recalc();
SetCurrWeapon(&weapon);
}
SetInfiniteBulletMode();
InitAI();
{
auto context = std::make_shared<BattleDataContext>();
SetNetData(context);
context->ForceInit
(
App::Instance()->AllocTempHeroUniId(),
meta,
GetCurrWeapon() ? App::Instance()->AllocTempWeaponUniId() : 0,
GetCurrWeapon() ? GetCurrWeapon()->meta : 0,
0,
nullptr
);
GetNetData()->Init(this);
}
SetHP(GetNetData()->GetMaxHP());
SetMaxHP(GetHP());
{
std::vector<int> skill_list;
GetNetData()->GetSkillList(skill_list);
for (auto& skill_id : skill_list) {
AddSkill(skill_id);
}
}
if (GetHeroMeta()->GetBasicMeta()) {
SetHeroLevel(1, 0, GetHeroMeta()->GetBasicMeta()->GetGrowMeta(room->GetMapMeta()->map_id()));
} else {
SetHeroLevel(1, 0, nullptr);
}
}
void Hero::Update(int delta_time)
{
++updated_times_;
if (poisoning) {
poisoning_time += delta_time;
UpdatePoisoning();
}
if (GetMovement()->GetPathSize() > 0) {
#ifdef MYDEBUG1
glm::vec3 old_pos = GetPos().ToGlmVec3();
#endif
App::Instance()->verify_set_pos = 1;
UpdateMove();
#ifdef MYDEBUG1
a8::XPrintf("updatemove old_pos:%f,%f new_pos:%f,%f\n",
{
old_pos.x,
old_pos.z,
GetPos().GetX(),
GetPos().GetZ(),
});
#endif
App::Instance()->verify_set_pos = 0;
} else {
if (HasBuffEffect(kBET_Jump)) {
glm::vec3 dir = GlmHelper::UP;
GlmHelper::RotateY(dir, (10 + rand() % 360)/ 180.0f);
GlmHelper::Normalize(dir);
GetMovement()->CalcTargetPos(60 + rand() % 200);
return;
}
}
if (playing_skill) {
UpdateSkill();
}
shot_hold = false;
CheckShotHold();
agent_->Exec();
}
void Hero::OnExplosionHit(Explosion* e)
{
if (IsInvincible()) {
return;
}
if (dead) {
return;
}
if (e->IsPreBattleExplosion()) {
return;
}
if (HasBuffEffect(kBET_Jump) ||
HasBuffEffect(kBET_Fly)) {
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 dmg_out = 0.0f;
float finaly_dmg = GetNetData()->CalcDmg(e);
DecHP(finaly_dmg,
VP_Explosion,
"",
e->GetExplosionEffect(),
real_killer_id,
real_killer_name,
dmg_out,
0,
0);
}
void Hero::OnBulletHit(IBullet* bullet)
{
if (IsInvincible()) {
return;
}
if (HasBuffEffect(kBET_Jump) ||
HasBuffEffect(kBET_Fly)) {
return;
}
RemoveBuffByEffectId(kBET_PeaceMode);
GetTrigger()->Attacked(bullet->GetSender().Get());
if (!IsDead(room) && (bullet->IsBomb() || bullet->GetSender().Get()->team_id != team_id)) {
float finaly_dmg = bullet->GetSender().Get()->GetNetData()->CalcDmg(this, bullet);
if (bullet->GetSender().Get()->IsHuman()) {
bullet->GetSender().Get()->AsHuman()->stats->damage_amount_out += finaly_dmg;
SetLastAttacker(bullet->GetSender());
}
if (bullet->GetBulletMeta()->_buff_meta) {
MustBeAddBuff(bullet->GetSender().Get(), bullet->GetBulletMeta()->buffid());
}
if (!bullet->IsPreBattleBullet()) {
float dmg_out = 0.0f;
DecHP(finaly_dmg,
bullet->GetSender().Get()->GetUniId(),
bullet->GetSender().Get()->GetName(),
bullet->GetGunMeta()->id(),
bullet->GetSender().Get()->GetUniId(),
bullet->GetSender().Get()->GetName(),
dmg_out,
0,
0);
if (bullet->GetSender().Get() &&
!bullet->GetSender().Get()->dead &&
dmg_out > 0.0f &&
!bullet->GetSkillMeta()
) {
{
if (bullet->GetSender().Get()->GetNetData()->GetBrainLifePct() > 0.0f) {
float recover_hp = dmg_out *
bullet->GetSender().Get()->GetNetData()->GetBrainLifePct();
if (recover_hp > 0.0f) {
bullet->GetSender().Get()->AddHp(recover_hp);
}
}
}
{
if (bullet->GetSender().Get()->IsEntityType(ET_Hero)) {
Hero* hero = (Hero*)bullet->GetSender().Get();
if (hero->GetAbility()->GetSwitchTimes(kEnableDmgForwardTimes) > 0 &&
hero->master.Get() &&
!hero->master.Get()->dead &&
hero->master.Get()->GetNetData()->GetBrainLifePct() > 0.0f){
float recover_hp = dmg_out *
hero->master.Get()->GetNetData()->GetBrainLifePct();
if (recover_hp > 0.0f) {
hero->master.Get()->AddHp(recover_hp);
}
}
}
}
}
}
}
}
float Hero::GetSpeed()
{
return Creature::GetSpeed();
}
void Hero::UpdateMove()
{
Creature::UpdateMove();
}
float Hero::GetRadius()
{
return meta->radius();
}
float Hero::GetHitRadius()
{
return meta->hit_radius();
}
void Hero::DetachFromMaster()
{
if (!detached_) {
if (master.Get()) {
master.Get()->SlaveOnRemove(this);
}
detached_ = true;
}
if (!list_empty(&entry)) {
list_del_init(&entry);
}
}
void Hero::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,
float& real_dmg_out,
int dmg_type,
int dmg_bp)
{
real_dmg_out = 0.0f;
if (!room->BattleStarted()) {
return;
}
if (dec_hp < 0.001f) {
return;
}
if (HasBuffEffect(kBET_Invincible)) {
return;
}
last_receive_dmg_frameno = room->GetFrameNo();
float old_health = GetHP();
float new_health = std::max(0.0f, GetHP() - dec_hp);
SetHP(std::max(0.0f, new_health));
if (old_health - GetHP() > 0.001f) {
real_dmg_out = old_health - GetHP();
}
if (new_health < old_health && room->IsPveRoom()) {
room->pve_data.AddDamageInfo(killer_id, GetUniId(), old_health - new_health);
}
if (GetHP() <= 0.0001f && !IsDead(room)) {
BeKill(killer_id, killer_name, weapon_id);
}
Creature* killer = room->GetCreatureByUniId(real_killer_id);
if (killer && real_dmg_out > 0.999) {
if (killer->IsPlayer()) {
room->frame_event.AddPropChgEx
(
killer->GetWeakPtrRef(),
kPropDmgShow,
GetUniId(),
real_dmg_out,
0,
killer->GetUniId(),
true);
} else if (killer->IsHero() &&
killer->AsHero()->master.Get() &&
killer->AsHero()->master.Get()->IsPlayer()) {
room->frame_event.AddPropChgEx
(
killer->AsHero()->master.Get()->GetWeakPtrRef(),
kPropDmgShow,
GetUniId(),
real_dmg_out,
0,
killer->AsHero()->master.Get()->GetUniId(),
true);
}
}
room->frame_event.AddHpChg(GetWeakPtrRef());
}
void Hero::BeKill(int killer_id, const std::string& killer_name, int weapon_id)
{
std::vector<int> items;
dead = true;
if (meta->HasDrop() && !room->IsPveRoom()) {
room->ScatterDrop(GetPos().ToGlmVec3(), meta->RandDrop(), false, &items);
}
if (!room->IsPveRoom()) {
for (int id : meta->_drop_list) {
room->ScatterDrop(GetPos().ToGlmVec3(), id, false, &items);
}
}
room->frame_event.AddDead(GetWeakPtrRef(), 0);
room->xtimer.SetTimeoutEx
(
meta->delay_delete() / FRAME_RATE_MS,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
BroadcastDeleteState(room);
RemoveFromAroundPlayers(room);
room->grid_service->RemoveCreature(this);
room->RemoveObjectLater(this);
delete_frameno = room->GetFrameNo();
std::vector<Human*> watch_list;
room->GetPartObjectWatchList(this, watch_list);
if (!watch_list.empty()) {
A8_ABORT();
}
}
},
&xtimer_attacher);
if (room->IsPveRoom()) {
--room->pve_data.mon_num;
++room->pve_data.killed_num;
room->pve_data.OnBeKill(this);
room->NotifyUiUpdate();
}
AllocDeadExp(killer_id);
GetTrigger()->Die(killer_id, weapon_id);
if (room->IsMobaModeRoom() && !room->IsGameOver()) {
{
int revive_time = room->GetMapMeta()->GetMobaRoomMeta()->GetMonsterReviveTime(GetHeroMeta()->id());
if (revive_time >= 0) {
room->xtimer.SetTimeoutEx
(revive_time * SERVER_FRAME_RATE,
[room = room, hero_meta = GetHeroMeta(), pos = src_pos] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
Hero* hero = room->CreateHero
(nullptr,
hero_meta,
pos,
GlmHelper::UP,
666,
0);
}
},
&room->xtimer_attacher_);
}
}
{
int life_time = room->GetMapMeta()->GetMobaRoomMeta()->GetMonsterLootLifeTime(GetHeroMeta()->id());
if (life_time >= 0) {
room->xtimer.SetTimeoutEx
(life_time * SERVER_FRAME_RATE,
[room = room, items] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
for (int obj_uniid : items) {
Entity* e = room->GetEntityByUniId(obj_uniid);
if (e && e->IsLoot()) {
Loot* l = e->AsLoot();
if (!l->pickuped && !l->removing) {
room->RemoveObjectLater(l);
}
}
}
}
},
&room->xtimer_attacher_);
}
}
}
}
void Hero::OnAddToTargetPartObject(Entity* target)
{
if (delete_frameno > 0) {
#if 1
f8::UdpLog::Instance()->Warning
("Hero::OnAddToTargetPartObject "
"delete_frameno:%d "
"room.frameno:%d",
{
delete_frameno,
room->GetFrameNo()
});
#else
A8_ABORT();
#endif
}
}
void Hero::OnRemoveFromTargetPartObject(Entity* target)
{
}
void Hero::InitAI()
{
agent_->SetOwner(this);
f8::BtMgr::Instance()->BtLoad(agent_, meta->new_bt().c_str());
f8::BtMgr::Instance()->BtSetCurrent(agent_, meta->new_bt().c_str());
}
void Hero::OnBattleStart(Room* room)
{
if (master.Get()) {
Destory();
}
}
void Hero::Destory()
{
#if MYDEBUG
room->BroadcastDebugMsg(a8::Format("hero destory uniid:%d pos:%d,%d",
{
GetUniId(),
GetPos().GetX(),
GetPos().GetY()
}));
#endif
room->xtimer.SetTimeoutEx
(
0,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (delete_frameno == 0) {
BroadcastDeleteState(room);
RemoveFromAroundPlayers(room);
room->grid_service->RemoveCreature(this);
room->RemoveObjectLater(this);
delete_frameno = room->GetFrameNo();
std::vector<Human*> watch_list;
room->GetPartObjectWatchList(this, watch_list);
if (!watch_list.empty()) {
A8_ABORT();
}
}
}
},
&xtimer_attacher);
}
std::string Hero::GetName()
{
return meta->name();
}
void Hero::DropItems(Obstacle* obstacle)
{
bool is_treasure_box = false;
std::vector<int> drops = obstacle->meta->RandDrop();
for (int drop_id : drops) {
room->ScatterDrop(obstacle->GetPos().ToGlmVec3(), drop_id);
}
}
void Hero::Active()
{
}
void Hero::Deactive()
{
}
void Hero::DoSkillPostProc(bool used, int skill_id, int target_id)
{
if (used) {
#if 0
++stats->skill_times;
#endif
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());
}
#if 0
OnAttack();
#endif
}
}