game2006/server/gameserver/hero_agent.cc
aozhiwei b2188464fd 1
2023-11-14 14:39:19 +08:00

1342 lines
37 KiB
C++

#include "precompile.h"
#include <f8/btmgr.h>
#include "hero_agent.h"
#include "hero.h"
#include "room.h"
#include "movement.h"
#include "netdata.h"
#include "glmhelper.h"
#include "target_agent.h"
#include "weapon.h"
#include "mapinstance.h"
#include "collision.h"
#include "human.h"
#include "team.h"
#include "master_agent.h"
#include "team_agent.h"
#include "skill.h"
#include "loot.h"
#include "car.h"
#include "roomobstacle.h"
#include "mt/Hero.h"
#include "mt/Equip.h"
#include "mt/Skill.h"
#include "mt/Map.h"
#include "behaviac_generated/types/internal/behaviac_customized_types.h"
HeroAgent::HeroAgent():BaseAgent()
{
current_target_agent = behaviac::Agent::Create<TargetAgent>();
master_agent = behaviac::Agent::Create<MasterAgent>();
team_agent = behaviac::Agent::Create<TeamAgent>();
INIT_LIST_HEAD(&coroutines_list_);
}
HeroAgent::~HeroAgent()
{
{
f8::BtMgr::Instance()->BtDestory(current_target_agent);
current_target_agent = nullptr;
}
{
f8::BtMgr::Instance()->BtDestory(master_agent);
master_agent = nullptr;
}
{
f8::BtMgr::Instance()->BtDestory(team_agent);
team_agent = nullptr;
}
}
void HeroAgent::SetOwner(Creature* owner)
{
owner_ = owner;
current_target_agent->SetOwner(owner_);
master_agent->SetOwner(owner);
room_agent = owner_->room->GetRoomAgent();
}
int HeroAgent::GetUniId()
{
return owner_->GetUniId();
}
int HeroAgent::GetAgentType()
{
abort();
}
bool HeroAgent::IsMoving()
{
return owner_->GetMovement()->GetPathSize() > 0;
}
glm::vec3 HeroAgent::GetPos()
{
return owner_->GetPos().ToGlmVec3();
}
bool HeroAgent::IsDead()
{
return owner_->dead;
}
glm::vec3 HeroAgent::GetSafeAreaCenter()
{
return glm::vec3(
owner_->room->GetGasData().pos_new.x,
0.0f,
owner_->room->GetGasData().pos_new.y
);
}
float HeroAgent::GetSafeAreaRadius()
{
return owner_->room->GetGasData().gas_progress;
}
float HeroAgent::GetHp()
{
return owner_->GetHP();
}
float HeroAgent::GetMaxHp()
{
return owner_->GetMaxHP();
}
void HeroAgent::OpenBulletTraceMode()
{
bullet_trace_mode_ = true;
}
void HeroAgent::CloseBulletTraceMode()
{
bullet_trace_mode_ = false;
}
float HeroAgent::CalcDistance(const glm::vec3& target_pos)
{
return owner_->GetPos().DistanceGlmVec3(target_pos);
}
int HeroAgent::GetHeroId()
{
return owner_->GetHeroMeta()->id();
}
int HeroAgent::GetLevel()
{
return owner_->level;
}
bool HeroAgent::CanShot()
{
if (owner_->GetActionType() == AT_Reload) {
return false;
}
return owner_->CanShot(true);
}
bool HeroAgent::CanUseSkill(int skill_id)
{
return owner_->CanUseSkill(skill_id);
}
void HeroAgent::SendEmote(int emote)
{
owner_->room->frame_event.AddEmote(owner_->GetWeakPtrRef(), emote);
}
int HeroAgent::GetBattleTimes()
{
return owner_->GetBattleContext()->GetBattleTimes();
}
void HeroAgent::SetMoveDir(const glm::vec3& dir)
{
owner_->SetMoveDir(dir);
}
void HeroAgent::SetAttackDir(const glm::vec3& dir)
{
owner_->SetAttackDir(dir);
}
void HeroAgent::ShotNormal(const glm::vec3& dir)
{
if (owner_->dead) {
return;
}
if (owner_->CanShot(true)) {
bool shot_ok = false;
glm::vec3 shot_dir = owner_->GetAttackDir();
if (bullet_angle_offset_max_ > 0) {
GlmHelper::RotateY(shot_dir, a8::RandEx(bullet_angle_offset_min_, bullet_angle_offset_max_)/180.0);
owner_->SetAttackDir(shot_dir);
}
if (bullet_trace_mode_) {
owner_->Shot(shot_dir, shot_ok, 0, 0);
} else {
owner_->Shot(shot_dir, shot_ok, 0, 0);
}
last_shot_frameno_ = owner_->room->GetFrameNo();
}
}
void HeroAgent::ShotTrace()
{
if (owner_->dead) {
return;
}
if (!current_target_agent->IsValid()) {
return;
}
if (owner_->CanShot(true)) {
bool shot_ok = false;
glm::vec3 shot_dir = owner_->GetAttackDir();
if (bullet_trace_mode_) {
owner_->Shot(shot_dir, shot_ok, 0, current_target_agent->GetUniId());
} else {
owner_->Shot(shot_dir, shot_ok, 0, current_target_agent->GetUniId());
}
last_shot_frameno_ = owner_->room->GetFrameNo();
}
}
glm::vec3 HeroAgent::GetRandomDir()
{
glm::vec3 dir = owner_->GetAttackDir();
GlmHelper::RotateY(dir, (10 + rand() % 360)/ 180.0f);
return dir;
}
glm::vec3 HeroAgent::GetTargetDir()
{
if (!current_target_agent->IsValid()) {
return owner_->GetAttackDir();
}
if (GlmHelper::IsEqual2D(owner_->GetPos().ToGlmVec3(),
current_target_agent->GetPos())) {
return owner_->GetAttackDir();
}
glm::vec3 dir = current_target_agent->GetPos() - owner_->GetPos().ToGlmVec3();
GlmHelper::Normalize(dir);
return dir;
}
glm::vec3 HeroAgent::RandomPoint(const glm::vec3& center, float range)
{
glm::vec3 hit_point;
bool hit_result = false;
glm::vec3 start = center;
glm::vec3 dir = GlmHelper::UP;
GlmHelper::RotateY(dir, (10 + rand() % 360)/ 180.0f);
GlmHelper::Normalize(dir);
glm::vec3 end = center + dir * range;
owner_->room->map_instance->Scale(start);
owner_->room->map_instance->Scale(end);
if (owner_->room->map_instance->Raycast
(
start,
end,
hit_point,
hit_result
)) {
owner_->room->map_instance->Scale(hit_point);
}
return hit_point;
}
behaviac::EBTStatus HeroAgent::RandomSafeZonePoint(int try_count, int step_len)
{
PRE_ENTER_COROUTINE();
auto context = MAKE_BTCONTEXT
(
);
auto co = std::make_shared<BtCoroutine>(context, co_id, "RandomSafeZonePoint");
co->runing_cb =
[this, context, try_count, step_len] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if (owner_->dead) {
return behaviac::BT_FAILURE;
}
glm::vec3 gas_center = GlmHelper::Vec2ToVec3(owner_->room->GetGasData().pos_new);
gas_center.y = owner_->GetPos().ToGlmVec3().y;
if (GlmHelper::IsEqual2D(owner_->GetPos().ToGlmVec3(),
gas_center)) {
out_point0 = gas_center;
return behaviac::BT_SUCCESS;
}
glm::vec3 dir = gas_center - owner_->GetPos().ToGlmVec3();
GlmHelper::Normalize(dir);
glm::vec3 center = owner_->GetPos().ToGlmVec3() +
dir * (50.0f + (float)(try_count + 1) * step_len);
owner_->room->map_instance->Scale(center);
glm::vec3 point;
bool ok = owner_->room->map_instance->FindConnectableNearestPoint(center, 50, point);
if (ok) {
owner_->room->map_instance->UnScale(point);
out_point0 = point;
return behaviac::BT_SUCCESS;
}
return behaviac::BT_FAILURE;
};
return StartCoroutine(co);
}
float HeroAgent::GetShotRange()
{
if (owner_->GetCurrWeapon()) {
return owner_->GetCurrWeapon()->meta->range();
}
return 0.0f;
}
void HeroAgent::SetV(int id, int val)
{
auto itr = dyn_hash_.find(id);
if (itr != dyn_hash_.end()) {
itr->second = val;
} else {
dyn_hash_[id] = val;
}
}
int HeroAgent::GetV(int id)
{
auto itr = dyn_hash_.find(id);
if (itr != dyn_hash_.end()) {
return itr->second;
} else {
return 0;
}
}
int HeroAgent::IncV(int id, int val)
{
auto itr = dyn_hash_.find(id);
if (itr != dyn_hash_.end()) {
itr->second += val;
return itr->second;
} else {
dyn_hash_[id] = val;
return val;
}
}
int HeroAgent::DecV(int id, int val)
{
return IncV(id, -val);
}
bool HeroAgent::HasBuffEffect(int effect_id)
{
return owner_->HasBuffEffect(effect_id);
}
bool HeroAgent::IsNearGas(float anti_range)
{
return !Collision::InSquare
(GlmHelper::Vec2ToVec3(owner_->room->GetGasData().pos_old),
owner_->GetPos().ToGlmVec3(),
std::max(owner_->room->GetGasData().rad_new,
owner_->room->GetGasData().gas_progress) * 0.7 -
anti_range);
}
bool HeroAgent::MasterInRange(float range)
{
if (!owner_->IsHero() ||
!owner_->AsHero()->master.Get()) {
return false;
}
return Collision::InSquare
(owner_->AsHero()->master.Get()->GetPos().ToGlmVec3(),
owner_->GetPos().ToGlmVec3(),
range);
}
behaviac::EBTStatus HeroAgent::SearchEnemy(float range)
{
Creature* myself = owner_;
Creature* target = nullptr;
float last_distance = range + 1;
owner_->room->grid_service->TraverseCreatures
(owner_->room->GetRoomIdx(),
owner_->GetGridList(),
[myself, &last_distance, &target, range] (Creature* c, bool& stop)
{
if (!c->dead &&
!a8::HasBitFlag(c->status, CS_Disable) &&
!c->HasBuffEffect(kBET_Hide) &&
!c->HasBuffEffect(kBET_Invincible) &&
c->team_id != myself->team_id &&
!c->IsCar() &&
!myself->IsIgnoreTarget(c->GetUniId())) {
if (a8::HasBitFlag(myself->status, CS_DisableAttackAndroid) &&
c->IsAndroid()) {
} else {
float distance = c->GetPos().Distance2D2(myself->GetPos());
if (distance <= range) {
if (distance < last_distance) {
target = c;
last_distance = distance;
}
}
}
}
return true;
});
if (target) {
current_target_agent->SetTarget(target);
return behaviac::BT_SUCCESS;
}
return behaviac::BT_FAILURE;
}
void HeroAgent::SetBulletAngleOffset(int min_val, int max_val)
{
bullet_angle_offset_min_ = min_val;
bullet_angle_offset_max_ = max_val;
}
behaviac::EBTStatus HeroAgent::TrySearchEnemy(float range, int min_interval, int max_interval)
{
int rnd = a8::RandEx(min_interval, max_interval);
if ((owner_->room->GetFrameNo() - last_try_search_enemy_frameno_) * FRAME_RATE_MS <
rnd) {
return behaviac::BT_FAILURE;
}
last_try_search_enemy_frameno_ = owner_->room->GetFrameNo();
Creature* myself = owner_;
Creature* target = nullptr;
float last_distance = range + 1;
owner_->room->grid_service->TraverseCreatures
(owner_->room->GetRoomIdx(),
owner_->GetGridList(),
[myself, &last_distance, &target, range] (Creature* c, bool& stop)
{
if (!c->dead &&
!a8::HasBitFlag(c->status, CS_Disable) &&
!c->HasBuffEffect(kBET_Hide) &&
!c->HasBuffEffect(kBET_Invincible) &&
c->team_id != myself->team_id &&
!c->IsCar() &&
!myself->IsIgnoreTarget(c->GetUniId())) {
if (a8::HasBitFlag(myself->status, CS_DisableAttackAndroid) &&
c->IsAndroid()) {
} else {
float distance = c->GetPos().Distance2D2(myself->GetPos());
if (distance <= range) {
if (distance < last_distance) {
target = c;
last_distance = distance;
}
}
}
}
return true;
});
if (target) {
return behaviac::BT_SUCCESS;
}
return behaviac::BT_FAILURE;
}
behaviac::EBTStatus HeroAgent::CoIdle(int min_val, int max_val)
{
PRE_ENTER_COROUTINE();
auto context = MAKE_BTCONTEXT
(
int time = 0;
);
context->time = a8::RandEx(min_val, max_val);
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoIdle");
co->runing_cb =
[this, context] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if ((GetRoom()->GetFrameNo() - context->frameno) * FRAME_RATE_MS <
context->time) {
return behaviac::BT_RUNNING;
} else {
return behaviac::BT_SUCCESS;
}
};
return StartCoroutine(co);
}
behaviac::EBTStatus HeroAgent::CoMoveCurrentTargetRaycast()
{
PRE_ENTER_COROUTINE();
auto context = MAKE_BTCONTEXT
(
);
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoMoveCurrentTargetRaycast");
co->runing_cb =
[this, context] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if (!current_target_agent->IsValid()) {
return behaviac::BT_FAILURE;
}
bool ret = owner_->room->MoveCanReach(owner_->GetPos().ToGlmVec3(),
current_target_agent->GetPos());
if (ret) {
return behaviac::BT_SUCCESS;
} else {
return behaviac::BT_FAILURE;
}
};
return StartCoroutine(co);
}
behaviac::EBTStatus HeroAgent::CoShotCurrentTargetRaycast()
{
PRE_ENTER_COROUTINE();
auto context = MAKE_BTCONTEXT
(
);
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoShotCurrentTargetRaycast");
co->runing_cb =
[this, context] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if (!current_target_agent->IsValid()) {
return behaviac::BT_FAILURE;
}
bool ret = owner_->room->MoveCanReach(owner_->GetPos().ToGlmVec3(),
current_target_agent->GetPos());
if (ret) {
return behaviac::BT_SUCCESS;
} else {
return behaviac::BT_FAILURE;
}
};
return StartCoroutine(co);
}
behaviac::EBTStatus HeroAgent::CoMoveMasterRaycast()
{
PRE_ENTER_COROUTINE();
auto context = MAKE_BTCONTEXT
(
a8::XTimerWp timer_ptr;
);
context->timer_ptr = owner_->room->xtimer.SetTimeoutWpEx
(
1000 / FRAME_RATE_MS,
[] (int event, const a8::Args* args)
{
},
&owner_->xtimer_attacher);
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoMoveMasterRaycast");
co->runing_cb =
[this, context] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if (!context->timer_ptr.expired()) {
return behaviac::BT_RUNNING;
} else {
return behaviac::BT_SUCCESS;
}
};
return StartCoroutine(co);
}
behaviac::EBTStatus HeroAgent::CoFindPath(const glm::vec3& pos)
{
PRE_ENTER_COROUTINE_EX(kCoFindPath);
auto context = MAKE_BTCONTEXT
(
bool find_ok = false;
glm::vec3 target_pos;
);
context->target_pos = pos;
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoFindPath");
co->runing_cb =
[this, context, pos] (BtCoroutine* co)
{
if (co->IsAbort()) {
owner_->GetMovement()->ClearPath();
return behaviac::BT_FAILURE;
}
if (owner_->dead) {
return behaviac::BT_FAILURE;
}
if (context->find_ok) {
if (owner_->GetMovement()->GetPathSize() <= 0) {
return behaviac::BT_SUCCESS;
} else {
return behaviac::BT_RUNNING;
}
}
bool ret = owner_->GetMovement()->FindPath(context->target_pos, 0);
if (ret) {
context->find_ok = true;
} else {
return behaviac::BT_FAILURE;
}
return behaviac::BT_RUNNING;
};
return StartCoroutine(co);
}
behaviac::EBTStatus HeroAgent::CoFindPathEx(const glm::vec3& pos, float distance)
{
PRE_ENTER_COROUTINE_EX(kCoFindPathEx);
auto context = MAKE_BTCONTEXT
(
bool find_ok = false;
glm::vec3 target_pos;
);
context->target_pos = pos;
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoFindPathEx");
co->runing_cb =
[this, context, distance] (BtCoroutine* co)
{
if (co->IsAbort()) {
owner_->GetMovement()->ClearPath();
return behaviac::BT_FAILURE;
}
if (owner_->dead) {
return behaviac::BT_FAILURE;
}
if (context->find_ok) {
if (owner_->GetMovement()->GetPathSize() <= 0) {
return behaviac::BT_SUCCESS;
} else {
return behaviac::BT_RUNNING;
}
}
bool ret = owner_->GetMovement()->FindPath(context->target_pos, distance);
if (ret) {
context->find_ok = true;
} else {
return behaviac::BT_FAILURE;
}
return behaviac::BT_RUNNING;
};
return StartCoroutine(co);
}
behaviac::EBTStatus HeroAgent::CoStartMove(int min_val, int max_val)
{
PRE_ENTER_COROUTINE();
float distance = a8::RandEx(min_val, max_val);
auto context = MAKE_BTCONTEXT
(
);
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoStartMove");
co->runing_cb =
[this, context, distance] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if (!owner_->dead) {
owner_->GetMovement()->CalcTargetPos(distance);
}
return behaviac::BT_SUCCESS;
};
return StartCoroutine(co);
}
behaviac::EBTStatus HeroAgent::CoSleep(int time)
{
PRE_ENTER_COROUTINE();
auto context = MAKE_BTCONTEXT
(
a8::XTimerWp timer_ptr;
);
context->timer_ptr = owner_->room->xtimer.SetTimeoutWpEx
(
time / FRAME_RATE_MS,
[] (int event, const a8::Args* args)
{
},
&owner_->xtimer_attacher);
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoSleep");
co->runing_cb =
[this, context] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if (!context->timer_ptr.expired()) {
return behaviac::BT_RUNNING;
} else {
return behaviac::BT_SUCCESS;
}
};
return StartCoroutine(co);
}
behaviac::EBTStatus HeroAgent::CoUseSkill(int skill_id)
{
int wait_time = 0;
if (InternalUseSkill(skill_id, wait_time)) {
last_useskill_frameno_ = owner_->room->GetFrameNo();
return behaviac::BT_SUCCESS;
}
return behaviac::BT_FAILURE;
}
Room* HeroAgent::GetRoom()
{
return owner_->room;
}
bool HeroAgent::HasFlag(int tag)
{
return a8::HasBitFlag(flags_, tag);
}
void HeroAgent::SetFlag(int tag)
{
a8::SetBitFlag(flags_, tag);
}
void HeroAgent::UnSetFlag(int tag)
{
a8::UnSetBitFlag(flags_, tag);
}
behaviac::EBTStatus HeroAgent::RegisterEvents(behaviac::vector<BtEvent_e> events)
{
return behaviac::BT_SUCCESS;
}
behaviac::EBTStatus HeroAgent::ClearEvents()
{
return behaviac::BT_SUCCESS;
}
behaviac::EBTStatus HeroAgent::CoMoveForward(int min_val, int max_val)
{
PRE_ENTER_COROUTINE();
float distance = a8::RandEx(min_val, max_val);
auto context = MAKE_BTCONTEXT
(
);
owner_->GetMovement()->CalcTargetPos(distance);
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoMoveForward");
co->runing_cb =
[this, context] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if (owner_->GetMovement()->GetPathSize() <= 0) {
return behaviac::BT_SUCCESS;
} else {
return behaviac::BT_RUNNING;
}
};
return StartCoroutine(co);
}
behaviac::EBTStatus HeroAgent::DebugOut(std::string msg, int arg0, int arg1, int arg2)
{
#ifdef DEBUG
//a8::XPrintf((msg+"\n").c_str(), {arg0, arg1, arg2});
std::string data = a8::Format(msg.c_str(),{arg0, arg1, arg2} );
owner_->room->BroadcastDebugMsg(data);
#endif
return behaviac::BT_SUCCESS;
}
bool HeroAgent::TargetInShotRange()
{
if (!current_target_agent->IsValid()) {
return false;
}
float shot_range = GetShotRange();
bool in_square = Collision::InSquare
(GetPos(),
current_target_agent->GetPos(),
shot_range / 0.7);
if (!in_square) {
return false;
}
return shot_range > owner_->GetPos().DistanceGlmVec3(current_target_agent->GetPos());
}
bool HeroAgent::InTargetShotRange()
{
if (!current_target_agent->IsValid()) {
return false;
}
float shot_range = current_target_agent->GetShotRange();
bool in_square = Collision::InSquare
(GetPos(),
current_target_agent->GetPos(),
shot_range / 0.7);
if (!in_square) {
return false;
}
return shot_range > owner_->GetPos().DistanceGlmVec3(current_target_agent->GetPos());
}
void HeroAgent::ResetShotTimes()
{
shot_times_ = 0;
last_shot_frameno_ = owner_->room->GetFrameNo();
}
void HeroAgent::ResetUseSkillTimes()
{
useskill_times_ = 0;
last_useskill_frameno_ = owner_->room->GetFrameNo();
}
int HeroAgent::GetShotTimes()
{
return shot_times_;
}
int HeroAgent::GetUseSkillTimes()
{
return useskill_times_;
}
float HeroAgent::GetTargetManhattanDistance()
{
if (!current_target_agent->IsValid()) {
return 0;
}
Position pos;
pos.FromGlmVec3(current_target_agent->GetPos());
return owner_->GetPos().ManhattanDistance2D(pos);
}
std::string HeroAgent::GetSkillBtFile()
{
switch (GetHeroId()) {
case 30100:
{
return "skill/30100_hill";
}
break;
case 30200:
{
return "skill/30200_yamada";
}
break;
case 30300:
{
return "skill/30300_aoi";
}
break;
case 30400:
{
return "skill/30400_astral";
}
break;
case 30500:
{
return "skill/30500_miffy";
}
break;
case 30600:
{
return "skill/30600_canoe";
}
break;
case 30700:
{
return "skill/30700_mariana";
}
break;
case 30800:
{
return "skill/30800_dragonscale";
}
break;
case 30900:
{
return "skill/30900_lazar";
}
break;
case 31000:
{
return "skill/31000_kurosawa";
}
break;
case 60100:
{
return "skill/60100_leo";
}
break;
default:
{
abort();
}
}
}
void HeroAgent::Abort(behaviac::string msg, behaviac::vector<int> args)
{
abort();
}
bool HeroAgent::HasUseableSkill()
{
return owner_->HasUseableSkill();
}
bool HeroAgent::InternalUseSkill(int skill_id, int& wait_time)
{
if (!current_target_agent->IsValid()) {
return false;
}
if (GlmHelper::IsEqual2D(owner_->GetPos().ToGlmVec3(),
current_target_agent->GetPos())) {
return false;
}
Skill* skill = owner_->GetSkill(skill_id);
if (skill) {
wait_time = 500;
glm::vec3 skill_dir = current_target_agent->GetPos() - owner_->GetPos().ToGlmVec3();
float skill_distance = GlmHelper::Norm(skill_dir);
GlmHelper::Normalize(skill_dir);
bool use_ok = false;
switch (skill->GetCurrSkillMeta()->GetMagicId()) {
case MAGIC_20101_HL:
{
use_ok = true;
}
break;
case MAGIC_20701_BAO:
{
use_ok = true;
}
break;
case MAGIC_20801_LONG:
{
use_ok = true;
}
break;
case MAGIC_20901_XIONG:
{
use_ok = true;
}
break;
case MAGIC_21001_NIU:
{
abort();
}
break;
case MAGIC_20201_HX:
{
use_ok = true;
}
break;
case MAGIC_20401_MAO:
{
use_ok = true;
}
break;
case MAGIC_20601_DJS:
{
use_ok = true;
}
break;
case MAGIC_20301_XL:
{
skill_distance = a8::RandEx(20, 60);
use_ok = true;
}
break;
case MAGIC_20501_TZ:
{
use_ok = true;
}
break;
case MAGIC_60100_1_BOSS:
case MAGIC_60100_2_BOSS:
case MAGIC_60100_3_BOSS:
{
use_ok = true;
}
break;
default:
{
}
break;
}
if (use_ok) {
owner_->DoSkill(skill->GetSkillId(), current_target_agent->GetUniId(), skill_dir, skill_distance);
return true;
}
}
return false;
}
bool HeroAgent::HasObserver()
{
return owner_->IsHuman() && owner_->AsHuman()->HasObserver();
}
int HeroAgent::GetAliveEnemyNum()
{
if (owner_->IsHuman()) {
return std::max(0, owner_->room->RealAliveCount() - owner_->GetTeam()->GetAliveNum());
}
return 0;
}
int HeroAgent::GetLastShotPassTime()
{
return (owner_->room->GetFrameNo() - last_shot_frameno_) * FRAME_RATE_MS;
}
int HeroAgent::GetLastUseSkillPassTime()
{
return (owner_->room->GetFrameNo() - last_useskill_frameno_) * FRAME_RATE_MS;
}
int HeroAgent::GetLastAttackPassTime()
{
return std::min(GetLastShotPassTime(), GetLastUseSkillPassTime());
}
float HeroAgent::GetHPRate()
{
return GetHp() / std::max(1.0f, GetMaxHp());
}
behaviac::EBTStatus HeroAgent::CoGetRunAwayPoint()
{
PRE_ENTER_COROUTINE();
if (!current_target_agent->IsValid()) {
return behaviac::BT_FAILURE;
}
auto context = MAKE_BTCONTEXT
(
int try_count = 0;
int step_len = 200;
);
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoGetRunAwayPoint");
co->runing_cb =
[this, context] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if (owner_->dead) {
return behaviac::BT_FAILURE;
}
if (!current_target_agent->IsValid()) {
return behaviac::BT_FAILURE;
}
if (context->try_count >= 3) {
return behaviac::BT_FAILURE;
}
glm::vec3 gas_center = GlmHelper::Vec2ToVec3(owner_->room->GetGasData().pos_new);
gas_center.y = owner_->GetPos().ToGlmVec3().y;
if (GlmHelper::IsEqual2D(owner_->GetPos().ToGlmVec3(),
gas_center)) {
out_point0 = gas_center;
return behaviac::BT_SUCCESS;
}
glm::vec3 dir = gas_center - owner_->GetPos().ToGlmVec3();
GlmHelper::Normalize(dir);
context->step_len = a8::RandEx(200, 260);
glm::vec3 center = gas_center;
if (owner_->room->GetGasData().gas_progress > context->step_len + 50) {
center = gas_center + dir * (owner_->room->GetGasData().gas_progress - context->step_len);
}
GlmHelper::RotateY(dir, (10 + rand() % 360)/ 360.0f);
center = center + dir * (float)context->step_len;
owner_->room->map_instance->Scale(center);
glm::vec3 point;
bool ok = owner_->room->map_instance->FindConnectableNearestPoint(center, 50, point);
if (ok) {
owner_->room->map_instance->UnScale(point);
out_point0 = point;
return behaviac::BT_SUCCESS;
}
++context->try_count;
return behaviac::BT_RUNNING;
};
return StartCoroutine(co);
}
bool HeroAgent::TargetInRange(float range)
{
if (!current_target_agent->IsValid()) {
return false;
}
return Collision::InSquare
(current_target_agent->GetPos(),
owner_->GetPos().ToGlmVec3(),
range);
}
float HeroAgent::GetNewAttackerHPRate()
{
return owner_->GetLastAttacker().Get()->GetHP() /
std::max(1.0f, owner_->GetLastAttacker().Get()->GetMaxHP());
}
bool HeroAgent::GetNewAttackerInRange(float range)
{
if (!HasNewAttacker()) {
return false;
}
return Collision::InSquare
(owner_->GetLastAttacker().Get()->GetPos().ToGlmVec3(),
owner_->GetPos().ToGlmVec3(),
range);
}
int HeroAgent::GetNewAttackerPassTime()
{
return (owner_->room->GetFrameNo() - owner_->GetLastBeAttackFrameNo()) * FRAME_RATE_MS;
}
bool HeroAgent::HasNewAttacker()
{
if (!current_target_agent->IsValid()) {
return false;
}
if (!owner_->GetLastAttacker().Get()) {
return false;
}
return current_target_agent->GetUniId() != owner_->GetLastAttacker().Get()->GetUniId() &&
owner_->GetLastAttacker().Get()->revive_count == owner_->GetLastAttackerReviveTimes();
}
bool HeroAgent::NewAttackerIsHuman()
{
return owner_->GetLastAttacker().Get()->IsHuman();
}
bool HeroAgent::SwitchToNewAttacker()
{
if (HasNewAttacker()) {
current_target_agent->SetTarget(owner_->GetLastAttacker().Get());
}
return true;
}
int HeroAgent::GetReviveCount()
{
return owner_->revive_count;
}
behaviac::EBTStatus HeroAgent::CoGetNextMobaModeRoadPoint()
{
if (!GetRoom()->IsMobaModeRoom()) {
return behaviac::BT_FAILURE;
}
auto& road = GetRoom()->GetMapMeta()->moba_path_points.at(owner_->road_idx);
glm::vec3 dir = GlmHelper::UP;
GlmHelper::RotateY(dir, (10 + rand() % 360)/ 180.0f);
GlmHelper::Normalize(dir);
if (owner_->point_idx < road.size()) {
++owner_->point_idx;
} else {
owner_->road_idx = rand() % owner_->room->GetMapMeta()->moba_path_points.size();
owner_->point_idx = 0;
owner_->path_dir = owner_->path_dir == 1 ? 0 : 1;
}
if (owner_->path_dir == 1) {
out_point0 = std::get<0>(road.at(road.size() - owner_->point_idx - 1))->pos;
} else {
out_point0 = std::get<0>(road.at(owner_->point_idx))->pos;
out_point0 += dir * (float)a8::RandEx(0, 100);
}
if (owner_->GetPos().Distance2D2(out_point0) > 500) {
std::vector<std::tuple<std::shared_ptr<mt::WorldObject>, int, int>> paths;
int r = 0;
for (auto& road : GetRoom()->GetMapMeta()->moba_path_points) {
if (owner_->path_dir == 1) {
int p = 0;
for (auto itr = road.rbegin(); itr != road.rend(); ++itr) {
auto& point = std::get<0>(*itr);
if (point->pos.x < owner_->GetPos().GetX()) {
if (owner_->GetPos().Distance2D2(point->pos) < 500) {
paths.push_back(std::make_tuple
(
point,
r,
p
));
}
break;
}
++p;
}
} else {
int p = 0;
for (auto itr = road.begin(); itr != road.end(); ++itr) {
auto& point = std::get<0>(*itr);
if (point->pos.x > owner_->GetPos().GetX()) {
if (owner_->GetPos().Distance2D2(point->pos) < 500) {
paths.push_back(std::make_tuple
(
point,
r,
p
));
}
break;
}
++p;
}
}
++r;
}
if (paths.empty()) {
std::shared_ptr<std::tuple<std::shared_ptr<mt::WorldObject>, int, int>> path;
int r = 0;
for (auto& road : GetRoom()->GetMapMeta()->moba_path_points) {
int p = 0;
for (auto itr = road.begin(); itr != road.end(); ++itr) {
auto& point = std::get<0>(*itr);
if (!path) {
path = std::make_shared<std::tuple<std::shared_ptr<mt::WorldObject>, int, int>>
(
std::make_tuple
(
point,
r,
p
)
);
} else {
if (owner_->GetPos().Distance2D2(point->pos) <
owner_->GetPos().Distance2D2(std::get<0>(*path)->pos)) {
}
}
++p;
}
++r;
}
if (!path) {
abort();
}
paths.push_back(*path);
}
auto& path = paths.at(rand() % paths.size());
owner_->road_idx = std::get<1>(path);
owner_->point_idx = std::get<2>(path);
if (owner_->path_dir == 1) {
out_point0 = std::get<0>(road.at(road.size() - owner_->point_idx - 1))->pos;
} else {
out_point0 = std::get<0>(road.at(owner_->point_idx))->pos;
out_point0 += dir * (float)a8::RandEx(0, 100);
}
}
return behaviac::BT_SUCCESS;
}
int HeroAgent::SearchPickupObj()
{
return 0;
}
bool HeroAgent::PickupObjIsValid()
{
if (curr_pickup_obj_.Get() && owner_->IsHuman()) {
if (curr_pickup_obj_.Get()->IsLoot()) {
Loot* loot = curr_pickup_obj_.Get()->AsLoot();
return !loot->pickuped;
} else if (curr_pickup_obj_.Get()->IsRoomObstacle()) {
RoomObstacle* ob = curr_pickup_obj_.Get()->AsRoomObstacle();
} else if (curr_pickup_obj_.Get()->IsCar()) {
if (owner_->HasBuffEffect(kBET_Driver) ||
owner_->HasBuffEffect(kBET_Passenger)) {
return false;
} else {
Car* car = curr_pickup_obj_.Get()->AsCar();
if (car->CanOn(owner_->AsHuman())) {
return true;
}
}
}
}
return false;
}
void HeroAgent::AbandonPickup(int min_time, int max_time)
{
curr_pickup_obj_.Reset();
}
behaviac::EBTStatus HeroAgent::Pickup()
{
PRE_ENTER_COROUTINE();
auto context = MAKE_BTCONTEXT
(
);
int pickup_time = a8::RandEx(500, 1000 * 3);
auto co = std::make_shared<BtCoroutine>(context, co_id, "Pickup");
co->runing_cb =
[this, context, pickup_time] (BtCoroutine* co)
{
if (co->IsAbort()) {
return behaviac::BT_FAILURE;
}
if (owner_->dead) {
return behaviac::BT_FAILURE;
}
if (owner_->HasBuffEffect(kBET_Vertigo)) {
return behaviac::BT_FAILURE;
}
if (!PickupObjIsValid()) {
return behaviac::BT_FAILURE;
}
if (!owner_->IsHuman()) {
return behaviac::BT_RUNNING;
}
if ((GetRoom()->GetFrameNo() - context->frameno) * FRAME_RATE_MS < pickup_time) {
return behaviac::BT_RUNNING;
}
if (curr_pickup_obj_.Get()->IsLoot()) {
Loot* loot = curr_pickup_obj_.Get()->AsLoot();
owner_->AsHuman()->LootInteraction(loot);
} else if (curr_pickup_obj_.Get()->IsRoomObstacle()) {
RoomObstacle* ob = curr_pickup_obj_.Get()->AsRoomObstacle();
owner_->AsHuman()->ObstacleInteraction(ob);
} else if (curr_pickup_obj_.Get()->IsCar()) {
if (owner_->HasBuffEffect(kBET_Driver) ||
owner_->HasBuffEffect(kBET_Passenger)) {
return behaviac::BT_FAILURE;
} else {
Car* car = curr_pickup_obj_.Get()->AsCar();
owner_->AsHuman()->DoGetOn(car->GetUniId());
}
}
return behaviac::BT_SUCCESS;
};
return StartCoroutine(co);
}