214 lines
5.9 KiB
C++
214 lines
5.9 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"
|
|
|
|
Hero::Hero():Creature()
|
|
{
|
|
++PerfMonitor::Instance()->entity_num[ET_Hero];
|
|
}
|
|
|
|
Hero::~Hero()
|
|
{
|
|
--PerfMonitor::Instance()->entity_num[ET_Hero];
|
|
}
|
|
|
|
void Hero::Initialize()
|
|
{
|
|
Creature::Initialize();
|
|
RecalcSelfCollider();
|
|
ai = new HeroAI;
|
|
ai->owner = this;
|
|
ai->SetAiLevel(8);
|
|
}
|
|
|
|
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(GetEntityUniId());
|
|
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(GetEntityUniId());
|
|
TypeConvert::ToPb(GetPos(), p->mutable_pos());
|
|
TypeConvert::ToPb(GetMoveDir(), p->mutable_dir());
|
|
p->set_heroid(meta->i->id());
|
|
p->set_master_uniid(master ? master->GetEntityUniId() : 0);
|
|
}
|
|
|
|
void Hero::Update(int delta_time)
|
|
{
|
|
ai->Update(delta_time);
|
|
++updated_times_;
|
|
}
|
|
|
|
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 (!IsCollisionInMapService()) {
|
|
room->grid_service->MoveCreature(this);
|
|
} else {
|
|
if (on_move_collision && !on_move_collision()) {
|
|
SetPos(old_pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Hero::IsCollisionInMapService()
|
|
{
|
|
if (room->OverBorder(GetPos(), meta->i->radius())){
|
|
return true;
|
|
}
|
|
if (HasBuffEffect(kBET_ThroughWall)) {
|
|
return false;
|
|
}
|
|
|
|
std::set<ColliderComponent*> colliders;
|
|
room->map_service->GetColliders(room, GetX(), GetY(), colliders);
|
|
|
|
AabbCollider aabb_box;
|
|
GetAabbBox(aabb_box);
|
|
for (ColliderComponent* collider : colliders) {
|
|
switch (collider->owner->GetEntityType()) {
|
|
case ET_Obstacle:
|
|
{
|
|
Obstacle* obstacle = (Obstacle*)collider->owner;
|
|
if (!obstacle->IsDead(room) &&
|
|
(
|
|
(collider->type == CT_Aabb && aabb_box.Intersect((ColliderComponent*)collider)) ||
|
|
(collider->type == CT_Circle && self_collider_->Intersect((ColliderComponent*)collider))
|
|
)
|
|
) {
|
|
if (last_collision_door_ != collider->owner) {
|
|
if (!obstacle->IsDead(room) &&
|
|
obstacle->Attackable() &&
|
|
obstacle->meta->i->drop() != 0 &&
|
|
room->GetGasData().gas_mode != GasInactive &&
|
|
(!obstacle->IsTerminatorAirDropBox(room))
|
|
) {
|
|
obstacle->Die(room);
|
|
if (obstacle->IsDead(room)) {
|
|
#if 0
|
|
DropItems(obstacle);
|
|
#endif
|
|
}
|
|
obstacle->BroadcastFullState(room);
|
|
if (obstacle->IsTerminatorAirDropBox(room) &&
|
|
!HasBuffEffect(kBET_Terminator)) {
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(TERMINATOR_BUFF_ID);
|
|
if (buff_meta) {
|
|
#if 0
|
|
AddBuff(this, buff_meta, 1);
|
|
#endif
|
|
}
|
|
}
|
|
} else {
|
|
Global::last_collider = collider;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ET_Building:
|
|
{
|
|
if (
|
|
(
|
|
(collider->type == CT_Aabb && aabb_box.Intersect((ColliderComponent*)collider)) ||
|
|
(collider->type == CT_Circle && self_collider_->Intersect((ColliderComponent*)collider))
|
|
)
|
|
) {
|
|
if (last_collision_door_ != collider->owner) {
|
|
Global::last_collider = collider;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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();
|
|
}
|