aozhiwei 092f8c1764 1
2021-06-03 17:15:02 +08:00

395 lines
11 KiB
C++

#include "precompile.h"
#include "car.h"
#include "collider.h"
#include "human.h"
#include "room.h"
#include "metamgr.h"
#include "loot.h"
#include "perfmonitor.h"
#include "typeconvert.h"
#include "bullet.h"
Car::Car():Creature()
{
++PerfMonitor::Instance()->entity_num[ET_Car];
}
Car::~Car()
{
--PerfMonitor::Instance()->entity_num[ET_Car];
}
void Car::Initialize()
{
Creature::Initialize();
hero_meta_ = MetaMgr::Instance()->GetPlayer(meta->i->heroid());
if (!hero_meta_) {
abort();
}
MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(hero_meta_->i->default_weapon());
if (weapon_meta) {
weapons[GUN_SLOT1].weapon_idx = GUN_SLOT1;
weapons[GUN_SLOT1].weapon_id = weapon_meta->i->id();
weapons[GUN_SLOT1].weapon_lv = 1;
weapons[GUN_SLOT1].meta = weapon_meta;
weapons[GUN_SLOT1].Recalc();
weapons[GUN_SLOT1].ammo = weapons[GUN_SLOT1].GetClipVolume();
SetCurrWeapon(&weapons[GUN_SLOT1]);
}
born_frameno_ = room->GetFrameNo();
ability.hp = hero_meta_->i->health();
ability.max_hp = std::max(ability.hp, ability.max_hp);
TryAddBuff(this, meta->car_deactive_buff_id);
}
void Car::FillMFObjectPart(Room* room, Human* hum, cs::MFObjectPart* part_data)
{
part_data->set_object_type(ET_Car);
cs::MFCarPart* p = part_data->mutable_union_obj_11();
p->set_obj_uniid(GetEntityUniId());
TypeConvert::ToPb(GetPos(), p->mutable_pos());
TypeConvert::ToPb(GetAttackDir(), p->mutable_dir());
}
void Car::FillMFObjectFull(Room* room, Human* hum, cs::MFObjectFull* full_data)
{
full_data->set_object_type(ET_Car);
cs::MFCarFull* p = full_data->mutable_union_obj_11();
p->set_obj_uniid(GetEntityUniId());
TypeConvert::ToPb(GetPos(), p->mutable_pos());
TypeConvert::ToPb(GetAttackDir(), p->mutable_dir());
p->set_car_id(meta->i->id());
p->set_heroid(meta->i->heroid());
p->set_driver(driver_ ? driver_->GetEntityUniId() : 0);
for (auto hum : passengers_) {
auto less_data = p->add_passengers();
hum->FillMFObjectLess(room, hum, less_data);
}
p->set_born_frameno(ceil(born_frameno_ / 2.0));
p->set_dead(dead);
p->set_health(GetHP());
p->set_max_health(GetMaxHP());
FillBuffList(hum, p->mutable_buff_list());
}
Human* Car::GetPassengerBySeat(int seat)
{
for (auto hum : passengers_) {
if (hum->GetSeat() == seat) {
return hum;
}
}
return nullptr;
}
void Car::GetDown(Human* passenger)
{
if (later_removed_) {
return;
}
if (passengers_.find(passenger) == passengers_.end()) {
return;
}
if (driver_ == passenger) {
driver_ = nullptr;
}
passengers_.erase(passenger);
passenger->SetCar(nullptr);
passenger->SetSeat(0);
passenger->second_weapon = Weapon();
passenger->CancelAction();
passenger->RemoveBuffByEffectId(kBET_Driver);
passenger->RemoveBuffByEffectId(kBET_Passenger);
room->frame_event.AddCarChg(passenger);
if (passengers_.empty()) {
team_id = 0;
room->TakeOffCarObject(GetEntityUniId(), GetPos());
RemoveBuffByEffectId(kBET_CarActive);
TryAddBuff(this, meta->car_deactive_buff_id);
if (meta->i->buffid() != 0) {
passenger->RemoveBuffById(meta->i->buffid());
}
}
SyncAroundPlayers(__FILE__, __LINE__, __func__);
room->NotifyUiUpdate();
}
void Car::GetOn(Human* passenger)
{
if (later_removed_) {
return;
}
if (meta->int_param2 <= 0) {
abort();
}
if (meta->int_param2 <= passengers_.size()) {
return;
}
if (passengers_.find(passenger) != passengers_.end()) {
return;
}
if (passenger->GetCar()) {
return;
}
for (auto hum : passengers_) {
if (hum->team_id != passenger->team_id) {
return;
}
}
if (passengers_.empty()) {
team_id = passenger->team_id;
}
int seat = AllocSeat();
if (seat < 0) {
return;
}
passengers_.insert(passenger);
if (!driver_) {
driver_ = passenger;
SetAttackDir(driver_->GetAttackDir());
}
passenger->SetCar(this);
passenger->SetSeat(seat);
passenger->SetPos(GetPos());
{
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff
(driver_ == passenger ? DRIVER_BUFFID : PASSENGER_BUFFID);
if (buff_meta) {
passenger->AddBuff(passenger, buff_meta, 1);
}
}
if (meta->i->buffid() != 0) {
passenger->TryAddBuff(passenger, meta->i->buffid());
}
passenger->CancelAction();
room->frame_event.AddCarChg(passenger);
if (passengers_.size() == 1) {
RemoveBuffByEffectId(kBET_CarDeactive);
TryAddBuff(this, meta->car_active_buff_id);
}
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
void Car::SwitchSeat(Human* passenger, int seat)
{
if (seat != 0) {
return;
}
if (driver_) {
return;
}
if (!IsPassenger(passenger)) {
return;
}
if (passenger->GetSeat() == seat) {
return;
}
if (GetPassengerBySeat(seat)) {
return;
}
if (!IsDriver(passenger)) {
passenger->RemoveBuffByEffectId(kBET_Passenger);
passenger->SetSeat(seat);
driver_ = passenger;
passenger->MustBeAddBuff(passenger, DRIVER_BUFFID);
room->frame_event.AddCarChg(passenger);
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
}
bool Car::CanShot(Human* passenger)
{
if (!IsPassenger(passenger)) {
return false;
}
return passenger->GetSeat() < meta->shoot_offsets.size() &&
std::get<0>(meta->shoot_offsets[passenger->GetSeat()]);
}
int Car::AllocSeat()
{
int seat = -1;
for (int i = 0; i < meta->int_param2; ++i) {
bool found = false;
for (auto hum : passengers_) {
if (hum->GetSeat() == i) {
found = true;
break;
}
}
if (!found) {
seat = i;
break;
}
}
return seat;
}
void Car::SyncPos()
{
if (driver_) {
SetPos(driver_->GetPos());
SetMoveDir(driver_->GetMoveDir());
for (auto hum : passengers_) {
if (hum != driver_) {
hum->SetPos(GetPos());
hum->SetMoveDir(GetMoveDir());
room->grid_service->MoveCreature(hum);
}
}
room->grid_service->MoveCreature(this);
}
}
float Car::GetRadius()
{
return hero_meta_->i->radius();
}
float Car::GetSpeed()
{
float speed = hero_meta_->i->move_speed();
return speed;
}
void Car::OnBulletHit(Bullet* bullet)
{
if (!IsDead(room)) {
float dmg = bullet->GetAtk() * (1 + bullet->sender.Get()->GetAttrRate(kHAT_Atk)) +
bullet->sender.Get()->GetAttrAbs(kHAT_Atk);
float def = ability.def * (1 + GetAttrRate(kHAT_Def)) +
GetAttrAbs(kHAT_Def);
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
finaly_dmg = std::max(finaly_dmg, 0.0f);
DecHP(finaly_dmg,
bullet->sender.Get()->GetEntityUniId(),
bullet->sender.Get()->GetName(),
bullet->gun_meta->i->id());
if (bullet->meta->buff_meta) {
MustBeAddBuff(this, bullet->meta->i->buffid());
}
}
}
void Car::DecHP(float dec_hp, int killer_id, const std::string& killer_name, int weapon_id)
{
if (dec_hp < 0.001f) {
return;
}
float old_health = GetHP();
float new_health = std::max(0.0f, GetHP() - dec_hp);
ability.hp = std::max(0.0f, new_health);
if (GetHP() <= 0.0001f && !IsDead(room)) {
BeKill(killer_id, killer_name, weapon_id);
}
room->frame_event.AddHpChg(GetWeakPtrRef());
float hp_rate = GetHP() / GetMaxHP();
int new_buff_idx = cur_buff_idx_;
while (new_buff_idx + 1 < meta->car_buff_list.size()) {
if (hp_rate > std::get<0>(meta->car_buff_list[new_buff_idx + 1])) {
break;
}
++new_buff_idx;
}
if (new_buff_idx != cur_buff_idx_) {
if (cur_buff_id_ != 0) {
RemoveBuffById(cur_buff_id_);
}
cur_buff_idx_ = new_buff_idx;
cur_buff_id_ = std::get<1>(meta->car_buff_list[cur_buff_idx_]);
if (cur_buff_id_ != 0) {
MustBeAddBuff(this, cur_buff_id_);
#ifdef DEBUG
#endif
}
}
}
void Car::BeKill(int killer_id, const std::string& killer_name, int weapon_id)
{
dead = true;
BroadcastDeleteState(room);
RemoveFromAroundPlayers(room);
room->grid_service->RemoveCreature(this);
room->RemoveObjectLater(this);
int team_id = 0;
for (Human* passenger : passengers_) {
team_id = passenger->team_id;
passenger->SetCar(nullptr);
passenger->SetSeat(0);
passenger->second_weapon = Weapon();
passenger->CancelAction();
passenger->RemoveBuffByEffectId(kBET_Driver);
passenger->RemoveBuffByEffectId(kBET_Passenger);
room->frame_event.AddCarChg(passenger);
}
Explosion(team_id);
}
void Car::GetAabbBox(AabbCollider& aabb_box)
{
aabb_box.active = true;
aabb_box.owner = this;
aabb_box._min.x = -hero_meta_->i->radius();
aabb_box._min.y = -hero_meta_->i->radius();
aabb_box._max.x = hero_meta_->i->radius();
aabb_box._max.y = hero_meta_->i->radius();
}
void Car::Explosion(int team_id)
{
if (meta->i->explosion_range() <= 0) {
return;
}
std::set<Creature*> objects;
TraverseProperTargetsNoTeammate
(
[this, &objects, team_id] (Creature* c, bool& stop)
{
float distance = (c->GetPos() - GetPos()).Norm();
if (distance < meta->i->explosion_range()) {
objects.insert(c);
}
});
room->frame_event.AddExplosionEx(GetWeakPtrRef(),
0,
GetPos(),
meta->i->explosion_effect());
for (auto& target : objects) {
switch (target->GetEntityType()) {
case ET_Player:
{
Human* hum = (Human*)target;
if (!hum->dead) {
float dmg = meta->i->atk();
float def = hum->ability.def;
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
hum->DecHP(finaly_dmg, VP_Mine, TEXT("battle_server_killer_mine", "地雷"), VW_Mine);
}
}
break;
default:
{
}
break;
}
}
}
void Car::SendDebugMsg(const std::string& debug_msg)
{
#if 1
room->BroadcastDebugMsg("载具debugmsg: " + debug_msg);
#else
for (auto& passenger : passengers_) {
passenger->SendDebugMsg("载具debugmsg: " + debug_msg);
}
#endif
}
bool Car::IsPassenger(Human* hum)
{
return passengers_.find(hum) != passengers_.end();
}