#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 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(); }