#include "precompile.h" #include #include "obstacle.h" #include "room.h" #include "human.h" #include "app.h" #include "typeconvert.h" #include "bullet.h" #include "perfmonitor.h" #include "roomobstacle.h" #include "loot.h" #include "explosion.h" #include "entityfactory.h" #include "pbutils.h" #include "netdata.h" #include "mt/Equip.h" #include "mt/MapThing.h" #include "mt/Buff.h" #include "mt/Hero.h" #include "mt/Skill.h" Obstacle::Obstacle():Entity() { ++PerfMonitor::Instance()->entity_num[ET_Obstacle]; } Obstacle::~Obstacle() { --PerfMonitor::Instance()->entity_num[ET_Obstacle]; } void Obstacle::Initialize() { Entity::Initialize(); health_ = meta->hp(); } bool Obstacle::IsDead(Room* room) { if (IsPermanent()) { return dead_; } else { return dead_; } } long long Obstacle::GetDeadFrameNo(Room* room) { if (IsPermanent()) { return dead_frameno_; } else { return dead_frameno_; } } float Obstacle::GetHealth(Room* room) { if (IsPermanent()) { return health_; } else { return health_; } } void Obstacle::SetHealth(Room* room, float value) { { health_ = value; } } void Obstacle::Die(Room* room) { { health_ = 0; dead_ = true; dead_frameno_ = room->GetFrameNo(); } } bool Obstacle::IsPermanent() { if (is_permanent) { if (GetUniId() >= FIXED_OBJECT_MAXID) { A8_ABORT(); } } else { if (GetUniId() < FIXED_OBJECT_MAXID) { A8_ABORT(); } } return is_permanent; } bool Obstacle::Throughable() { return meta->bullet_hit() == kBulletHitPass && meta->collision_hit() == kCollisionHitPass && meta->explosion_hit() == kExplosionHitPass; } int Obstacle::GetTeamId(Room* room) { return team_id_; } void Obstacle::SetTeamId(Room* room, int team_id) { { team_id_ = team_id; } } int Obstacle::GetMasterId(Room* room) { return master_id_; } void Obstacle::SetMasterId(Room* room, int master_id) { { master_id_ = master_id; } } void Obstacle::OnBulletHit(IBullet* bullet) { if (meta->bullet_hit() == kBulletHitEatDmg) { return; } if (bullet->IsPreBattleBullet()) { return; } if (!IsDead(bullet->GetRoom())) { if (meta->_receive_special_damage_type != 0 && ((bullet->GetGunMeta()->_special_damage_type & meta->_receive_special_damage_type) == 0)) { return; } if (meta->thing_type() == kObstacleOilBucket) { Entity* real_object = AsRoomObstacle()->GetRealObject(bullet->GetRoom()); if (real_object->IsEntityType(ET_Loot)) { Loot* loot = (Loot*)real_object; if (loot->pickuped) { return; } } } float finaly_dmg = bullet->GetSender().Get()->GetBattleContext()->CalcDmg(this, bullet); SetHealth(bullet->GetRoom(), std::max(0.0f, GetHealth(bullet->GetRoom()) - finaly_dmg)); if (GetHealth(bullet->GetRoom()) <= 0.01f) { Die(bullet->GetRoom()); if (meta->thing_type() == kObstacleOilBucket) { Entity* real_object = AsRoomObstacle()->GetRealObject(bullet->GetRoom()); if (real_object->IsEntityType(ET_Loot)) { Loot* loot = (Loot*)real_object; loot->pickuped = true; bullet->GetRoom()->RemoveObjectLater(loot); bullet->GetRoom()->RemoveObjectLater(AsRoomObstacle()); RoomObstacle* obstacle = bullet->GetRoom()->CreateObstacle ( meta->_int_param1, GetPos().GetX(), GetPos().GetY(), GetPos().GetZ() ); } } } if (IsDead(bullet->GetRoom())) { ProcDieExplosion(bullet->GetRoom()); bullet->GetSender().Get()->DropItems(this); if (meta->thing_type() == kObstacleOilBucket) { const mt::MapThing* bomb_meta = mt::MapThing::GetById(meta->_int_param1); if (bomb_meta) { RoomObstacle* obstacle = bullet->GetRoom()->CreateObstacle ( bomb_meta->thing_id(), GetPos().GetX(), GetPos().GetY(), GetPos().GetZ() ); } } } BroadcastFullState(bullet->GetRoom()); } } void Obstacle::OnExplosionHit(Explosion* e) { if (meta->explosion_hit() == kExplosionHitEatDmg) { return; } if (IsDead(e->GetRoom())) { return; } if (e->GetDmg() < 0.001f) { return; } if (meta->_receive_special_damage_type != 0 && ((e->GetSpecialDamageType() & meta->_receive_special_damage_type) == 0)) { return; } if (e->IsPreBattleExplosion()) { return; } float dmg = e->GetDmg(); float def = 0; float finaly_dmg = dmg; SetHealth(e->GetRoom(), std::max(0.0f, GetHealth(e->GetRoom()) - finaly_dmg)); if (GetHealth(e->GetRoom()) <= 0.01f) { Die(e->GetRoom()); } if (IsDead(e->GetRoom())) { ProcDieExplosion(e->GetRoom()); if (meta->HasDrop()) { std::vector drops = meta->RandDrop(); for (int drop_id : drops) { e->GetRoom()->ScatterDrop(GetPos().ToGlmVec3(), drop_id); } } if (meta->thing_type() == kObstacleOilBucket) { const mt::MapThing* bomb_meta = mt::MapThing::GetById(meta->_int_param1); if (bomb_meta) { RoomObstacle* obstacle = e->GetRoom()->CreateObstacle ( bomb_meta->thing_id(), GetPos().GetX(), GetPos().GetY(), GetPos().GetZ() ); } } } BroadcastFullState(e->GetRoom()); } bool Obstacle::CanThroughable(Creature* c) { if (IsDead(c->room)) { return true; } switch (meta->collision_hit()) { case kCollisionHitPass: { return true; } break; default: { return false; } break; } return false; } bool Obstacle::CanThroughable(IBullet* bullet) { switch (meta->bullet_hit()) { case kBulletHitPass: { return true; } break; case kBulletHitOnlySpecDmg: { return !(meta->_receive_special_damage_type != 0 && ((bullet->GetGunMeta()->_special_damage_type & meta->_receive_special_damage_type) != 0)); } break; default: { return false; } break; } return false; } bool Obstacle::DoInteraction(Human* sender) { switch (meta->thing_type()) { case kObstacleHideHouse: { DoHideHouseInteraction(sender); } break; default: { if (!IsDead(sender->room) && IsOpenInteraction()) { dead_reason = 1; Die(sender->room); sender->DropItems(this); BroadcastFullState(sender->room); } } break; } return false; } void Obstacle::DoHideHouseInteraction(Human* sender) { } std::tuple* Obstacle::GetInteractionData(Human* sender) { if (IsPermanent()) { return nullptr; } else { return nullptr; } } void Obstacle::AddObstacleBuff(Creature* c) { glm::vec3 old_context_dir = c->context_dir; Position old_context_pos = c->context_pos; c->context_dir = c->GetAttackDir(); c->context_pos = c->GetPos(); for (int buff_id : meta->_buff_list) { c->TryAddBuff(c, buff_id); } c->context_pos = old_context_pos; c->context_dir = old_context_dir; } void Obstacle::ClearObstacleBuff(Creature* c) { for (int buff_id : meta->_buff_list) { c->RemoveBuffById(buff_id); } } bool Obstacle::IsTouchInteraction() { return meta->interaction_mode() == 1; } bool Obstacle::IsOpenInteraction() { return meta->interaction_mode() == 2; } bool Obstacle::IsRoomObstacle() { return !IsPermanent(); } RoomObstacle* Obstacle::AsRoomObstacle() { return (RoomObstacle*)this; } bool Obstacle::CanSeeMe(Human* hum) { switch (meta->view_mode()) { case 1: { return GetMasterId(hum->room) == hum->GetUniId(); } break; case 2: { return GetTeamId(hum->room) == hum->team_id; } break; default: { return true; } break; } } bool Obstacle::Attackable(Room* room) { if (IsDead(room)) { return false; } return true; } bool Obstacle::ReceiveExplosionDmg(Explosion* explosion) { switch (meta->explosion_hit()) { case kExplosionHitPass: { return false; } break; case kExplosionHitAnyDmg: { return true; } break; case kExplosionHitOnlySpecDmg: { if (meta->_receive_special_damage_type == 0) { return true; } return (meta->_receive_special_damage_type & explosion->GetSpecialDamageType()) != 0; } break; case kExplosionHitEatDmg: { return false; } break; default: { return false; } break; } return false; } void Obstacle::ProcDieExplosion(Room* room) { if (meta->damage_dia() > 0.01f) { std::shared_ptr explosion = EntityFactory::Instance()->MakeExplosion(); explosion->IndifferenceAttack( room, GetPos(), meta->damage_dia(), meta->explosion_effect(), meta->damage() ); } } void Obstacle::SetRotate(float rotate) { rotate_ = rotate; }