395 lines
11 KiB
C++
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();
|
|
}
|