451 lines
10 KiB
C++
451 lines
10 KiB
C++
#include "precompile.h"
|
|
|
|
#include <math.h>
|
|
|
|
#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 "battledatacontext.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;
|
|
// 999
|
|
#if 1
|
|
float finaly_dmg = dmg;
|
|
#else
|
|
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
|
|
#endif
|
|
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<int> 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)
|
|
{
|
|
// 999
|
|
#if 1
|
|
#else
|
|
switch (meta->thing_type()) {
|
|
case kObstacleHideHouse:
|
|
{
|
|
DoHideHouseInteraction(sender);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
if (!IsDead(sender->room) && IsOpenInteraction()) {
|
|
Die(sender->room);
|
|
sender->DropItems(this);
|
|
BroadcastFullState(sender->room);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void Obstacle::DoHideHouseInteraction(Human* sender)
|
|
{
|
|
}
|
|
|
|
std::tuple<long long, glm::vec3>* 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> explosion = EntityFactory::Instance()->MakeExplosion();
|
|
explosion->IndifferenceAttack(
|
|
room,
|
|
GetPos(),
|
|
meta->damage_dia(),
|
|
meta->explosion_effect(),
|
|
meta->damage()
|
|
);
|
|
}
|
|
}
|
|
|
|
void Obstacle::SetRotate(float rotate)
|
|
{
|
|
rotate_ = rotate;
|
|
}
|