game2002/server/gameserver/obstacle.cc
2019-07-22 11:12:05 +08:00

248 lines
8.6 KiB
C++

#include "precompile.h"
#include "obstacle.h"
#include "metamgr.h"
#include "room.h"
#include "collider.h"
#include "building.h"
#include "human.h"
#include "app.h"
#include "typeconvert.h"
Obstacle::Obstacle():Entity()
{
entity_type = kET_Obstacle;
++App::Instance()->perf.entity_num[kET_Obstacle];
}
Obstacle::~Obstacle()
{
--App::Instance()->perf.entity_num[kET_Obstacle];
}
void Obstacle::Initialize()
{
Entity::Initialize();
health = meta->i->hp();
RecalcSelfCollider();
}
void Obstacle::RecalcSelfCollider()
{
if (is_door) {
//门
if (!self_collider2_) {
self_collider2_ = new AabbCollider();
self_collider2_->owner = this;
AddCollider(self_collider2_);
a8::Vec2 old_pos = pos;
{
pos = a8::Vec2(building->pos.x + door_state1->x() - building->meta->i->tilewidth() / 2.0,
building->pos.y + door_state1->y() - building->meta->i->tileheight() / 2.0);
self_collider2_->_min = a8::Vec2(0.0f - door_state0->width() / 2.0f,
0.0f - door_state0->height() / 2.0f);
self_collider2_->_max = a8::Vec2(door_state0->width() / 2.0f, door_state0->height() / 2.0f);
room->map_service.AddCollider(self_collider2_);
}
{
pos = a8::Vec2(building->pos.x + door_state0->x() - building->meta->i->tilewidth() / 2.0,
building->pos.y + door_state0->y() - building->meta->i->tileheight() / 2.0);
self_collider2_->_min = a8::Vec2(0.0f - door_state1->width() / 2.0f,
0.0f - door_state1->height() / 2.0f);
self_collider2_->_max = a8::Vec2(door_state1->width() / 2.0f, door_state1->height() / 2.0f);
room->map_service.AddCollider(self_collider2_);
}
pos = old_pos;
}
if (door_state == kDoorStateClose) {
self_collider2_->_min = a8::Vec2(0.0f - door_state0->width() / 2.0f,
0.0f - door_state0->height() / 2.0f);
self_collider2_->_max = a8::Vec2(door_state0->width() / 2.0f, door_state0->height() / 2.0f);
} else {
self_collider2_->_min = a8::Vec2(0.0f - door_state1->width() / 2.0f,
0.0f - door_state1->height() / 2.0f);
self_collider2_->_max = a8::Vec2(door_state1->width() / 2.0f, door_state1->height() / 2.0f);
}
} else if (meta->i->attack_type() != 2){
switch (meta->i->type()) {
case 1:
{
if (!self_collider_) {
self_collider_ = new CircleCollider();
self_collider_->owner = this;
AddCollider(self_collider_);
}
self_collider_->pos = a8::Vec2();
self_collider_->rad = meta->i->height() / 2.0;
room->map_service.AddCollider(self_collider_);
}
break;
case 2:
{
if (!self_collider2_) {
self_collider2_ = new AabbCollider();
self_collider2_->owner = this;
AddCollider(self_collider2_);
}
self_collider2_->_min = a8::Vec2(meta->i->width() / -2.0f, meta->i->height() / -2.0f);
self_collider2_->_max = a8::Vec2(meta->i->width() / 2.0f, meta->i->height() / 2.0f);
room->map_service.AddCollider(self_collider2_);
}
break;
}
}
}
void Obstacle::FillMFObjectPart(cs::MFObjectPart* part_data)
{
part_data->set_object_type(kET_Obstacle);
cs::MFObstaclePart* p = part_data->mutable_union_obj_2();
p->set_obj_uniid(entity_uniid);
TypeConvert::ToPb(pos, p->mutable_pos());
p->set_scale(1.0f);
}
void Obstacle::FillMFObjectFull(cs::MFObjectFull* full_data)
{
full_data->set_object_type(kET_Obstacle);
cs::MFObstacleFull* p = full_data->mutable_union_obj_2();
p->set_obj_uniid(entity_uniid);
TypeConvert::ToPb(pos, p->mutable_pos());
p->set_scale(1.0f);
p->set_obstacle_id(meta->i->thing_id());
p->set_health(health);
p->set_dead(dead);
p->set_dead_at_thisframe(dead ? dead_frameno <= room->frameno : false);
if (master) {
p->set_master_id(master->entity_uniid);
}
p->set_is_door(is_door);
if (is_door) {
p->set_door_id(door_id);
p->set_door_open_times(door_open_times);
p->set_door_old_state((int)door_state);
p->set_door_new_state((int)door_state);
p->set_door_house_uniid(door_house_uniid);
p->set_door_house_id(building->meta->i->mapid());
if (door_state == kDoorStateClose) {
p->set_door_width(door_state0->width());
p->set_door_height(door_state0->height());
} else {
p->set_door_width(door_state1->width());
p->set_door_height(door_state1->height());
}
}
}
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._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.active = true;
aabb_box.owner = this;
}
void Obstacle::GetCircleBox(CircleCollider& circle_box)
{
}
void Obstacle::Explosion()
{
if (explosioned) {
return;
}
CircleCollider collider;
collider.owner = this;
collider.rad = meta->i->damage_dia();
if (meta->i->damage_dia() > 0.01f &&
meta->i->damage() > 0.01f) {
std::set<Entity*> objects;
std::set<GridCell*> grid_list;
room->grid_service.GetAllCellsByXy(pos.x, pos.y, grid_list);
for (auto& grid : grid_list) {
for (Human* hum: grid->human_list) {
if (hum->TestCollision(&collider)) {
objects.insert(hum);
}
}
for (Entity* entity : grid->entity_list) {
switch (entity->entity_type) {
case kET_Obstacle:
case kET_Building:
{
if (entity != this && entity->TestCollision(&collider)) {
objects.insert(entity);
}
}
break;
default:
{
}
break;
}
}//end for
}
a8::Vec2 bomb_pos = pos;
room->frame_event.AddExplosion(meta->i->thing_id(), bomb_pos, 0);
for (auto& target : objects) {
switch (target->entity_type) {
case kET_Player:
{
Human* hum = (Human*)target;
if (!hum->dead && hum != master) {
float dmg = meta->i->damage();
if (master) {
dmg += master->ability.atk;
}
float def = hum->ability.def;
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
hum->OnHit();
if (!hum->HasBuffEffect(kBET_Invincible)) {
hum->DecHP(finaly_dmg, kVP_Mine, "地雷", kVW_Mine);
}
}
}
break;
case kET_Obstacle:
{
Obstacle* obstacle = (Obstacle*)target;
if (!obstacle->dead && obstacle->meta->i->attack_type() == 1) {
float dmg = meta->i->damage();
float def = 0;
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
obstacle->health = std::max(0.0f, obstacle->health - finaly_dmg);
obstacle->dead = obstacle->health <= 0.01f;
obstacle->dead_frameno = room->frameno;
if (obstacle->dead) {
room->ScatterDrop(obstacle->pos, obstacle->meta->i->drop());
}
obstacle->BroadcastFullState();
}
}
break;
default:
break;
}
}
}
explosioned = true;
NotifyDelObject();
room->RemoveObjectLater(this);
}