aozhiwei ca9c9ed456 1
2021-07-22 02:10:48 +00:00

252 lines
6.3 KiB
C++

#include "precompile.h"
#include "hero.h"
#include "human.h"
#include "room.h"
#include "metamgr.h"
#include "loot.h"
#include "perfmonitor.h"
#include "typeconvert.h"
#include "hero.ai.h"
#include "obstacle.h"
#include "collider.h"
#include "bullet.h"
Hero::Hero():Creature()
{
++PerfMonitor::Instance()->entity_num[ET_Hero];
}
Hero::~Hero()
{
DetachFromMaster();
if (ai) {
A8_SAFE_DELETE(ai);
}
--PerfMonitor::Instance()->entity_num[ET_Hero];
}
void Hero::Initialize()
{
Creature::Initialize();
RecalcSelfCollider();
ai = new HeroAI;
ai->owner = this;
ai->SetAiLevel(8);
MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(meta->i->default_weapon());
if (weapon_meta) {
weapons[GUN_SLOT1].weapon_idx = GUN_SLOT1;
weapons[GUN_SLOT1].weapon_id = weapon_meta->i->id();
weapons[GUN_SLOT1].weapon_lv = 1;
weapons[GUN_SLOT1].ammo = 10000;
weapons[GUN_SLOT1].meta = weapon_meta;
weapons[GUN_SLOT1].Recalc();
SetCurrWeapon(&weapons[GUN_SLOT1]);
}
SetInfiniteBulletMode();
}
void Hero::FillMFObjectPart(Room* room, Human* hum, cs::MFObjectPart* part_data)
{
part_data->set_object_type(ET_Hero);
cs::MFHeroPart* p = part_data->mutable_union_obj_10();
p->set_obj_uniid(GetUniId());
TypeConvert::ToPb(GetPos(), p->mutable_pos());
TypeConvert::ToPb(GetMoveDir(), p->mutable_dir());
}
void Hero::FillMFObjectFull(Room* room, Human* hum, cs::MFObjectFull* full_data)
{
full_data->set_object_type(ET_Hero);
cs::MFHeroFull* p = full_data->mutable_union_obj_10();
p->set_obj_uniid(GetUniId());
TypeConvert::ToPb(GetPos(), p->mutable_pos());
TypeConvert::ToPb(GetMoveDir(), p->mutable_dir());
p->set_heroid(meta->i->id());
p->set_master_uniid(master.Get() ? master.Get()->GetUniId() : 0);
p->set_dead(dead);
p->set_health(GetHP());
p->set_max_health(GetMaxHP());
FillBuffList(hum, p->mutable_buff_list());
}
void Hero::Update(int delta_time)
{
ai->Update(delta_time);
++updated_times_;
}
void Hero::OnBulletHit(Bullet* bullet)
{
if (IsInvincible()) {
return;
}
if (!IsDead(room) && (bullet->IsBomb() || bullet->sender.Get()->team_id != team_id)) {
float dmg = bullet->GetAtk();
float def = GetDef() * (1 + GetAbility()->GetAttrRate(kHAT_Def)) +
GetAbility()->GetAttrAbs(kHAT_Def);
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
finaly_dmg = std::max(finaly_dmg, 0.0f);
#if 0
sender->stats.damage_amount_out += finaly_dmg;
#endif
if (bullet->meta->buff_meta) {
MustBeAddBuff(bullet->sender.Get(), bullet->meta->i->buffid());
}
DecHP(finaly_dmg,
bullet->sender.Get()->GetUniId(),
bullet->sender.Get()->GetName(),
bullet->gun_meta->i->id());
}
}
float Hero::GetSpeed()
{
float speed = meta->i->move_speed();
return speed;
}
void Hero::_UpdateMove(int speed)
{
do {
int distance = std::min(5, speed);
InternalUpdateMove(distance);
speed -= distance;
} while (speed > 0);
}
void Hero::InternalUpdateMove(float speed)
{
a8::Vec2 old_pos = GetPos();
a8::Vec2 new_pos = GetPos() + GetMoveDir() * speed;
SetPos(new_pos);
if (!CheckCollision()) {
room->grid_service->MoveCreature(this);
} else {
if (on_move_collision && !on_move_collision()) {
SetPos(old_pos);
}
}
}
void Hero::RecalcSelfCollider()
{
if (!self_collider_) {
self_collider_ = new CircleCollider();
self_collider_->owner = this;
AddEntityCollider(self_collider_);
}
self_collider_->pos = a8::Vec2();
self_collider_->rad = meta->i->radius();
}
float Hero::GetRadius()
{
return meta->i->radius();
}
float Hero::GetHitRadius()
{
return meta->i->hit_radius();
}
void Hero::GetAabbBox(AabbCollider& aabb_box)
{
if (!meta) {
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();
}
void Hero::GetHitAabbBox(AabbCollider& aabb_box)
{
if (!meta) {
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();
}
void Hero::SetAiLevel(int ai_level)
{
if (ai) {
ai->SetAiLevel(ai_level);
}
}
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)
{
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 (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->i->dead_drop() != 0) {
room->ScatterDrop(GetPos(), meta->i->dead_drop());
}
room->frame_event.AddDead(GetWeakPtrRef(), 0);
room->xtimer.AddDeadLineTimerAndAttach
(
meta->i->delay_delete() / FRAME_RATE_MS,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
Hero* hero = (Hero*)param.sender.GetUserData();
hero->BroadcastDeleteState(hero->room);
hero->RemoveFromAroundPlayers(hero->room);
hero->room->grid_service->RemoveCreature(hero);
hero->room->RemoveObjectLater(hero);
hero->delete_frameno = hero->room->GetFrameNo();
std::vector<Human*> watch_list;
hero->room->GetPartObjectWatchList(hero, watch_list);
if (!watch_list.empty()) {
abort();
}
},
&xtimer_attacher.timer_list_);
}
void Hero::OnAddToTargetPartObject(Entity* target)
{
if (delete_frameno > 0) {
abort();
}
}
void Hero::OnRemoveFromTargetPartObject(Entity* target)
{
}