345 lines
8.8 KiB
C++
345 lines
8.8 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 "collider.h"
|
|
#include "bullet.h"
|
|
#include "explosion.h"
|
|
#include "roomobstacle.h"
|
|
#include "app.h"
|
|
#include "pbutils.h"
|
|
#include "trigger.h"
|
|
#include "battledatacontext.h"
|
|
|
|
#include "mt/Hero.h"
|
|
#include "mt/Equip.h"
|
|
#include "mt/MapThing.h"
|
|
|
|
Hero::Hero():Creature()
|
|
{
|
|
++PerfMonitor::Instance()->entity_num[ET_Hero];
|
|
}
|
|
|
|
Hero::~Hero()
|
|
{
|
|
DetachFromMaster();
|
|
--PerfMonitor::Instance()->entity_num[ET_Hero];
|
|
}
|
|
|
|
void Hero::Initialize()
|
|
{
|
|
Creature::Initialize();
|
|
RecalcSelfCollider();
|
|
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>();
|
|
SetBattleContext(context);
|
|
context->ForceInit
|
|
(
|
|
App::Instance()->AllocTempHeroUniId(),
|
|
meta,
|
|
GetCurrWeapon() ? App::Instance()->AllocTempWeaponUniId() : 0,
|
|
GetCurrWeapon() ? GetCurrWeapon()->meta : 0,
|
|
0,
|
|
nullptr
|
|
);
|
|
GetBattleContext()->Init(this);
|
|
}
|
|
SetHP(GetBattleContext()->GetMaxHP());
|
|
SetMaxHP(GetHP());
|
|
}
|
|
|
|
void Hero::Update(int delta_time)
|
|
{
|
|
++updated_times_;
|
|
}
|
|
|
|
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 finaly_dmg = GetBattleContext()->CalcDmg(e);
|
|
DecHP(finaly_dmg,
|
|
VP_Explosion,
|
|
"",
|
|
e->GetExplosionEffect(),
|
|
real_killer_id,
|
|
real_killer_name);
|
|
}
|
|
|
|
void Hero::OnBulletHit(IBullet* bullet)
|
|
{
|
|
if (IsInvincible()) {
|
|
return;
|
|
}
|
|
if (HasBuffEffect(kBET_Jump) ||
|
|
HasBuffEffect(kBET_Fly)) {
|
|
return;
|
|
}
|
|
|
|
RemoveBuffByEffectId(kBET_PeaceMode);
|
|
if (!IsDead(room) && (bullet->IsBomb() || bullet->GetSender().Get()->team_id != team_id)) {
|
|
float 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->IsPreBattleBullet()) {
|
|
DecHP(finaly_dmg,
|
|
bullet->GetSender().Get()->GetUniId(),
|
|
bullet->GetSender().Get()->GetName(),
|
|
bullet->GetGunMeta()->id(),
|
|
bullet->GetSender().Get()->GetUniId(),
|
|
bullet->GetSender().Get()->GetName());
|
|
}
|
|
}
|
|
}
|
|
|
|
float Hero::GetSpeed()
|
|
{
|
|
float speed = meta->move_speed();
|
|
return speed;
|
|
}
|
|
|
|
void Hero::UpdateMove()
|
|
{
|
|
Creature::UpdateMove();
|
|
}
|
|
|
|
void Hero::RecalcSelfCollider()
|
|
{
|
|
if (!self_collider_) {
|
|
self_collider_ = new CircleCollider();
|
|
self_collider_->owner = this;
|
|
AddEntityCollider(self_collider_);
|
|
}
|
|
self_collider_->pos = a8::Vec2(meta->move_offset_x(), meta->move_offset_y());
|
|
self_collider_->rad = meta->radius();
|
|
}
|
|
|
|
|
|
float Hero::GetRadius()
|
|
{
|
|
return meta->radius();
|
|
}
|
|
|
|
float Hero::GetHitRadius()
|
|
{
|
|
return meta->hit_radius();
|
|
}
|
|
|
|
void Hero::GetAabbBox(AabbCollider& aabb_box)
|
|
{
|
|
if (!meta) {
|
|
A8_ABORT();
|
|
}
|
|
aabb_box.active = true;
|
|
aabb_box.owner = this;
|
|
aabb_box._min.x = -GetRadius();
|
|
aabb_box._min.y = -GetRadius();
|
|
aabb_box._max.x = GetRadius();
|
|
aabb_box._max.y = GetRadius();
|
|
aabb_box.MoveCenter(meta->move_offset_x(), meta->move_offset_y());
|
|
}
|
|
|
|
void Hero::GetHitAabbBox(AabbCollider& aabb_box)
|
|
{
|
|
if (!meta) {
|
|
A8_ABORT();
|
|
}
|
|
aabb_box.active = true;
|
|
aabb_box.owner = this;
|
|
aabb_box._min.x = -GetHitRadius();
|
|
aabb_box._min.y = -GetHitRadius();
|
|
aabb_box._max.x = GetHitRadius();
|
|
aabb_box._max.y = GetHitRadius();
|
|
aabb_box.MoveCenter(meta->hit_offset_x(), meta->hit_offset_y());
|
|
}
|
|
|
|
void Hero::DetachFromMaster()
|
|
{
|
|
if (!detached_) {
|
|
if (master.Get()) {
|
|
master.Get()->SlaveOnRemove(this);
|
|
}
|
|
detached_ = true;
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (dec_hp < 0.001f) {
|
|
return;
|
|
}
|
|
float old_health = GetHP();
|
|
float new_health = std::max(0.0f, GetHP() - dec_hp);
|
|
SetHP(std::max(0.0f, new_health));
|
|
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);
|
|
}
|
|
room->frame_event.AddHpChg(GetWeakPtrRef());
|
|
}
|
|
|
|
void Hero::BeKill(int killer_id, const std::string& killer_name, int weapon_id)
|
|
{
|
|
dead = true;
|
|
if (meta->HasDrop() && !room->IsPveRoom()) {
|
|
room->ScatterDrop(GetPos(), meta->RandDrop());
|
|
}
|
|
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();
|
|
}
|
|
GetTrigger()->Die(killer_id, weapon_id);
|
|
}
|
|
|
|
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()
|
|
{
|
|
}
|
|
|
|
void Hero::OnBattleStart(Room* room)
|
|
{
|
|
if (master.Get()) {
|
|
Destory();
|
|
}
|
|
}
|
|
|
|
void Hero::Destory()
|
|
{
|
|
#if DEBUG
|
|
room->BroadcastDebugMsg(a8::Format("hero destory uniid:%d pos:%d,%d",
|
|
{
|
|
GetUniId(),
|
|
GetPos().x,
|
|
GetPos().y
|
|
}));
|
|
#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;
|
|
if (obstacle->IsEntitySubType(EST_RoomObstacle)) {
|
|
is_treasure_box = ((RoomObstacle*)obstacle)->is_treasure_box;
|
|
}
|
|
int drop_id = obstacle->meta->RandDrop();
|
|
if (drop_id == 0) {
|
|
return;
|
|
}
|
|
room->ScatterDrop(obstacle->GetPos(), drop_id);
|
|
}
|