game2006/server/gameserver/obstacle.cc
aozhiwei 52afae222a 1
2022-12-27 11:12:37 +08:00

637 lines
15 KiB
C++

#include "precompile.h"
#include <math.h>
#include "obstacle.h"
#include "room.h"
#include "collider.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();
RecalcSelfCollider();
}
void Obstacle::RecalcSelfCollider()
{
// 999
#if 1
#else
if (!Throughable()){
switch (meta->type()) {
case 1:
{
if (!self_collider_) {
self_collider_ = new CircleCollider();
self_collider_->owner = this;
AddEntityCollider(self_collider_);
}
self_collider_->pos = a8::Vec2();
self_collider_->rad = meta->height() / 2.0;
permanent_map_service->AddCollider(self_collider_);
}
break;
case 2:
{
if (!self_collider2_) {
self_collider2_ = new AabbCollider();
self_collider2_->owner = this;
AddEntityCollider(self_collider2_);
}
self_collider2_->_min = a8::Vec2(meta->width() / -2.0f, meta->height() / -2.0f);
self_collider2_->_max = a8::Vec2(meta->width() / 2.0f, meta->height() / 2.0f);
permanent_map_service->AddCollider(self_collider2_);
}
break;
case 3:
{
}
break;
default:
{
A8_ABORT();
}
break;
}
}
if (!self_collider_) {
self_collider_ = new CircleCollider();
self_collider_->owner = this;
AddEntityCollider(self_collider_);
self_collider_->pos = a8::Vec2();
self_collider_->rad = 0.0f;
}
for (auto collider : colliders_) {
collider->tag = collider_tag;
collider->param1 = collider_param1;
collider->param2 = collider_param2;
if (IsHalfWallCollider()) {
a8::SetBitFlag(collider->tag, kHalfWallTag);
}
#if 1
//长宽为0的物件
if (meta->width() <= 0 && meta->height() <= 0) {
collider->active = false;
}
#endif
}
#endif
}
void Obstacle::GetAabbBox(AabbCollider& aabb_box)
{
if (self_collider2_) {
aabb_box = *self_collider2_;
return;
}
if (self_collider_) {
aabb_box.active = true;
aabb_box.owner = this;
aabb_box.tag = collider_tag;
aabb_box._min.x = -self_collider_->rad;
aabb_box._min.y = -self_collider_->rad;
aabb_box._max.x = self_collider_->rad;
aabb_box._max.y = self_collider_->rad;
return;
}
aabb_box.tag = collider_tag;
aabb_box.active = true;
aabb_box.owner = this;
}
void Obstacle::GetCircleBox(CircleCollider& circle_box)
{
}
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_;
}
}
void Obstacle::OnPreCollision(Room* room)
{
if (IsPermanent()) {
}
}
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().x,
GetPos().y
);
}
}
}
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().x,
GetPos().y
);
}
}
}
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()) {
e->GetRoom()->ScatterDrop(GetPos(), meta->RandDrop());
}
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().x,
GetPos().y
);
}
}
}
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;
}
int Obstacle::OnCollisionTrigger(Creature* c, ColliderComponent* collider)
{
if (IsDead(c->room)) {
return 0;
}
switch (meta->collision_hit()) {
case kCollisionHitPass:
{
return 0;
}
break;
case kCollisionHitBlock:
{
Global::last_collider = collider;
return 1;
}
break;
case kCollisionHitDeadAndDrop:
{
if (c->room->GetGasData().GetGasMode() != GasInactive &&
meta->HasDrop() &&
c->IsHuman()) {
Die(c->room);
c->DropItems(this);
BroadcastFullState(c->room);
return 0;
}
}
break;
case kCollisionHitSpecEvent:
{
if (ProcSpecEvent(c, collider)) {
return 0;
}
}
break;
default:
{
}
break;
}
Global::last_collider = collider;
return 1;
}
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::IsHalfWallCollider()
{
return meta->collision_hit() == kCollisionHitPass &&
meta->bullet_hit() != kBulletHitPass;
}
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;
}
bool Obstacle::ProcSpecEvent(Creature* c, ColliderComponent* collider)
{
switch (meta->thing_type()) {
case kObstacleSpring:
{
if (c->IsHuman()) {
if (!c->AsHuman()->GetCar()) {
AddObstacleBuff(c);
return true;
}
}
}
break;
case kObstacleMine:
case kObstacleTrap:
{
if (c->team_id != GetTeamId(c->room)) {
AddObstacleBuff(c);
Die(c->room);
ProcDieExplosion(c->room);
BroadcastFullState(c->room);
}
return true;
}
break;
default:
{
}
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;
for (auto collider : colliders_) {
if (collider->type == CT_Circle) {
CircleCollider* circle_collider = (CircleCollider*)collider;
if (fabs(rotate) > 0.0001) {
circle_collider->pos.Rotate(rotate);
}
}
}
}